什么是容器退出碼
當容器終止時,容器引擎使用退出碼來報告容器終止的原因。如果您是 Kubernetes 用戶,容器故障是 pod 異常最常見的原因之一,了解容器退出碼可以幫助您在排查時找到 pod 故障的根本原因。以下是容器使用的最常見的退出碼:
退出碼 | 名稱 | 含義 |
---|---|---|
0 | 正常退出 | 開發者用來表明容器是正常退出 |
1 | 應用錯誤 | 容器因應用程序錯誤或鏡像規范中的錯誤引用而停止 |
125 | 容器未能運行 | docker run 命令沒有執行成功 |
126 | 命令調用錯誤 | 無法調用鏡像中指定的命令 |
127 | 找不到文件或目錄 | 找不到鏡像中指定的文件或目錄 |
128 | 退出時使用的參數無效 | 退出是用無效的退出碼觸發的(有效代碼是 0-255 之間的整數) |
134 | 異常終止 (SIGABRT) | 容器使用 abort() 函數自行中止 |
137 | 立即終止 (SIGKILL) | 容器被操作系統通過 SIGKILL 信號終止 |
139 | 分段錯誤 (SIGSEGV) | 容器試圖訪問未分配給它的內存并被終止 |
143 | 優雅終止 (SIGTERM) | 容器收到即將終止的警告,然后終止 |
255 | 退出狀態超出范圍 | 容器退出,返回可接受范圍之外的退出代碼,表示錯誤原因未知 |
下面我們將解釋如何在宿主機和 Kubernetes 中對失敗的容器進行故障排除,并提供有關上面列出的所有退出代碼的更多詳細信息。
容器生命周期
為了更好地理解容器故障的原因,讓我們先討論容器的生命周期。以 Docker 為例 —— 在任何給定時間,Docker 容器都會處于以下幾種狀態之一:
Created:Docker 容器已創建但尚未啟動(這是運行?docker create?后但實際運行容器之前的狀態)
Up:Docker 容器當前正在運行。這意味著容器管理的操作系統進程正在運行。當您使用命令?docker start?或?docker run?時會發生這種情況,使用?docker start?或?docker run?可能會發生這種情況。
Paused:容器進程正在運行,但 Docker 暫停了容器。通常,當您運行?docker pause?命令時會發生這種情況
Exited:Docker 容器已經被終止,通常是因為容器的進程被殺死了
當一個容器達到 Exited 狀態時,Docker 會在日志中報告一個退出碼,告訴你容器發生了什么導致它退出。
了解容器退出碼
下面我們將更詳細地介紹每個退出碼。
退出碼 0:正常退出
退出代碼 0 由開發人員在任務完成后故意停止容器時觸發。從技術上講,退出代碼 0 意味著前臺進程未附加到特定容器。
如果容器以退出碼 0 終止怎么辦?
檢查容器日志,確定哪個庫導致容器退出;
查看現有庫的代碼,并確定它觸發退出碼 0 的原因,以及它是否正常運行。
退出碼 1:應用錯誤
退出代碼 1 表示容器由于以下原因之一停止:
應用程序錯誤:這可能是容器運行的代碼中的簡單編程錯誤,例如“除以零”,也可能是與運行時環境相關的高級錯誤,例如 Java、Python 等;
無效引用:這意味著鏡像規范引用了容器鏡像中不存在的文件。
如果容器以退出碼 1 終止怎么辦?
檢查容器日志以查看是否找不到映像規范中列出的文件之一。如果這是問題所在,請更正鏡像以指向正確的路徑和文件名。
如果您找不到不正確的文件引用,請檢查容器日志以查找應用程序錯誤,并調試導致錯誤的庫。
退出碼 125:容器未能運行
退出碼 125 表示該命令用于運行容器。例如?docker run?在 shell 中被調用但沒有成功執行。以下是可能發生這種情況的常見原因:
命令中使用了未定義的 flag,例如?docker run --abcd;
鏡像中用戶的定義命令在本機權限不足;
容器引擎與宿主機操作系統或硬件不兼容。
如果容器以退出碼 125 終止怎么辦?
檢查運行容器的命令語法是否正確;
檢查運行容器的用戶,或者鏡像中執行命令的上下文,是否有足夠的權限在宿主機上創建容器;
如果您的容器引擎提供了運行容器的 option,請嘗試它們。例如,在 Docker 中,嘗試?docker start?而不是?docker run;
測試您是否能夠使用相同的用戶名或上下文在主機上運行其他容器。如果不能,重新安裝容器引擎,或者解決容器引擎和主機設置之間的底層兼容性問題。
退出碼 126:命令調用錯誤
退出碼 126 表示無法調用容器鏡像中使用的命令。這通常是用于運行容器的持續集成腳本中缺少依賴項或錯誤的原因。
如果容器以退出碼 126 終止怎么辦?
檢查容器日志,查看無法調用哪個命令;
嘗試在沒有命令的情況下運行容器以確保隔離問題;
對命令進行故障排除以確保您使用正確的語法,并且所有依賴項都可用;
更正容器規范并重試運行容器。
退出碼 127:找不到文件或目錄
退出碼 127 表示容器中指定的命令引用了不存在的文件或目錄。
如果容器以退出碼 127 終止怎么辦?
與退出碼 126 相同,識別失敗的命令,并確保容器鏡像中引用的文件名或文件路徑真實有效。
退出碼 128:退出時使用的參數無效
退出碼 128 表示容器內的代碼觸發了退出命令,但沒有提供有效的退出碼。Linux exit?命令只允許 0-255 之間的整數,因此如果進程以退出碼 3.5 退出,則日志將報告退出代碼 128。
如果容器以退出碼 128 終止怎么辦?
檢查容器日志以確定哪個庫導致容器退出。
確定有問題的庫在哪里使用了?exit?命令,并更正它以提供有效的退出代碼。
退出碼 134:異常終止 (SIGABRT)
退出碼 134 表示容器自身異常終止,關閉進程并刷新打開的流。此操作是不可逆的,類似?SIGKILL(請參閱下面的退出碼 137)。進程可以通過執行以下操作之一來觸發?SIGABRT:
調用?libc?庫中的?abort()?函數;
調用?assert()?宏,用于調試。如果斷言為假,則該過程中止。
如果容器以退出碼 134 終止怎么辦?
檢查容器日志,查看哪個庫觸發了?SIGABRT?信號;
檢查中止進程是否是預期內的(例如,因為庫處于調試模式),如果不是,則對庫進行故障排除,并修改以避免中止容器。
退出碼 137:立即終止 (SIGKILL)
退出碼 137 表示容器已收到來自主機操作系統的?SIGKILL?信號。該信號指示進程立即終止,沒有寬限期。可能的原因是:
當通過容器引擎殺死容器時觸發,例如使用?docker kill?命令時;
由 Linux 用戶向進程發送?kill -9?命令觸發;
在嘗試終止容器并等待 30 秒的寬限期后由 Kubernetes 觸發(默認情況下);
由主機自動觸發,通常是由于內存不足。在這種情況下,docker inspect?命令將指示?OOMKilled?錯誤。
如果容器以退出碼 137 終止怎么辦?
檢查主機上的日志,查看在容器終止之前發生了什么,以及在接收到?SIGKILL?之前是否之前收到過?SIGTERM?信號(優雅終止);
如果之前有?SIGTERM?信號,請檢查您的容器進程是否處理?SIGTERM?并能夠正常終止;
如果沒有?SIGTERM?并且容器報告了?OOMKilled?錯誤,則排查主機上的內存問題。
退出碼 139:分段錯誤 (SIGSEGV)
退出碼 139 表示容器收到了來自操作系統的?SIGSEGV?信號。這表示分段錯誤 —— 內存違規,由容器試圖訪問它無權訪問的內存位置引起。SIGSEGV?錯誤有三個常見原因:
編碼錯誤:容器進程沒有正確初始化,或者它試圖通過指向先前釋放的內存的指針來訪問內存
二進制文件和庫之間不兼容:容器進程運行的二進制文件與共享庫不兼容,因此可能會嘗試訪問不適當的內存地址
硬件不兼容或配置錯誤:如果您在多個庫中看到多個分段錯誤,則主機上的內存子系統可能存在問題或系統配置問題
如果容器以退出碼 139 終止怎么辦?
檢查容器進程是否處理?SIGSEGV。在 Linux 和 Windows 上,您都可以處理容器對分段錯誤的響應。例如,容器可以收集和報告堆棧跟蹤;
如果您需要對?SIGSEGV?進行進一步的故障排除,您可能需要將操作系統設置為即使在發生分段錯誤后也允許程序運行,以便進行調查和調試。然后,嘗試故意造成分段錯誤并調試導致問題的庫;
如果您無法復現問題,請檢查主機上的內存子系統并排除內存配置故障。
退出碼 143:優雅終止 (SIGTERM)
退出碼 143 表示容器收到來自操作系統的?SIGTERM?信號,該信號要求容器正常終止,并且容器成功正常終止(否則您將看到退出碼 137)。該退出碼可能的原因是:
容器引擎停止容器時觸發,例如使用?docker stop?或?docker-compose down?命令時;
由 Kubernetes 將 Pod 設置為 Terminating 狀態觸發,并給容器 30 秒的時間以正常關閉。
如果容器以退出碼 143 終止怎么辦?
檢查主機日志,查看操作系統發送?SIGTERM?信號的上下文。如果您使用的是 Kubernetes,請檢查 kubelet 日志,查看 pod 是否以及何時關閉。
一般來說,退出碼 143 不需要故障排除。這意味著容器在主機指示后正確關閉。
退出碼 255:退出狀態超出范圍
當您看到退出碼 255 時,意味著容器的 entrypoint 以該狀態停止。這意味著容器停止了,但不知道是什么原因。
如果容器以退出碼 255 終止怎么辦?
如果容器在虛擬機中運行,首先嘗試刪除虛擬機上配置的 overlay 網絡并重新創建它們。
如果這不能解決問題,請嘗試刪除并重新創建虛擬機,然后在其上重新運行容器。
如果上述操作失敗,則 bash 進入容器并檢查有關 entrypoint 進程及其失敗原因的日志或其他線索。
評論
查看更多