Kubernetes 對kubeadm進(jìn)行故障排查

2022-06-01 09:01 更新

對 kubeadm 進(jìn)行故障排查

與任何程序一樣,你可能會在安裝或者運(yùn)行 kubeadm 時(shí)遇到錯(cuò)誤。 本文列舉了一些常見的故障場景,并提供可幫助你理解和解決這些問題的步驟。

如果你的問題未在下面列出,請執(zhí)行以下步驟:

  • 如果你認(rèn)為問題是 kubeadm 的錯(cuò)誤:
  • 如果你對 kubeadm 的工作方式有疑問,可以在 Slack 上的 ?#kubeadm? 頻道提問, 或者在 StackOverflow 上提問。 請加入相關(guān)標(biāo)簽,例如 ?#kubernetes? 和 ?#kubeadm?,這樣其他人可以幫助你。

由于缺少 RBAC,無法將 v1.18 Node 加入 v1.17 集群

自從 v1.18 后,如果集群中已存在同名 Node,kubeadm 將禁止 Node 加入集群。 這需要為 bootstrap-token 用戶添加 RBAC 才能 GET Node 對象。

但這會導(dǎo)致一個(gè)問題,v1.18 的 ?kubeadm join? 無法加入由 kubeadm v1.17 創(chuàng)建的集群。

要解決此問題,你有兩種選擇:

使用 kubeadm v1.18 在控制平面節(jié)點(diǎn)上執(zhí)行 ?kubeadm init phase bootstrap-token?。 請注意,這也會啟用 bootstrap-token 的其余權(quán)限。

或者,也可以使用 ?kubectl apply -f ...? 手動應(yīng)用以下 RBAC:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kubeadm:get-nodes
rules:
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubeadm:get-nodes
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kubeadm:get-nodes
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:bootstrappers:kubeadm:default-node-token

在安裝過程中沒有找到 ebtables 或者其他類似的可執(zhí)行文件

如果在運(yùn)行 ?kubeadm init? 命令時(shí),遇到以下的警告

[preflight] WARNING: ebtables not found in system path
[preflight] WARNING: ethtool not found in system path

那么或許在你的節(jié)點(diǎn)上缺失 ?ebtables?、?ethtool ?或者類似的可執(zhí)行文件。 你可以使用以下命令安裝它們:

  • 對于 Ubuntu/Debian 用戶,運(yùn)行 ?apt install ebtables ethtool? 命令。
  • 對于 CentOS/Fedora 用戶,運(yùn)行 ?yum install ebtables ethtool? 命令。

在安裝過程中,kubeadm 一直等待控制平面就緒

如果你注意到 ?kubeadm init? 在打印以下行后掛起:

[apiclient] Created API client, waiting for the control plane to become ready

這可能是由許多問題引起的。最常見的是:

  • 網(wǎng)絡(luò)連接問題。在繼續(xù)之前,請檢查你的計(jì)算機(jī)是否具有全部聯(lián)通的網(wǎng)絡(luò)連接。
  • 容器運(yùn)行時(shí)的 cgroup 驅(qū)動不同于 kubelet 使用的 cgroup 驅(qū)動。
  • 控制平面上的 Docker 容器持續(xù)進(jìn)入崩潰狀態(tài)或(因其他原因)掛起。你可以運(yùn)行 docker ps 命令來檢查以及 docker logs 命令來檢視每個(gè)容器的運(yùn)行日志。 

當(dāng)刪除托管容器時(shí) kubeadm 阻塞 

如果容器運(yùn)行時(shí)停止并且未刪除 Kubernetes 所管理的容器,可能發(fā)生以下情況:

sudo kubeadm reset
[preflight] Running pre-flight checks
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
[reset] Removing kubernetes-managed containers
(block)

一個(gè)可行的解決方案是重新啟動 Docker 服務(wù),然后重新運(yùn)行 ?kubeadm reset?: 你也可以使用 ?crictl ?來調(diào)試容器運(yùn)行時(shí)的狀態(tài)。

Pods 處于 RunContainerError、CrashLoopBackOff 或者 Error 狀態(tài)

