<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          解讀Kubernetes常見退出碼

          共 8613字,需瀏覽 18分鐘

           ·

          2024-04-11 09:36

          c53f74ee0a339cffef76aaae79402b52.webp

          在這篇文章中,我們將深入分析Kubernetes中的典型退出碼127與137,解釋它們是什么,K8s和Docker中常見的原因是什么,以及如何修復(fù)


          916d71ca4f2e6541eeada8e94501b191.webp

          編輯|zouyee
          1f483eec781354bfc72f1b66e95438b8.webp

          退出碼歷史

          退出碼的歷史可以追溯到Unix操作系統(tǒng)的早期。在Unix系統(tǒng)中,進程退出碼是進程終止時向其父進程傳遞的一個整數(shù)值,用于表示進程的終止?fàn)顟B(tài)。這個整數(shù)值通常在0到255之間,其中0表示進程成功終止,其他值通常用來表示不同的錯誤或異常情況。

          進程退出碼最初被設(shè)計用于提供一種簡單的機制,使父進程能夠了解子進程的執(zhí)行結(jié)果。這使得父進程能夠根據(jù)子進程的退出碼來采取適當(dāng)?shù)男袆樱热缣幚礤e誤情況或繼續(xù)執(zhí)行其他操作。

          在Unix系統(tǒng)中,特定的退出碼值通常具有特定的含義,例如:

          • 0:表示成功執(zhí)行,沒有錯誤。

          • 1:通常表示通用的錯誤。

          • 2:表示命令的語法錯誤。

          • 127:表示命令未找到。

          隨著時間的推移,Unix操作系統(tǒng)的發(fā)展和不同的實現(xiàn),進程退出碼的含義可能有所不同,但基本的概念保持不變。

          在Linux系統(tǒng)中,進程退出碼的使用與Unix系統(tǒng)類似。Linux繼承了Unix的進程管理機制,并在其基礎(chǔ)上進行了擴展和改進。因此,Linux中的進程退出碼仍然是一個重要的概念,用于幫助理解和診斷進程的執(zhí)行狀態(tài)。

          進程退出碼的歷史可以追溯到早期的Unix系統(tǒng),是Unix和Linux操作系統(tǒng)中的一個重要概念,為進程間通信提供了一種簡單而有效的機制。當(dāng)應(yīng)用程序或命令因致命錯誤而終止或執(zhí)行失敗時,將產(chǎn)生 128 系列退出碼(128+n),其中 n 為信號編號。n 包括所有類型的終止代碼,如 SIGTERM、SIGKILL 等。


          dfa74952be722c963d1a58fee8d30412.webp

          退出碼 127

          退出碼 127 不是特定于 Kubernetes 的錯誤代碼,而是 Linux 和類 Unix 操作系統(tǒng)中使用的標(biāo)準(zhǔn)退出碼。當(dāng)然,我們在Kubernetes中經(jīng)常看到它,并且通常表示容器內(nèi)執(zhí)行的命令或二進制文件找不到。

          一些標(biāo)準(zhǔn)的退出碼包括:

          4df5ea2b9b105576556992a912698101.webp

          常見原因

          讓我們看一下退出碼 127 的一些常見原因:

          1. 命令或二進制文件未安裝

            Kubernetes 容器的 command 字段中指定的可執(zhí)行文件未安裝在容器的文件系統(tǒng)中。需要確保所需的二進制文件或命令可用。

          2. 路徑或命令不正確

            Pod 定義中指定的命令不正確或在指定的路徑中不存在。這是錯誤的最常見原因之一,通常是由于 Dockerfile 或 pod  spec中的entrypoint或command輸入不正確造成的。

          3. 缺少依賴

            在容器內(nèi)運行的應(yīng)用程序或腳本未安裝相關(guān)依賴。需要確保所有必需的依賴項包含在容器映像中。

          4. shell 解釋器

            如果指定了腳本作為命令,需要確保腳本有效 (例如#!/bin/bash),且在容器中可用。

          5. shell 腳本語法錯誤

            如果 shell 腳本退出碼是127,請檢查腳本是否存有語法錯誤或可能阻止其執(zhí)行的問題。

          6. 權(quán)限不足

            在容器內(nèi)運行命令的用戶可能沒有執(zhí)行指定命令所需的必要權(quán)限。確保容器以適當(dāng)?shù)奶貦?quán)運行。

          7. 鏡像兼容性問題

            確保使用的容器鏡像與宿主機架構(gòu)和操作系統(tǒng)兼容。不匹配的映像可能導(dǎo)致命令找不到,比如x86的鏡像運行在arm的機器上

          8. 卷掛載

            如果命令是卷掛載的文件,請檢查卷掛載是否配置正確,且所需的文件可以被訪問到。

          9. 環(huán)境變量

            一些命令可能依賴于特定的環(huán)境變量。確保必需的環(huán)境變量設(shè)置正確。

          10. Kubernetes RBAC 策略

            如果啟用了RBAC,需要確保具有執(zhí)行指定命令所需的權(quán)限。

          如何排查

          要排除問題,可以使用以下命令檢查 Pod 的日志:

                
                  kubectl logs -f <pod-name>
                
              

          還可以檢查 Pod 狀態(tài),該狀態(tài)提供有關(guān) Pod 的詳細信息,包括其當(dāng)前狀態(tài)、最近事件和任何錯誤消息。

                
                  kubectl describe pod <pod-name>
                
              

          還可以為把調(diào)試容器attach到Pod 中,該容器包括一個 shell(例如 BusyBox)。這允許您進入容器并手動檢查環(huán)境、路徑和命令的可用性。

          使用 BusyBox 進行調(diào)試的示例:

                
                  containers:
                
                
                    - name: my-container
                
                
                      image: my-image:latest
                
                
                      command: ["/bin/sleep", "infinity"]
                
                
                    - name: debug-container
                
                
                      image: busybox:latest
                
                
                      command: ["/bin/sh"]
                
                
                      tty: true
                
                
                      stdin: true
                
              

          如果是高版本K8s,也可以使用Ephemeral Containers,它就是一個臨時容器。這是一個自Kubernetes v1.16中作為alpha引入的新功能,啟用臨時容器的特性也非常簡單,在kubernetes v1.16之后的版本中將啟動參數(shù)--feature-gates=EphemeralContainers=true配置到kube-api和kubelet服務(wù)上重啟即可。

          通過仔細查看日志并排查上述幾個方向,應(yīng)該能夠確定退出碼 127 問題的原因。

          如何修復(fù)

          我們知道了退出碼 127 的常見原因以及排查方式,現(xiàn)在讓我們看看如何修復(fù)它們。

          1. 命令或二進制文件未安裝

          如果所需的命令或二進制文件丟失,則可能需要在容器鏡像中安裝。修改 Dockerfile 或構(gòu)建過程安裝所需軟件。

          示例:

                
                  FROM alpine:latest 
                
                
                  RUN apk --no-cache add <package-name>
                
              
          1. 路徑或命令不正確

          在 Pod 定義中指定命令時,考慮使用二進制文件的絕對路徑。這有助于確保不受當(dāng)前工作目錄的影響, runtime可以找到二進制文件。

          示例:

                
                  containers:
                
                
                    - name: my-container
                
                
                      image: my-image:latest
                
                
                      command: ["/usr/local/bin/my-command"]
                
              
          1. 缺少依賴項

          導(dǎo)致命令無法運行的原因可能是容器鏡像需要安裝額外的軟件。如果命令需要額外的設(shè)置或安裝步驟,可以使用init容器在主容器啟動之前執(zhí)行這些任務(wù)。

          示例(使用init容器安裝軟件包):

                
                  initContainers:
                
                
                    - name: install-package
                
                
                      image: alpine:latest
                
                
                      command: ["apk", "--no-cache", "add", "<package-name>"]
                
                
                      volumeMounts:
                
                
                      - name: shared-data
                
                
                        mountPath: /data
                
              
          1. shell解釋器

          如果指定了腳本作為命令,需要確保腳本有效 (例如#!/bin/bash),且在容器中可用。

          示例:

                
                  
                    #!/bin/bash
                  
                
              
          1. 卷掛載

          檢查Pod的配置,確保卷已正確掛載。驗證卷名稱、掛載路徑和 subPaths是否正確。

          示例:

                
                  volumes:
                
                
                    - name: my-volume
                
                
                      emptyDir: {}
                
                
                  containers:
                
                
                    - name: my-container
                
                
                      image: my-image:latest
                
                
                      volumeMounts:
                
                
                      - name: my-volume
                
                
                        mountPath: /path/in/container
                
              

          同時我們需要確認(rèn)Pod 定義指定的卷存在且可用。如果是持久卷(PV),需要檢查其狀態(tài)。如果是 emptyDir 或其他類型的卷,需要驗證其是否正確創(chuàng)建和掛載。如果在卷掛載中使用了 subPaths,需要確保源目錄或文件中存在指定的 subPaths。

          示例:

                
                  volumeMounts:
                
                
                    - name: my-volume
                
                
                      mountPath: /path/in/container
                
                
                      subPath: my-file.txt
                
              



          b06bbd2bd0fcb08e1a1446a7cd7d8ee4.webp

          退出碼 137

          在Kubernetes中,137退出碼表示進程被強制終止。在Unix和Linux系統(tǒng)中,當(dāng)進程由于信號而終止時,退出碼由信號編號加上128確定。信號編號為9,意味著“SIGKILL”,因此將9加上128,得到137退出碼。

          當(dāng)Kubernetes集群中容器超出其內(nèi)存限制時,它可能會被Kubernetes系統(tǒng)終止,并顯示“OOMKilled”錯誤,這表示進程因內(nèi)存不足而被終止。此錯誤的退出碼為137OOM代表“內(nèi)存耗盡(out-of-memory)”。

          如果Pod狀態(tài)將顯示為“OOMKilled”,你可以使用以下命令查看:

                
                  kubectl describe pod <podname>
                
              


          OOMKiller

          OOMKiller是Linux內(nèi)核中的一種機制,它負(fù)責(zé)通過終止消耗過多內(nèi)存的進程來防止系統(tǒng)耗盡內(nèi)存。當(dāng)系統(tǒng)內(nèi)存耗盡時,內(nèi)核會調(diào)用OOMKiller來選擇一個要終止的進程,以釋放內(nèi)存并保持系統(tǒng)運行。

          內(nèi)核中有兩種不同的OOM Killer;一種是全局的OOM Killer,另一種是基于cgroup內(nèi)存控制器的OOM Killer,可以是cgroup v1或cgroup v2。

          簡單來說是,當(dāng)內(nèi)核在分配物理內(nèi)存頁面時遇到問題時,全局的OOM Killer 會觸發(fā)。當(dāng)內(nèi)核嘗試分配內(nèi)存頁面(無論是用于內(nèi)核使用還是用于需要頁面的進程),并且最初失敗時,它將嘗試各種方式來回收和整理內(nèi)存。如果這種嘗試成功或者至少取得了一些進展,內(nèi)核將繼續(xù)重試分配;如果無法釋放頁面或者取得進展,在許多情況下它將觸發(fā)OOM Killer。

          一旦OOMKiller選擇要終止的進程,它會向該進程發(fā)送信號,要求其優(yōu)雅地終止。如果進程不響應(yīng)信號,則內(nèi)核會強制終止該進程并釋放其內(nèi)存。

          注意:由于內(nèi)存問題而被終止的Pod不一定會被節(jié)點驅(qū)逐,如果其設(shè)置的重啟策略設(shè)置為“Always”,它將嘗試重新啟動Pod。

          在系統(tǒng)層面,Linux內(nèi)核為運行在主機上的每個進程維護一個oom_score。進程被終止的機率取決于分?jǐn)?shù)有多高。

          oom_score_adj值允許用戶自定義OOM進程,并定義何時應(yīng)終止進程。Kubernetes在定義Pod的Quality of Service(QoS)時使用oom_score_adj值。

          K8s針對Pod定義了三種QoS,每個類型具有對應(yīng)的oom_score_adj值:

          • Guaranteed: -997

          • BestEffort: 1000

          • Burstable: min(max(2, 1000 — (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

          其中Pod為Guaranteed QoS,則其oom_score_adj的值是-997,因此它們在節(jié)點內(nèi)存不足時最后一個被終止。BestEffort Pod配置的是1000,所以它們第一個被被終止。

          要查看Pod的QoS,可以通過下述命令:

                
                  kubectl get pod -o jsonpath='{.status.qosClass}'
                
              

          下面是定義PodGuaranteed QoS 類型的計算策略:

          • Pod 中的每個容器必須有內(nèi)存 limit 和內(nèi)存 request。

          • 對于 Pod 中的每個容器,內(nèi)存 limit 必須等于內(nèi)存 request。

          • Pod 中的每個容器必須有 CPU limit 和 CPU request。

          • 對于 Pod 中的每個容器,CPU limit 必須等于 CPU request。

          退出碼137通常有兩種情況:

          1. 最常見的原因是與資源限制相關(guān)。通常情況下,Kubernetes超出了容器的分配內(nèi)存限制。

             2. 另一種情況是手動干預(yù) - 用戶或腳本可能會向容器進程發(fā)送“SIGKILL”信號,導(dǎo)致此退出碼。


          如何排查

          1. 檢查Pod日志

          診斷OOMKilled錯誤的第一步是檢查Pod日志,查看是否有任何內(nèi)存相關(guān)的錯誤消息。

                
                  kubectl describe pod <podname>
                
                
                  State:          Running
                
                
                         Started:      Fri, 12 May 2023 11:14:13 +0200
                
                
                         Last State:   Terminated
                
                
                         Reason:       OOMKilled
                
                
                         Exit Code:    137
                
                
                         ...
                
              

          您還可以查詢Pod日志:

                
                  cat /var/log/pods/<podname>
                
              

          當(dāng)然也可以通過(標(biāo)準(zhǔn)輸出)

                
                  kubectl logs -f <podname>
                
              
          1. 監(jiān)視內(nèi)存使用情況

          使用監(jiān)視系統(tǒng)(如Prometheus或Grafana)監(jiān)視Pod和容器中的內(nèi)存使用情況。這可以幫助我們排查出哪些容器消耗了過多的內(nèi)存從而觸發(fā)了OOMKilled錯誤,同時也可以在容器宿主機使用dmesg查看當(dāng)時oomkiller的現(xiàn)場

          1. 使用內(nèi)存分析器

          使用內(nèi)存分析器(如pprof)來識別可能導(dǎo)致過多內(nèi)存使用的內(nèi)存泄漏或低效代碼。

          如何修復(fù)

          以下是OOMKilled Kubernetes錯誤的常見原因及其解決方法。

          1. 容器內(nèi)存限制已達到

          這可能是由于在容器指定的內(nèi)存限制值設(shè)置不當(dāng)導(dǎo)致的。解決方法是增加內(nèi)存限制的值,或者調(diào)查導(dǎo)致負(fù)載增加的根本原因并進行糾正。導(dǎo)致這種情況的常見原因包括大文件上傳,因為上傳大文件可能會消耗大量內(nèi)存資源,特別是當(dāng)多個容器在一個Pod內(nèi)運行時,以及突然增加的流量量。

          1. 因為應(yīng)用程序內(nèi)存泄漏,容器內(nèi)存使用達到上限

          需要調(diào)試應(yīng)用程序來定位內(nèi)存泄漏的原因,

          1. 所有Pod使用的總內(nèi)存大于節(jié)點可用內(nèi)存

          通過增加節(jié)點可用內(nèi)存來增加節(jié)點內(nèi)存,或者將Pod遷移到內(nèi)存更多的節(jié)點。當(dāng)然也可以調(diào)整運行在節(jié)點上的Pod的內(nèi)存限制,使其符合內(nèi)存限制,注意你還應(yīng)該注意內(nèi)存請求設(shè)置,它指定了Pod應(yīng)該使用的最小內(nèi)存量。如果設(shè)置得太高,可能不是有效利用可用內(nèi)存,關(guān)于資源配置相關(guān)的建議,可以參看VPA組件

          在調(diào)整內(nèi)存請求和限制時,當(dāng)節(jié)點過載時,Kubernetes按照以下優(yōu)先級順序終止Pod:

          • 沒有請求或限制的Pod。

          • 具有請求但沒有限制的Pod。

          • 使用超過其內(nèi)存請求值的內(nèi)存 - 指定的最小內(nèi)存值 - 但低于其內(nèi)存限制的Pod。

          • 使用超過其內(nèi)存限制的Pod。

          如何預(yù)防

          有幾種方法可以防止OOMKilled的發(fā)生:

          1. 設(shè)置適當(dāng)?shù)膬?nèi)存限制

          通過壓測及監(jiān)控來確定應(yīng)用程序的內(nèi)存使用,通過上述方式配置容器允許使用的最大內(nèi)存量。過度保守可能會導(dǎo)致因資源利用率低效而造成資金的浪費,同時低估會導(dǎo)致頻繁出現(xiàn)OOMKilled現(xiàn)象。

          1. HPA

          最佳做法是利用K8s提供的HPA機制,當(dāng)應(yīng)用程序的內(nèi)存使用升高時自動增加Pod副本數(shù)量。

          1. 節(jié)點資源分配

          確保節(jié)點具有足夠的資源來處理業(yè)務(wù)。

          1. 優(yōu)化應(yīng)用程序內(nèi)存使用

          監(jiān)視應(yīng)用程序并進行適當(dāng)優(yōu)化,以減少內(nèi)存消耗。

          1. 避免應(yīng)用程序中的內(nèi)存泄漏

          從應(yīng)用程序來看,需要長期檢查并修復(fù)內(nèi)存泄漏。

          由于筆者時間、視野、認(rèn)知有限,本文難免出現(xiàn)錯誤、疏漏等問題,期待各位讀者朋友、業(yè)界專家指正交流。

          參考文獻 1. https://spacelift.io/blog/oomkilled-exit-code-137

          2. https://spacelift.io/blog/exit-code-127

          3. https://cloud.tencent.com/developer/news/1152344

          4. https://utcc.utoronto.ca/~cks/space/blog/linux/OOMKillerWhen


          瀏覽 27
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产性爱第一页 | 青青草免费视频在线 | 亚州无码高清视频 | 日韩精品一区二区三区四区 | 成人精品久久久 |