跳至內容
出自 Arch Linux 中文维基

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

原因:缺少詳細提示(在Talk:Kubernetes討論)

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

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


安裝

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

部署工具

kubeadm

如果要使用 kubeadm 來引導 Kubernetes 集群,請在每一個節點上 安裝 kubeadmkubelet

手動配置

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

集群管理

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

容器運行時

控制平面節點和常規 worker 節點都需要一個容器運行時以運行 kubelet 實例。 安裝 containerdcri-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.servicekube-controller-manager.servicekube-proxy.servicekube-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 initkubeadm join

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

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

Containerd

在 Kubernetes 1.27.4 版本之前,當使用 containerd 作為容器運行時,需要向 kubeadm initkubeadm 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 initkubeadm 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 initkubeadm 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.servicekube-controller-manager.servicekube-proxy.servicekube-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.servicekubelet.service

提示與技巧

拆除集群

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

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

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

隨後重置該節點:

# kubeadm reset

在代理後方操作

kubeadm 會讀取 https_proxyhttp_proxyno_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.servicekubelet.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 以解決此問題。

參見