如果您想知道如何使用Docker Compose創建可重現的Docker容器,您來对地方了。在這個逐步進行的Docker Compose教程中,您將學習如何創建簡單的容器,以及如何使用Docker Compose映射端口,一直到複雜的多容器情景。
準備好了嗎?讓我們開始吧!
先決條件
如果您想逐步跟隨,請確保您擁有以下內容:
- A fresh install of Ubuntu Server LTS with SSH Enabled. This guide will use Ubuntu Server LTS 20.04.1 as the Docker host machine.
- A computer with VS Code installed (optional). This guide will use Visual Studio Code 1.52.1 to SSH to the Docker host and run commands.
- 已安裝並連接到Docker主機的VS Code官方SSH擴展(可選)
什麼是Docker Compose?
在Docker中,單個命令可能會變得很長,真的很長。以下面的例子為例。此示例創建了一個名為bookstack的軟件應用程式的容器。
隨著 Docker 環境的複雜性增加,需要一個正常運作的容器設定所需的標誌和條件也隨之增加。Docker 命令行開始變得繁瑣且難以進行故障排除,特別是一旦多容器設置進入混合情況。
Docker Compose 是一種使用配置文件而不是極長的 Docker 命令來創建可重複使用的 Docker 容器的方法。通過使用結構化的配置文件,錯誤更容易發現,容器之間的交互作用更容易定義。
在處理容器相依性或多容器環境時,Docker Compose 迅速變得不可或缺。
Docker Compose 是一種絕佳的方式,讓您踏入基礎架構即代碼,而不需要像 Kubernetes 這樣的分散式系統所帶來的複雜性。
Docker Compose 使用一種名為 YAML 的配置文件結構。YAML 類似於 JSON 或 HTML,因為 YAML 是一種結構化的、機器可讀的語言。YAML 專注於保持盡可能人類可讀,同時保持結構化的功能。
YAML 的一個缺點是,制表符和其他空白字符是有意義的,必須進行適當的格式化。VS Code 會為您處理許多這些繁重的工作,這也是為什麼您會看到許多示例在 VS Code 中完成的原因。
安裝 Docker Compose
現在讓我們開始動手吧。假設您已連接到 Docker 主機,現在是時候安裝 Docker Compose 了。
Docker Compose 是 Docker 執行時的獨立套件。但安裝 Docker Compose 也會安裝 Docker 執行時,因此一舉兩得!
要安裝 Docker Compose 和 Docker 執行時,執行以下兩個命令。

