Kubernetes - Arch Linux 中文维基

跳至內容

# Kubernetes

出自 Arch Linux 中文维基
翻譯狀態：

- 本文（或部分內容）譯自 Kubernetes，最近一次同步於 2025-02-12，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

本文或本章節的語言、語法或風格需要改進。參考：幫助:風格

原因：缺少詳細提示（在Talk:Kubernetes討論）

Kubernetes (簡稱k8s)是一套用於自動部署，擴展以及管理容器化應用的開源系統。

k8s集群由一個控制平面組件和一個或多個節點組件構成(每個組件代表一台或多台運行容器運行時和 `kubelet.service` 服務的主機機器)。安裝 Kubernetes 有兩種選擇：一種是更為正統的Kubernetes安裝方式（此處所描述的方式），另一種則是使用 k3s，kind 或者 minikube包 進行本地安裝。

## 安裝

配置一個 Kubernetes 集群的方法有很多，本文將主要介紹如何使用 kubeadm包 進行配置。

### 部署工具

#### kubeadm

如果要使用 kubeadm 來引導 Kubernetes 集群，請在每一個節點上安裝 kubeadm包 和 kubelet包。

#### 手動配置

如你想要手動創建一個 Kubernetes 集群，請安裝 etcdAUR，並安裝軟體包組 kubernetes-control-plane包組 (在控制平面節點) 或 kubernetes-node包組 (在 worker 節點)。

#### 集群管理

要管理一個 Kubernetes 集群，請在控制平面節點和要與集群交互的主機上安裝 kubectl包。

### 容器運行時

控制平面節點和常規 worker 節點都需要一個容器運行時以運行 `kubelet` 實例。 安裝 containerd包 或 cri-o包 來提供一個運行時。

#### containerd 運行時

有兩種方式可以安裝 containerd:

1. 安裝 containerd包 軟體包。
2. 安裝非特權模式(rootless)containerd，你需要安裝 nerdctl-full-binAUR，其是一個完整的 nerdctl 包（containerd，CNI 插件，和 RootlessKit）。隨後你需要運行 `containerd-rootless-setuptool.sh install` 以安裝非特權模式 containerd。

請注意，由於 Arch Linux 使用 systemd 作為 init 系統，你需要在部署控制平面之前選擇 systemd cgroup 驅動。

### (可選) 包管理器

helm包 是一個用於管理預配置的 Kubernetes 資源的工具，這可能會有所幫助。

## 配置

集群中的所有節點（控制平面和工作節點）都需要運行一個 `kubelet.service` 實例。

提示：在啟動 `kubelet.service` 或使用 `kubeadm` 之前，請仔細閱讀以下小節。

所有提供的 systemd 服務都允許通過環境文件進行命令行參數覆蓋：

- `kubelet.service`: `/etc/kubernetes/kubelet.env`
- `kube-apiserver.service`: `/etc/kubernetes/kube-apiserver.env`
- `kube-controller-manager.service`: `/etc/kubernetes/kube-controller-manager.env`
- `kube-proxy.service`: `/etc/kubernetes/kube-proxy.env`
- `kube-scheduler.service`: `/etc/kubernetes/kube-scheduler.env`

這篇文章的某些內容需要擴充。

原因：

- 不使用 `kubeadm` 的配置示例，使用 `kube-apiserver.service`、`kube-controller-manager.service`、`kube-proxy.service` 和 `kube-scheduler.service`。
- 使用 配置文件 來進行對 `kubeadm` 的配置。

(在 Talk:Kubernetes 中討論)

### 禁用交換分區

Kubernetes 目前不支持在系統上啟用交換分區。詳情請參閱 KEP-2400: 節點系統交換支持。

有關如何禁用交換分區的說明，請參閱 Swap#關閉交換分區。

### 為 containerd 選擇 cgroup 驅動

如要在使用 `runc` 時，同時也在 `/etc/containerd/config.toml` 中使用 `systemd` cgroup 驅動，請設置：

    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
      ...
      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
        SystemdCgroup = true

如果 `/etc/containerd/config.toml` 不存在，可以使用以下命令生成默認配置：

    # mkdir -p /etc/containerd/
    # containerd config default > /etc/containerd/config.toml

請記住重啟 `containerd.service` 以使更改生效。

有關是否保留 `cgroupfs` 驅動或使用 `systemd` cgroup 驅動的深入討論，請參閱官方文檔。

### 選擇容器運行時接口 (CRI)

在使用 `kubelet.service` 之前，必須配置並啟動容器運行時。

