kubeadm 疑難排解
如同任何程式一樣,您在安裝或執行 kubeadm 時可能會遇到錯誤。本頁列出了一些常見的失敗情境,並提供步驟來協助您理解和修正問題。
如果您的問題未在下方列出,請依照下列步驟操作
如果您認為您的問題是 kubeadm 的錯誤
- 前往 github.com/kubernetes/kubeadm 並搜尋現有的 Issue。
- 如果沒有現有的 Issue,請開啟一個 Issue 並依照 Issue 範本。
如果您不確定 kubeadm 的運作方式,您可以在 Slack 的
#kubeadm
頻道中提問,或在 StackOverflow 上開啟一個問題。請包含相關標籤,例如#kubernetes
和#kubeadm
,以便大家可以協助您。
由於缺少 RBAC,無法將 v1.18 節點加入到 v1.17 叢集
在 v1.18 中,kubeadm 新增了防止將節點加入叢集的機制,如果叢集中已存在同名的節點。這需要為 bootstrap-token 使用者新增 RBAC,使其能夠 GET 節點物件。
然而,這會導致一個問題,即來自 v1.18 的 kubeadm join
無法加入由 kubeadm v1.17 建立的叢集。
要解決此問題,您有兩個選項
在控制平面節點上使用 kubeadm v1.18 執行 kubeadm init phase bootstrap-token
。請注意,這也會啟用其餘的 bootstrap-token 權限。
或者
使用 kubectl apply -f ...
手動套用以下 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
或類似的可執行檔
如果您在執行 kubeadm init
時看到以下警告
[preflight] WARNING: ebtables not found in system path
[preflight] WARNING: ethtool not found in system path
那麼您的節點上可能缺少 ebtables
、ethtool
或類似的可執行檔。您可以使用以下命令安裝它們
- 對於 Ubuntu/Debian 使用者,執行
apt install ebtables ethtool
。 - 對於 CentOS/Fedora 使用者,執行
yum install ebtables ethtool
。
kubeadm 在安裝期間封鎖等待控制平面
如果您注意到 kubeadm init
在印出以下行後掛起
[apiclient] Created API client, waiting for the control plane to become ready
這可能是由許多問題引起的。最常見的是
- 網路連線問題。請先檢查您的機器是否已完全連線至網路,再繼續操作。
- 容器執行階段的 cgroup 驅動程式與 kubelet 的驅動程式不同。若要瞭解如何正確設定,請參閱設定 cgroup 驅動程式。
- 控制平面容器正在 CrashLoopBackOff 或卡住。您可以執行
docker ps
並透過執行docker logs
來調查每個容器,以檢查此問題。對於其他容器執行階段,請參閱使用 crictl 偵錯 Kubernetes 節點。
kubeadm 在移除受管理的容器時卡住
如果容器執行階段停止且未移除任何 Kubernetes 管理的容器,可能會發生以下情況
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)
可能的解決方案是重新啟動容器執行階段,然後重新執行 kubeadm reset
。您也可以使用 crictl
偵錯容器執行階段的狀態。請參閱使用 crictl 偵錯 Kubernetes 節點。
Pod 處於 RunContainerError
、CrashLoopBackOff
或 Error
狀態
在 kubeadm init
執行後,不應該有任何 Pod 處於這些狀態。
- 如果在執行
kubeadm init
之後立即有 Pod 處於這些狀態之一,請在 kubeadm repo 中開啟一個 issue。在您部署網路附加元件之前,coredns
(或kube-dns
) 應該處於Pending
狀態。 - 如果您在部署網路附加元件後看到 Pod 處於
RunContainerError
、CrashLoopBackOff
或Error
狀態,且coredns
(或kube-dns
) 沒有任何反應,則很可能是您安裝的 Pod 網路附加元件在某方面已損壞。您可能需要授予它更多 RBAC 權限或使用較新版本。請在 Pod 網路供應商的 issue 追蹤器中提交 issue,並在那裡對 issue 進行分類。
coredns
卡在 Pending
狀態
這是預期的,也是設計的一部分。kubeadm 與網路供應商無關,因此管理員應安裝所選的 Pod 網路附加元件。您必須先安裝 Pod 網路,CoreDNS 才能完全部署。因此,在網路設定完成之前,會處於 Pending
狀態。
HostPort
服務無法運作
HostPort
和 HostIP
功能的可用性取決於您的 Pod 網路供應商。請聯絡 Pod 網路附加元件的作者,以了解 HostPort
和 HostIP
功能是否可用。
Calico、Canal 和 Flannel CNI 供應商已驗證支援 HostPort。
如需更多資訊,請參閱 CNI portmap 文件。
如果您的網路供應商不支援 portmap CNI 外掛程式,您可能需要使用服務的 NodePort 功能或使用 HostNetwork=true
。
Pod 無法透過其 Service IP 存取
許多網路附加元件尚未啟用髮夾模式,該模式允許 Pod 透過其 Service IP 存取自身。這是與 CNI 相關的問題。請聯絡網路附加元件供應商,以取得他們對髮夾模式支援的最新狀態。
如果您使用 VirtualBox(直接或透過 Vagrant),則需要確保
hostname -i
傳回可路由的 IP 位址。預設情況下,第一個介面連線到不可路由的僅限主機網路。一種解決方法是修改/etc/hosts
,請參閱此 Vagrantfile 範例。
TLS 憑證錯誤
以下錯誤表示可能存在憑證不符的情況。
# 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")
驗證
$HOME/.kube/config
檔案是否包含有效的憑證,並在必要時重新產生憑證。kubeconfig 檔案中的憑證是 base64 編碼的。base64 --decode
命令可用於解碼憑證,而openssl x509 -text -noout
可用於檢視憑證資訊。使用以下命令取消設定
KUBECONFIG
環境變數unset KUBECONFIG
或將其設定為預設的
KUBECONFIG
位置export KUBECONFIG=/etc/kubernetes/admin.conf
另一種解決方法是覆寫 "admin" 使用者的現有
kubeconfig
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 用戶端憑證輪換失敗
預設情況下,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
之類的錯誤。若要修正此問題,您必須遵循以下步驟
從失敗的節點備份並刪除
/etc/kubernetes/kubelet.conf
和/var/lib/kubelet/pki/kubelet-client*
。從叢集中具有
/etc/kubernetes/pki/ca.key
的工作控制平面節點執行kubeadm kubeconfig user --org system:nodes --client-name system:node:$NODE > kubelet.conf
。$NODE
必須設定為叢集中現有失敗節點的名稱。手動修改產生的kubelet.conf
以調整叢集名稱和伺服器端點,或傳遞kubeconfig user --config
(請參閱為其他使用者產生 kubeconfig 檔案)。如果您的叢集沒有ca.key
,您必須在外部簽署kubelet.conf
中嵌入的憑證。將此產生的
kubelet.conf
複製到失敗節點上的/etc/kubernetes/kubelet.conf
。在失敗的節點上重新啟動 kubelet (
systemctl restart kubelet
),並等待/var/lib/kubelet/pki/kubelet-client-current.pem
重新建立。手動編輯
kubelet.conf
以指向輪換後的 kubelet 用戶端憑證,方法是將client-certificate-data
和client-key-data
替換為client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
重新啟動 kubelet。
確保節點變為
Ready
狀態。
在 Vagrant 中使用 flannel 作為 Pod 網路時的預設 NIC
以下錯誤可能表示 Pod 網路中存在問題
Error from server (NotFound): the server could not find the requested resource
如果您在 Vagrant 內部使用 flannel 作為 Pod 網路,則必須為 flannel 指定預設介面名稱。
Vagrant 通常會為所有 VM 分配兩個介面。第一個介面(所有主機都被分配 IP 位址
10.0.2.15
)用於進行 NAT 的外部流量。這可能會導致 flannel 出現問題,flannel 預設為主機上的第一個介面。這導致所有主機都認為它們具有相同的公用 IP 位址。為了防止這種情況,請將
--iface eth1
旗標傳遞給 flannel,以便選擇第二個介面。
容器使用非公用 IP
在某些情況下,即使叢集功能正常,kubectl logs
和 kubectl run
命令也可能會傳回以下錯誤
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 無法與表面上位於同一子網路上的其他 IP 通訊,可能是由於機器供應商的策略所致。
DigitalOcean 為
eth0
分配了一個公用 IP,也分配了一個私有 IP,在內部用作其浮動 IP 功能的錨點,但kubelet
會選擇後者作為節點的InternalIP
,而不是公用 IP。使用
ip addr show
而不是ifconfig
來檢查這種情況,因為ifconfig
不會顯示有問題的別名 IP 位址。或者,DigitalOcean 特有的 API 端點允許從 droplet 查詢錨點 IPcurl http://169.254.169.254/metadata/v1/interfaces/public/0/anchor_ipv4/address
解決方法是告知
kubelet
要使用哪個 IP,方法是使用--node-ip
。使用 DigitalOcean 時,它可以是公用 IP(分配給eth0
)或私有 IP(分配給eth1
),如果您想使用選用的私有網路。kubeadmNodeRegistrationOptions
結構的kubeletExtraArgs
區段可用於此目的。然後重新啟動
kubelet
systemctl daemon-reload systemctl restart kubelet
coredns
Pod 處於 CrashLoopBackOff
或 Error
狀態
如果您的節點執行的是具有舊版 Docker 的 SELinux,則可能會遇到 coredns
Pod 無法啟動的情況。為了解決這個問題,您可以嘗試以下選項之一
升級到較新版本的 Docker。
修改
coredns
部署以將allowPrivilegeEscalation
設定為true
kubectl -n kube-system get deployment coredns -o yaml | \
sed 's/allowPrivilegeEscalation: false/allowPrivilegeEscalation: true/g' | \
kubectl apply -f -
CoreDNS 發生 CrashLoopBackOff
的另一個原因是 Kubernetes 中部署的 CoreDNS Pod 偵測到迴圈。有多種解決方法可以避免 Kubernetes 在每次 CoreDNS 偵測到迴圈並退出時嘗試重新啟動 CoreDNS Pod。
警告
停用 SELinux 或將allowPrivilegeEscalation
設定為 true
可能會危及叢集的安全性。etcd Pod 持續重新啟動
如果您遇到以下錯誤
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\""
如果您在 CentOS 7 上執行 Docker 1.13.1.84,則會出現此問題。此版本的 Docker 可能會阻止 kubelet 執行到 etcd 容器中。
為了解決此問題,請選擇以下選項之一
回退到較舊版本的 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
旗標內的引數
kubeadm init
旗標(例如 --component-extra-args
)允許您將自訂引數傳遞給控制平面元件,例如 kube-apiserver。但是,由於用於剖析值的基礎類型 (mapStringString
),此機制受到限制。
如果您決定傳遞支援多個逗號分隔值的引數,例如 --apiserver-extra-args "enable-admission-plugins=LimitRanger,NamespaceExists"
,則此旗標將失敗,並顯示 flag: malformed pair, expect string=string
。發生這種情況的原因是 --apiserver-extra-args
的引數列表預期為 key=value
對,而在這種情況下,NamespacesExists
被視為缺少值的金鑰。
或者,您可以嘗試像這樣分隔 key=value
對:--apiserver-extra-args "enable-admission-plugins=LimitRanger,enable-admission-plugins=NamespaceExists"
,但這將導致金鑰 enable-admission-plugins
僅具有值 NamespaceExists
。
已知的解決方法是使用 kubeadm 組態檔。
kube-proxy 在 cloud-controller-manager 初始化節點之前排程
在雲端供應商情境中,kube-proxy 可能會在 cloud-controller-manager 初始化節點位址之前最終排程到新的工作節點上。這會導致 kube-proxy 無法正確擷取節點的 IP 位址,並對管理負載平衡器的 Proxy 功能產生連鎖反應。
在 kube-proxy Pod 中可以看到以下錯誤
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
已知的解決方案是修補 kube-proxy DaemonSet,以允許在控制平面節點上排程它,而不管其狀況如何,使其在其他節點上保持關閉狀態,直到其初始保護狀況減輕。
kubectl -n kube-system patch ds kube-proxy -p='{
"spec": {
"template": {
"spec": {
"tolerations": [
{
"key": "CriticalAddonsOnly",
"operator": "Exists"
},
{
"effect": "NoSchedule",
"key": "node-role.kubernetes.io/control-plane"
}
]
}
}
}
}'
此問題的追蹤 issue 在這裡。
/usr
在節點上以唯讀方式掛載
在 Linux 發行版(例如 Fedora CoreOS 或 Flatcar Container Linux)上,目錄 /usr
以唯讀檔案系統掛載。對於 flex-volume 支援,Kubernetes 元件(例如 kubelet 和 kube-controller-manager)使用預設路徑 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/
,但 flex-volume 目錄必須可寫入才能使該功能運作。
注意
FlexVolume 已在 Kubernetes v1.23 版本中棄用。為了解決此問題,您可以使用 kubeadm 組態檔來設定 flex-volume 目錄。
在主要控制平面節點(使用 kubeadm init
建立)上,使用 --config
傳遞以下檔案
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
- name: "volume-plugin-dir"
value: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
controllerManager:
extraArgs:
- name: "flex-volume-plugin-dir"
value: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
在加入節點時
apiVersion: kubeadm.k8s.io/v1beta4
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
- name: "volume-plugin-dir"
value: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
或者,您可以修改 /etc/fstab
以使 /usr
掛載可寫入,但請注意,這會修改 Linux 發行版的設計原則。
kubeadm upgrade plan
印出 context deadline exceeded
錯誤訊息
在升級具有 kubeadm
的 Kubernetes 叢集(在執行外部 etcd 的情況下)時,會顯示此錯誤訊息。這不是嚴重的錯誤,發生原因是舊版 kubeadm 會對外部 etcd 叢集執行版本檢查。您可以繼續執行 kubeadm upgrade apply ...
。
此問題已在 1.19 版中修正。
kubeadm reset
取消掛載 /var/lib/kubelet
如果 /var/lib/kubelet
正在掛載,則執行 kubeadm reset
將有效地取消掛載它。
為了解決此問題,請在執行 kubeadm reset
操作後重新掛載 /var/lib/kubelet
目錄。
這是 kubeadm 1.15 中引入的迴歸問題。此問題已在 1.20 中修正。
無法在 kubeadm 叢集中安全地使用 metrics-server
在 kubeadm 叢集中,可以透過將 --kubelet-insecure-tls
傳遞給 metrics-server 來不安全地使用它。不建議在生產叢集中使用此方法。
如果您想在 metrics-server 和 kubelet 之間使用 TLS,則會出現問題,因為 kubeadm 會為 kubelet 部署自我簽署的伺服器憑證。這可能會在 metrics-server 端導致以下錯誤
x509: certificate signed by unknown authority
x509: certificate is valid for IP-foo not IP-bar
請參閱啟用已簽署的 kubelet 伺服器憑證,以了解如何在 kubeadm 叢集中設定 kubelet 以使其具有正確簽署的伺服器憑證。
由於 etcd 雜湊值未變更,升級失敗
僅適用於使用 kubeadm 二進制檔案 v1.28.3 或更高版本升級控制平面節點,且該節點目前由 kubeadm 版本 v1.28.0、v1.28.1 或 v1.28.2 管理的情況。
以下是您可能會遇到的錯誤訊息
[upgrade/etcd] Failed to upgrade etcd: couldn't upgrade control plane. kubeadm has tried to recover everything into the earlier state. Errors faced: static Pod hash for component etcd on Node kinder-upgrade-control-plane-1 did not change after 5m0s: timed out waiting for the condition
[upgrade/etcd] Waiting for previous etcd to become available
I0907 10:10:09.109104 3704 etcd.go:588] [etcd] attempting to see if all cluster endpoints ([https://172.17.0.6:2379/ https://172.17.0.4:2379/ https://172.17.0.3:2379/]) are available 1/10
[upgrade/etcd] Etcd was rolled back and is now available
static Pod hash for component etcd on Node kinder-upgrade-control-plane-1 did not change after 5m0s: timed out waiting for the condition
couldn't upgrade control plane. kubeadm has tried to recover everything into the earlier state. Errors faced
k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade.rollbackOldManifests
cmd/kubeadm/app/phases/upgrade/staticpods.go:525
k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade.upgradeComponent
cmd/kubeadm/app/phases/upgrade/staticpods.go:254
k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade.performEtcdStaticPodUpgrade
cmd/kubeadm/app/phases/upgrade/staticpods.go:338
...
此失敗的原因是受影響的版本在 PodSpec 中產生具有非預期預設值的 etcd manifest 檔案。這將導致 manifest 比較產生差異,且 kubeadm 會預期 Pod 雜湊值發生變更,但 kubelet 永遠不會更新雜湊值。
如果您在叢集中遇到此問題,有兩種方法可以解決
可以使用以下方式,在受影響的版本和 v1.28.3(或更高版本)之間跳過 etcd 升級
kubeadm upgrade {apply|node} [version] --etcd-upgrade=false
如果後續的 v1.28 修補程式版本引入了新的 etcd 版本,則不建議這樣做。
在升級之前,修補 etcd 靜態 Pod 的 manifest 檔案,以移除有問題的預設屬性
diff --git a/etc/kubernetes/manifests/etcd_defaults.yaml b/etc/kubernetes/manifests/etcd_origin.yaml index d807ccbe0aa..46b35f00e15 100644 --- a/etc/kubernetes/manifests/etcd_defaults.yaml +++ b/etc/kubernetes/manifests/etcd_origin.yaml @@ -43,7 +43,6 @@ spec: scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 - successThreshold: 1 timeoutSeconds: 15 name: etcd resources: @@ -59,26 +58,18 @@ spec: scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 - successThreshold: 1 timeoutSeconds: 15 - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File volumeMounts: - mountPath: /var/lib/etcd name: etcd-data - mountPath: /etc/kubernetes/pki/etcd name: etcd-certs - dnsPolicy: ClusterFirst - enableServiceLinks: true hostNetwork: true priority: 2000001000 priorityClassName: system-node-critical - restartPolicy: Always - schedulerName: default-scheduler securityContext: seccompProfile: type: RuntimeDefault - terminationGracePeriodSeconds: 30 volumes: - hostPath: path: /etc/kubernetes/pki/etcd
更多資訊可以在此錯誤的追蹤 issue 中找到。