安裝完成後,現在應該建立一個資料夾結構來存儲容器。
為 Docker Compose 創建文件夾結構
在使用 Docker Compose 創建容器之前,您應該首先創建一個用於存儲容器的文件夾。不僅應該創建一個用於存儲容器的文件夾結構,而且您會發現各種 Docker 命令對各種配置文件的位置都很敏感;Docker Compose 也不例外。
Docker Compose 的最重要組件是其配置文件,稱為 docker-compose.yaml。正如上面所解釋的,這個配置文件決定了 Docker 運行時應該如何構建容器。
當您運行 Docker Compose 時,該命令將在與命令相同的文件夾中尋找其配置文件。由於這一要求,最好總是在運行 Docker Compose 時創建一個單獨的文件夾。
每個文件夾只能有一個 Docker Compose 配置文件。
為了演示使用 Docker Compose 創建 Docker 容器,首先創建一個文件夾結構,用於存儲未來的容器和其配置文件,使用一個名為 Caddy 的小型文件伺服器。
Caddy 是一個檔案伺服器,類似於 apache httpd 或 nginx,但是使用 Go 語言編寫。Caddy 專為使用便利性而設計(並將自動生成或提供 index.html 檔案)而不需配置。這種組合使得 Caddy 成為初學者的不錯選擇。
假設您已登錄到您的 Docker 主機上,請按照以下步驟創建文件結構:
- 在您的主目錄中,創建一個名為 containers 的文件夾。這個文件夾將是此容器和其他容器的良好佔位符。
- 在 containers 文件夾內,創建一個名為 caddy 的子文件夾。這個文件夾將包含 Docker Compose 配置文件和 Caddy 容器本身。
- 最後,在容器文件夾 caddy 內,創建一個名為 docker-compose.yaml 的空文本文件,這將成為 Docker Compose 配置文件。
創建了文件結構和 Docker Compose 配置文件後,現在可以開始填寫該配置文件的 Docker Compose 配置。
創建 Docker Compose 配置文件
在其最基本的形式下,用於 caddy 容器的 docker-compose.yaml 文件如下所示。在您喜歡的 Linux 文本編輯器或使用 VS Code 中,將下面的代碼複製並粘貼到之前創建的 Docker Compose 配置文件中。
讓我們逐步了解每個顯示的選項:
version
指定了 docker-compose 文件的版本。每个新的 Docker Compose 定义都包含对规范的重大更改。因此版本很重要,这样 Docker Compose 就可以知道需要使用哪些功能。版本 3.7 是 Ubuntu 20.04.1 LTS 支持的最新版本。
Docker Compose 3.x 的完整规范可以在这里找到。链接的文档提及了你可以在 Docker Compose 中使用的每个选项。
services
包含了实际容器的规范。您可以在此部分定义多个容器。caddy
是第一个容器的名称(仅供参考)。container_name
定义了 Docker 给容器的实际名称,并且必须是唯一的。image
是镜像的名称。在这种情况下,caddy 是来自Docker Hub的定义。标签后面的名称或数字由冒号分隔是版本。
端口映射
特别需要提及的是最后一个选项:
在 Docker Compose 中,ports
指令允許您將一個或多個對應從主機到容器。例如,上面您已將主機上的端口80
映射到容器上的端口80
。但是,您不需要匹配端口號。下面的示例將主機上的端口8800
映射到容器中的端口80
。
您還可以定義多個端口,如下所示。
這樣做將會將端口80
和443
都映射到主機(這是 Web 服務器的常見配置,用於提供 HTTP 和 HTTPS)。
在 Docker 映像創建者在創建時定義了可用端口。請務必查看您在 Docker Hub 上使用的映像的文檔或維護者網站以了解可映射的端口。如果該端口未被使用,則沒有映射該端口的意義!
牢記這一點,讓我們來實際運行容器。
運行容器
現在您應該已經在您的~\containers\caddy文件夾中有了docker-compose.yaml文件。現在是創建並啟動 Caddy 容器的時候了。
在您的終端上運行以下命令,該命令將啟動在ocker-compose.yaml文件中定義的 Docker 容器。
您可能注意到,在运行
sudo docker-compose up -d
时,您无需指定 docker-compose.yaml 文件的位置。Docker Compose 期望您在包含 docker-compose.yaml 文件的文件夹中运行所有命令,因为许多命令是相对于该文件夹的。
现在,通过转到 http://<your ip> 验证容器是否正在运行。本指南使用 http://homelab-docker 作为参考。
您可以在以下动画中通过 SSH 进入 Docker 主机时,在 VS Code 中看到此处理过程:

成功!您现在已成功使用 Docker Compose 从配置文件启动容器。完成了这个重要的第一步后,让我们看看如何管理容器的状态。
管理分离容器的命令
在前一节中,您使用 -d
标志启动了 caddy 容器。这样做会以分离状态运行容器。当容器处于分离状态时,容器将继续在后台运行。但是,这带来了一个问题:如果您不再直接控制容器,该如何管理它?
为解决这个问题,Docker Compose 提供了一系列命令,用于管理使用 docker-compose.yaml 文件启动的容器:
docker-compose restart
用于重新启动当前正在运行的容器。这与实际重新运行docker-compose up -d
不同。重新启动命令将简单地重新启动现有容器,重新运行docker-compose up -d
命令,并根据需要从头开始重新创建容器(如果配置文件已更改)。docker-compose stop
将停止运行的容器而不销毁容器。同样,docker-compose start
将再次启动容器。docker-compose down
将停止运行的容器并销毁它们。这就是绑定挂载卷的作用(在下面阅读更多)。docker-compose pull
将从存储库中拉取当前版本的 Docker 镜像(或镜像)。如果使用latest
标签,您可以使用docker-compose down && sudo docker-compose up -d
来替换容器为最新版本。使用docker-compose pull
是一种快速更新容器的便捷方式,减少停机时间。docker-compose logs
将显示运行中(或已停止)容器的日志。如果在组合文件中定义了多个容器,则还可以通过docker-compose logs <container name>
来处理各个容器。
A full list of docker-compose commands can be seen by running
docker-compose
with no additional arguments or referenced here in the documentation.
现在您有一个正在运行的容器,让我们看看如何使用本地保存在您的计算机上的内容。
在Docker Compose中创建绑定挂载
Bind Mounts 是 Docker 將重要的使用者數據映射到伺服器本地存儲的方式。首先,為容器生成一些內容:
- 在 Docker 主機上,在 ~/containers/caddy 文件夾內創建一個名為 files 的新文件夾。
2. 在 ~/containers/caddy 文件夾內創建一個名為 index.html 的新文件,內容如下。這將是 Caddy web 伺服器提供的主頁。
3. 修改 Docker Compose 配置文件,使其如下所示。下面的示例文件添加了 volumes
部分,並將綁定掛載指向剛剛創建的 files 文件夾,以使其對容器可用。
4. 再次運行 docker-compose up -d
。Docker Compose 現在將識別文件已更改並重新創建容器。
5. 使用瀏覽器訪問容器的頁面,現在您應該看到它正在提供“Hello World!”頁面。
您可以在以下動畫中看到以下內容:

