如何在 Docker 容器內修復 Ctrl+C?
簡介
本文的實際問題陳述是,開發人員在執行或建立 Docker 容器時無法使用中斷訊號。這不是 Docker 中的錯誤,而是 Linux 的一個特性。本文解釋了完整的問題以及重現問題的方法和解決方案。
Linux 中的程序
當前正在執行或執行的程式是一個程序。此程序可以是前臺程序或後臺程序。要檢視這些程序,我們有一些終端命令,如 ps 和 top。ps 顯示活動程序,而 top 顯示程序的即時更新。
$ps
輸出將提供程序 ID、連結的tty、程序時間以及正在執行的實際命令或程式。
輸出
PID TTY TIME CMD 2584 pts/0 00:00:00 bash 4146 pts/0 00:00:00 ps
檢視系統中所有正在執行的程序。
$ps –e
輸出
PID TTY TIME CMD 1 ? 00:00:02 systemd 2 ? 00:00:00 kthreadd 3 ? 00:00:00 rcu_gp 4 ? 00:00:00 rcu_par_gp 5 ? 00:00:00 netns . . . . 3650 ? 00:00:01 kworker/1:0-cgroup_destroy 3694 ? 00:00:00 kworker/u4:1-events_unbound 4138 ? 00:00:00 kworker/0:1-cgroup_destroy 4197 ? 00:00:00 kworker/0:2-events 4198 pts/0 00:00:00 ps
這裡有超過四千個程式正在執行。
Linux 終端上的訊號
訊號,或者我們可以稱之為中斷。這些訊號是使用鍵盤快捷鍵傳送到終端的。例如,要貼上,我們使用Ctrl+V。這將傳送一箇中斷,並將其優先順序高於其他正在進行的程序,並將文字或影像貼上到其中。類似地,我們有一些鍵盤快捷鍵可以向 Linux 終端傳送各種中斷。這些訊號如下所示。
Tab
Ctrl+C
Ctrl+D
Ctrl+U
Ctrl+A
Tab
Tab 鍵使用起來很有效率。它有助於自動完成命令。它識別命令的模式,按下時會為您完成命令。例如,停止容器 4b534b34h34b34,$docker stop 4b5,然後按 Tab 鍵,它將獲取完整的容器 ID。
Ctrl+C
此快捷鍵將終止/中止/殺死當前正在執行的程序或命令。當命令陷入迴圈或您忘記向命令新增某些內容時,這很有用。只需使用快捷鍵終止命令,然後重新執行編輯後的命令。
Ctrl+D
此中斷將殺死當前使用者終端,並回溯到上次使用的使用者終端。
Ctrl+U
這將刪除整行並使游標移動到該行的開頭。
Ctrl+A
這將游標移回命令的開頭,而不會刪除命令。
重現問題的方法
實施下面給出的方法以在您的機器上重現問題。問題是 Docker 容器對中斷訊號 Ctrl+C 沒有響應。
方法 1
在沒有任何模式的情況下執行容器,併發出一個命令,該命令將使程序保持幾秒鐘。
$docker run busybox sleep 10
輸出
無論您按下 Ctrl+C 多少次,都不會有任何響應。此快捷鍵應該已經終止了容器中執行的sleep 10命令。該命令將完全執行。
方法 2
以互動模式執行容器。應該傳遞相同的sleep命令,然後按下鍵盤上的快捷鍵。
$docker run -i busybox sleep 10
命令在容器內執行。
方法 3
現在使用 -t 標記新增 tty 選項,並檢查是否有任何變化。
$docker run -t busybox sleep 10
相同的結果,命令將完全執行。
方法 4
使用互動式和 tty
$docker run -it busybox sleep 10
方法 5
包含分離標記。
$docker run -itd busybox sleep 10
Docker 容器將在後臺執行 10 秒。如果您在執行命令後立即按下 Ctrl+C,它將不會響應中斷。
問題的解決方法
在瞭解解決方案之前,我們必須知道為什麼中斷訊號在上述方法中不起作用。我們傳遞給容器的命令 sleep 獲取一個程序 ID 作為PID 1。而PID 1對其他程序具有一些特殊許可權。這就是中斷無法終止PID 1或sleep命令的原因。
為了解決此問題,Docker 提供了一個名為--init的選項。這將克服我們與不同中斷訊號相關的所有問題。
$docker run --init busybox sleep 10
現在 Docker 容器將響應Ctrl+C中斷,並將終止命令sleep 10,而不會完全執行。
上述解決方案的證明
不帶 --init |
帶 --init |
---|---|
$docker run busybox ps |
$docker run --init busybox ps |
PID USER TIME COMMAND 1 root 0:00 ps |
PID USER TIME COMMAND 1 root 0:00 /sbin/docker-init -- ps 7 root 0:00 ps |
在第一種情況下,ps 命令的PID為1,但在第二種情況下,PID 1是docker-init,這就是我們能夠在第二種情況下終止ps命令的原因。
結論
有時一些小問題會阻礙您的整個專案。在這裡,我們討論了各種中斷訊號以及如何在特殊情況下將它們連線到 Docker 容器。Docker 不僅僅是關於學習容器化,還關於以最有效的方式使用它來實現我們的目標。