如何在 Docker Compose 中保持容器運行
1.概述
Docker 容器運行一個進程、應用程序,或者有時只是一個腳本或命令,來執行它設計的任務。
一旦容器內沒有任何進程或腳本運行,**每個容器就會停止並退出。有些容器預設持續運行,直到使用者選擇停止它們,例如 MySQL 資料庫、Spring Boot Web 應用程式或 SMTP 郵件伺服器的容器。但有時我們需要讓容器在主要任務完成後仍保持運行**,例如 Ubuntu 容器。
在本文中,我們將學習如何使用 Docker Compose 來實現這一目標。
2. Docker Compose 設定
Docker Compose 是我們用來定義和執行多容器服務的工具。唯一的先決條件是在受支援的作業系統平台上安裝 Docker(Docker 伺服器、Docker 用戶端和 Docker Compose)(在本教學中我們將使用 Linux Ubuntu)。
3. 運行 Ubuntu 容器
我們將使用名為docker-compose.yml
的範例 Docker Compose 設定檔來定義服務:
services:
demo:
image: ubuntu
3.1.啟動 Docker Compose 服務
讓我們使用-d
選項在背景執行服務的容器:
$ docker-compose up -d
該命令的輸出表明它創建了一個容器:
Creating ubuntu_demo_1 ... done
讓我們來看看 Docker Compose 服務建立的容器是否正在執行。我們使用docker ps -a
指令列出容器:
$ docker ps -a
結果是正在運行和已退出的容器列表:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a66cec15e72c ubuntu "/bin/bash" 10 seconds ago Exited (0) 9 seconds ago ubuntu_demo_1
Docker Compose 服務啟動的ubuntu_demo_1
容器在建立後不久就退出。
現在我們的設定已經完成,讓我們看看透過以下方法來保持這個容器運作:
- 分配 TTY
- 使用
tail
指令 - 使用
sleep
指令 - 使用無限循環腳本
3.2.測試之間的清理
在瀏覽每個範例時,刪除我們演示的每個策略之間的容器將會很有幫助。我們可以使用docker-compose down
指令來實現這一點:
$ docker-compose down
Stopping ubuntu_demo_1 ... done
Removing ubuntu_demo_1 ... done
Removing network ubuntu_default
這也會刪除為 Docker Compose 服務建立的所有網路或磁碟區。
4. 分配 TTY
我們可以為範例 Ubuntu 容器指派一個偽 TTY 以使其保持運作。之所以被稱為“psuedo”,是因為沒有使用任何實體設備驅動程式;偽終端驅動程式使容器看起來像終端連接會話。
讓我們透過將key: value
字典對tty: true
加到範例設定檔來分配一個 TTY:
services:
demo:
image: ubuntu
tty: true
現在,我們使用相同的命令建立服務的容器:
$ docker-compose up -d
我們會看到它仍在運行:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dcc44f90a9eb ubuntu "/bin/bash" 16 seconds ago Up 13 seconds ubuntu_demo_1
Docker Compose服務啟動的ubuntu_demo_1
容器正在運作。當我們連接 TTY 時,Docker 守護程序會保持主程序運行,從而保持容器運行。
5.使用tail
命令
我們必須保持容器運作的另一種方法是使用tail
指令:
services:
demo:
image: ubuntu
command: "tail -f /dev/null"
我們在這裡所做的是使用tail
指令及其-f
選項從 TTY 上的 stdin 連續讀取。透過使用/dev/null
, tail
永久「讀取」該設備,從而使我們的容器保持運作。
讓我們啟動 Docker Compose 服務,然後列出所有正在執行的容器:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5b293dbf6cc9 ubuntu "tail -f /dev/null" 18 seconds ago Up 17 seconds ubuntu_demo_1
確實,我們的ubuntu_demo_1
容器仍在運行。
6.使用sleep
指令
我們可以使用**sleep
指令保持容器運作:**
services:
demo:
image: ubuntu
command: "sleep infinity"
這是有效的,因為它在我們的容器的 bash shell 中創建了一個 TTY 。使用infinity
意味著命令永遠不會完成,從而使我們的容器永遠運作。
讓我們再次建立服務的容器。之後,讓我們列出所有正在運行的容器:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c55a8b1f3839 ubuntu "sleep infinity" 2 minutes ago Up 2 minutes ubuntu_demo_1
確實,容器正在運行。
7.使用無限循環腳本
此外,我們可以在使用 Docker Compose 啟動的容器內執行無限循環腳本,結合使用while
和do
指令來保持容器運作。讓我們來看一個例子:
services:
demo:
image: ubuntu
command: "sh -c 'while true; do sleep 1; done'"
讓我們執行修改過的 Docker Compose 服務,然後列出所有正在執行的容器:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f690849f774 ubuntu "sh -c 'while true; …" 14 seconds ago Up 12 seconds ubuntu_demo_1
Docker 容器繼續運行,因為當條件while true
,它始終為真。
與使用sleep infinity
指令相比,使用無限while
循環腳本的優點在於,使用者可以在while
循環中執行其他指令來執行任務,例如輸出日誌訊息或尋找進程狀態。
8.為什麼這對hello-world
不起作用?
有趣的是,我們不能使用這些方法來保持所有類型的容器運作。我們上面的所有範例都假設我們可以在容器內啟動 bash shell 來執行 Linux 命令。這對於使用ubuntu
映像或任何其他基於 Linux 的映像建立的 Docker Compose 服務非常有效。
但作為一個例子,我們無法讓基於hello-world
映像的容器保持運作。為了找出原因,讓我們回顧一下hello-world
映像的Dockerfile
:
FROM scratch
COPY hello /
CMD ["/hello"]
scratch
映像通常用於建立基礎映像,其本身不提供 Linux 環境。如果沒有 Linux 環境,就沒有可以執行指令的 shell。
9. 結論
在本教學中,我們了解了在 Docker Compose 中保持 Docker 容器運作的不同方法。讓我們記住,我們不需要對所有 Docker 容器執行明確配置來保持它們運作。這是因為一些 Docker 容器在容器內啟動一個應用程式或一個進程作為其典型功能,這使得容器預設保持運行。
此外,我們無法讓所有類型的容器保持運行,因為某些容器不支援在其中運行 Bash shell 和其他 Linux 命令。
與往常一樣,本文中使用的 Docker 命令腳本可在 GitHub 上找到。