您現在正在主機上存儲本地機器上的內容!但是,如果您的內容位於外部源,例如網絡共享,該怎麼辦呢?
使用 Docker Compose 與 Docker Volumes
一旦您使用Docker Compose創建了一個簡單的容器,您可能需要該容器訪問其他地方的文件,也許是在網絡共享上。如果是這樣,您可以在Docker Compose配置文件中直接配置容器使用Docker卷。
為了演示目的,本指南將在Docker主機上創建一個網絡文件共享(NFS)服務器。將本地內容作為NFS掛載在演示之外沒有實際目的。如果要掛載NFS卷,通常是從外部源(如NAS或遠程服務器)。
設置NFS共享
如果您尚未設置NFS共享,請立即在本教程的Docker主機上建立一個。要這樣做:
- 通過運行
apt install nfs-kernel-server -y
來安裝NFS服務器套件。
2. 通過運行以下命令將容器添加為NFS導出(類似於Windows CIFS共享)。
3. 現在,運行showmount -e localhost
來驗證主機是否公開了NFS共享。此命令將顯示目前公開的NFS共享以及誰有訪問權限。
在下面的截圖中,您可以看到/home/homelab/containers被公開,但只對本地主機(即運行Docker主機的同一台伺服器)可用。

如果在輸出中看到文件夾/home/<username>/containers,則NFS共享已設置。
定義Docker命名卷
創建了NFS共享後,現在需要告訴Docker如何訪問該共享。使用Docker Compose,您可以通過在Docker Compose配置文件中定義命名卷來完成這一點。
A named volume is a way for Docker to abstract network-based file shares. Network file sharing comes in all sorts of shapes and sizes these days: CIFS (windows) shares, NFS (Linux) shares, AWS S3 Buckets, and more. By creating a Named Volume, Docker does the hard part of figuring out how to talk to the network share and lets the container just treat the share as if it is local storage.
創建一個命名卷:
- 打開Docker Compose配置文件(docker-compose.yaml)。如果您正在按照進行操作,則文件應該位於~/containers/caddy文件夾中。
2. 在Docker Compose配置文件內,添加一個volumes
部分,位於services
部分之後。您的配置文件應如下所示。volumes
部分創建了一個名為MyWebsite的命名卷。在該命名卷內,指定了所需的參數(例如IP、NFS設置和路徑)。services
部分內的volumes
參數也被修改為指向名稱卷,而不是本地文件夾。
3. 一旦在 Docker Compose 配置文件中定義了指向 NFS 共享的命名卷,運行 docker-compose up -d
以創建並啟動容器。如果一切順利,容器和網站應該會重新啟動。

4. 再次訪問容器的頁面。index.html 的內容應該會顯示,就像該文件被本地掛載一樣。但是,該文件是通過在網絡上設置的 NFS 服務器進行掛載的。

