docker-swarm-tutorial
Docker Swarm 基本教學 - 從無到有 Docker-Swarm-Beginners-Guide📝
- Youtube Tutorial PART 1 - Docker Machine 介紹
- Youtube Tutorial PART 2 - Docker Swarm 簡介
- Youtube Tutorial PART 3 - Docker Swarm 建立 - 基礎篇
- Youtube Tutorial PART 4 - Deploy Services to a Swarm - 基礎篇
- Youtube Tutorial PART 5 - Docker Swarm + Django - 實戰篇
- Youtube Tutorial PART 6 - Docker Swarm + HAProxy - 實戰篇
- Youtube Tutorial PART 7 - Docker Swarm Manage sensitive data with Docker secrets - 實戰篇
簡介
因為 Docker Swarm 很多指令其實都和 Docker 類似,所以建議大家對 Docker 先有
一定的了解,這樣才不會對很多指令都很陌生,可以參考我之前的文章。
分散式系統通常都是非常複雜的 😱,Docker Swarm 的學習曲線比較低,建議
先對他有些認識,如果你目前猶豫 Kubernetes ( k8s ) 和 Docker Swarm 要先學哪一個 😕
而且你也沒有任何相關分散式系統的經驗,這樣不用思考了,先學 Docker Swarm 就對了:smile:
透過這篇文章,你將會學會
docker-machine 教學
可以在本地端練習控制多個虛擬機,等熟悉後,要控制雲端的機器也是一樣的。
docker-machine 安裝教學
Docker Toolbox
使用 Docker Toolbox 安裝
安裝過程基本上很簡單
灰色的基本上就是一定要安裝的,其他的就看你需不需要安裝。
最後在輸入下列指令確認是否安裝成功
docker-machine version
使用指令安裝
詳細安裝教學可參考 https://docs.docker.com/machine/install-machine/
Windows
使用 Git BASH 執行下列指令 ( 如果你有安裝 git ,通常電腦上都會有 )
if [[ ! -d "$HOME/bin" ]]; then mkdir -p "$HOME/bin"; fi && \
curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-Windows-x86_64.exe > "$HOME/bin/docker-machine.exe" && \
chmod +x "$HOME/bin/docker-machine.exe"
Mac
curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-`uname -s`-`uname -m` >/usr/local/bin/docker-machine && \
chmod +x /usr/local/bin/docker-machine
以上兩種方法我都有使用過,都沒什麼問題:smile:
docker-machine 指令介紹
這邊先簡單介紹一下他的指令,
建立一台 machine,這邊我分 Windows ( 比較麻煩 😤 ) 和 Mac,
Windows ( 因為 Hyper-V and VirtualBox 互相會衝突 )
docker-machine create --driver hyperv vm1
--driver, -d
, 選擇 Driver to create machine
windows 用戶還需要額外做設定 😩 請參考 docker-machine - windows 額外設定,
詳細可參考 https://docs.docker.com/machine/drivers/hyper-v/。
順帶一下,有時候如果遇到很怪的問題,請將你的防火牆暫時關閉。
Mac
docker-machine create --driver virtualbox vm1
詳細可參考 https://docs.docker.com/machine/drivers/virtualbox/
docker-machine create
更多可參考 https://docs.docker.com/machine/reference/create/
查看目前 machine
docker-machine ls
可參考 https://docs.docker.com/machine/reference/ls/
這邊補充一下,
如果你使用 docker-machine ls
然後看到類似下面的錯誤訊息
Unable to query docker version: Get https://192.168.99.102:2376/v1.15/version: x509: certificate is valid for 192.168.99.105, not 192.168.99.102
這時候可以用這個指令修復
docker-machine regenerate-certs [OPTIONS] [arg...]
可參考 https://docs.docker.com/machine/reference/regenerate-certs/
環境變數設定
docker-machine env machinename
可參考 https://docs.docker.com/machine/reference/env/
連線到指定的 Docker Machine
docker-machine ssh machinename
範例為 ssh 進去 vm1
可參考 https://docs.docker.com/machine/reference/ssh/
啟動 machine
docker-machine start machinename
停止 machine
docker-machine stop machinename
移除 machine
docker-machine rm machinename
可參考 https://docs.docker.com/machine/reference/rm/
查看目前 machine 狀態
docker-machine status machinename
docker-machine - windows 額外設定
當使用 docker-machine env vm1
查看時,你會發現我們沒有 ipv4
這時候就需要做一些額外設定了 😰
我參考這邊圖解給大家看 https://docs.docker.com/machine/drivers/hyper-v/#example
先找到 Hyper-V 管理員
接著選擇虛擬交換器管理員
建立一個外部的虛擬交換器
名稱可以自己訂,這邊就用官方範例的名稱 Primary Virtual Switch
接著 重開機 ,避免遇到很怪的問題。
建立 machine 的指令變成下列這樣
docker-machine create -d hyperv --hyperv-virtual-switch "<NameOfVirtualSwitch>" <nameOfNode>
NameOfVirtualSwitch
這是我們剛剛設定的名稱。
試著建立一台 machine
docker-machine create -d hyperv --hyperv-virtual-switch "Primary Virtual Switch" vm2
接下來可以再用 docker-machine env vm2
查看
我們得到 ipv4 了:flushed:
docker swarm 教學
docker swarm 簡介
參考 https://docs.docker.com/engine/swarm/,我簡單整理 Feature highlights 給大家
-
Cluster management integrated with Docker Engine
只需要使用 Docker Engine CLI 就可以建立 swarm,不需要再安裝其他的軟體,而且很多指令都和 docker 類似。
-
Decentralized design
可以從單一個 image 直接建立整個 swarm。
-
Declarative service model
docker 使用 declarative 的方式讓你定義各個 service 的狀態。( 建議 google 一下 Declarative service 😏 )
-
Scaling
對於每一個 service,你可以宣告要執行多少數量的任務,當你 scale up or down 的時候,swarm manager 會自動增減來保持所需的狀態。
-
Desired state reconciliation
swarm manager node 會一直監控 cluster 狀態,保持你所需的狀態。舉個例子,假設你設定一個服務有十個 replicas,其中有一台 worker machine 死了兩個 replicas,swarm manager node 會再指派給可運作的 worker 兩個 replicas,保持服務有十個 replicas( 保持你所需的狀態 )。
-
Multi-host networking
你可以為你的服務指定 overlay network。在 overlay network 中,當初始化或更新時,swarm manager 會自動指派網路給容器。( 建議 google 一下 overlay network 😏 )
-
Load balancing
你可以將服務的 ports 暴露給外部 Load balancer。在內部,swarm 讓你可以在節點之間指定如何分配服務。
-
Secure by default
在 swarm 中,每一個節點強制使用 TLS 互相認證和加密,用來保護自己以及和其他節點的溝通。你也可以選擇使用自己定義的 certificates。
-
Rolling updates
swarm manager 讓你控制服務佈署到不同的節點之間的延遲,如果出現任何問題,可以 roll-back( 回滾 )任務到之前的服務。
docker swarm 概念
請參考 https://docs.docker.com/engine/swarm/key-concepts/
Swarm
swarm 是由多個 docker hosts 主機組成,這些 docker hosts 以 swarm mode 運行,角色主要有 manager
( 管理成員以及指派任務 )和 work( 執行 swarm service )。docker hosts 可以是 managers 或 works,
docker 的工作原理是維持所需的狀態,舉個例子, 假如一個 worker node 崩潰了,docker 會在其他可運
作的 worker 中調用 tasks,tasks 是在 swarm 服務中正在執行的一個容器, 他是由 swarm manager 管理,
而不是一個獨立的容器。
swarm service 相對於獨立的 container 的優勢是可以在不需要手動重新啟動服務的狀態下,修改服務的設
定 ( 包含網路和volumes )。
當 docker 執行在 swarm mode 時,你仍然可以在 docker hosts 上面獨立執行 containers, 獨立的容器和
swarm services 主要的的區別是,swarm services 只有 swarm managers 可以管理群集,而獨立的容器可以
在任何的 daemon 上執行。
Nodes
節點是 docker engine 中的一個 instance,你也可以將他視為 docker 的節點。你可以在機器中運行一或多個
節點,通常產品 swarm 佈署會分佈多個 physical computer 和雲端機器的 docker 節點。
當 deploy 一個應用程式到 swarm 時,我們需要定義一個 manager node,這個 manager node 將分配 tasks
給其他的 workers,manager nodes 會選出一個 leader 來編排任務。
worker 節點收到來自 manager nodes 分派的任務,預設的 manager nodes 也會執行服務( 如同 wokers ),
當然,你也可以設定 manager nodes 只做管理的工作,並成為唯一的管理者。
work node 通知 manager node 目前自己負責的 tasks 的狀態, 讓 manager 可以維持每個 worker 該負責的任
務(以達到期望的狀態 )。
Services and tasks
服務是在 manager nodes 或 worker nodes 中執行任務的定義。 當你建立一個服務時,你可以指定哪個容器需要
用那個 image 以及需要哪些指令。
在 replicated services 中,swarm manager 會根據節點之間的比例分配特定數量的 replica tasks。
在 global services 中,swarm 在每一個可用的節點中執行一項服務任務。
task 攜帶一個 docker 容器和在容器中執行的命令,當 task 被指派給一個 node 時,他就不能移動到其他的節點。
他只可以執行( or 失敗 )在被分派的節點上
Load balancing
swarm manager 使用 ingress load balancing 來 expose 你想要在群集外的服務。 swarm manager 可以自動指定服
務一個 PublishedPort 或者你可以設定他, 如果你沒有指定 port,swarm manager 將分配一個 30000-32767 之間的
port 給他。
swarm 模式有一個內部的 DNS 元件,可以自動為群集中每一個服務分配一個 DNS entry, swarm manager 使用內部
的 load balancing 去分配服務之間的請求。
How nodes work
docker swarm 中,主要的就是 managers and workers
請可參考 https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/
How services work
請參考 https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/
Raft consensus in swarm mode
當 Docker Engine 執行在 Swarm mode 時,manager nodes 實現 Raft Consensus Algorithm( 建議觀看 )來管理
全部的 cluster 的狀態。
假如現在有 A、B、C 三個 manager nodes,並且 A 是 Leader,今天 A 節點因為某種原因失效了,這時候 B、C 兩個
節點會互相選舉,選出一個 Leader 以維持整個系統。
Raft 容忍 (N-1)/2
失效,假設 5 個 Manager nodes 中,有 3 個 nodes 失效,雖然正在執行的 tasks 會保持執行,
但整個系統的 scheduler 將失效,也就是無法 balance tasks。
更多請參考 https://docs.docker.com/engine/swarm/raft/
docker swarm 基礎篇
先建立三台 machine ( vm1 , vm2 , vm3 )
這邊拿 vm1 當作 manager ( ip 為 192.168.1.107
)
先 ssh 進去 vm1
docker-machine ssh vm1
接著初始化 docker swarm
docker swarm init --advertise-addr 192.168.1.107
A 的部分告訴你 vm1 是 manager,
B 的部分則是增加一個 worker 到 swarm 中的指令。
docker swarm join --token SWMTKN-1-5ixph5gyd5gj51jg1749d4c6mms31kdnzcpji5c2yz4ke95rdw-2o9ias3hkslk29ph08wa3seon 192.168.1.107:2377
這邊要再提醒大家一下,注意那個 To add a worker to this swarm,
那我如果想要加入其他的 manager 呢:question:
這時候我們可以使用下面的指令
docker swarm join-token [OPTIONS] (worker|manager)
會顯示 To add a manager to this swarm
docker swarm join-token manager
會顯示 To add a worker to this swarm
docker swarm join-token worker
這邊大家可以自己玩玩看,可以有多個 manager ,但只能有一個 Leader !!
更多可參考 https://docs.docker.com/engine/reference/commandline/swarm_join-token/
到 machine vm2 執行
到 machine vm3 執行
更多 docker swarm init 可參考 https://docs.docker.com/engine/reference/commandline/swarm_init/
如果要離開 swarm,可使用
docker swarm leave [OPTIONS]
可參考 https://docs.docker.com/engine/reference/commandline/swarm_leave/
接下來回到 vm1 ( manager ) ,使用以下指令查看 swarm 中的 node
docker node ls
從上圖中可以發現 vm1 是 Leader
可參考 https://docs.docker.com/engine/reference/commandline/node_ls/
查看 node 詳細資料
docker node inspect [OPTIONS] self|NODE [NODE...]
可參考 https://docs.docker.com/engine/reference/commandline/node_inspect/
移除 node 節點
docker node rm [OPTIONS] NODE [NODE...]
可參考 https://docs.docker.com/engine/reference/commandline/node_rm/
這邊要注意的是,當我們移除的 node 是 manager 時,你會發現無法移除,
這時候,就必須先 demote 節點,然後才可以刪除
demote 節點
docker node demote NODE [NODE...]
範例 ( 假設 vm2 是 manager 節點 ),先將 vm2 demote 為 worker,再將他刪除
docker node demote vm2
docker node rm -f vm2
可參考 https://docs.docker.com/engine/reference/commandline/node_demote/
既然有 demote ,那一定有 promote
promote 節點
docker node promote NODE [NODE...]
範例 ( 假設 vm3 是 worker 節點 ),將 vm3 promote 為 manager
docker node promote vm3
可參考 https://docs.docker.com/engine/reference/commandline/node_promote/
Update a node
docker node update [OPTIONS] NODE
詳細參數可參考 https://docs.docker.com/engine/reference/commandline/node_update/
有時候可能某些節點需要進行維護的工作,所以必須先離線,這時候可以透過
--availability
這個參數來完成,指令如下
docker node update [OPTIONS] NODE
舉個例子,vm3 這個節點需要進行維護,將 vm3 drain
docker node update --availability drain vm3
這時候可以用 docker node ls
觀察,會發現他的 AVAILABILITY 變成 Drain 了
可以再用 docker stack ps [OPTIONS] STACK
去觀察,其他的 node 會去幫被 Drain 的節點做 cover 的動作。
如果 vm3 這個節點維護好了,只需要執行以下指令即可回復
docker node update --availability active vm3
到這邊基本上就完成了,我們可以開始建立服務 😄
docker service
接下來我們先用 docker service
來玩玩 docker swarm
詳細可參考 https://docs.docker.com/engine/swarm/services/
先 ssh 到 vm1 ( manager )
建立 service
docker service create [OPTIONS] IMAGE [COMMAND] [ARG...]
範例
docker service create --name=my_nginx nginx
--name
,service 的名稱
--detach
如果設定為 false ,則會在 foreground ( 前景 ) 執行,
沒特別指定,就是在背景執行,如下方
( 這邊特別補充一下,未來的 docker 版本,沒指定都會默認 --detach=false
)
docker service create --detach=false --name my_nginx nginx
也可以寫成
docker service create --detach=false --name my_nginx --mode replicated nginx
這邊指定了 mode 為 replicated,假如你沒指定,預設為 replicated mode。
可以加上 -p , --publish
,publish port 給 swarm 之外的 client 端使用。
可參考 https://docs.docker.com/engine/reference/commandline/service_create/
接著查看 service
docker service ls [OPTIONS]
可參考 https://docs.docker.com/engine/reference/commandline/service_ls/
更新 service
docker service update [OPTIONS] SERVICE
範例 ( 將剛剛的範例增加 published port )
docker service update --publish-add 80 my_nginx
可參考 https://docs.docker.com/engine/reference/commandline/service_update/
如果要更新已經存在的 service,需使用 --publish-add
,
也可以透過 --publish-rm
移除之前 published 的 port。
可以使用 docker service ls
查看
這時候可以試著瀏覽 vm2 ( http://192.168.1.106:30000/ ) or vm1 ( http://192.168.1.107:30000/ )
or vm3 ( http://192.168.1.108:30000/ )
( ip 請使用你自己的,你的 ip 應該會和我的不一樣 😑 )
都能成功看到畫面:kissing_smiling_eyes:
這時候你可能會問,vm2 ( http://192.168.1.106 ) 和 vm3 ( http://192.168.1.108 ) 裡面沒有任何 container 在執行,
目前只有 vm1 ( http://192.168.1.107:30000/ ) 中有一個 container 在執行,
那為什麼 vm2 和 vm3 也能正常工作 ❓
原因是因為 docker swarm 內建的 Loan Balance + Routing Mesh 幫我們完成了 😮
Routing Mesh 會將你的 request route 到正在運行的 container 上,可參考下方這張圖
更多的 Routing Mesh 可參考官網說明 https://docs.docker.com/engine/swarm/ingress/
docker service scale
docker service scale SERVICE=REPLICAS [SERVICE=REPLICAS...]
範例 ( 將 my_nginx scale=5 )
docker service scale my_nginx=5
有注意到 REPLICAS 的地方嗎 ? 為什麼會從 2/5 -> 5/5,因為他是在背景執行。
如果我們想停止 service,也可以將 scale 設定為 0
docker service scale my_nginx=0
可參考 https://docs.docker.com/engine/reference/commandline/service_scale/
這邊還是簡單提一下, scale up
和 scale out
這兩個簡單的名詞:relaxed:
scale up
又稱 Vertical Scaling,最常見的就是增加硬體,像是提高 CPU、Ram。
scale out
又稱 Horizontal Scaling,可以思考成像 docker swarm 這樣的分散式架構( 可以無限拓展 ),
通常整體價格會比 scale up
低。
相信大家看完下面這張圖會更了解:satisfied:
查看 service 的任務狀態 ( List the tasks of one or more services )
docker service ps [OPTIONS] SERVICE [SERVICE...]
範例
docker service ps my_nginx
注意那個 NODE,指的是這些 service 分別分散部署到不同的 node ( machine )
可參考 https://docs.docker.com/engine/reference/commandline/service_ps/
查看 service 的詳細資料
docker service inspect [OPTIONS] SERVICE [SERVICE...]
範例
docker service inspect --pretty my_nginx
--pretty
,更適合閱讀
可參考 https://docs.docker.com/engine/reference/commandline/service_inspect/
刪除 service
docker service rm SERVICE [SERVICE...]
查看 service 的 log
docker service logs [OPTIONS] SERVICE|TASK
docker service logs -f my_nginx
他會自己做 Loan Balance,這邊都是分到 vm3 上 😉
可參考 https://docs.docker.com/engine/reference/commandline/service_logs/
Docker Swarm Visualizer
接下來推薦大家一個套件 Docker Swarm Visualizer,
顧名思義,他就是可以將 Docker Swarm 視覺化。
run in a docker swarm
docker service create --name=viz --publish=8080:8080/tcp --constraint=node.role==manager --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock dockersamples/visualizer
這時候可以試著瀏覽 http://192.168.1.107:8080/,應該會看到類似的圖
可以發現 6 個 service 分散到每個 machine 裡面。
Docker Swarm + Django
前面已經用 nginx 帶大家認識 docker service
以及 docker swarm
了,現在要用 Docker Swarm + Django 來實戰
步驟一
首先,要先建立 image,為什麼呢:question: 不是可以使用 build :question:
因為現在要使用 docker stack
的方式佈署,而 docker stack
強制規定一定要使用 image ,可參考官網 image-required,
Django 的範例使用之前介紹的 用 Docker 實戰 Django 以及 Postgre
所以先 clone 下來
git clone https://github.com/twtrubiks/docker-tutorial.git
接著到目錄底下
cd docker-tutorial
執行 docker-compose up
再開啟另一個 terminal,先使用 docker ps
找到正在執行的 web container,
之後就是 commit,可參考下面指令
docker commit -m "create" CONTAINER_ID twtrubiks/my_django
push image
docker push twtrubiks/my_django
因為 repo 是 pubilc 的,所以大家可以到這邊查看 twtrubiks/my_django,
你可以自己練習操作一遍,或是直接使用我的 image 😏
如果你對 docker push
不熟,可參考之前的教學 Docker push image to Docker Hub 教學。
步驟二
建立 docker-stack.yml
,可參考 docker-stack.yml
version: "3"
services:
db:
image: postgres
environment:
POSTGRES_PASSWORD: password123
volumes:
- db-data:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- backend
deploy:
placement:
constraints: [node.role == manager]
web:
image: twtrubiks/my_django
# volumes:
# - api-data:/docker_api
ports:
- "8000:8000"
networks:
- backend
depends_on:
- db
deploy:
replicas: 10
update_config:
parallelism: 2
restart_policy:
condition: on-failure
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
backend:
volumes:
db-data:
# api-data:
基本上這個 docker-stack.yml
是從 docker-compose.yml 修改來的,
有注意到嗎? 已經使用了 twtrubiks/my_django 這個剛剛建立出來的 image,
其餘的 docker-stack.yml
參數介紹請參考官網 https://docs.docker.com/compose/compose-file/,
這邊基本上都可以找到說明,在頁面上用關鍵字找即可
補充一下,depends_on
這個參數在 swarm 中是會被忽略的,
可參考 https://docs.docker.com/compose/compose-file/#depends_on,
The depends_on option is ignored when deploying a stack in swarm mode with a version 3 Compose file。
步驟三
終於可以開始佈署了 😆
一樣使用三台 machine,vm1 是 Leader
接著 ssh 進去 vm1
先 clone 一份下來,因為我們需要 docker-stack.yml
( 你也可以用其他的方法 )
git clone https://github.com/twtrubiks/docker-swarm-tutorial
切換到目錄底下
cd docker-swarm-tutorial/
接著使用 docker stack deploy
指令佈署,
docker stack deploy --compose-file docker-stack.yml my_app
也可以寫成
docker stack deploy -c docker-stack.yml my_app
--compose-file
, -c
代表 Path to a Compose file
當使用 docker service ls
查看時,可能要等一下:relaxed:
因為每一台機器 ( vm1 vm2 vm3 ) 都需要從 docker hub pull image 下來,
更多 docker stack deploy
說明,可參考 https://docs.docker.com/engine/reference/commandline/stack_deploy/
這邊補充一下 docker stack
的其他指令
List stacks
docker stack ls
可參考 https://docs.docker.com/engine/reference/commandline/stack_ls/
List the tasks in the stack
docker stack ps [OPTIONS] STACK
可參考 https://docs.docker.com/engine/reference/commandline/stack_ps/
Remove one or more stacks
docker stack rm STACK [STACK...]
可參考 https://docs.docker.com/engine/reference/commandline/stack_rm/
List the services in the stack
docker stack services [OPTIONS] STACK
可參考 https://docs.docker.com/engine/reference/commandline/stack_services/
接下來就是 migrate,隨便進去一個 web service 的 container migrate 即可,使用的指令如下,
先查看 container id,並且進入 container
docker ps
docker exec -it <Container ID> bash
開始 migrate
python manage.py makemigrations musics
python manage.py migrate
再建立一個 superuser
python manage.py createsuperuser
到這邊就完成了:smiley:
以我的範例可以瀏覽 http://192.168.1.105:8000/api/music/ 或
http://192.168.1.106:8000/api/music/ 或 http://192.168.1.107:8000/api/music/
都可以順利看到 😆
溫馨小提醒 ❤️
這邊有可能有時候會遇到,你打開網頁,發現顯示找不到網頁的狀況,會發生這個原因是因為啟動順序
的問題,因為有可能 web service 比 db service 早啟動完成,所以導致 web 無法連上 db 😭
這時候該怎麼解決呢:question:
這裡先提供一個方法,想法很簡單,就是將 web service 重新啟動,這樣就可以連到 db 了
如果有更好的方法歡迎提供,謝謝。
先將 my_app_web service scale 為 0
docker service scale my_app_web=0
再將他 scale 為 10 ( 原本設定為 10 )
docker service scale my_app_web=10
基本上這樣 web service 就一定會成功連線到 db service
port 8080 則是 Docker Swarm Visualizer ,瀏覽 http://192.168.1.105:8080 或
http://192.168.1.106:8080 或 http://192.168.1.107:8080
雖然一切看起來美好,但有個小缺點,假設我將 vm3 ( 192.168.1.107 ) 關機(或是因為其他原因這台機器掛了),
然後去瀏覽 http://192.168.1.107:8000/api/music/ ,你會發現連不進去 😭
你總不可能叫使用者改連 http://192.168.1.105:8000/api/music/ 或 http://192.168.1.106:8000/api/music/,
不被打飛才怪 😡
所以這時候我們還需要一個 外部 的 load balancer !!
load balancer 之前也有介紹過,那時候是使用 nginx 介紹的,
可參考 實戰 Docker + Django + Nginx + uWSGI + Postgres - Load Balance 📝
我在 文章 最後也提到,如果要專注在 load balancer,使用 HAProxy 效果應該會更好,
所以現在,我們就來加上 HAProxy 吧:satisfied:
Docker Swarm + HAProxy
HAProxy( High Availability Proxy )最常見的用途是提高分散式環境的效能和可靠性,以這個範例,就非常適合使用。
參考官網 https://docs.docker.com/engine/swarm/ingress/#using-the-routing-mesh
注意,這邊是本機中執行,不是在 swarm 中執行了,
先切換到 haproxy-tutorial
資料夾中,
cd haproxy-tutorial
修改 haproxy.cfg
,主要是最後面修改成自己的 ip
defaults
mode http
option httplog
timeout connect 4000ms
timeout client 50000ms
timeout server 50000ms
stats enable
stats refresh 5s
stats show-node
stats uri /stats/haproxy # http://0.0.0.0:8080/stats/haproxy
global
log 0.0.0.0:1514 local0 debug
user haproxy
group haproxy
# Configure HAProxy to listen on port 80
frontend http_front
log global
bind *:80
default_backend http_back
# Configure HAProxy to route requests to swarm nodes on port 8000
backend http_back
log global
balance roundrobin
http-request replace-value Host .* info.cern.ch
server node1 192.168.1.105:8000 check
server node2 192.168.1.106:8000 check
server node3 192.168.1.107:8000 check
haproxy.cfg
的設定真的很多,詳細可以參考 官網 說明。
方法一 :
( 這個方法無法取得 HAProxy 的 Log ,但 Load Balance 正常,可能是要設定其他的東西,建議使用方法二 )
接著 build image
docker build -t my-haproxy .
將他執行起來
docker run -p 8080:80 my-haproxy
方法二 :
直接使用 pgaertig/haproxy-docker 這個 image。
docker run -v D:\docker-swarm-tutorial\haproxy-tutorial\haproxy-data:/haproxy-data -p 8080:80 pgaertig/haproxy:latest
( 記得使用完整的路徑 )
接著瀏覽網頁時,你會發現 log 中有 node1、node2、node3 ,這就是 HAProxy 的 Load Balance。
當瀏覽 http://localhost:8080/api/music/ 時,就算 vm3 ( 192.168.99.102 ) 掛了,我們一樣可以正常使用網頁 😆
HAProxy 會透過 Health Check 檢查是否這台 server 可以處理 request(會將你的 request 導到可以處理的 server 上)
只要還有一台存在,都可以正常使用網頁(不會掛點)。
也可以瀏覽 http://localhost:8080/stats/haproxy 查看狀態,
但也不要開心的太早,雖然有 HAProxy 幫我們處理 load balancer,但是也有可以 HAProxy 那台機器出了問題,
也就是 單點失效 ( SPOF ) single point of failure,也就導致整個系統無法運作:scream:
可以使用 HAproxy + Keepalived 解決,這部份有機會會再介紹給大家:relaxed:
Docker Swarm - Manage sensitive data with Docker secrets
如果你不想將敏感資料存在 image 或者程式碼中,可以使用 docker secrets 來管理容器執行時需要的敏感資料,
像是 passwords、ssl certificates 、ssh private keys ......
思考一個問題,當你有開發機、測試機、正式機,然後每個環境都有不同的密碼,這樣管理 swarm 上會非常麻煩,
這時候可以透過 docker secrets 來管理這些密碼,我們只需要知道 secrets name 就可以在這三個環境上運作。
這邊要注意,Docker secrets
只能夠使用在 swarm 下,不能夠使用在獨立的 container 中,
更多介紹,請參考 Manage sensitive data with Docker secrets
其餘的 Docker secrets
指令可參考 https://docs.docker.com/engine/reference/commandline/secret/
簡單的來實戰一下:smile:
先到 swarm 環境中,假設 vm1 是 manager,先 clone 範例
git clone https://github.com/twtrubiks/docker-swarm-tutorial.git
接著 cd docker-swarm-tutorial/docker-swarm-secrets/
到 docker-swarm-secrets 資料夾底下,
主要只會用到 docker-stack.yml 這個檔案,這個範例是從 Docker 基本教學 - 從無到有 Docker-Beginners-Guide 修改過來的,
修改了 api/django_rest_framework_tutorial/settings.py 這個檔案,修改如下
def secret_path(name):
path = '/run/secrets/{}'.format(name)
if not os.path.isfile(path):
raise Warning(name)
return path
def secret(name, strip=True):
with open(secret_path(name), 'r') as f:
val = f.read()
if strip:
val = val.strip()
return val
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'postgres',
'USER': 'postgres',
'PASSWORD': secret('my_password'),
'HOST': 'db',
'PORT': 5432,
}
}
目的是去讀取路徑中的 /run/secrets/<secret_name>
檔案。( 我們會將 secrets 名稱設定為 my_password )。
在 Docker 17.05 或更早的版本,secrets 路徑總是會存在 /run/secrets/
資料夾裡,
在 Docker 17.06 之後,可以指定路徑( 沒指定默認路徑也是 /run/secrets/
)。
前面說過了,docker stack
強制規定一定要使用 image,這邊大家可以自己 build,然後 push 到 docker hub,
也可以直接使用我幫大家做好的 twtrubiks/my_swarm_secrets_demo😉
接著來看 docker-stack.yml
version: '3.1'
services:
db:
image: postgres
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/my_password
ports:
- "5432:5432"
networks:
- backend
volumes:
- pgdata:/var/lib/postgresql/data/
secrets:
- my_password
web:
image: twtrubiks/my_swarm_secrets_demo
ports:
- "8000:8000"
networks:
- backend
deploy:
replicas: 4
update_config:
parallelism: 2
restart_policy:
condition: on-failure
secrets:
- my_password
depends_on:
- db
volumes:
api_data:
pgdata:
networks:
backend:
secrets:
my_password:
external: true
解釋幾個名詞,
版本使用 3.1
是避免遇到 secrets Additional property secrets is not allowed 這個錯誤訊息。
POSTGRES_PASSWORD_FILE
這個是讀取我們創造的 secrets,
secrets
則是指定我們創造的 secrets,這邊還要提一個參數 external
,
當設定為 true
時,代表為外部資源,也就是他已經在 docker 中被定義了,
所以當啟動時,不會再去創造他,如果找不到,則會顯示 secret not found
錯誤。
詳細的說明可參考
https://docs.docker.com/compose/compose-file/#secrets
https://docs.docker.com/compose/compose-file/#external
接下來就真的要佈署了:grin:
在 vm1 manager 節點下,先建立 secret
echo "password123yoyo" | docker secret create my_password -
注意最後面有一個 -
,代表輸入是從標準輸入讀取的。
密碼你要打多少都可以,因為現在我們只需要知道 secrets name 就可以讀取敏感資訊了。
可以使用 docker secret ls
查詢,會看到剛剛建立的 my_password
開始佈署
docker stack deploy -c docker-stack.yml demo_secret
執行 docker stack services demo_secret
確認佈署狀態,
確定都佈署完成了之後,
可以執行 docker stack ps demo_secret
查看分布在各主機的狀況,
在這邊我們隨便進入一個 container ,
都可以找到 /run/secrets/my_password
這個檔案
( 原因是因為 db
以及 web
都有指定 secrets )
cat /run/secrets/my_password
從上圖可以發現,看到剛剛設定的密碼了:smile:
接下來就是 migrate,隨便進去一個 web service 的 container migrate 即可,使用的指令如下,
先查看 container id,並且進入 container
docker ps
docker exec -it <Container ID> bash
開始 migrate
python manage.py makemigrations musics
python manage.py migrate
再建立一個 superuser
python manage.py createsuperuser
接下來就可以正常使用了
後記:
如果你真的很有耐心的看到這邊,而且你也是第一次接觸這種分散式系統的人,相信你會覺得 Docker Swarm
真的很棒,而且入門也不會很困難 😄
Docker Swarm 可以玩得真的非常非常多,這篇只是一個基礎的介紹,有機會我再介紹其他的東西給大家 😚
當然,分散式系統也有很多,像是文章開頭說的 Kubernetes ( k8s ) 也可以玩玩看 ~
如果你有想分享或是補充的,歡迎聯絡我,感謝閱讀到最後的你 ( 妳 ) 😘
執行環境
- Mac
- Python 3.6.2
- windows 10
Reference
- https://docs.docker.com/
- http://www.haproxy.org/
- An Introduction to HAProxy and Load Balancing Concepts
- docker-swarm-visualizer
- Keepalived
Donation
文章都是我自己研究內化後原創,如果有幫助到您,也想鼓勵我的話,歡迎請我喝一杯咖啡:laughing:
License
MIT license