如何在 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 1sleep命令的原因。

為了解決此問題,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 命令的PID1,但在第二種情況下,PID 1docker-init,這就是我們能夠在第二種情況下終止ps命令的原因。

結論

有時一些小問題會阻礙您的整個專案。在這裡,我們討論了各種中斷訊號以及如何在特殊情況下將它們連線到 Docker 容器。Docker 不僅僅是關於學習容器化,還關於以最有效的方式使用它來實現我們的目標。

更新於: 2023 年 1 月 11 日

3K+ 次檢視

啟動您的職業生涯

透過完成課程獲得認證

開始
廣告