由於現在可以在 Docker Compose 中掛載外部 Docker 卷,因此可以將各種類型的網絡存儲引入容器中。但是,Docker Compose 不僅可以定義單個容器或卷。讓我們深入研究更複雜的多容器場景。
此教程將不再使用 caddy 容器,因此您可以使用
docker-compose down
刪除容器。
在 Docker Compose 中定義多個容器
大多數 Docker 容器不能獨立運行。 Docker 容器通常具有依賴服務,如數據庫或通過 API 交互的獨立 Web 服務。
使用 Docker Compose,您可以將容器分組在一個單獨的文件中定義。通過在單個文件中定義多個容器,容器可以在依賴服務之間進行通信,並簡化複雜容器布局的組織。
為了演示這樣的情況,讓我們設置一個名為BookStack 的流行 Wiki 應用程式。
BookStack是一款以易用性和分层布局(而非扁平布局,如mediawiki)而闻名的流行维基软件。
BookStack,像许多Web应用一样,需要一个单独的数据库来正常运行,以及与数据库通信所需的信息。设置这样的情况正是Docker Compose的优势所在。
创建Docker Compose配置文件
BookStack没有内部维护的Docker镜像,然而linuxserver.io代表BookStack维护着一个声誉良好的Docker Hub镜像。虽然Docker Hub网站上的文档有推荐的Docker Compose配置文件,但本教程将构建一个新的配置文件,并解释其中的概念。
在Docker主机上:
- 首先,为BookStack创建一个文件夹。如果您按照上一节的教程进行操作,您应该有一个~/containers文件夹。在其中创建一个名为bookstack的文件夹。
2. 然后,在bookstack文件夹内创建一个名为docker-compose.yaml的空白Docker Compose配置文件。

3. 现在打开Docker Compose配置文件,并定义两个容器:bookstack
容器和bookstack_db
(mariadb)容器。
到目前為止,這個docker-compose.yaml文件主要使用了已經介紹過的概念:您有兩個服務(bookstack
和 bookstack_db
),都有映像和綁定掛載。bookstack容器將主機端口8080映射到內部端口80。
鑑於Docker容器的極低開銷,將每個Web應用程序定義一個單獨的數據庫容器是一種常見做法。這樣做可以實現更大的職責分離。這與傳統的數據庫設置有明顯區別,傳統設置中單個數據庫安裝可能為數百個Web應用程序提供服務。
您在上述文件中可以看到的一個新選項是depends_on
命令。此命令告訴Docker容器應該以什麼順序啟動。定義depends_on
命令告訴Dockerbookstack_db
容器必須首先啟動。必須
使用環境變量設置容器通信
上一節中構建的此配置文件還不完整。雖然您已經定義了兩個服務(容器),但它們彼此之間並不通信!bookstack
容器不知道如何與bookstack_db
容器通信。讓我們使用環境變量來解決這個問題。
環境變量是向Docker容器提供變量的最常見方法。這些是在運行時提供的變量(或在docker-compose.yaml配置文件中定義的),用於提供有關容器需要執行的操作的信息。
環境變數是由創建 Docker 映像的人定義的。根據您使用的 Docker 映像不同,這些環境變數也會有所不同,您必須參考創建者的文檔,了解應該使用哪些環境變數。
定義環境變數有兩種方法:直接在 docker-compose.yaml 文件中或作為一個獨立文件。
A separate file is, typically, the recommended method, especially if variables contain sensitive data such as passwords. A docker-compose.yaml file is designed to be shared or even uploaded to a public-facing GitHub repo. Having a separate file for sensitive data reduces the chance of an accidental security breach.
在 Docker 主機上,現在創建兩個環境變數;一個用於 bookstack 容器,另一個用於 bookstack_db 容器。
- 在 ~/containers/bookstack 文件夾中創建一個名為 bookstack.env 的新文件,其內容如下:
2. 在 ~/containers/bookstack 文件夾中創建一個名為 bookstack_db.env 的新文件,並包含以下內容:
3. 作為最佳實踐,現在確保這兩個 env 文件對其他用戶不可讀。
您應該更改讀取權限,因為 bookstack.env 和 bookstack_db.env 文件中都包含敏感數據。
4. 更新 ~/containers/bookstack/docker-compose.yaml Docker Compose 文件,以引用下面顯示的這兩個環境文件。
5. 現在使用 Docker Compose 啟動 bookstack 和 bookstack_db 容器。
您可以在下面的 VS Code 中看到本節中提到的每個步驟的執行過程。