在 ?kubeadm init? 命令運(yùn)行后,系統(tǒng)中不應(yīng)該有 pods 處于這類狀態(tài)。

  • 在 ?kubeadm init? 命令執(zhí)行完后,如果有 pods 處于這些狀態(tài)之一,請?jiān)?nbsp;kubeadm 倉庫提起一個(gè) issue。?coredns ?(或者 ?kube-dns?) 應(yīng)該處于 ?Pending ?狀態(tài), 直到你部署了網(wǎng)絡(luò)插件為止。
  • 如果在部署完網(wǎng)絡(luò)插件之后,有 Pods 處于 ?RunContainerError?、?CrashLoopBackOff ?或 ?Error ?狀態(tài)之一,并且 ?coredns ?(或者 ?kube-dns?)仍處于 ?Pending ?狀態(tài), 那很可能是你安裝的網(wǎng)絡(luò)插件由于某種原因無法工作。你或許需要授予它更多的 RBAC 特權(quán)或使用較新的版本。請?jiān)?nbsp;Pod Network 提供商的問題跟蹤器中提交問題, 然后在此處分類問題。
  • 如果你安裝的 Docker 版本早于 1.12.1,請?jiān)谑褂?nbsp;?systemd ?來啟動 ?dockerd ?和重啟 ?docker ?時(shí), 刪除 ?MountFlags=slave? 選項(xiàng)。 你可以在 ?/usr/lib/systemd/system/docker.service? 中看到 MountFlags。 MountFlags 可能會干擾 Kubernetes 掛載的卷,并使 Pods 處于 ?CrashLoopBackOff ?狀態(tài)。 當(dāng) Kubernetes 不能找到 ?var/run/secrets/kubernetes.io/serviceaccount? 文件時(shí)會發(fā)生錯(cuò)誤。

coredns 停滯在 Pending 狀態(tài)

這一行為是 預(yù)期之中 的,因?yàn)橄到y(tǒng)就是這么設(shè)計(jì)的。 kubeadm 的網(wǎng)絡(luò)供應(yīng)商是中立的,因此管理員應(yīng)該選擇 安裝 pod 的網(wǎng)絡(luò)插件。 你必須完成 Pod 的網(wǎng)絡(luò)配置,然后才能完全部署 CoreDNS。 在網(wǎng)絡(luò)被配置好之前,DNS 組件會一直處于 ?Pending ?狀態(tài)。

HostPort 服務(wù)無法工作

此 ?HostPort ?和 ?HostIP ?功能是否可用取決于你的 Pod 網(wǎng)絡(luò)配置。請聯(lián)系 Pod 網(wǎng)絡(luò)插件的作者, 以確認(rèn) ?HostPort ?和 ?HostIP ?功能是否可用。

已驗(yàn)證 Calico、Canal 和 Flannel CNI 驅(qū)動程序支持 HostPort。

有關(guān)更多信息,請參考 CNI portmap 文檔.

如果你的網(wǎng)絡(luò)提供商不支持 portmap CNI 插件,你或許需要使用 NodePort 服務(wù)的功能 或者使用 ?HostNetwork=true?。

無法通過其服務(wù) IP 訪問 Pod

  • 許多網(wǎng)絡(luò)附加組件尚未啟用 hairpin 模式 該模式允許 Pod 通過其服務(wù) IP 進(jìn)行訪問。這是與 CNI 有關(guān)的問題。 請與網(wǎng)絡(luò)附加組件提供商聯(lián)系,以獲取他們所提供的 hairpin 模式的最新狀態(tài)。
  • 如果你正在使用 VirtualBox (直接使用或者通過 Vagrant 使用),你需要 確保 ?hostname -i? 返回一個(gè)可路由的 IP 地址。默認(rèn)情況下,第一個(gè)接口連接不能路由的僅主機(jī)網(wǎng)絡(luò)。 解決方法是修改 ?/etc/hosts?,請參考示例 Vagrantfile。

TLS 證書錯(cuò)誤

以下錯(cuò)誤指出證書可能不匹配。

# kubectl get pods
Unable to connect to the server: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "kubernetes")
  • 驗(yàn)證 ?$HOME/.kube/config? 文件是否包含有效證書,并 在必要時(shí)重新生成證書。在 kubeconfig 文件中的證書是 base64 編碼的。 該 ?base64 --decode? 命令可以用來解碼證書,?openssl x509 -text -noout? 命令 可以用于查看證書信息。
  • 使用如下方法取消設(shè)置 ?KUBECONFIG ?環(huán)境變量的值:
  • unset KUBECONFIG
    

    或者將其設(shè)置為默認(rèn)的 ?KUBECONFIG ?位置:

    export KUBECONFIG=/etc/kubernetes/admin.conf
    
  • 另一個(gè)方法是覆蓋 ?kubeconfig ?的現(xiàn)有用戶 "管理員":
  • mv  $HOME/.kube $HOME/.kube.bak
    mkdir $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

Kubelet 客戶端證書輪換失敗 