你需要在創建或加入集群時，將帶有容器運行時接口端點的標誌 `--cri-socket` 傳遞給 `kubeadm init` 或 `kubeadm join`。

例如，如果你選擇 containerd包 作為 CRI 運行時，則在創建時附帶上`--cri-socket`標誌：

    kubeadm init --cri-socket /run/containerd/containerd.sock

#### Containerd

在 Kubernetes 1.27.4 版本之前，當使用 containerd包 作為容器運行時，需要向 `kubeadm init` 或 `kubeadm join` 提供其 CRI 端點。為此，請將其 `--cri-socket` 標誌指定為 `/run/containerd/containerd.sock`[1]。

    kubeadm join --cri-socket=/run/containerd/containerd.sock

在 Kubernetes 1.27.4 版本之後，kubeadm 將自動檢測此 CRI，只有在安裝了多個 CRI 時才需要 `--cri-socket` 標誌。

#### CRI-O

當使用 CRI-O 作為容器運行時，需要向 `kubeadm init` 或 `kubeadm join` 提供其 CRI 端點：`--cri-socket='unix:///run/crio/crio.sock'`

### 選擇集群網絡參數

#### 選擇 Pod CIDR 範圍

必須為相應的容器運行時配置集群的網絡設置。這可以使用 cni-plugins包 來完成。

Pod CIDR 地址指的是分配給 Kubernetes 集群中 Pod 的 IP 地址範圍。當 Pod 被調度到集群中的節點上運行時，它們會從此 CIDR 範圍中分配 IP 地址。

Pod CIDR 範圍在部署 Kubernetes 集群時指定，並且僅限於集群網絡內。它不應與集群中使用的其他 IP 範圍（例如如service CIDR 範圍）重疊。

你將向 `kubeadm init` 或 `kubeadm join` 傳遞 `--pod-network-cidr` 標誌，並指定虛擬網絡的 CIDR 值，以創建或加入集群。

例如：

    kubeadm init --pod-network-cidr='10.85.0.0/16'

會將你的 Kubernetes Pod CIDR 範圍設置為 `10.85.0.0/16`。

#### （可選）選擇 API 伺服器廣播地址

如果你的控制平面節點位於多個子網中（例如，你可能安裝了 Tailscale tailnet），在使用 kubeadm init 初始化 Kubernetes 主節點時，你可以使用 `--apiserver-advertise-address` 標誌指定 API 伺服器將廣播的 IP 地址。注意，此 IP 地址應可被集群中的所有節點訪問。

#### （可選）選擇其他的節點網絡代理提供者

節點代理提供者（如 `kube-proxy`）是在集群中每個節點上運行的網絡代理，用於維護節點上的網絡規則，以允許從集群內部或外部的網絡會話與你的 Pod 進行網絡通信。

默認情況下，kubeadm包 選擇 `kube-proxy` 作為在集群中每個節點上運行的節點代理。

容器網絡接口 (CNI) 插件（如 Cilium）提供了 kube-proxy 的完整替代方案。

如果你想使用 Cilium 的節點網絡代理實現以充分利用 Cilium 的網絡策略功能，你應向 `kubeadm init` 傳遞 `--skip-phases=addon/kube-proxy` 標誌，以跳過 kube-proxy 的安裝。

Cilium 將在其安裝過程中安裝完整的替代方案。詳情請參閱 [2]。

## 創建集群

在使用 `kubeadm` 創建新的 Kubernetes 集群之前，請先啟動並啟用 `kubelet.service`。

注意：`kubelet.service` 會失敗（但會重啟），直到為其提供配置。

這篇文章的某些內容需要擴充。

原因：

- 不使用 `kubeadm` 進行設置的示例，使用 `kube-apiserver.service`、`kube-controller-manager.service`、`kube-proxy.service` 和 `kube-scheduler.service`。
- 使用 `kubeadm` 進行設置的示例，使用 配置文件。

(在 Talk:Kubernetes 中討論)

### 不使用配置文件的 kubeadm

在使用 `kubeadm` 創建新的 Kubernetes 集群時，必須先創建一個控制平面，然後其他工作節點才能加入。

提示：

- 如果集群以後要轉換為 高可用性 集群（堆疊式 etcd 拓撲），則需要在 `kubeadm init` 時提供 `--control-plane-endpoint=<IP 或域名>`（無法事後進行此操作！）。
- 可以使用 配置文件 來代替一組參數進行 `kubeadm init`。

#### 初始化控制平面

要初始化控制平面，你需要向 `kubeadm init` 傳遞以下必要的標誌。

