當前位置: 妍妍網 > 碼農

Kubernetes上生產環境後,99%會遇到這兩個故障

2024-04-23碼農

隨著微服務的不斷推進,使用 k8s 集群越來越多,越來越深入,隨之而來會遇到一系列的問題,本文向大家介紹實際使用 k8s 遇到的一些問題以及解決方法。

問題一:修復 K8S 記憶體泄露問題

1.問題描述

1)當 k8s 集群執行日久以後,有的 node 無法再新建 pod,並且出現如下錯誤

當重新開機伺服器之後,才可以恢復正常使用。檢視 pod 狀態的時候會出現以下報錯。

applying cgroup … caused: mkdir …no space left on device或者在describe pod的時候出現cannot allocate memory

這時候你的 k8s 集群可能就存在記憶體泄露的問題了,當建立的 pod 越多的時候記憶體會泄露的越多,越快。

2)具體檢視是否存在記憶體泄露

at /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo當出現cat: /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo: Input/output error則說明不存在記憶體泄露的情況如果存在記憶體泄露會出現slabinfo - version: 2.1# name <active_objs><num_objs><objsize><objperslab><pagesperslab> : tunables <limit><batchcount><sharedfactor> : slabdata <active_slabs><num_slabs><sharedavail>

2.解決方案

1)解決方法思路

關閉 runc 和 kubelet 的 kmem,因為升級內核的方案改動較大,此處不采用。

2)kmem 導致記憶體泄露的原因

內核對於每個 cgroup 子系統的的條目數是有限制的,限制的大小定義在 kernel/cgroup.c #L139,當正常在 cgroup 建立一個 group 的目錄時,條目數就加 1。我們遇到的情況就是因為開啟了 kmem accounting 功能,雖然 cgroup 的目錄刪除了,但是條目沒有回收。這樣後面就無法建立 65535 個 cgroup 了。也就是說,在當前內核版本下,開啟了 kmem accounting 功能,會導致 memory cgroup 的條目泄漏無法回收。

3.具體實作