默認(rèn)情況下,kubeadm 使用 ?/etc/kubernetes/kubelet.conf? 中指定的 ?/var/lib/kubelet/pki/kubelet-client-current.pem? 符號鏈接 來配置 kubelet 自動輪換客戶端證書。如果此輪換過程失敗,你可能會在 kube-apiserver 日志中看到 諸如 ?x509: certificate has expired or is not yet valid? 之類的錯(cuò)誤。要解決此問題,你必須執(zhí)行以下步驟:

  1. 從故障節(jié)點(diǎn)備份和刪除 ?/etc/kubernetes/kubelet.conf? 和 ?/var/lib/kubelet/pki/kubelet-client*?。
  2. 在集群中具有 ?/etc/kubernetes/pki/ca.key? 的、正常工作的控制平面節(jié)點(diǎn)上 執(zhí)行 ?kubeadm kubeconfig user --org system:nodes --client-name system:node:$NODE > kubelet.conf?。 ?$NODE? 必須設(shè)置為集群中現(xiàn)有故障節(jié)點(diǎn)的名稱。 手動修改生成的 ?kubelet.conf? 以調(diào)整集群名稱和服務(wù)器端點(diǎn), 或傳遞 ?kubeconfig user --config?(此命令接受 ?InitConfiguration?)。 如果你的集群沒有 ?ca.key?,你必須在外部對 ?kubelet.conf? 中的嵌入式證書進(jìn)行簽名。
  3. 將得到的 ?kubelet.conf? 文件復(fù)制到故障節(jié)點(diǎn)上,作為 ?/etc/kubernetes/kubelet.conf?。
  4. 在故障節(jié)點(diǎn)上重啟 kubelet(?systemctl restart kubelet?),等待 ?/var/lib/kubelet/pki/kubelet-client-current.pem? 重新創(chuàng)建。
  5. 手動編輯 ?kubelet.conf? 指向輪換的 kubelet 客戶端證書,方法是將 ?client-certificate-data? 和 ?client-key-data? 替換為:
  6. client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
    client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
  7. 重新啟動 kubelet。
  8. 確保節(jié)點(diǎn)狀況變?yōu)?nbsp;?Ready?。

在 Vagrant 中使用 flannel 作為 pod 網(wǎng)絡(luò)時(shí)的默認(rèn) NIC

以下錯(cuò)誤可能表明 Pod 網(wǎng)絡(luò)中出現(xiàn)問題:

Error from server (NotFound): the server could not find the requested resource
  • 如果你正在 Vagrant 中使用 flannel 作為 pod 網(wǎng)絡(luò),則必須指定 flannel 的默認(rèn)接口名稱。
  • Vagrant 通常為所有 VM 分配兩個(gè)接口。第一個(gè)為所有主機(jī)分配了 IP 地址 ?10.0.2.15?,用于獲得 NATed 的外部流量。

    這可能會導(dǎo)致 flannel 出現(xiàn)問題,它默認(rèn)為主機(jī)上的第一個(gè)接口。這導(dǎo)致所有主機(jī)認(rèn)為它們具有 相同的公共 IP 地址。為防止這種情況,傳遞 ?--iface eth1? 標(biāo)志給 flannel 以便選擇第二個(gè)接口。

容器使用的非公共 IP

在某些情況下 ?kubectl logs? 和 ?kubectl run? 命令或許會返回以下錯(cuò)誤,即便除此之外集群一切功能正常:

Error from server: Get https://10.19.0.41:10250/containerLogs/default/mysql-ddc65b868-glc5m/mysql: dial tcp 10.19.0.41:10250: getsockopt: no route to host
  • 這或許是由于 Kubernetes 使用的 IP 無法與看似相同的子網(wǎng)上的其他 IP 進(jìn)行通信的緣故, 可能是由機(jī)器提供商的政策所導(dǎo)致的。
  • DigitalOcean 既分配一個(gè)共有 IP 給 ?eth0?,也分配一個(gè)私有 IP 在內(nèi)部用作其浮動 IP 功能的錨點(diǎn), 然而 ?kubelet ?將選擇后者作為節(jié)點(diǎn)的 ?InternalIP ?而不是公共 IP
  • 使用 ?ip addr show? 命令代替 ?ifconfig ?命令去檢查這種情況,因?yàn)?nbsp;?ifconfig ?命令 不會顯示有問題的別名 IP 地址。或者指定的 DigitalOcean 的 API 端口允許從 droplet 中 查詢 anchor IP:

    curl http://169.254.169.254/metadata/v1/interfaces/public/0/anchor_ipv4/address
    

    解決方法是通知 ?kubelet ?使用哪個(gè) ?--node-ip?。當(dāng)使用 DigitalOcean 時(shí),可以是公網(wǎng)IP(分配給 ?eth0 ?的), 或者是私網(wǎng)IP(分配給 ?eth1 ?的)。私網(wǎng) IP 是可選的。 kubadm ?NodeRegistrationOptions ?結(jié)構(gòu) 的 ?KubeletExtraArgs ?部分被用來處理這種情況。

    然后重啟 ?kubelet?:

    systemctl daemon-reload
    systemctl restart kubelet