如果成功運行，`kubeadm init` 將在 `/etc/kubernetes/` 和 `/var/lib/kubelet/` 下生成 `kubelet` 和各種控制平面組件的配置。

最後，它將輸出可以複製並粘貼的命令，用於設置 kubectl包 並使工作節點加入集群（基於有效期為 24 小時的令牌）。

要將 `kubectl` 與剛創建的控制平面節點一起使用，請設置配置（以 root 或普通用戶身份）：

    $ mkdir -p $HOME/.kube
    # cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    # chown $(id -u):$(id -g) $HOME/.kube/config

#### 安裝 CNI 插件（Pod 網絡插件）

注意：你必須部署一個基於 Container Network Interface (CNI) 的 Pod 網絡插件，以便你的 Pod 可以相互通信。集群 DNS (CoreDNS) 在網絡安裝之前不會啟動。

Pod 網絡插件（CNI 插件）以不同的方式實現 Kubernetes 網絡模型，從簡單的解決方案如 flannel 到更複雜的解決方案如 calico。有關更多選項，請參閱此列表。

一個日益被採用的高級 CNI 插件是 cilium，它通過 eBPF 實現了令人印象深刻的性能。要安裝 `cilium` 作為 CNI 插件，請使用 cilium-cli包：

    # cilium-cli install

這將創建 `/opt/cni/bin/cilium-cni` 插件、配置文件 `/etc/cni/net.d/05-cilium.conflist`，並在 Kubernetes 集群上部署兩個 Pod。

注意：如果你使用 CRI-O，請確保已啟用 `/opt/cni/bin/` 插件目錄。請參閱 CRI-O#Plugin directories。

### 使用配置文件的 kubeadm

你很可能會發現，創建控制平面需要多次嘗試才能找到適合你特定設置的最佳配置。為了使此過程更容易（並且使 kubeadm包 的過程更具可重複性），你可以使用配置文件運行初始化步驟。

提示：計劃使用兩個配置文件，一個用於初始化，一個用於重置，以便更快地測試配置。

#### 創建初始化配置文件

你可以在任何地方創建此文件，但在此示例中我們將使用 `/etc/kubeadm`。

    # mkdir -pv /etc/kubeadm
    # cd /etc/kubeadm
    # kubeadm config print init-defaults > init.yaml

這將生成以下文件。

    /etc/kubeadm/init.yaml

    apiVersion: kubeadm.k8s.io/v1beta3
    bootstrapTokens:
    - groups:
      - system:bootstrappers:kubeadm:default-node-token
      token: abcdef.0123456789abcdef
      ttl: 24h0m0s
      usages:
      - signing
      - authentication
    kind: InitConfiguration
    localAPIEndpoint:
      advertiseAddress: 1.2.3.4
      bindPort: 6443
    nodeRegistration:
      criSocket: unix:///var/run/containerd/containerd.sock
      imagePullPolicy: IfNotPresent
      name: node
      taints: null
    ---
    apiServer:
      timeoutForControlPlane: 4m0s
    apiVersion: kubeadm.k8s.io/v1beta3
    certificatesDir: /etc/kubernetes/pki
    clusterName: kubernetes
    controllerManager: {}
    dns: {}
    etcd:
      local:
        dataDir: /var/lib/etcd
    imageRepository: registry.k8s.io
    kind: ClusterConfiguration
    kubernetesVersion: 1.29.0
    networking:
      dnsDomain: cluster.local
      serviceSubnet: 10.96.0.0/12
    scheduler: {}

大多數默認設置應該可以工作，但你需要更新其中的一些設置。

##### 引導令牌

使用 `kubeadm token generate` 創建一個令牌，並在配置中使用它代替 `token: abcdef.0123456789abcdef`。

##### 公告地址

`advertiseAddress: 1.2.3.4` 應該是正在初始化的控制平面的網絡接口的 IPv4 地址，可能是 `192.168.0.0/16` 子網中的某個地址。

##### 節點名稱

默認節點名稱可以保留為 `node` 並添加到本地 DNS 伺服器或 hosts 文件中，或者你可以將其更改為本地網絡上可路由的地址。它應該是一個 DNS 兼容的主機名，例如 `kcp01.example.com`。這將允許你的控制平面在加入其他節點時在本地網絡上被發現。

#### 初始化集群

完成所有這些更改後，我們可以初始化我們的集群。

    # kubeadm init --config /etc/kubeadm/init.yaml

這將產生大量輸出，輸出提供了有關如何將節點加入集群、更新 kubeconfig 以與新集群交互以及其他任務的說明。

##### 使用 calico 進行 CNI 配置

