docker compose 啟動多容器 示範

建立 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 到版本控制系統中了

留言

張貼留言

如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com