建立 docker-compose.yml
平時我們可以使用 docker run 來啟動 docker 容器,但是每次啟動時通常都需要附加許多參數,指令就會變得很長,例如:
docker run --name my-nginx-container -p 8080:80 -v .\nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
上面指令的意思是建立一個名為 my-nginx-container 的容器,使用的 docker image 為 nginx ,將 80 port 暴露到外面的 8080 port,並且將當前路徑下的 nginx.conf 檔案放到容器內的 /etc/nginx/nginx.conf
假設我們要常常執行這個容器,這樣每次都需要先停止容器、刪除容器,然後才能再次執行上面的指令(因為容器名稱不能一樣)。不過我們可以使用 docker compose 的功能,建立一個 yaml 檔案,將所有指令寫到這個 yaml 中,以後只要使用 docker compose 的指令就可以了,不需要附加這麼多參數,因為都寫在設定檔內了。
docker compose 預設的設定檔名稱為 docker-compose.yml,也可以使用其他的名稱,只是在執行時就需要手動指定是哪個檔案,所以通常都會直接命名為 docker-compose.yml 。這裡我們將上面的 docker run 指令轉換為 docker-compose.yml:
services:
nginx: # 辨識的名稱
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
寫好了 docker-compose.yml 後,要執行也很簡單,指令如下(-d 代表在背景執行):
docker compose up -d
這裡的容器名稱命名規則為:
[資料夾名稱]-[辨識的名稱]-[流水號]
這裡順便列出其他的指令:
停止所有容器:
docker compose stop
刪除所有容器:
docker compose down
如果 yaml 檔案內容更新後要套用最簡單的方式就是先 down 再 up 一次,資料都會被清空,如果是需要儲存的資料就需要使用 volumes 參數將容器內部資料儲存在外部中。
同時啟用多個容器
我們現在有了 nginx 這一個容器,假設現在還需要另一個容器,假設是 mariadb 好了,我們可以這樣寫:
services:
nginx: # 辨識用的名稱
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on: # 依賴的服務
- db
db: # 辨識用的名稱
image: mariadb:11.3.2
restart: always
environment:
MARIADB_USER: user
MARIADB_PASSWORD: mypassword
MARIADB_ROOT_PASSWORD: myrootpassword
並且因為有些服務有先後順序,我們在 nginx 服務使用 depends_on 參數指定 db ,代表 nginx 一定會在 db 服務啟動之後才啟動
容器間的資料交換和 port 映射
從上面的 yaml 中可以發現,筆者沒有映射 mariadb 的 3306 port,那這樣 nginx 容器可以讀取的到嗎?其實在 docker compose 中會自動建立 docker network ,就算沒有任何設定,在 nginx 容器中可以直接連線到 db 容器的 3306, db 容器也可以直接連線到 nginx 的 80 port,下面做一個簡單的示範來證明:首先先進入到 db 容器中(因為筆者存放 yaml 的資料夾名稱叫做 docker-compose-test):
docker exec -it docker-compose-test-db-1 bash
安裝 curl 套件:
apt-get update && apt-get install -y curl
我們先查看 google 的網頁做測試:
(這裡應該會跑出一大堆 html 語法)
curl https://www.google.com
這時候再查看 nginx 容器的 80 port,結果應該會我們本機連線到 8080 port 的內容一樣(只是是 html 語法):
curl http://nginx:80
這裡有幾個很特別的地方:
就和上面說的一樣,因為會自動建立 docker network,所以就算沒有開放 80 port 也可以連線到另一個容器的 port。這樣像資料庫等只要讓其他容器連線,但不需要讓外部存取的 port 的就根本不需要定義。
另外使用 http://nginx:80 這樣的連結也可以成功存取到資源是因為 docker 內部有 DNS,nginx 這個 Domain Name (網域名稱)是依據 yaml 中用來辨識的名稱自動建立的,要連線到其他服務時都可以這樣做,非常方便。
建立 .env 檔案儲存機密內容
在上面的 yaml 檔案中可以看到我們的資料庫密碼,通常我們會將這些設定值抽出來,寫在環境變數中,而如果有很多變數要一一加入到環境變數中也很麻煩,這時候就可以使用 .env 檔案指定變數和機密值(不需要使用單引號和雙引號):
DB_MARIADB_USER=user
DB_MARIADB_PASSWORD=mypassword
DB_MARIADB_ROOT_PASSWORD=myrootpassword
將原本的 yaml 檔案的機密資訊換成變數名稱:
services:
nginx: # 辨識用的名稱
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on: # 依賴的服務
- db
db: # 辨識用的名稱
image: mariadb:11.3.2
restart: always
environment:
MARIADB_USER: ${DB_MARIADB_USER}
MARIADB_PASSWORD: ${DB_MARIADB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${DB_MARIADB_ROOT_PASSWORD}
這樣我們的 yaml 檔案就可以放心的 commit 到版本控制系統中了
感謝教學~
回覆刪除