1)編譯 runc

  • 配置 go 語言環境

  • wget https://dl.google.com/go/go1.12.9.linux-amd64.tar.gztar xf go1.12.9.linux-amd64.tar.gz -C /usr/local/寫入bashrcvim ~/.bashrc export GOPATH="/data/Documents"export GOROOT="/usr/local/go"export PATH="$GOROOT/bin:$GOPATH/bin:$PATH"export GO111MODULE=off驗證source ~/.bashrc go env

  • 下載 runc 源碼

  • mkdir-p /data/Documents/src/github.com/opencontainers/cd/data/Documents/src/github.com/opencontainers/gitclone https://github.com/opencontainers/runccdrunc/gitcheckout v1.0.0-rc9 # 切到v1.0.0-rc9 tag

  • 編譯

  • 安裝編譯元件sudoyum install libseccomp-develmakeBUILDTAGS='seccomp nokmem'編譯完成之後會在當前目錄下看到一個runc的可執行檔,等kubelet編譯完成之後會將其替換

    2)編譯 kubelet

  • 下載 kubernetes 源碼

  • mkdir-p /root/k8s/cd/root/k8s/gitclone https://github.com/kubernetes/kubernetescdkubernetes/gitcheckout v1.15.3

  • 制作編譯環境的映像(Dockerfile 如下)

  • FROM centos:centos7.3.1611ENV GOROOT /usr/local/goENV GOPATH /usr/local/gopathENV PATH /usr/local/go/bin:$PATHRUN yum install rpm-build whichwhere rsync gcc gcc-c++ automake autoconf libtool make -y \ && curl -L https://studygolang.com/dl/golang/go1.12.9.linux-amd64.tar.gz | tar zxvf - -C /usr/local

  • 在制作好的 go 環境映像中來進行編譯 kubelet

  • docker run -it --rm -v /root/k8s/kubernetes:/usr/local/gopath/src/k8s.io/kubernetes build-k8s:centos-7.3-go-1.12.9-k8s-1.15.3 bashcd /usr/local/gopath/src/k8s.io/kubernetes#編譯GO111MODULE=off KUBE_GIT_TREE_STATE=clean KUBE_GIT_VERSION=v1.15.3 make kubelet GOFLAGS="-tags=nokmem"

    3)替換原有的 runc 和 kubelet

  • 將原有 runc 和 kubelet 備份

  • mv/usr/bin/kubelet /home/kubeletmv/usr/bin/docker-runc /home/docker-runc

  • 停止 docker 和 kubelet

  • systemctlstop dockersystemctlstop kubelet

  • 將編譯好的 runc 和 kubelet 進行替換

  • cpkubelet /usr/bin/kubeletcpkubelet /usr/local/bin/kubeletcprunc /usr/bin/docker-runc

  • 檢查 kmem 是否關閉前需要將此節點的 pod 殺掉重新開機或者重新開機伺服器,當結果為 0 時成功

  • cat /sys/fs/cgroup/memory/kubepods/burstable/memory.kmem.usage_in_bytes

  • 檢查是否還存在記憶體泄露的情況

  • cat /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo

    問題二:k8s 證書過期問題的兩種處理方法

    1.前情提要

    公司測試環境的 k8s 集群使用已經很長時間了,突然有一天開發聯系我說 k8s 集群無法存取,開始以為是測試環境的機器磁盤空間不夠了,導致元件異常或者把開發使用的映像自動清理掉了,但是當登上機器去查驗的時候發現不是這個原因。當時覺得也很疑惑。因為開發環境使用人數較少,不應該會出問題,所以就去查驗 log 的相關報錯資訊。

    2.問題現象

    出現 k8s api 無法調取的現象,使用 kubectl 命令獲取資源均返回如下報錯:

    Unable to connect to the server: x509: certificate has expired or is not yet valid

    經網上搜尋之後發現應該是 k8s 集群的證書過期了,使用命令排查證書的過期時間。

    kubeadm alpha certs check-expiration

    發現確實是證書過期了。

    3.相關介紹以及問題解決

    因為我們是使用 kubeadm 部署的 k8s 集群,所以更新起證書也是比較方便的,預設的證書時間有效期是一年,我們集群的 k8s 版本是 1.15.3 版本是可以使用以下命令來更新證書的,但是一年之後還是會到期,這樣就很麻煩,所以我們需要了解一下 k8s 的證書,然後我們來生成一個時間很長的證書,這樣我們就可以不用去總更新證書了。

    kubeadmalpha certs renew all --config=kubeadm.yamlsystemctlrestart kubeletkubeadminit phase kubeconfig all --config kubeadm.yaml

    然後將生成的配置檔替換,重新開機 kube-apiserver、kube-controller、kube-scheduler、etcd 這4個容器即可。

    另外 kubeadm 會在控制台升級的時候自動更新所有證書,所以使用 kubeadm 搭建的集群最佳的做法是經常升級集群,這樣可以確保你的集群保持最新狀態並保持合理的安全性。但是對於實際的生產環境我們可能並不會去頻繁的升級集群,所以這個時候我們就需要去手動更新證書。

    下面我們透過呼叫 k8s 的 api 來實作更新一個 10 年的證書。

    首先在 /etc/kubernetes/manifests/kube-controller-manager.yaml 檔加入配置。

    spec:containers:-command:-kube-controller-manager # 設定證書有效期為 10年---experimental-cluster-signing-duration=87600h---client-ca-file=/etc/kubernetes/pki/ca.crt

    修改完成後 kube-controller-manager 會自動重新開機生效。然後我們需要使用下面的命令為 Kubernetes 證書 API 建立一個證書簽名請求。如果您設定例如 cert-manager 等外部簽名者,則會自動批準證書簽名請求(CSRs)。否則,您必須使用 kubectl certificate 命令手動批準證書。以下 kubeadm 命令輸出要批準的證書名稱,然後等待批準發生:

    kubeadm alpha certs renew all --use-api --config kubeadm.yaml &

    需要將全部 pending 的證書全部批準。

    我們還不能直接重新開機控制台的幾個元件,這是因為使用 kubeadm 安裝的集群對應的 etcd 預設是使用的 /etc/kubernetes/pki/etcd/ca.crt 這個證書進行前面的,而上面我們用命令 kubectl certificate approve 批準過後的證書是使用的預設的 /etc/kubernetes/pki/ca.crt 證書進行簽發的,所以我們需要替換 etcd 中的 ca 機構證書:

    # 先拷貝靜態 Pod 資源清單cp-r /etc/kubernetes/manifests/ /etc/kubernetes/manifests.bakvi/etc/kubernetes/manifests/etcd.yaml......spec:containers:-command:-etcd # 修改為 CA 檔---peer-trusted-ca-file=/etc/kubernetes/pki/ca.crt---trusted-ca-file=/etc/kubernetes/pki/ca.crt......volumeMounts:-mountPath: /var/lib/etcdname: etcd-data-mountPath: /etc/kubernetes/pki # 更改證書目錄name: etcd-certsvolumes:-hostPath:path: /etc/kubernetes/pki # 將 pki 目錄掛載到 etcd 中去type: DirectoryOrCreatename: etcd-certs-hostPath:path: /var/lib/etcdtype: DirectoryOrCreatename: etcd-data......

    由於 kube-apiserver 要連線 etcd 集群,所以也需要重新修改對應的 etcd ca 檔:

    vi/etc/kubernetes/manifests/kube-apiserver.yaml......spec:containers:-command:-kube-apiserver # 將etcd ca檔修改為預設的ca.crt檔---etcd-cafile=/etc/kubernetes/pki/ca.crt......

    除此之外還需要替換 requestheader-client-ca-file 檔,預設是 /etc/kubernetes/pki/front-proxy-ca.crt 檔,現在也需要替換成預設的 CA 檔,否則使用聚合 API,比如安裝了 metrics-server 後執行 kubectl top 命令就會報錯:

    cp/etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/front-proxy-ca.crtcp/etc/kubernetes/pki/ca.key /etc/kubernetes/pki/front-proxy-ca.key

    這樣我們就得到了一個 10 年證書的 k8s 集群,還可以透過重新編譯 kubeadm 來實作一個 10 年證書的,這個我沒有嘗試,不過在初始化集群的時候也是一個方法。

    作者丨知了乎

    來源丨zhuanlan.zhihu.com/p/343031257

    dbaplus社群歡迎廣大技術人員投稿,投稿信箱: [email protected]

    活動推薦

    2024 XCOPS智慧運維管理人年會·廣州站將於5月24日舉辦 ,深究大模型、AI Agent等新興技術如何落地於運維領域,賦能企業智慧運維水平提升,構建全面運維自治能力! 碼上報名,享早鳥優惠。