在開始添加節點和運行工作負載之前，你最後需要的東西是 正確配置的 CNI。此示例將使用 calico 來實現這一點。

    # cd /etc/cni/net.d
    # curl https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/calico.yaml -O
    # kubectl create -f calico.yaml

如果此操作成功完成，你就可以開始添加節點並在集群上運行工作負載啦。

#### 創建重置配置文件

為防止 kubeadm包 第一次初始化不成功，你還可以創建一個用於重置命令的配置文件：

    # kubeadm config print reset-defaults > /etc/kubeadm/reset.yaml

這將創建以下文件：

    /etc/kubeadm/reset.yaml

    apiVersion: kubeadm.k8s.io/v1beta4
    certificatesDir: /etc/kubernetes/pki
    criSocket: unix:///var/run/containerd/containerd.sock
    kind: ResetConfiguration

##### 重置集群

要將集群重置為零，請運行以下命令：

    # kubeadm reset --config /etc/kubeadm/reset.yaml

可以根據需要多次執行此操作，以確定集群的理想配置。

#### 創建加入配置文件

很可能在初始化集群後，你可以使用 init 命令輸出中列出的命令加入任何節點，但如果你遇到問題，在要加入的節點上準備一個加入配置文件將會很有幫助。你可以在控制平面上創建此文件，或者在要加入集群的節點上運行命令，我們假設你執行了後者。

    # kubeadm config print join-defaults > /etc/kubeadm/join.yaml

這將創建以下文件。

    /etc/kubeadm/join.yaml

    apiVersion: kubeadm.k8s.io/v1beta3
    caCertPath: /etc/kubernetes/pki/ca.crt
    discovery:
      bootstrapToken:
        apiServerEndpoint: kcp01.example.com:6443
        token: abcdef.0123456789abcdef
        unsafeSkipCAVerification: true
      timeout: 5m0s
      tlsBootstrapToken: abcdef.0123456789abcdef
    kind: JoinConfiguration
    nodeRegistration:
      criSocket: unix:///var/run/containerd/containerd.sock
      imagePullPolicy: IfNotPresent
      name: node01.example.com
      taints: null

注意：你需要為此配置文件創建兩個不同的令牌，第一個用於 `discovery.bootstrapToken.token`，第二個用於 `discovery.tlsBootstrapToken` 屬性。

## 加入集群

使用在#創建集群中生成的令牌信息，可以通過命令 `kubeadm join` 使另一台機器作為工作節點加入集群。

請記住，你還需要通過將標誌 `<SOCKET>` 傳遞給命令 `kubeadm join` 來為工作節點選擇容器運行時接口。

例如：

    # kubeadm join <api-server-ip>:<port> --token <token> --discovery-token-ca-cert-hash sha256:<hash> --node-name=<name_of_the_node> --cri-socket=<SOCKET>

要生成新的引導令牌，可以使用以下命令：

    kubeadm token create --print-join-command

如果你使用 Cilium 並且發現工作節點仍然處於 `NotReady` 狀態，請使用以下命令檢查工作節點的狀態：

    kubectl describe node <node-id> --namespace=kube-system

如果你發現以下條件狀態：

    Type                  Status       Reason
    ----                  ------       ------
    NetworkUnavailable    False        CiliumIsUp
    Ready                 False        KubeletNotReady container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized

請在工作節點上重啟 `containerd.service` 和 `kubelet.service`。

## 提示與技巧

### 拆除集群

當需要從頭開始重建集群時，可使用 kubectl包 按官方文檔拆除集群的步驟操作：

    kubectl drain <节点名称> --delete-local-data --force --ignore-daemonsets

此處 `<節點名稱>` 是需要清空並重置的節點名稱，可通過 `kubectl get node -A` 列出所有節點。

隨後重置該節點：

    # kubeadm reset

### 在代理後方操作

`kubeadm` 會讀取 `https_proxy`、`http_proxy` 和 `no_proxy` 環境變量。需確保 Kubernetes 內部網絡包含在 `no_proxy` 中，例如：

    export no_proxy="192.168.122.0/24,10.96.0.0/12,192.168.123.0/24"

其中第二個 CIDR（10.96.0.0/12）是 Kubernetes 默認的服務網絡地址段。

## 故障排除

### 無法獲取容器統計信息

如果 `kubelet.service` 輸出以下錯誤：

    Failed to get system container stats for "/system.slice/kubelet.service": failed to get cgroup stats for "/system.slice/kubelet.service": failed to get container info for "/system.slice/kubelet.service": unknown container "/system.slice/kubelet.service"