監控 Docker Compose 日誌
Docker引擎與Docker Compose一同在後台執行多項任務。在處理多個容器時,能夠監控正在發生的事情尤其有幫助。
舉例來說,要監控bookstack容器,使用logs
指令。在本教程中,一旦看到日誌顯示[services.d] done
,即可轉到bookstack的URL。


在這個階段,您應該擁有一個在自己的容器中運行的完全功能的wiki,擁有自己的數據庫,完全在Docker中運行!
只要擁有bookstack和bookstack_db文件夾,您就可以從頭開始重建bookstack環境。
Docker Compose和網絡
到目前為止,您對容器如何協同工作的通信和網絡方面了解不多。讓我們改變這一點。
當您在單個docker-compose.yaml文件中創建多個容器,就像在之前的部分中所做的那樣,它們都被分配到同一個網絡(通常稱為name-of-parent-folder_default)。
當您運行docker-compose up -d
時,您可以看到為容器創建的網絡,如下所示。

當所有容器都分配到同一網絡時,Docker在內部為它們創建DNS條目。這就是為什麼在前面的示例中,您在環境變數中將數據庫稱為bookstack_db
的原因。該bookstack_db
名稱實際上是指向數據庫容器的IP地址的DNS條目。
您也不需要依賴Docker Compose來自動生成網絡。您可以手動定義內部或外部網絡。當您有一個需要和另一個在分開的docker-compose.yaml文件中的容器通信的容器時,手動定義網絡很有用。您可以公開端口,或者您可以創建一個它們都可以加入的網絡!
請注意,當您開始明確定義網絡時,您還必須明確定義默認網絡。一旦您開始定義網絡,Docker Compose將停止自動創建該網絡
現在修改bookstack docker-compose.yaml以包括外部創建的網絡。
- 使用
docker network create my_external_network
命令創建外部網絡。
2. 在docker-compose.yaml中定義外部網絡:
3. 運行docker-compose up -d
以重新創建容器。您的兩個容器現在加入了兩個網絡,如下所示。

bookstack容器現在也加入了一個外部定義的網絡。這允許您在容器離開Docker之前將bookstack的HTTP流量轉換為HTTPS(稱為反向代理)時創建另一個容器。
設置特定用戶運行容器
默認情況下,所有Docker容器都以沙盒化的root用戶運行。這相當於以默認管理員用戶身份登錄的虛擬機運行。儘管這通常不是問題,但如果沙盒被入侵,就會存在安全問題。
以root身份運行還存在文件權限問題。您可能會注意到,如果您試圖刪除bookstack文件夾中的db文件夾,您實際上無法刪除;內容的所有者是root。
儘管大多數映像不建議以非root用戶身份運行,特別是linuxserver.io映像提供了一個環境變量來設置容器內運行的用戶。您可以通過在bookstack.env配置文件中添加UID=1000和GID=1000來這樣做。
1000:1000是ubuntu中第一個用戶的默認用戶ID和組ID(您可能不是)。您可以在以下位置閱讀有關用戶ID和組ID的更多信息:相關鏈接:Windows世界的Linux之旅:用戶和文件權限)
您還可以在docker-compose中使用user參數強制指定UID和GID,但不建議這樣做,因為大多數容器在被強制為不同用戶時表現不佳
設置重啟策略
如果您希望使用Docker Compose建立的容器在故障时重新启动,請在docker-compose.yaml中的容器設定下添加一個restart: <option>
參數,使用restart
策略。
添加此參數將導致容器在發生故障時自動重新啟動,以幫助保持正常運行時間,以應對意外斷電問題。
手動設置容器的DNS記錄
就像在Windows和Linux中一樣,Docker也有“主機文件”。通過在配置文件中使用extra_hosts參數,您可以強制主機解析為特定IP。當您有DNS限制時,例如分割DNS或者暫時想與測試服務器交互時,這將非常有用。
執行命令
一旦容器啟動,您可以使用docker-compose run
在容器內運行命令。例如,也許您想在bookstack容器內啟動Bash終端。要做到這一點,您可以運行以下命令。
結論
在這個階段,您應該已經有足夠的信息來跟隨網上的大多數docker-compose教程。擁有這些知識可以大大擴展您進入Docker世界以及基於基礎架構的網絡應用程序的能力。
Source:
https://adamtheautomator.com/docker-compose-tutorial/