昨天我們用 Compose file 一次描述三個容器, Compose file 如下:
// docker-compose-bridge.yml
version: '2'
services:
database:
image: mongo:4.1
container_name: mongo4
ports:
- "27017:27017"
volumes:
- "./data/mongo/data:/data/db"
frontend:
image: ithelp/frontend:1.0.0
container_name: ithelp.frontend
ports:
- "80:80"
volumes:
- "./data/nginx/log:/var/log/nginx"
backend:
image: ithelp/backend:1.0.0
container_name: ithelp.backend
ports:
- "3001:3001"
command: >
/bin/bash -c "
sleep 15;
npm run start;"
environment:
PORT: 3001
NODE_ENV: "development"
MONGODB_URL: "mongodb://database:27017"
在用指令 docker-compose
建立並執行它們:
仔細看有一行:Creating network "ithelp-30dayfullstack-day30_default" with the default driver
。這是什麼呢?
這就是今天要討論的內容:network 。 network 很重要,因為關係它各服務間的通信。
我們會重心放在如何使用,而不是放在解析 docker network。先學會使用,再去深究其原理。有興趣的人可以挑戰看看這篇 Docker Reference Architecture: Designing Scalable, Portable Docker Container Networks。
今天的內容全是指在單一主機用 Docker Compose 可能會發生的 network 情況。在還沒進到叢集的世界之前,不同主機的連線,用 IP 連就可以了。光是用 Docker Compose 你就能感受到 docker 的威力。
在開始前,我們開一個 ithelp-30dayfullstack-Day30
資料夾,所有的 Compose file 都會放在裡面。
這是 Docker Compose 預設的網路模式,所有有 service 預設 network_mode:
都是 bridge (見 network_mode)。當我們 docker-compose up
時,會建立一個名為 <dir_name>_default
的 network 出來,所有 bridge mode 的 container 會自己配網路卡並接上那個預設的 network。
我們在回憶中的 Compose file,用圖解如下:
圖片重繪自:Networking for Docker Containers (a Primer) Part I
172.28.0.0/16
是指一網路的網段從172.28.0.1 ~ 172.28.255.255
,子網路的主機可以互相通訊。 16 是指 16 bits 的子網路遮罩255.255.0.0
。
你可以用
docker network ls
列出所有 network
Container 間的通訊有幾個方法:
backend:
…略
environment:
PORT: 3001
NODE_ENV: "development"
MONGODB_URL: "mongodb://database:27017"
backend
可以訪問 database
。docker network inspect ithelp-30dayfullstack-day30_default
可以查詢「接上此 network 的 container 資訊」ithelp-30dayfullstack-day30_default
有三個容器及它們配置的 IP。另外還有 gateway 和 subnet。若外界 192.168.0.5
要訪問我們的主機 192.168.0.2:80
的 ithelp.front
服務,我們要設定 --publish
/-p
。就是我們在 Docker file 中的 ports:
或 docker run -p
設定 publish。同時, Network Address Translation(NAT) 也會自動設定內外部 network 的轉換。
從外界來看,邏輯上就像:
外界不會發現內部的網路。
若 container 要與外界通訊,可以跟往常一樣用 hostname / ip。除非你刻意去調整 dns/host 之類的設定,不然正常使用就可以了,我們不打算深究。
反而, Container 存取 HOST 是有可能發生的,因為在還沒完全引入 docker 前,我們可能在 HOST 已架好 MongoDB / MySQL 之類的服務。接下來考慮兩種可能的情況。
container 建立時會配置網路設定,沒重建立的話 IP 是不會變的。 在 bridge mode 下,NAT 那單元可以直接看成是 HOST,所以 HOST 的 IP 在 DOCKER0 BRIDGET
network 中的位置就是 gateway IP
。因此,在容器中,要訪問到 HOST 是 DOCKER0 BRIDGET
下的 gateway IP
而不是 127.0.0.1
(127.0.0.1
是指容器本身)。
你可以登入 container (
docker run -it <id/container_name> bash
) 試打看看(ex: telenet/ping/wget/curl),就可以知道有沒有通。
指令 docker network inspect ithelp-30dayfullstack-day30_default
就可以查到 gateway IP。
練習時,你可能要
docker-compose -f docker-compose-bridge.yml down
刪除之前的容器、網路。
容器內的環境有時需要 hard code 寫 HOST 的 IP,像是 Nginx 要導轉到 HOST 的舊網址、Nginx 要導轉轉到某個 Container 或 MonoDB 連線網址寫死在 Compose file。這時候每次重建 containers 網路就會變了。因此,我們可以客製化 bridge 的設定固定 IP,一方面可以固定 Container IP 又可以固定 HOST IP。
為了固定 IP,我們要建立一個 network ithelp_application
設定裡面的 subnet:
和 gateway:
,接著,每個容器使用 ithelp_application
network 並指定固定 IP。 如下:
version: '2'
services:
database:
image: mongo:4.1
container_name: mongo4
networks:
ithelp_application:
ipv4_address: 172.28.0.2
ports:
- "27017:27017"
volumes:
- "./data/mongo/data:/data/db"
frontend:
image: ithelp/frontend:1.0.0
container_name: ithelp.frontend
networks:
ithelp_application:
ipv4_address: 172.28.0.3
ports:
- "80:80"
volumes:
- "./data/nginx/log:/var/log/nginx"
backend:
image: ithelp/backend:1.0.0
container_name: ithelp.backend
networks:
ithelp_application:
ipv4_address: 172.28.0.4
ports:
- "3001:3001"
command: >
/bin/bash -c "
sleep 15;
npm run start;"
environment:
PORT: 3001
NODE_ENV: "development"
MONGODB_URL: "mongodb://database:27017"
networks:
ithelp_application:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
gateway: 172.28.0.1
執行 docker-compose -f docker-compose-bridge-static.yml up
,完成後去看看 docker network inspect ithelp-30dayfullstack-day30_ithelp_application
,就是我們固定的 IP
練習時,你可能要
docker-compose -f docker-compose-bridge-static.yml down
刪除之前的容器、網路。
這是最簡單的模式,直接想成 container 執行在 HOST 的 process,它監聽什麼 port , HOST 什麼 port 就會被使用,連 --publish
/-p
都不用了。
這模式的通訊比較簡單,不像 bridge mode 複雜。127.0.0.1
就是指 HOST,所以每個容器可以用 127.0.0.1:<port>
通訊,與其它的 HOST 服務也是一樣;外界就是用 192.168.0.2
。
version: '2'
services:
database:
image: mongo:4.1
container_name: mongo4
network_mode: "host"
volumes:
- "./data/mongo/data:/data/db"
frontend:
image: ithelp/frontend:1.0.0
container_name: ithelp.frontend
network_mode: "host"
volumes:
- "./data/nginx/log:/var/log/nginx"
backend:
image: ithelp/backend:1.0.0
container_name: ithelp.backend
network_mode: "host"
command: >
/bin/bash -c "
sleep 15;
npm run start;"
environment:
PORT: 3001
NODE_ENV: "development"
MONGODB_URL: "mongodb://127.0.0.1:27017"
圖片重繪自:Networking for Docker Containers (a Primer) Part I
我們介紹了 Bridge mode、Host mode,它們有各自的特色:
bridge mode:
Host mode:
到這裡為止,我打算就結束今天的內容。今天的最後我們來回顧一下,我們做了什麼事、什麼事沒做?
先恭喜看到這的你,熬過三十天的疲勞轟炸。我們歷經了三個周目:
在 Day 1 - 前言/開發環境準備 曾提過我們三十天要涵盖的內容如下,若有提到我們就把它們劃掉
我想達成率只有 65% 左右,有些內容還被我刪減,離我想寫完整的東西還有一段路。每天的內容一直調整,很多時候因為時間不夠、篇幅有限、考慮到完整性、可讀性,我只能做刪減。但是,不論我怎麼調整,目標只有一個: 帶讀者瀏覽從前端到後端再到 DevOps 的歷程。
本主題只是打開你在各個技術的大門,能否或需不需要踏入就要由你自行決定了。我相信一定有很多專門的主題或文章可以說的更好,希望我能作為你看那些文章的墊腳石。
因為寫的很趕,寫完後,只能校稿一次,也許會有不通順的地方請見諒。內容不完整或缺少的部分,我目前在計畫找時間補上。未來的文章,有可能會在 Medium 或 iT邦幫忙 同時發佈,喜歡的話可以 Follow,謝謝各位。
恭喜完賽!謝謝分享~訂閱這個系列讓我收穫很多!
謝謝妳回饋
能讓讀者學到東西,一切的幸苦都值得了。
恭喜大大完賽,雖然內容不是很懂,但感受的到,撰寫時的用心,謝謝您!恭喜。
謝謝你的回應
第一次參加鐵人賽,我還有很多進步空間,我會再努力的
我發現 小信豬的原始部落 - [Docker] Bridge Network 簡介 寫的很好,邊實驗邊解釋並得到結論,有興趣的人可以看一下,會對 Bridge Network 更了解。