則需要為 kubelet 添加配置（參見相關的上游問題）。

    /var/lib/kubelet/config.yaml

    systemCgroups: '/systemd/system.slice'
    kubeletCgroups: '/systemd/system.slice'

### 使用 Flannel CNI 和 systemd-networkd 時 Pod 無法通信

參見上游問題報告。

systemd-networkd 會為每個連結分配一個持久的 MAC 地址。此策略在其默認配置文件 `/usr/lib/systemd/network/99-default.link` 中定義。然而，Flannel 依賴於能夠選擇自己的 MAC 地址。要覆蓋 systemd-networkd 對 `flannel*` 接口的行為，請創建以下配置文件：

    /etc/systemd/network/50-flannel.link

    [Match]
    OriginalName=flannel*

    [Link]
    MACAddressPolicy=none

然後重啟 `systemd-networkd.service`。

如果集群已經在運行，你可能需要手動刪除每個節點上的 `flannel.1` 接口和 `kube-flannel-ds-*` Pod，包括主節點。Pod 會立即重新創建，並且它們自己會重新創建 `flannel.1` 接口。

刪除 `flannel.1` 接口：

    # ip link delete flannel.1

刪除 `kube-flannel-ds-*` Pod。使用以下命令刪除所有節點上的所有 `kube-flannel-ds-*` Pod：

    $ kubectl -n kube-system delete pod -l="app=flannel"

### CoreDNS Pod 一直處於 Pending 狀態，控制平面節點保持 "NotReady"

當在單台機器上使用 `kubeadm init` 引導 Kubernetes 時，如果沒有其他機器 `kubeadm join` 集群，控制平面節點默認會被添加上污點（Taint）。因此，工作負載將不會調度到該機器上。

可以通過以下命令確認控制平面節點是否被添加了污點：

    kubectl get nodes -o json | jq '.items[].spec.taints

要臨時允許在控制平面節點上調度，執行：

    kubectl taint nodes <your-node-name> node-role.kubernetes.io/control-plane:NoSchedule-

然後重啟 `containerd.service` 和 `kubelet.service` 以應用更新。

### [kubelet-finalize] 畸形頭：缺少 HTTP content-type

你可能忘記了選擇 systemd cgroup 驅動。參見 kubeadm 問題 2767 報告此問題。

### CoreDNS Pod 由於循環無法啟動

當主機節點運行本地 DNS 緩存（如 systemd-resolved）時，CoreDNS 可能會由於檢測到轉發循環而無法啟動。可以通過以下方式檢查：

    # kubectl get pods -n kube-system

    NAME                               READY   STATUS             RESTARTS      AGE
    cilium-jc98m                       1/1     Running            0             21m
    cilium-operator-64664858c8-zjzcq   1/1     Running            0             21m
    coredns-7db6d8ff4d-29zfg           0/1     CrashLoopBackOff   6 (41s ago)   21m
    coredns-7db6d8ff4d-zlvsm           0/1     CrashLoopBackOff   6 (50s ago)   21m
    etcd-k8s                           1/1     Running            19            21m
    kube-apiserver-k8s                 1/1     Running            17            21m
    kube-controller-manager-k8s        1/1     Running            16            21m
    kube-proxy-cvntt                   1/1     Running            0             21m
    kube-scheduler-k8s                 1/1     Running            23            21m

    # kubectl logs -n kube-system coredns-7db6d8ff4d-29zfg

    ...
    [FATAL] plugin/loop: Loop ([::1]:46171 -> :53) detected for zone ".", see https://coredns.io/plugins/loop#troubleshooting. Query: "HINFO 64811921068182325.3042126689798234092."

這是由於 kubelet 將主機的 `/etc/resolv.conf` 文件傳遞給所有使用默認 `dnsPolicy` 的 Pod。CoreDNS 使用此 `/etc/resolv.conf` 作為上游轉發請求的列表。由於它包含一個環回地址（如 127.0.0.53），CoreDNS 最終將請求轉發給自己。

參見 https://coredns.io/plugins/loop/#troubleshooting 以解決此問題。

## 參見

- Kubernetes Documentation - The upstream documentation
- Kubernetes Cluster with Kubeadm - Upstream documentation on how to setup a Kubernetes cluster using kubeadm
- Kubernetes Glossary - The official glossary explaining all Kubernetes specific terminology
- Kubernetes Addons - A list of third-party addons
- Kubelet Config File - Documentation on the Kubelet configuration file
- Taints and Tolerations - Documentation on node affinities and taints

分類：​

- 虛擬化
- 使用「模板:風格」標記的頁面或章節

Kubernetes
新增話題