Docker Compose 使用 YAML 文件來(lái)定義多服務(wù)的應(yīng)用。YAML 是 JSON 的一個(gè)子集,因此也可以使用 JSON。
Docker Compose 默認(rèn)使用文件名 docker-compose.yml。當(dāng)然,也可以使用 -f 參數(shù)指定具體文件。
如下是一個(gè)簡(jiǎn)單的 Compose 文件的示例,它定義了一個(gè)包含兩個(gè)服務(wù)(web-fe 和 redis)的小型 Flask 應(yīng)用。
這是一個(gè)能夠?qū)υL問(wèn)者進(jìn)行計(jì)數(shù)并將其保存到 Redis 的簡(jiǎn)單的 Web 服務(wù)。
version: "3.5"
services:
web-fe:
build: .
command: python app.py
ports:
- target: 5000
published: 5000
networks:
- counter-net
volumes:
- type: volume
source: counter-vol
target: /code
redis:
image: "redis:alpine"
networks:
counter-net:
networks:
counter-net:
volumes:
counter-vol:
在深入研究之前粗略觀察文件的基本結(jié)構(gòu),首先可以注意到,它包含 4 個(gè)一級(jí) key:version、services、networks、volumes。
version 是必須指定的,而且總是位于文件的第一行。它定義了 Compose 文件格式(主要是 API)的版本。
注意,version 并非定義 Docker Compose 或 Docker 引擎的版本號(hào)。
示例中 Compose 文件將使用版本 3 及以上的版本。
services 用于定義不同的應(yīng)用服務(wù)。上邊的例子定義了兩個(gè)服務(wù):一個(gè)名為 web-fe 的 Web 前端服務(wù)以及一個(gè)名為 redis 的內(nèi)存數(shù)據(jù)庫(kù)服務(wù)。
Docker Compose 會(huì)將每個(gè)服務(wù)部署在各自的容器中。
networks 用于指引 Docker 創(chuàng)建新的網(wǎng)絡(luò)。默認(rèn)情況下,Docker Compose 會(huì)創(chuàng)建 bridge 網(wǎng)絡(luò)。
這是一種單主機(jī)網(wǎng)絡(luò),只能夠?qū)崿F(xiàn)同一主機(jī)上容器的連接。當(dāng)然,也可以使用 driver 屬性來(lái)指定不同的網(wǎng)絡(luò)類(lèi)型。
下面的代碼可以用來(lái)創(chuàng)建一個(gè)名為 over-net 的 Overlay 網(wǎng)絡(luò),允許獨(dú)立的容器(standalone container)連接(attachable)到該網(wǎng)絡(luò)上。
networks:
over-net:
driver: overlay
attachable: true
volumes 用于指引 Docker 來(lái)創(chuàng)建新的卷。
上面例子中的 Compose 文件使用的是 v3.5 版本的格式,定義了兩個(gè)服務(wù),一個(gè)名為 counter-net 的網(wǎng)絡(luò)和一個(gè)名為 counter-vol 的卷。
更多的信息在 services 中,下面仔細(xì)分析一下。
Compose 文件中的 services 部分定義了兩個(gè)二級(jí) key:web-fe 和 redis。
它們各自定義了一個(gè)應(yīng)用程序服務(wù)。需要明確的是,Docker Compose 會(huì)將每個(gè)服務(wù)部署為一個(gè)容器,并且會(huì)使用 key 作為容器名字的一部分。
本例中定義了兩個(gè) key:web-fe 和 redis。因此 Docker Compose 會(huì)部署兩個(gè)容器,一個(gè)容器的名字中會(huì)包含 web-fe,而另一個(gè)會(huì)包含 redis。
web-fe 的服務(wù)定義中,包含如下指令。
⒈build
指定 Docker 基于當(dāng)前目錄(.)下 Dockerfile 中定義的指令來(lái)構(gòu)建一個(gè)新鏡像。該鏡像會(huì)被用于啟動(dòng)該服務(wù)的容器。
⒉command
python app.py 指定 Docker 在容器中執(zhí)行名為 app.py 的 Python 腳本作為主程序。
因此鏡像中必須包含 app.py 文件以及 Python,這一點(diǎn)在 Dockerfile 中可以得到滿足。
⒊ ports
指定 Docker 將容器內(nèi)(-target)的 5000 端口映射到主機(jī)(published)的 5000 端口。
這意味著發(fā)送到 Docker 主機(jī) 5000 端口的流量會(huì)被轉(zhuǎn)發(fā)到容器的 5000 端口。容器中的應(yīng)用監(jiān)聽(tīng)端口 5000。
⒋ networks
使得 Docker 可以將服務(wù)連接到指定的網(wǎng)絡(luò)上。這個(gè)網(wǎng)絡(luò)應(yīng)該是已經(jīng)存在的,或者是在 networks 一級(jí) key 中定義的網(wǎng)絡(luò)。
對(duì)于 Overlay 網(wǎng)絡(luò)來(lái)說(shuō),它還需要定義一個(gè) attachable 標(biāo)志,這樣獨(dú)立的容器才可以連接上它(這時(shí) Docker Compose 會(huì)部署獨(dú)立的容器而不是 Docker 服務(wù))。
⒌ volumes
指定 Docker 將 counter-vol 卷(source:)掛載到容器內(nèi)的 /code(target:)。
counter-vol 卷應(yīng)該是已存在的,或者是在文件下方的 volumes 一級(jí) key 中定義的。
綜上,Docker Compose 會(huì)調(diào)用 Docker 來(lái)為 web-fe 服務(wù)部署一個(gè)獨(dú)立的容器。該容器基于與 Compose 文件位于同一目錄下的 Dockerfile 構(gòu)建的鏡像。
基于該鏡像啟動(dòng)的容器會(huì)運(yùn)行 app.py 作為其主程序,將 5000 端口暴露給宿主機(jī),連接到 counter-net 網(wǎng)絡(luò)上,并掛載一個(gè)卷到/code。
從技術(shù)上講,本例并不需要配置 command: python app.py。因?yàn)殓R像的 Dockerfile 已經(jīng)將 python app.py 定義為了默認(rèn)的啟動(dòng)程序。
但是,本例主要是為了展示其如何執(zhí)行,因此也可用于覆蓋 Dockerfile 中配置的 CMD 指令。
redis 服務(wù)的定義相對(duì)比較簡(jiǎn)單。
⒍ image
redis:alpine 使得 Docker 可以基于 redis:alpine 鏡像啟動(dòng)一個(gè)獨(dú)立的名為 redis 的容器。
這個(gè)鏡像會(huì)被從 Docker Hub 上拉取下來(lái)。
⒎ networks
配置 redis 容器連接到 counter-net 網(wǎng)絡(luò)。
由于兩個(gè)服務(wù)都連接到 counter-net 網(wǎng)絡(luò),因此它們可以通過(guò)名稱解析到對(duì)方的地址。了解這一點(diǎn)很重要,本例中上層應(yīng)用被配置為通過(guò)名稱與 Redis 服務(wù)通信。