coredns pods 有 CrashLoopBackOff 或者 Error 狀態(tài)

如果有些節(jié)點(diǎn)運(yùn)行的是舊版本的 Docker,同時(shí)啟用了 SELinux,你或許會遇到 ?coredns ?pods 無法啟動的情況。 要解決此問題,你可以嘗試以下選項(xiàng)之一:

  • 升級到 Docker 的較新版本
  • 禁用 SELinux
  • 修改 ?coredns ?部署以設(shè)置 ?allowPrivilegeEscalation ?為 ?true?:
kubectl -n kube-system get deployment coredns -o yaml | \
  sed 's/allowPrivilegeEscalation: false/allowPrivilegeEscalation: true/g' | \
  kubectl apply -f -

CoreDNS 處于 ?CrashLoopBackOff ?時(shí)的另一個(gè)原因是當(dāng) Kubernetes 中部署的 CoreDNS Pod 檢測 到環(huán)路時(shí)。有許多解決方法 可以避免在每次 CoreDNS 監(jiān)測到循環(huán)并退出時(shí),Kubernetes 嘗試重啟 CoreDNS Pod 的情況。

Warning: 禁用 SELinux 或設(shè)置 ?allowPrivilegeEscalation ?為 ?true ?可能會損害集群的安全性。

etcd pods 持續(xù)重啟

如果你遇到以下錯(cuò)誤:

rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:247: starting container process caused "process_linux.go:110: decoding init error from pipe caused \"read parent: connection reset by peer\""

如果你使用 Docker 1.13.1.84 運(yùn)行 CentOS 7 就會出現(xiàn)這種問題。 此版本的 Docker 會阻止 kubelet 在 etcd 容器中執(zhí)行。

為解決此問題,請選擇以下選項(xiàng)之一:

  • 回滾到早期版本的 Docker,例如 1.13.1-75
  • yum downgrade docker-1.13.1-75.git8633870.el7.centos.x86_64 docker-client-1.13.1-75.git8633870.el7.centos.x86_64 docker-common-1.13.1-75.git8633870.el7.centos.x86_64
    
  • 安裝較新的推薦版本之一,例如 18.06:
  • sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    yum install docker-ce-18.06.1.ce-3.el7.x86_64

無法將以逗號分隔的值列表傳遞給 --component-extra-args 標(biāo)志內(nèi)的參數(shù)

?kubeadm init? 標(biāo)志例如 ?--component-extra-args? 允許你將自定義參數(shù)傳遞給像 kube-apiserver 這樣的控制平面組件。然而,由于解析 (?mapStringString?) 的基礎(chǔ)類型值,此機(jī)制將受到限制。

如果你決定傳遞一個(gè)支持多個(gè)逗號分隔值(例如 ?--apiserver-extra-args "enable-admission-plugins=LimitRanger,NamespaceExists"?)參數(shù), 將出現(xiàn) ?flag: malformed pair, expect string=string? 錯(cuò)誤。 發(fā)生這種問題是因?yàn)閰?shù)列表 ?--apiserver-extra-args? 預(yù)期的是 ?key=value? 形式, 而這里的 ?NamespacesExists? 被誤認(rèn)為是缺少取值的鍵名。

一種解決方法是嘗試分離 ?key=value? 對,像這樣: ?--apiserver-extra-args "enable-admission-plugins=LimitRanger,enable-admission-plugins=NamespaceExists"? 但這將導(dǎo)致鍵 ?enable-admission-plugins? 僅有值 ?NamespaceExists?。

已知的解決方法是使用 kubeadm 配置文件。

在節(jié)點(diǎn)被云控制管理器初始化之前,kube-proxy 就被調(diào)度了

在云環(huán)境場景中,可能出現(xiàn)在云控制管理器完成節(jié)點(diǎn)地址初始化之前,kube-proxy 就被調(diào)度到新節(jié)點(diǎn)了。 這會導(dǎo)致 kube-proxy 無法正確獲取節(jié)點(diǎn)的 IP 地址,并對管理負(fù)載平衡器的代理功能產(chǎn)生連鎖反應(yīng)。

