介紹 Docker Network mode 和三十天的回顧
回憶
昨天我們用 Compose file 一次描述三個容器, Compose file 如下:
1// docker-compose-bridge.yml
2version: '2'
3services:
4 database:
5 image: mongo:4.1
6 container_name: mongo4
7 ports:
8 - "27017:27017"
9 volumes:
10 - "./data/mongo/data:/data/db"
11 frontend:
12 image: ithelp/frontend:1.0.0
13 container_name: ithelp.frontend
14 ports:
15 - "80:80"
16 volumes:
17 - "./data/nginx/log:/var/log/nginx"
18 backend:
19 image: ithelp/backend:1.0.0
20 container_name: ithelp.backend
21 ports:
22 - "3001:3001"
23 command: >
24 /bin/bash -c "
25 sleep 15;
26 npm run start;"
27 environment:
28 PORT: 3001
29 NODE_ENV: "development"
30 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 Network mode
Bridge mode
這是 Docker Compose 預設的網路模式,所有有 service 預設 network_mode: 都是 bridge (見 network_mode)。當我們 docker-compose up 時,會建立一個名為 <dir_name>_default 的 network 出來,所有 bridge mode 的 container 會自己配網路卡並接上那個預設的 network。
我們在回憶中的 Compose file,用圖解如下:
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 間如何通訊: Container <-> Container
Container 間的通訊有幾個方法:
- 用 service/container name:直接寫 serivce name/container。
就如同前面寫的
1backend: 2 …略 3 environment: 4 PORT: 3001 5 NODE_ENV: "development" 6 MONGODB_URL: "mongodb://database:27017"backend可以訪問database。 - 用 IP: 我們也可以直接指定 IP。
指令
docker network inspect ithelp-30dayfullstack-day30_default可以查詢「接上此 network 的 container 資訊」
ithelp-30dayfullstack-day30_default有三個容器及它們配置的 IP。另外還有 gateway 和 subnet。
外界(NET-0)如何存取 container: 外界(NET-0) -> Container
若外界 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 的轉換。
從外界來看,邏輯上就像:
存取 host/外界 : Container -> 外界(NET-0)/HOST
若 container 要與外界通訊,可以跟往常一樣用 hostname / ip。除非你刻意去調整 dns/host 之類的設定,不然正常使用就可以了,我們不打算深究。
反而, Container 存取 HOST 是有可能發生的,因為在還沒完全引入 docker 前,我們可能在 HOST 已架好 MongoDB / MySQL 之類的服務。接下來考慮兩種可能的情況。
非固定 IP 情況
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。
固定 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。 如下:
1version: '2'
2services:
3 database:
4 image: mongo:4.1
5 container_name: mongo4
6 networks:
7 ithelp_application:
8 ipv4_address: 172.28.0.2
9 ports:
10 - "27017:27017"
11 volumes:
12 - "./data/mongo/data:/data/db"
13 frontend:
14 image: ithelp/frontend:1.0.0
15 container_name: ithelp.frontend
16 networks:
17 ithelp_application:
18 ipv4_address: 172.28.0.3
19 ports:
20 - "80:80"
21 volumes:
22 - "./data/nginx/log:/var/log/nginx"
23 backend:
24 image: ithelp/backend:1.0.0
25 container_name: ithelp.backend
26 networks:
27 ithelp_application:
28 ipv4_address: 172.28.0.4
29 ports:
30 - "3001:3001"
31 command: >
32 /bin/bash -c "
33 sleep 15;
34 npm run start;"
35 environment:
36 PORT: 3001
37 NODE_ENV: "development"
38 MONGODB_URL: "mongodb://database:27017"
39networks:
40 ithelp_application:
41 driver: bridge
42 ipam:
43 driver: default
44 config:
45 - subnet: 172.28.0.0/16
46 gateway: 172.28.0.1
執行 docker-compose -f docker-compose-bridge-static.yml up,完成後去看看 docker network inspect ithelp-30dayfullstack-day30_ithelp_application,就是我們固定的 IP
Host mode
練習時,你可能要
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。
1version: '2'
2services:
3 database:
4 image: mongo:4.1
5 container_name: mongo4
6 network_mode: "host"
7 volumes:
8 - "./data/mongo/data:/data/db"
9 frontend:
10 image: ithelp/frontend:1.0.0
11 container_name: ithelp.frontend
12 network_mode: "host"
13 volumes:
14 - "./data/nginx/log:/var/log/nginx"
15 backend:
16 image: ithelp/backend:1.0.0
17 container_name: ithelp.backend
18 network_mode: "host"
19 command: >
20 /bin/bash -c "
21 sleep 15;
22 npm run start;"
23 environment:
24 PORT: 3001
25 NODE_ENV: "development"
26 MONGODB_URL: "mongodb://127.0.0.1:27017"
Docker Network mode 小總結
我們介紹了 Bridge mode、Host mode,它們有各自的特色:
bridge mode:
- 高彈性的網路設定
- 不同容器間的 port 號可以一樣,因為容器有自己的 IP
- 可以降低 HOST port 相衝的可能
- 用起來設定複雜
- 容器、 HOST 、外界不容易通訊
Host mode:
- 容易與 HOST port 、容器 port 的相衝、
- 用起來設定簡單
- 容器、 HOST 、外界容易通訊
到這裡為止,我打算就結束今天的內容。今天的最後我們來回顧一下,我們做了什麼事、什麼事沒做?
三十天的回顧
先恭喜看到這的你,熬過三十天的疲勞轟炸。我們歷經了三個周目:
- 一周目 - 一次串完所有的服務 在本地端建立前端和後端並把它們串接起來
- 二周目 - 深入了解前後端 我分別從前後端挑選了重要的概念或是工具作為二周目的主題。
- 三周目 - 發佈、維運 以 Docker 為基礎,製作、發佈自己的前端和後端程式。
在 Day 1 - 前言/開發環境準備 曾提過我們三十天要涵盖的內容如下,若有提到我們就把它們劃掉
前言一輩子受用的工具shell常用指令markdown - 打筆記draw.io - 畫圖
一周目 - 一次串完所有的服務js/nodejs projectjs 速成 - es6語法、模組化eslint - 程式碼品質工具quick backendPostman - api 測式工具quick frontend
- 二周目
開發流程- 後端
基本知識awilix - 依賴注入process.envmiddleware / router / request / response建立與連線 MongoDB- 後端多工/ 叢集/child process
Auth: token - JWT- 常用庫: lodash, monent, mongoose
- 可研究方向: GraphQL, websocket, redis, server-side rending, Oauth
- 測試
基本知識 - 依賴注入單元測試、整合測試- 替身
- 常用庫
- sinon.createFakeServer()
- unexpected/ unexpected react
- 前端
基本知識-打包, sass, rwd(mdiea query, boostrip)tooles: chrome extensiongoogle devtools- snadbox - codesandbox
React - pure/container, Fragments, lifecycle, Context, loop/condition expression, lifecycle sandbox, loop key strategyRedux - flux- RxJs - 非同步action
material-ui - UI元件庫- 可研究方向: PWA, functional programing
- 串連前後端
- 串接api
- 單元測試、整合測試(puppeteer)
- nginx, single page application(spa) 設定
- 三周目 - 發佈、維運
- 發佈
Docker, Docker-compose: volumn, ps, image, network打包 image, shell scriptverdaccio - 建立自己的私有庫
- 維運
- ELK
- Zabbix - email, slask
- vegeta - 壓測工具
- MongoDB 備份
- 發佈
我想達成率只有 65% 左右,有些內容還被我刪減,離我想寫完整的東西還有一段路。每天的內容一直調整,很多時候因為時間不夠、篇幅有限、考慮到完整性、可讀性,我只能做刪減。但是,不論我怎麼調整,目標只有一個: 帶讀者瀏覽從前端到後端再到 DevOps 的歷程。
本主題只是打開你在各個技術的大門,能否或需不需要踏入就要由你自行決定了。我相信一定有很多專門的主題或文章可以說的更好,希望我能作為你看那些文章的墊腳石。
因為寫的很趕,寫完後,只能校稿一次,也許會有不通順的地方請見諒。內容不完整或缺少的部分,我目前在計畫找時間補上。未來的文章,有可能會在 Medium 或 iT邦幫忙 同時發佈,喜歡的話可以 Follow,謝謝各位。
評論