在介紹Dockerfile的用法之後,本文中將繼續談談關聯性相當高的「 Docker Compose 」用法,不過進入主題之前,讓我們先來搞清楚Dockerfile和Docker Compose有什麼差別?以我個人的理解,可以用以下簡單的方式去解釋:(觀念有錯的話請留言告之)
註:這篇文章原本應該在介紹完Dockerfile之後就撰寫,不過時間上真的有點不允許,所以整整遲了快二年才發佈,希望對大家還是有幫助 XD
簡單的來說,Dockerfile是用來描述一個映像檔應該長的什麼樣子,而Docker Compose則是用來描述一個Service(服務)應該怎麼來組成,例如:在架設網站的時候你可能會用到Tomcat、MySQL等不同的容器,而Docker Compose的描述檔就是用來設定這些容器之間的關聯,諸如誰要先啟動、Port要怎麼設定等等的,用Docker Compose的方式可以一次帶起所有的服務 (即管理多個Container),不需要一個一個執行
官方範例
Docker Compose標準的配置檔案(docker-compose.yml)是採用YAML的格式撰寫,內容大概如下所示(此內容取自官方參考範例),每個Service可以視為一個Container,也就是一個服務,以此範例來說,這個組態檔中定義了
註:YAML的撰寫規範不在本文的說明當中,例如空格、對齊、Key/Value、大小寫等等的用法,請自行注意或參考網路上的文件說明
# 官方範例
version: '3.3'
services:
db: # 服務名稱一,可自訂名稱
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress: # 服務名稱二,可自訂名稱
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
安裝 Docker Compose
在官方的安裝文件說明中,有各平台的安裝方式,在本文將以Linux Ubuntu為例來進行示範。(安裝Docker Compose前建議先安裝Docker)
到這邊查最新版本,把版本號1.29.2換成你想要的版本,原則上還是越新版本越好,然後執行以下二行指令即可:
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
最後可以執行以下指令來查看安裝後的版本號
docker-compose version (or -version / --version)
頂級層級元素 (top-level element)
由於Docker Compose的組態檔變化其實還蠻多的,但大致上比較常見可以分為:version、services、networks、volumes等幾個部份,因此,本文將著重在這些元素的解釋,並配合上面的官方範例進行說明,以求新手可以快速建立Docker Compose撰寫架構,至於詳細的撰寫規定及更多的用法,可參考官方的文件。
version
用來指定Docker Compose的架構版本,可參考官方的列表,不同的版本支援的語法或元素標籤可能會有所不同,建議還是以新版本為主,例如:
version: '3.3'
services
設定各服務(容器)的參數與值,例如,可以定義上述範例中的db、wordpress這二個服務應該長什麼樣子,一般而言,常見的搭配服務層級(service level)元件有以下幾個:
image
指定服務的映像檔名稱或映像檔ID,例如 db 這個service的映像檔來源是mysql的5.7版本
services:
db:
image: mysql:5.7
volumes
即掛載目錄或者已存在的資料volume,基本的格式為
volumes:
- db_data:/var/lib/mysql # 掛載已定義好的volume db_data,請參考volumes頂級元素說明
- /opt/data:/var/lib/demo # 本機/opt/data連通到Container的/var/lib/demo
- /var/lib/demo # 只指定容器內的資料夾路徑,此案例本機會自動產生連通的目錄
如果只設定容器內的資料夾路徑,而沒有指定本機路徑,則本機的Volume是會自動產生的,可以利用以下指令來查詢
docker inspect -f '{{.Mounts}}' 容器名稱/容器ID
restart
設定Container重新啟動的規則,目前支援no、always、on-failure、unless-stopped等四個選項,一般會設為「always」,即當Container停止或開機時可以自動啟動Container
restart: always
environment
定義容器內的環境變數,類似
environment:
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
RACK_ENV: development
SHOW: "true" # 建議如果是布林值的話,則加入引號
USER_INPUT:
environment:
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
- RACK_ENV=development
- SHOW=true
- USER_INPUT
depends_on
設定容器間的依賴關係,即決定容器啟動的先後順序,以範例而言,wordpress依賴db服務,換言之就是db服務先啟動後才換wordpress啟動
services:
db: # 服務名稱一
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
wordpress: # 服務名稱二
depends_on: # 依賴 db 服務
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
ports
用來定義本機與容器間Port的對映關係,基本的格式也是
ports:
- "3000" # 不指定本機Port,本機會隨機自動產生
- "45678:22" # 本機的45678 Port對映到容器的Port 22
所以,以本次的例子來看,wordpress這個服務設定了8000 Port來對映容器內部的80 Port
wordpress: # 服務名稱
depends_on:
- db
image: wordpress:latest
ports: # 設定本機Port和容器Port間的對映關係
- "8000:80"
restart: always
networks
網路連線的相關設定,例如可設定不同的Container運行在同一個網路中,當沒有指定網路環境時,預設Docker Compose會自動建立default network,其名稱為「
因上面的範例中沒有networks的元素,所以我改寫了官方提供的其他範例給大家參考,在此範例中,服務「frontend」用的是front-tier、back-tier這二個網路,而「backend」用的則是back-tier網路。
services:
frontend: # 服務一
image: awesome/webapp
networks:
- front-tier
- back-tier
backend: # 服務二
image: awesome/backapp
networks:
- back-tier
networks: # 定義網路
front-tier:
back-tier:
指令
volumes
儲存空間的相關設定,用來實現持久性數據的儲存,簡單的來說,設定volumes通常是為了避免Container被移除後導致資料遺失,所以才需要把資料夾掛載出來,此元素亦可以省略。以是下來自官方的其他範例,這範例主要在說明不同的服務,可以共用相同的volumes名稱,如下方範例之
services:
backend:
image: awesome/database
volumes:
- db-data:/etc/data # 設定volume
backup:
image: backup-service
volumes:
- db-data:/var/lib/backup/data # 設定volume
volumes:
db-data: # 共用db-data這個volume
Docker Compose 動手做做看
在經過上面的解說後,讓我們直接執行看看吧,這樣會比較有感覺,步驟如下:
1. 先建立一個專案資料夾
建立資料夾便於管控我們的檔案,在此假設我們建立一個名為「mydemo」的資料夾
2. 編輯 docker-compose.yml
進入「mydemo」目錄並用自己的習慣的編輯器建立「docker-compose.yml」檔案,檔案內容為上述的官方範例
3. 執行 docker-compose.yml
執行以下指令,即可利用docker-compose.yml檔帶起所有的服務,其中
由下圖可以看到執行指令後會自動依 docker-compose.yml 的內容來動作,首先會先下載 MySQL (即 db 服務)
接下來會繼續拉取 WordPress 服務的 Image,因為在 docker-compose.yml 中我們並沒有設定Name,所以結尾時會自動幫我們建立
執行完成後,可以檢查一下,用下面的指令可以看的出來Container都已經準備好了,Name也如上圖所說已自動建好名稱,分別為「mydemo_db_1」與「mydemo_wordpress_1」
註:加
docker ps --format "table {{.ID}}:\t{{.Image}}\t{{.Names}}"
4. 連線至 WordPress
依照docker-compose中的設定,Wordpress服務是對外開放8000 Port (對映至Container的 80 Port),所以連線的時候用瀏覽器輸入以下的網址格式來連線即可 (把 your-ip 換成你真正的IP)
由下圖可以看到已可正常的存取Wordpress (此為首次連線,進行WP安裝的畫面)
安裝過後即可正常的登入,畫面如下:
5. 查看網路資訊
在前面有提到,如果YAML檔沒有指定網路環境時,預設會自動建立default network,其名稱為
註:說明一下grep後面的參數意義,
由下圖可以看到,網路資訊中的確顯示
6. 查看資料掛載的資料夾
在官方範例中,不管是db或是wordpress的service,他們都是把容器內的資料夾統一指向「db_data」,並沒有特別指定到哪個本機資料夾中,這代表Docker在執行時會自動產生對映的目錄,那麼這個目錄在哪呢?如上述service level的「volumes」介紹所提,可以利用以下二種方式查看:
# cce 換成你自己的Container ID
① docker inspect cce | grep -A 10 Mounts
② docker inspect -f '{{.Mounts}}' cce
由查詢的結果可以得知,「/var/lib/docker/volumes/8ba15b…(略)/_data」是掛載到本機的目錄位置,此時如果進入此目錄查看的話,的確會看到許多Wordpress相關的資料檔案,如下圖:
7. 刪除Container後資料還在嗎?
接下來做個實驗,試著把Container移除,再來看看資料是否還會存在?Volume會怎麼變化?移除Container的指令如下:
docker-compose down # 移除Container,此時Wordpress已無法連線
當移除Container後,使用
8. 重新執行Container後資料是否會正常?
那麼,試想一下,如果此時重新執行
此時,讓我們連線到Wordpress看看吧,如預期,其實是可以正常連線的,資料呈現也都正常
秉持的實驗精神,我們再利用
Docker Compose 常用指令列表
使用
註:docker-compose的用法其實和docker指令大同小異,若一些指令不熟的話,可以參考一下文末附上的文章
參數 | 範例 / 說明 |
---|---|
ps | docker-compose ps |
查看Container的狀態 | |
stop | docker-compose stop |
停止Container,但不會移除。可以用docker-compose start再重新啟動 | |
start | docker-compose start |
啟動Container,可搭配docker-compose stop使用 | |
restart | docker-compose restart |
重新啟動Container | |
down | docker-compose down / docker-compose down -v |
會把Container、Netwrok等移除,通常和docker-compose up搭配。參數 |
|
up | docker-compose up / docker-compose up -d |
建立、執行Network與Container,通常和docker-compose down搭配,習慣上會再加一個 |
|
logs | docker-compose logs / docker-compose logs -f |
查看Service輸出的日誌,可以加 |
|
rm | docker-compose rm / docker-compose rm -v |
刪除「已停止」的Container,若加上 |
|
exec | docker-compose exec |
和docker exec的差不多,可以進入容器內執行相關指令與操作,例如以本文的官方範例來看,你可以執行 |
小結:好囉,這個基本的Docker Compose架構就寫了一大篇文章,可能在撰寫的架構上還不是很嚴謹,會有一點亂,不過還是希望給一些想學Docker/Docker Compose的人一點幫助,如果文章內容有誤,也請留言告之,歡迎分享、討論。
參考資料:
.VS Code 使用者的 Docker 簡介 – 第7部分 使用 Docker Compose
.The Compose Specification
.Overview of docker-compose CLI
延伸閱讀:
.Docker – 新手入門,快速安裝與基本指令介紹
.Docker Container 指令:Docker run & Docker exec
.Docker – Dockerfile 指令教學,含範例解說