在 kube-proxy Pod 中可以看到以下錯(cuò)誤:

server.go:610] Failed to retrieve node IP: host IP unknown; known addresses: []
proxier.go:340] invalid nodeIP, initializing kube-proxy with 127.0.0.1 as nodeIP

一種已知的解決方案是修補(bǔ) kube-proxy DaemonSet,以允許在控制平面節(jié)點(diǎn)上調(diào)度它, 而不管它們的條件如何,將其與其他節(jié)點(diǎn)保持隔離,直到它們的初始保護(hù)條件消除:

kubectl -n kube-system patch ds kube-proxy -p='{ "spec": { "template": { "spec": { "tolerations": [ { "key": "CriticalAddonsOnly", "operator": "Exists" }, { "effect": "NoSchedule", "key": "node-role.kubernetes.io/master" }, { "effect": "NoSchedule", "key": "node-role.kubernetes.io/control-plane" } ] } } } }'

此問題的跟蹤在這里

節(jié)點(diǎn)上的 /usr 被以只讀方式掛載

在類似 Fedora CoreOS 或者 Flatcar Container Linux 這類 Linux 發(fā)行版本中, 目錄 ?/usr? 是以只讀文件系統(tǒng)的形式掛載的。 在支持 FlexVolume時(shí), 類似 kubelet 和 kube-controller-manager 這類 Kubernetes 組件使用默認(rèn)路徑 ?/usr/libexec/kubernetes/kubelet-plugins/volume/exec/?, 而 FlexVolume 的目錄 必須是可寫入的,該功能特性才能正常工作。 (注意:FlexVolume 在 Kubernetes v1.23 版本中已被棄用)

為了解決這個(gè)問題,你可以使用 kubeadm 的配置文件 來配置 FlexVolume 的目錄。

在(使用 ?kubeadm init? 創(chuàng)建的)主控制節(jié)點(diǎn)上,使用 ?--config? 參數(shù)傳入如下文件:

apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration:
  kubeletExtraArgs:
    volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
controllerManager:
  extraArgs:
    flex-volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"

在加入到集群中的節(jié)點(diǎn)上,使用下面的文件:

apiVersion: kubeadm.k8s.io/v1beta3
kind: JoinConfiguration
nodeRegistration:
  kubeletExtraArgs:
    volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"

或者,你要可以更改 ?/etc/fstab? 使得 ?/usr? 目錄能夠以可寫入的方式掛載,不過 請注意這樣做本質(zhì)上是在更改 Linux 發(fā)行版的某種設(shè)計(jì)原則。

kubeadm upgrade plan 輸出錯(cuò)誤信息 context deadline exceeded

在使用 ?kubeadm ?來升級某運(yùn)行外部 etcd 的 Kubernetes 集群時(shí)可能顯示這一錯(cuò)誤信息。 這并不是一個(gè)非常嚴(yán)重的一個(gè)缺陷,之所以出現(xiàn)此錯(cuò)誤信息,原因是老的 kubeadm 版本會對外部 etcd 集群執(zhí)行版本檢查。你可以繼續(xù)執(zhí)行 ?kubeadm upgrade apply ...?。

這一問題已經(jīng)在 1.19 版本中得到修復(fù)。

kubeadm reset 會卸載 /var/lib/kubelet

如果已經(jīng)掛載了 ?/var/lib/kubelet? 目錄,執(zhí)行 ?kubeadm reset? 操作的時(shí)候 會將其卸載。

要解決這一問題,可以在執(zhí)行了 ?kubeadm reset? 操作之后重新掛載 ?/var/lib/kubelet? 目錄。

這是一個(gè)在 1.15 中引入的故障,已經(jīng)在 1.20 版本中修復(fù)。

無法在 kubeadm 集群中安全地使用 metrics-server 

在 kubeadm 集群中可以通過為 metrics-server 設(shè)置 ?--kubelet-insecure-tls? 來以不安全的形式使用該服務(wù)。 建議不要在生產(chǎn)環(huán)境集群中這樣使用。

如果你需要在 metrics-server 和 kubelet 之間使用 TLS,會有一個(gè)問題, kubeadm 為 kubelet 部署的是自簽名的服務(wù)證書。這可能會導(dǎo)致 metrics-server 端報(bào)告下面的錯(cuò)誤信息:

x509: certificate signed by unknown authority
x509: certificate is valid for IP-foo not IP-bar

另請參閱 How to run the metrics-server securely。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號