{"id":20619737,"url":"https://github.com/twtrubiks/docker-swarm-tutorial","last_synced_at":"2025-08-21T05:31:56.484Z","repository":{"id":53933152,"uuid":"115267575","full_name":"twtrubiks/docker-swarm-tutorial","owner":"twtrubiks","description":"Docker Swarm 基本教學 - 從無到有 Docker-Swarm-Beginners-Guide📝","archived":false,"fork":false,"pushed_at":"2019-11-02T08:05:11.000Z","size":39,"stargazers_count":210,"open_issues_count":5,"forks_count":36,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-08T04:51:15.204Z","etag":null,"topics":["docker","docker-machine","docker-swarm","tutorial"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/twtrubiks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-24T14:19:44.000Z","updated_at":"2025-03-23T06:33:11.000Z","dependencies_parsed_at":"2022-08-13T04:50:42.656Z","dependency_job_id":null,"html_url":"https://github.com/twtrubiks/docker-swarm-tutorial","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/twtrubiks/docker-swarm-tutorial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twtrubiks%2Fdocker-swarm-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twtrubiks%2Fdocker-swarm-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twtrubiks%2Fdocker-swarm-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twtrubiks%2Fdocker-swarm-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/twtrubiks","download_url":"https://codeload.github.com/twtrubiks/docker-swarm-tutorial/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twtrubiks%2Fdocker-swarm-tutorial/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271430755,"owners_count":24758365,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-21T02:00:08.990Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","docker-machine","docker-swarm","tutorial"],"created_at":"2024-11-16T12:12:23.533Z","updated_at":"2025-08-21T05:31:56.180Z","avatar_url":"https://github.com/twtrubiks.png","language":"Python","readme":"# docker-swarm-tutorial\n\nDocker Swarm 基本教學 - 從無到有 Docker-Swarm-Beginners-Guide📝\n\n* [Youtube Tutorial PART 1 - Docker Machine 介紹](https://youtu.be/RSXlK0U-2Bo)\n* [Youtube Tutorial PART 2 - Docker Swarm 簡介](https://youtu.be/ir0ApK1rfA4)\n* [Youtube Tutorial PART 3 - Docker Swarm 建立 - 基礎篇](https://youtu.be/q2V3ZT5NdNo)\n* [Youtube Tutorial PART 4 - Deploy Services to a Swarm - 基礎篇](https://youtu.be/zW8dcez4EPM)\n* [Youtube Tutorial PART 5 - Docker Swarm + Django - 實戰篇](https://youtu.be/AeabcmHvSts)\n* [Youtube Tutorial PART 6 - Docker Swarm + HAProxy - 實戰篇](https://youtu.be/GaeLgRtiJEc)\n* [Youtube Tutorial PART 7 - Docker Swarm Manage sensitive data with Docker secrets - 實戰篇](https://youtu.be/T8mkecPQce4)\n\n## 簡介\n\n因為 Docker Swarm 很多指令其實都和 Docker 類似，所以建議大家對 Docker 先有\n\n一定的了解，這樣才不會對很多指令都很陌生，可以參考我之前的文章。\n\n* [Docker 基本教學 - 從無到有 Docker-Beginners-Guide](https://github.com/twtrubiks/docker-tutorial)\n\n* [Docker + Django + Nginx + uWSGI + Postgres Tutorial](https://github.com/twtrubiks/docker-django-nginx-uwsgi-postgres-tutorial)\n\n* [實戰 Docker + Django + Nginx + uWSGI + Postgres - Load Balance](https://github.com/twtrubiks/docker-django-nginx-uwsgi-postgres-load-balance-tutorial)\n\n* [實戰 Docker + Jenkins + Django + Postgres](https://github.com/twtrubiks/docker-jenkins-django-tutorial)\n\n分散式系統通常都是非常複雜的 :scream:，Docker Swarm 的學習曲線比較低，建議\n\n先對他有些認識，如果你目前猶豫 [Kubernetes](https://kubernetes.io/) ( k8s ) 和 Docker Swarm 要先學哪一個 :confused:\n\n而且你也沒有任何相關分散式系統的經驗，這樣不用思考了，先學 Docker Swarm 就對了:smile:\n\n透過這篇文章，你將會學會\n\n* [認識 Docker Machine](https://github.com/twtrubiks/docker-swarm-tutorial#docker-machine-%E6%95%99%E5%AD%B8)\n\n* [認識 Docker Swarm](https://github.com/twtrubiks/docker-swarm-tutorial#docker-swarm-%E6%95%99%E5%AD%B8)\n\n* [Deploy Services to a Swarm](https://github.com/twtrubiks/docker-swarm-tutorial#docker-service)\n\n* [認識 Docker Swarm Visualizer](https://github.com/twtrubiks/docker-swarm-tutorial#docker-swarm-visualizer)\n\n* [實戰 Docker Swarm + Django](https://github.com/twtrubiks/docker-swarm-tutorial#docker-swarm--django)\n\n* [Docker Swarm + HAProxy](https://github.com/twtrubiks/docker-swarm-tutorial#docker-swarm--haproxy)\n\n* [Docker Swarm - Manage sensitive data with Docker secrets](https://github.com/twtrubiks/docker-swarm-tutorial#docker-swarm---manage-sensitive-data-with-docker-secrets)\n\n## docker-machine 教學\n\n* [Youtube Tutorial PART 1 - Docker Machine 介紹](https://youtu.be/RSXlK0U-2Bo)\n\n![](https://i.imgur.com/n1QaEcm.png)\n\n可以在本地端練習控制多個虛擬機，等熟悉後，要控制雲端的機器也是一樣的。\n\n### docker-machine 安裝教學\n\n## Docker Toolbox\n\n使用 [Docker Toolbox](https://docs.docker.com/toolbox/overview/) 安裝\n\n安裝過程基本上很簡單\n\n![](https://i.imgur.com/FH3vuV8.png)\n\n![](https://i.imgur.com/CvRmdYm.png)\n\n灰色的基本上就是一定要安裝的，其他的就看你需不需要安裝。\n\n![](https://i.imgur.com/xahEJt9.png)\n\n最後在輸入下列指令確認是否安裝成功\n\n```cmd\n docker-machine version\n```\n\n![](https://i.imgur.com/MxHFzCy.png)\n\n## 使用指令安裝\n\n詳細安裝教學可參考  [https://docs.docker.com/machine/install-machine/](https://docs.docker.com/machine/install-machine/)\n\n***Windows***\n\n使用 [Git BASH](http://gitforwindows.org/) 執行下列指令 ( 如果你有安裝 git ，通常電腦上都會有 )\n\n```cmd\n if [[ ! -d \"$HOME/bin\" ]]; then mkdir -p \"$HOME/bin\"; fi \u0026\u0026 \\\ncurl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-Windows-x86_64.exe \u003e \"$HOME/bin/docker-machine.exe\" \u0026\u0026 \\\nchmod +x \"$HOME/bin/docker-machine.exe\"\n```\n\n***Mac***\n\n```cmd\n curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-`uname -s`-`uname -m` \u003e/usr/local/bin/docker-machine \u0026\u0026 \\\n  chmod +x /usr/local/bin/docker-machine\n```\n\n以上兩種方法我都有使用過，都沒什麼問題:smile:\n\n### docker-machine 指令介紹\n\n這邊先簡單介紹一下他的指令，\n\n建立一台 machine，這邊我分 Windows ( 比較麻煩 :triumph: ) 和 Mac，\n\n***Windows*** ( 因為 Hyper-V and VirtualBox 互相會衝突 )\n\n```cmd\ndocker-machine create --driver hyperv vm1\n```\n\n`--driver, -d`， 選擇 Driver to create machine\n\n![](https://i.imgur.com/6GkusmS.png)\n\nwindows 用戶還需要額外做設定 :weary: 請參考 [docker-machine - windows 額外設定](https://github.com/twtrubiks/docker-swarm-tutorial#docker-machine---windows-%E9%A1%8D%E5%A4%96%E8%A8%AD%E5%AE%9A)，\n\n詳細可參考 [https://docs.docker.com/machine/drivers/hyper-v/](https://docs.docker.com/machine/drivers/hyper-v/)。\n\n順帶一下，有時候如果遇到很怪的問題，請將你的**防火牆暫時關閉**。\n\n***Mac***\n\n```cmd\ndocker-machine create --driver virtualbox vm1\n```\n\n詳細可參考 [https://docs.docker.com/machine/drivers/virtualbox/](https://docs.docker.com/machine/drivers/virtualbox/)\n\n`docker-machine create` 更多可參考 [https://docs.docker.com/machine/reference/create/](https://docs.docker.com/machine/reference/create/)\n\n查看目前 machine\n\n```cmd\ndocker-machine ls\n```\n\n可參考 [https://docs.docker.com/machine/reference/ls/](https://docs.docker.com/machine/reference/ls/)\n\n這邊補充一下，\n\n如果你使用 `docker-machine ls` 然後看到類似下面的錯誤訊息\n\n```cmd\nUnable 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\n```\n\n這時候可以用這個指令修復\n\n```cmd\n docker-machine regenerate-certs [OPTIONS] [arg...]\n```\n\n可參考 [https://docs.docker.com/machine/reference/regenerate-certs/](https://docs.docker.com/machine/reference/regenerate-certs/)\n\n環境變數設定\n\n```cmd\ndocker-machine env machinename\n```\n\n可參考 [https://docs.docker.com/machine/reference/env/](https://docs.docker.com/machine/reference/env/)\n\n連線到指定的 Docker Machine\n\n```cmd\ndocker-machine ssh machinename\n```\n\n範例為 ssh 進去 vm1\n\n![](https://i.imgur.com/8BQq8aR.png)\n\n可參考 [https://docs.docker.com/machine/reference/ssh/](https://docs.docker.com/machine/reference/ssh/)\n\n啟動 machine\n\n```cmd\ndocker-machine start machinename\n```\n\n停止 machine\n\n```cmd\ndocker-machine stop machinename\n```\n\n移除 machine\n\n```cmd\ndocker-machine rm machinename\n```\n\n可參考 [https://docs.docker.com/machine/reference/rm/](https://docs.docker.com/machine/reference/rm/)\n\n查看目前 machine 狀態\n\n```cmd\ndocker-machine status machinename\n```\n\n### docker-machine - windows 額外設定\n\n當使用 `docker-machine env vm1` 查看時，你會發現我們沒有 ipv4\n\n![](https://i.imgur.com/Slr2vpc.png)\n\n這時候就需要做一些額外設定了 :cold_sweat:\n\n我參考這邊圖解給大家看 [https://docs.docker.com/machine/drivers/hyper-v/#example](https://docs.docker.com/machine/drivers/hyper-v/#example)\n\n先找到 Hyper-V 管理員\n\n![](https://i.imgur.com/8OwR0ax.png)\n\n接著選擇虛擬交換器管理員\n\n![](https://i.imgur.com/EPHduBV.png)\n\n建立一個外部的虛擬交換器\n\n![](https://i.imgur.com/rRHmeWG.png)\n\n名稱可以自己訂，這邊就用官方範例的名稱 Primary Virtual Switch\n\n![](https://i.imgur.com/9I0JScb.png)\n\n接著 **重開機** ，避免遇到很怪的問題。\n\n建立 machine 的指令變成下列這樣\n\n```cmd\ndocker-machine create -d hyperv --hyperv-virtual-switch \"\u003cNameOfVirtualSwitch\u003e\" \u003cnameOfNode\u003e\n```\n\n`NameOfVirtualSwitch` 這是我們剛剛設定的名稱。\n\n試著建立一台 machine\n\n```cmd\ndocker-machine create -d hyperv --hyperv-virtual-switch \"Primary Virtual Switch\" vm2\n```\n\n![](https://i.imgur.com/7BktDYg.png)\n\n接下來可以再用 `docker-machine env vm2` 查看\n\n![](https://i.imgur.com/bSFO07X.png)\n\n我們得到 ipv4 了:flushed:\n\n## docker swarm 教學\n\n![](https://i.imgur.com/bHwJXgO.png)\n\n### docker swarm 簡介\n\n* [Youtube Tutorial PART 2 - Docker Swarm 簡介](https://youtu.be/ir0ApK1rfA4)\n\n參考 [https://docs.docker.com/engine/swarm/](https://docs.docker.com/engine/swarm/)，我簡單整理 Feature highlights 給大家 :relaxed:\n\n* Cluster management integrated with Docker Engine\n\n    只需要使用 Docker Engine CLI 就可以建立 swarm，不需要再安裝其他的軟體，而且很多指令都和 docker 類似。\n\n* Decentralized design\n\n    可以從單一個 image 直接建立整個 swarm。\n\n* Declarative service model\n\n    docker 使用 declarative 的方式讓你定義各個 service 的狀態。（ 建議 google 一下 Declarative service :smirk: ）\n\n* Scaling\n\n    對於每一個 service，你可以宣告要執行多少數量的任務，當你 scale up or down 的時候，swarm manager 會自動增減來保持所需的狀態。\n\n* Desired state reconciliation\n\n    swarm manager node 會一直監控 cluster 狀態，保持你所需的狀態。舉個例子，假設你設定一個服務有十個 replicas，其中有一台 worker machine 死了兩個 replicas，swarm manager node 會再指派給可運作的 worker 兩個 replicas，保持服務有十個 replicas（ 保持你所需的狀態 ）。\n\n* Multi-host networking\n\n    你可以為你的服務指定 overlay network。在 overlay network 中，當初始化或更新時，swarm manager 會自動指派網路給容器。（ 建議 google 一下 overlay network :smirk: ）\n\n* Load balancing\n\n    你可以將服務的 ports 暴露給外部 Load balancer。在內部，swarm 讓你可以在節點之間指定如何分配服務。\n\n* Secure by default\n\n    在 swarm 中，每一個節點強制使用 TLS 互相認證和加密，用來保護自己以及和其他節點的溝通。你也可以選擇使用自己定義的 certificates。\n\n* Rolling updates\n\n    swarm manager 讓你控制服務佈署到不同的節點之間的延遲，如果出現任何問題，可以 roll-back（ 回滾 ）任務到之前的服務。\n\n### docker swarm 概念\n\n請參考 [https://docs.docker.com/engine/swarm/key-concepts/](https://docs.docker.com/engine/swarm/key-concepts/)\n\n#### Swarm\n\nswarm 是由多個 docker hosts 主機組成，這些 docker hosts 以 swarm mode 運行，角色主要有 manager\n\n（ 管理成員以及指派任務 ）和 work（ 執行 swarm service ）。docker hosts 可以是  managers 或 works，\n\ndocker 的工作原理是維持所需的狀態，舉個例子，\n假如一個 worker node 崩潰了，docker 會在其他可運\n\n作的 worker 中調用 tasks，tasks 是在 swarm 服務中正在執行的一個容器，\n他是由 swarm manager 管理，\n\n而不是一個獨立的容器。\n\nswarm service 相對於獨立的 container 的優勢是可以在不需要手動重新啟動服務的狀態下，修改服務的設\n\n定 ( 包含網路和volumes )。\n\n當 docker 執行在 swarm mode 時，你仍然可以在 docker hosts 上面獨立執行 containers，\n獨立的容器和\n\nswarm services 主要的的區別是，swarm services 只有 swarm managers 可以管理群集，而獨立的容器可以\n\n在任何的 daemon\n上執行。\n\n#### Nodes\n\n節點是 docker engine 中的一個 instance，你也可以將他視為 docker 的節點。你可以在機器中運行一或多個\n\n節點，通常產品\nswarm 佈署會分佈多個 physical computer  和雲端機器的 docker 節點。\n\n當 deploy 一個應用程式到 swarm 時，我們需要定義一個 manager node，這個 manager node 將分配 tasks\n\n給其他的 workers，manager nodes 會選出一個 leader 來編排任務。\n\n worker 節點收到來自 manager nodes 分派的任務，預設的  manager nodes 也會執行服務（ 如同 wokers ），\n\n 當然，你也可以設定\n manager nodes 只做管理的工作，並成為唯一的管理者。\n\n work node 通知 manager node 目前自己負責的 tasks 的狀態，\n 讓 manager 可以維持每個 worker 該負責的任\n\n 務（以達到期望的狀態 ）。\n\n#### Services and tasks\n\n服務是在 manager nodes 或 worker nodes 中執行任務的定義。\n當你建立一個服務時，你可以指定哪個容器需要\n\n用那個 image 以及需要哪些指令。\n\n在 replicated services 中，swarm manager 會根據節點之間的比例分配特定數量的 replica tasks。\n\n在 global services 中，swarm 在每一個可用的節點中執行一項服務任務。\n\ntask 攜帶一個 docker 容器和在容器中執行的命令，當 task 被指派給一個 node 時，他就不能移動到其他的節點。\n\n他只可以執行（ or 失敗 ）在被分派的節點上\n\n#### Load balancing\n\nswarm manager 使用 ingress load balancing 來 expose 你想要在群集外的服務。\nswarm manager 可以自動指定服\n\n務一個 PublishedPort 或者你可以設定他，\n如果你沒有指定 port，swarm manager 將分配一個 30000-32767 之間的\n\nport 給他。\n\nswarm 模式有一個內部的 DNS 元件，可以自動為群集中每一個服務分配一個  DNS entry，\nswarm manager 使用內部\n\n的 load balancing 去分配服務之間的請求。\n\n#### How nodes work\n\ndocker swarm 中，主要的就是 **managers** and **workers**\n\n![](https://i.imgur.com/pF1zdad.png)\n\n請可參考 [https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/](https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/)\n\n#### How services work\n\n請參考 [https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/](https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/)\n\n#### Raft consensus in swarm mode\n\n當 Docker Engine 執行在 Swarm mode 時，manager nodes 實現 [Raft Consensus Algorithm](http://thesecretlivesofdata.com/raft/)（ 建議觀看 ）來管理\n\n全部的 cluster 的狀態。\n\n假如現在有 A、B、C 三個 manager nodes，並且 A 是 Leader，今天 A 節點因為某種原因失效了，這時候 B、C 兩個\n\n節點會互相選舉，選出一個 Leader 以維持整個系統。\n\nRaft 容忍 `(N-1)/2` 失效，假設 5 個 Manager nodes 中，有 3 個 nodes 失效，雖然正在執行的 tasks 會保持執行，\n\n但整個系統的 scheduler 將失效，也就是無法 balance tasks。\n\n更多請參考 [https://docs.docker.com/engine/swarm/raft/](https://docs.docker.com/engine/swarm/raft/)\n\n### docker swarm 基礎篇\n\n* [Youtube Tutorial PART 3 - Docker Swarm 建立 - 基礎篇](https://youtu.be/q2V3ZT5NdNo)\n\n先建立三台 machine ( vm1 , vm2 , vm3 )\n\n![](https://i.imgur.com/tko77BZ.png)\n\n這邊拿 vm1 當作 manager ( ip 為 `192.168.1.107` )\n\n先 ssh 進去 vm1\n\n```cmd\ndocker-machine ssh vm1\n```\n\n接著初始化 docker swarm\n\n```cmd\ndocker swarm init --advertise-addr 192.168.1.107\n```\n\n![](https://i.imgur.com/wH5H51l.png)\n\nA 的部分告訴你 vm1 是 manager，\n\nB 的部分則是增加一個 worker 到 swarm 中的指令。\n\n```cmd\ndocker swarm join --token SWMTKN-1-5ixph5gyd5gj51jg1749d4c6mms31kdnzcpji5c2yz4ke95rdw-2o9ias3hkslk29ph08wa3seon 192.168.1.107:2377\n```\n\n這邊要再提醒大家一下，注意那個 **To add a worker to this swarm**，\n\n那我如果想要加入其他的 manager 呢:question:\n\n這時候我們可以使用下面的指令\n\n```cmd\ndocker swarm join-token [OPTIONS] (worker|manager)\n```\n\n會顯示 **To add a manager to this swarm**\n\n```cmd\ndocker swarm join-token manager\n```\n\n會顯示 **To add a worker to this swarm**\n\n```cmd\ndocker swarm join-token worker\n```\n\n這邊大家可以自己玩玩看，可以有多個 manager ，但只能有一個 **Leader** !!\n\n更多可參考 [https://docs.docker.com/engine/reference/commandline/swarm_join-token/](https://docs.docker.com/engine/reference/commandline/swarm_join-token/)\n\n到 machine vm2 執行\n\n![](https://i.imgur.com/Kf8a59i.png)\n\n到 machine vm3 執行\n\n![](https://i.imgur.com/sajS4pN.png)\n\n更多 docker swarm init 可參考 [https://docs.docker.com/engine/reference/commandline/swarm_init/](https://docs.docker.com/engine/reference/commandline/swarm_init/)\n\n如果要離開 swarm，可使用\n\n```cmd\ndocker swarm leave [OPTIONS]\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/swarm_leave/](https://docs.docker.com/engine/reference/commandline/swarm_leave/)\n\n接下來回到 vm1 ( manager ) ，使用以下指令查看 swarm 中的 node\n\n```cmd\ndocker node ls\n```\n\n![](https://i.imgur.com/QQFduc7.png)\n\n從上圖中可以發現 vm1 是 Leader\n\n可參考 [https://docs.docker.com/engine/reference/commandline/node_ls/](https://docs.docker.com/engine/reference/commandline/node_ls/)\n\n查看 node 詳細資料\n\n```cmd\ndocker node inspect [OPTIONS] self|NODE [NODE...]\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/node_inspect/](https://docs.docker.com/engine/reference/commandline/node_inspect/)\n\n移除 node 節點\n\n```cmd\ndocker node rm [OPTIONS] NODE [NODE...]\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/node_rm/](https://docs.docker.com/engine/reference/commandline/node_rm/)\n\n這邊要注意的是，當我們移除的 node 是 **manager** 時，你會發現無法移除，\n\n這時候，就必須先 demote 節點，然後才可以刪除\n\ndemote 節點\n\n```cmd\ndocker node demote NODE [NODE...]\n```\n\n範例 ( 假設 vm2 是 manager 節點 )，先將 vm2 demote 為 worker，再將他刪除\n\n```cmd\ndocker node demote vm2\ndocker node rm -f vm2\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/node_demote/](https://docs.docker.com/engine/reference/commandline/node_demote/)\n\n既然有 demote ，那一定有 promote\n\npromote 節點\n\n```cmd\ndocker node promote NODE [NODE...]\n```\n\n範例 ( 假設 vm3 是 worker 節點 )，將 vm3 promote 為 manager\n\n```cmd\ndocker node promote vm3\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/node_promote/](https://docs.docker.com/engine/reference/commandline/node_promote/)\n\nUpdate a node\n\n```cmd\ndocker node update [OPTIONS] NODE\n```\n\n詳細參數可參考 [https://docs.docker.com/engine/reference/commandline/node_update/](https://docs.docker.com/engine/reference/commandline/node_update/)\n\n有時候可能某些節點需要進行維護的工作，所以必須先離線，這時候可以透過\n\n`--availability` 這個參數來完成，指令如下\n\n```cmd\ndocker node update [OPTIONS] NODE\n```\n\n舉個例子，vm3 這個節點需要進行維護，將 vm3 drain\n\n```cmd\ndocker node update --availability drain vm3\n```\n\n這時候可以用 `docker node ls` 觀察，會發現他的 AVAILABILITY 變成 Drain 了\n\n![](https://i.imgur.com/J6z9FaF.png)\n\n可以再用 `docker stack ps [OPTIONS] STACK` 去觀察，其他的 node 會去幫被 Drain 的節點做 cover 的動作。\n\n如果 vm3 這個節點維護好了，只需要執行以下指令即可回復\n\n```cmd\ndocker node update --availability active vm3\n```\n\n到這邊基本上就完成了，我們可以開始建立服務 :smile:\n\n## docker service\n\n* [Youtube Tutorial PART 4 - Deploy Services to a Swarm - 基礎篇](https://youtu.be/zW8dcez4EPM)\n\n接下來我們先用 `docker service` 來玩玩 `docker swarm`\n\n詳細可參考 [https://docs.docker.com/engine/swarm/services/](https://docs.docker.com/engine/swarm/services/)\n\n先 ssh 到 vm1 ( manager )\n\n建立 service\n\n```cmd\ndocker service create [OPTIONS] IMAGE [COMMAND] [ARG...]\n```\n\n範例\n\n```cmd\ndocker service create --name=my_nginx nginx\n```\n\n`--name`，service 的名稱\n\n![](https://i.imgur.com/AplY3vq.png)\n\n`--detach` 如果設定為 false ，則會在 foreground ( 前景 ) 執行，\n\n沒特別指定，就是在背景執行，如下方\n\n( 這邊特別補充一下，未來的 docker 版本，沒指定都會默認 `--detach=false` )\n\n```cmd\ndocker service create --detach=false --name my_nginx nginx\n```\n\n![](https://i.imgur.com/eThAZPt.png)\n\n也可以寫成\n\n```cmd\ndocker service create --detach=false --name my_nginx --mode replicated nginx\n```\n\n這邊指定了 mode 為 replicated，假如你沒指定，預設為 replicated mode。\n\n可以加上 `-p , --publish`，publish port 給 swarm 之外的 client 端使用。\n\n可參考 [https://docs.docker.com/engine/reference/commandline/service_create/](https://docs.docker.com/engine/reference/commandline/service_create/)\n\n接著查看 service\n\n```cmd\ndocker service ls [OPTIONS]\n```\n\n![](https://i.imgur.com/Cfe56ZI.png)\n\n可參考 [https://docs.docker.com/engine/reference/commandline/service_ls/](https://docs.docker.com/engine/reference/commandline/service_ls/)\n\n更新 service\n\n```cmd\ndocker service update [OPTIONS] SERVICE\n```\n\n範例 ( 將剛剛的範例增加 published port )\n\n```cmd\ndocker service update --publish-add 80 my_nginx\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/service_update/](https://docs.docker.com/engine/reference/commandline/service_update/)\n\n如果要更新已經存在的 service，需使用 `--publish-add`，\n\n也可以透過 `--publish-rm` 移除之前 published 的 port。\n\n![](https://i.imgur.com/GL7FNuo.png)\n\n可以使用 `docker service ls`查看\n\n![](https://i.imgur.com/tOSYgN2.png)\n\n這時候可以試著瀏覽 vm2 ( [http://192.168.1.106:30000/](http://192.168.1.106:30000/) ) or vm1 ( [http://192.168.1.107:30000/](http://192.168.1.107:30000/) )\n\nor vm3 ( [http://192.168.1.108:30000/](http://192.168.1.108:30000/) )\n\n( ip 請使用你自己的，你的 ip 應該會和我的不一樣 :expressionless: )\n\n都能成功看到畫面:kissing_smiling_eyes:\n\n![](https://i.imgur.com/ds9fmas.png)\n\n這時候你可能會問，vm2 ( [http://192.168.1.106](http://192.168.1.106) ) 和 vm3 ( [http://192.168.1.108](http://192.168.1.108) ) 裡面沒有任何 container 在執行，\n\n目前只有 vm1 ( [http://192.168.1.107:30000/](http://192.168.1.107:30000/) ) 中有一個 container 在執行，\n\n那為什麼 vm2 和 vm3 也能正常工作 :question:\n\n原因是因為 docker swarm 內建的 Loan Balance +  **Routing Mesh** 幫我們完成了 :open_mouth:\n\n**Routing Mesh** 會將你的 request route 到正在運行的 container 上，可參考下方這張圖\n\n![](https://i.imgur.com/ZwaTYJO.png)\n\n更多的 **Routing Mesh** 可參考官網說明 [https://docs.docker.com/engine/swarm/ingress/](https://docs.docker.com/engine/swarm/ingress/)\n\ndocker service scale\n\n```cmd\ndocker service scale SERVICE=REPLICAS [SERVICE=REPLICAS...]\n```\n\n範例 ( 將 my_nginx scale=5 )\n\n```cmd\ndocker service scale my_nginx=5\n```\n\n![](https://i.imgur.com/g0YG7RZ.png)\n\n有注意到 REPLICAS 的地方嗎 ? 為什麼會從 2/5 -\u003e 5/5，因為他是在背景執行。\n\n如果我們想停止 service，也可以將 scale 設定為 0\n\n```cmd\ndocker service scale my_nginx=0\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/service_scale/](https://docs.docker.com/engine/reference/commandline/service_scale/)\n\n這邊還是簡單提一下， `scale up` 和 `scale out` 這兩個簡單的名詞:relaxed:\n\n`scale up` 又稱 Vertical Scaling，最常見的就是增加硬體，像是提高 CPU、Ram。\n\n`scale out` 又稱 Horizontal Scaling，可以思考成像 docker swarm 這樣的分散式架構（ 可以無限拓展 ），\n\n通常整體價格會比 `scale up` 低。\n\n相信大家看完下面這張圖會更了解:satisfied:\n\n![](https://i.imgur.com/DM6Bmy9.jpg)\n\n查看 service 的任務狀態 ( List the tasks of one or more services )\n\n```cmd\ndocker service ps [OPTIONS] SERVICE [SERVICE...]\n```\n\n範例\n\n```cmd\ndocker service ps my_nginx\n```\n\n![](https://i.imgur.com/3LtLVZR.png)\n\n注意那個 NODE，指的是這些 service 分別分散部署到不同的 node ( machine )\n\n可參考 [https://docs.docker.com/engine/reference/commandline/service_ps/](https://docs.docker.com/engine/reference/commandline/service_ps/)\n\n查看 service 的詳細資料\n\n```cmd\ndocker service inspect [OPTIONS] SERVICE [SERVICE...]\n```\n\n範例\n\n```cmd\ndocker service inspect --pretty my_nginx\n```\n\n`--pretty`，更適合閱讀\n\n![](https://i.imgur.com/HNlP4Fd.png)\n\n可參考 [https://docs.docker.com/engine/reference/commandline/service_inspect/](https://docs.docker.com/engine/reference/commandline/service_inspect/)\n\n刪除 service\n\n```cmd\ndocker service rm SERVICE [SERVICE...]\n```\n\n查看 service 的 log\n\n```cmd\ndocker service logs [OPTIONS] SERVICE|TASK\n```\n\n```cmd\ndocker service logs -f my_nginx\n```\n\n![](https://i.imgur.com/7JWrASF.png)\n\n他會自己做 Loan Balance，這邊都是分到 vm3 上 :wink:\n\n可參考 [https://docs.docker.com/engine/reference/commandline/service_logs/](https://docs.docker.com/engine/reference/commandline/service_logs/)\n\n## Docker Swarm Visualizer\n\n接下來推薦大家一個套件 [Docker Swarm Visualizer](https://github.com/ManoMarks/docker-swarm-visualizer)，\n\n顧名思義，他就是可以將 Docker Swarm 視覺化。\n\nrun in a docker swarm\n\n```cmd\ndocker 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\n```\n\n這時候可以試著瀏覽 [http://192.168.1.107:8080/](http://192.168.1.107:8080/)，應該會看到類似的圖\n\n![](https://i.imgur.com/2wJdVjS.png)\n\n可以發現 6 個 service 分散到每個 machine 裡面。\n\n## Docker Swarm + Django\n\n* [Youtube Tutorial PART 5 - Docker Swarm + Django - 實戰篇](https://youtu.be/AeabcmHvSts)\n\n前面已經用 nginx 帶大家認識 `docker service` 以及 `docker swarm` 了，現在要用 Docker Swarm + Django 來實戰\n\n### 步驟一\n\n首先，要先建立 image，為什麼呢:question: 不是可以使用 build :question:\n\n因為現在要使用 `docker stack` 的方式佈署，而 `docker stack` 強制規定一定要使用 image ，可參考官網 [image-required](https://docs.docker.com/docker-cloud/apps/stack-yaml-reference/#image-required)，\n\nDjango 的範例使用之前介紹的 [用 Docker 實戰 Django 以及 Postgre](https://github.com/twtrubiks/docker-tutorial#%E7%94%A8-docker-%E5%AF%A6%E6%88%B0-django-%E4%BB%A5%E5%8F%8A-postgre)\n\n所以先 clone 下來\n\n```cmd\ngit clone https://github.com/twtrubiks/docker-tutorial.git\n```\n\n接著到目錄底下\n\u003e cd docker-tutorial\n\n執行 `docker-compose up`\n\n再開啟另一個 terminal，先使用 `docker ps` 找到正在執行的 web container，\n\n之後就是 commit，可參考下面指令\n\n```cmd\ndocker commit -m \"create\" CONTAINER_ID twtrubiks/my_django\n```\n\npush image\n\n```cmd\ndocker push twtrubiks/my_django\n```\n\n因為 repo 是 pubilc 的，所以大家可以到這邊查看 [twtrubiks/my_django](https://hub.docker.com/r/twtrubiks/my_django/)，\n\n你可以自己練習操作一遍，或是直接使用我的 image :smirk:\n\n如果你對 `docker push` 不熟，可參考之前的教學 [Docker push image to Docker Hub 教學](https://github.com/twtrubiks/docker-tutorial#docker-registry)。\n\n### 步驟二\n\n建立 `docker-stack.yml`，可參考 [docker-stack.yml](https://github.com/twtrubiks/docker-swarm-tutorial/blob/master/docker-stack.yml)\n\n```yml\nversion: \"3\"\nservices:\n\n  db:\n    image: postgres\n    environment:\n        POSTGRES_PASSWORD: password123\n    volumes:\n      - db-data:/var/lib/postgresql/data\n    ports:\n        - \"5432:5432\"\n    networks:\n      - backend\n    deploy:\n      placement:\n        constraints: [node.role == manager]\n\n  web:\n      image: twtrubiks/my_django\n      # volumes:\n      #   - api-data:/docker_api\n      ports:\n        - \"8000:8000\"\n      networks:\n        - backend\n      depends_on:\n        - db\n      deploy:\n        replicas: 10\n        update_config:\n          parallelism: 2\n        restart_policy:\n          condition: on-failure\n\n  visualizer:\n    image: dockersamples/visualizer:stable\n    ports:\n      - \"8080:8080\"\n    stop_grace_period: 1m30s\n    volumes:\n      - \"/var/run/docker.sock:/var/run/docker.sock\"\n    deploy:\n      placement:\n        constraints: [node.role == manager]\n\nnetworks:\n  backend:\n\nvolumes:\n  db-data:\n  # api-data:\n```\n\n基本上這個 `docker-stack.yml` 是從 [docker-compose.yml](https://github.com/twtrubiks/docker-tutorial/blob/master/docker-compose.yml) 修改來的，\n\n有注意到嗎？ 已經使用了 [twtrubiks/my_django](https://hub.docker.com/r/twtrubiks/my_django/) 這個剛剛建立出來的 image，\n\n其餘的 `docker-stack.yml` 參數介紹請參考官網 [https://docs.docker.com/compose/compose-file/](https://docs.docker.com/compose/compose-file/)，\n\n這邊基本上都可以找到說明，在頁面上用關鍵字找即可 :relaxed:\n\n補充一下，`depends_on` 這個參數在 swarm 中是會被忽略的，\n\n可參考 [https://docs.docker.com/compose/compose-file/#depends_on](https://docs.docker.com/compose/compose-file/#depends_on)，\n\nThe depends_on option is ignored when deploying a stack in swarm mode with a version 3 Compose file。\n\n### 步驟三\n\n終於可以開始佈署了 :satisfied:\n\n一樣使用三台 machine，vm1 是 Leader\n\n![](https://i.imgur.com/0716ws1.png)\n\n接著 ssh 進去 vm1\n\n![](https://i.imgur.com/CIZyv09.png)\n\n先 clone 一份下來，因為我們需要 `docker-stack.yml`（ 你也可以用其他的方法 ）\n\n```cmd\ngit clone https://github.com/twtrubiks/docker-swarm-tutorial\n```\n\n切換到目錄底下\n\u003e cd docker-swarm-tutorial/\n\n![](https://i.imgur.com/0Rot4eX.png)\n\n接著使用 `docker stack deploy` 指令佈署，\n\n```cmd\ndocker stack deploy --compose-file docker-stack.yml my_app\n```\n\n也可以寫成\n\n```cmd\ndocker stack deploy -c docker-stack.yml my_app\n```\n\n`--compose-file` , `-c` 代表 Path to a Compose file\n\n![](https://i.imgur.com/kITmKDl.png)\n\n當使用 `docker service ls` 查看時，可能要等一下:relaxed:\n\n因為每一台機器 ( vm1 vm2 vm3 ) 都需要從 [docker hub](https://hub.docker.com/) pull image 下來，\n\n![](https://i.imgur.com/ajhH6TD.png)\n\n更多 `docker stack deploy` 說明，可參考 [https://docs.docker.com/engine/reference/commandline/stack_deploy/](https://docs.docker.com/engine/reference/commandline/stack_deploy/)\n\n這邊補充一下 `docker stack` 的其他指令\n\nList stacks\n\n```cmd\ndocker stack ls\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/stack_ls/](https://docs.docker.com/engine/reference/commandline/stack_ls/)\n\nList the tasks in the stack\n\n```cmd\ndocker stack ps [OPTIONS] STACK\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/stack_ps/](https://docs.docker.com/engine/reference/commandline/stack_ps/)\n\nRemove one or more stacks\n\n```cmd\ndocker stack rm STACK [STACK...]\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/stack_rm/](https://docs.docker.com/engine/reference/commandline/stack_rm/)\n\nList the services in the stack\n\n```cmd\ndocker stack services [OPTIONS] STACK\n```\n\n可參考 [https://docs.docker.com/engine/reference/commandline/stack_services/](https://docs.docker.com/engine/reference/commandline/stack_services/)\n\n接下來就是 migrate，隨便進去一個 web service 的 container migrate 即可，使用的指令如下，\n\n先查看 container id，並且進入 container\n\n```cmd\ndocker ps\ndocker exec -it \u003cContainer ID\u003e bash\n```\n\n![](https://i.imgur.com/daIIFT0.png)\n\n開始 migrate\n\n```cmd\npython manage.py makemigrations musics\npython manage.py migrate\n```\n\n![](https://i.imgur.com/5YkmSqQ.png)\n\n再建立一個 superuser\n\n```cmd\npython manage.py createsuperuser\n```\n\n![](https://i.imgur.com/BVzF9mk.png)\n\n到這邊就完成了:smiley:\n\n以我的範例可以瀏覽 [http://192.168.1.105:8000/api/music/](http://192.168.1.105:8000/api/music/) 或\n\n[http://192.168.1.106:8000/api/music/](http://192.168.1.106:8000/api/music/) 或 [http://192.168.1.107:8000/api/music/](http://192.168.1.107:8000/api/music/)\n\n都可以順利看到 :satisfied:\n\n溫馨小提醒  :heart:\n\n這邊有可能有時候會遇到，你打開網頁，發現顯示找不到網頁的狀況，會發生這個原因是因為啟動順序\n\n的問題，因為有可能 web service 比 db service 早啟動完成，所以導致 web 無法連上 db :sob:\n\n這時候該怎麼解決呢:question:\n\n這裡先提供一個方法，想法很簡單，就是將 web service 重新啟動，這樣就可以連到 db 了 :relaxed:\n\n如果有更好的方法歡迎提供，謝謝。\n\n先將  my_app_web service scale 為 0\n\n\u003e docker service scale my_app_web=0\n\n再將他 scale 為 10 ( 原本設定為 10 )\n\n\u003e docker service scale my_app_web=10\n\n基本上這樣 web service 就一定會成功連線到 db service  :relaxed:\n\n![](https://i.imgur.com/yXRmthx.png)\n\nport 8080 則是 Docker Swarm Visualizer ，瀏覽 [http://192.168.1.105:8080](http://192.168.1.105:8080) 或\n\n[http://192.168.1.106:8080](http://192.168.1.106:8080) 或 [http://192.168.1.107:8080](http://192.168.1.107:8080)\n\n![](https://i.imgur.com/AoEMe4O.png)\n\n雖然一切看起來美好，但有個小缺點，假設我將 vm3 ( [192.168.1.107](192.168.1.107) )  關機（或是因為其他原因這台機器掛了），\n\n然後去瀏覽 [http://192.168.1.107:8000/api/music/](http://192.168.1.107:8000/api/music/) ，你會發現連不進去 :sob:\n\n你總不可能叫使用者改連 [http://192.168.1.105:8000/api/music/](http://192.168.1.105:8000/api/music/) 或 [http://192.168.1.106:8000/api/music/](http://192.168.99.106:8000/api/music/)，\n\n不被打飛才怪 :rage:\n\n所以這時候我們還需要一個 **外部** 的 **load balancer** !!\n\nload balancer 之前也有介紹過，那時候是使用 nginx 介紹的，\n\n可參考 [實戰 Docker + Django + Nginx + uWSGI + Postgres - Load Balance 📝](https://github.com/twtrubiks/docker-django-nginx-uwsgi-postgres-load-balance-tutorial)\n\n我在 [文章](https://github.com/twtrubiks/docker-django-nginx-uwsgi-postgres-load-balance-tutorial#%E5%85%B6%E4%BB%96%E7%9A%84%E8%B2%A0%E8%BC%89%E5%B9%B3%E8%A1%A1) 最後也提到，如果要專注在 load balancer，使用 HAProxy 效果應該會更好，\n\n所以現在，我們就來加上 HAProxy 吧:satisfied:\n\n## Docker Swarm + HAProxy\n\n* [Youtube Tutorial PART 6 - Docker Swarm + HAProxy - 實戰篇](https://youtu.be/GaeLgRtiJEc)\n\n[HAProxy](http://www.haproxy.org/)（ High Availability Proxy ）最常見的用途是提高分散式環境的效能和可靠性，以這個範例，就非常適合使用。\n\n![](https://i.imgur.com/oWLFO83.png)\n\n參考官網 [https://docs.docker.com/engine/swarm/ingress/#using-the-routing-mesh](https://docs.docker.com/engine/swarm/ingress/#using-the-routing-mesh)\n\n注意，這邊是本機中執行，不是在 swarm 中執行了，\n\n先切換到 `haproxy-tutorial` 資料夾中，\n\u003e cd haproxy-tutorial\n\n修改 `haproxy.cfg`，主要是最後面修改成自己的 ip\n\n```cfg\ndefaults\n  mode http\n  option  httplog\n  timeout connect 4000ms\n  timeout client 50000ms\n  timeout server 50000ms\n\n  stats enable\n  stats refresh 5s\n  stats show-node\n  stats uri  /stats/haproxy  # http://0.0.0.0:8080/stats/haproxy\n\nglobal\n  log 0.0.0.0:1514 local0 debug\n  user haproxy\n  group haproxy\n\n# Configure HAProxy to listen on port 80\nfrontend http_front\n    log global\n    bind *:80\n    default_backend http_back\n\n# Configure HAProxy to route requests to swarm nodes on port 8000\nbackend http_back\n    log global\n    balance roundrobin\n    http-request replace-value Host .* info.cern.ch\n    server node1 192.168.1.105:8000 check\n    server node2 192.168.1.106:8000 check\n    server node3 192.168.1.107:8000 check\n```\n\n`haproxy.cfg` 的設定真的很多，詳細可以參考 [官網](http://www.haproxy.org/) 說明。\n\n**方法一** :\n\n ( 這個方法無法取得 HAProxy 的 Log ，但 Load Balance 正常，可能是要設定其他的東西，建議使用**方法二** )\n\n接著 build image\n\n```cmd\ndocker build -t my-haproxy .\n```\n\n![](https://i.imgur.com/yd8Ljgd.png)\n\n將他執行起來\n\n```cmd\ndocker run -p 8080:80  my-haproxy\n```\n\n![](https://i.imgur.com/z0g2jQp.png)\n\n**方法二** :\n\n直接使用 [pgaertig/haproxy-docker](https://github.com/pgaertig/haproxy-docker) 這個 image。\n\n```cmd\n docker run -v D:\\docker-swarm-tutorial\\haproxy-tutorial\\haproxy-data:/haproxy-data -p 8080:80 pgaertig/haproxy:latest\n```\n\n( 記得使用完整的路徑 )\n\n![](https://i.imgur.com/sKTyq1h.png)\n\n接著瀏覽[網頁]((http://localhost:8080/api/music/))時，你會發現 log 中有 node1、node2、node3 ，這就是 HAProxy 的 Load Balance。\n\n![](https://i.imgur.com/raGwlPQ.png)\n\n當瀏覽 [http://localhost:8080/api/music/](http://localhost:8080/api/music/) 時，就算 vm3 ( 192.168.99.102 )  掛了，我們一樣可以正常使用網頁 :satisfied:\n\n![](https://i.imgur.com/aOiXV3M.png)\n\nHAProxy 會透過 Health Check 檢查是否這台 server 可以處理 request（會將你的 request 導到可以處理的 server 上）\n\n只要還有一台存在，都可以正常使用網頁（不會掛點）。\n\n也可以瀏覽 [http://localhost:8080/stats/haproxy](http://localhost:8080/stats/haproxy) 查看狀態，\n\n![](https://i.imgur.com/wK2DP0O.png)\n\n但也不要開心的太早，雖然有 HAProxy 幫我們處理 load balancer，但是也有可以 HAProxy 那台機器出了問題，\n\n也就是 **單點失效 ( SPOF )  single point of failure**，也就導致整個系統無法運作:scream:\n\n可以使用 HAproxy + **Keepalived** 解決，這部份有機會會再介紹給大家:relaxed:\n\n## Docker Swarm - Manage sensitive data with Docker secrets\n\n* [Youtube Tutorial PART 7 - Docker Swarm Manage sensitive data with Docker secrets - 實戰篇](https://youtu.be/T8mkecPQce4)\n\n如果你不想將敏感資料存在 image 或者程式碼中，可以使用 docker secrets 來管理容器執行時需要的敏感資料，\n\n像是 passwords、ssl certificates 、ssh private keys ......\n\n思考一個問題，當你有開發機、測試機、正式機，然後每個環境都有不同的密碼，這樣管理 swarm 上會非常麻煩，\n\n這時候可以透過 docker secrets 來管理這些密碼，我們只需要知道 secrets name 就可以在這三個環境上運作。\n\n這邊要注意，`Docker secrets` 只能夠使用在 swarm 下，不能夠使用在獨立的 container 中，\n\n更多介紹，請參考 [Manage sensitive data with Docker secrets](https://docs.docker.com/engine/swarm/secrets/)\n\n其餘的 `Docker secrets` 指令可參考 [https://docs.docker.com/engine/reference/commandline/secret/](https://docs.docker.com/engine/reference/commandline/secret/)\n\n簡單的來實戰一下:smile:\n\n先到 swarm 環境中，假設 vm1 是 manager，先 clone 範例\n\n```cmd\ngit clone https://github.com/twtrubiks/docker-swarm-tutorial.git\n```\n\n接著  `cd docker-swarm-tutorial/docker-swarm-secrets/` 到 [docker-swarm-secrets](https://github.com/twtrubiks/docker-swarm-tutorial/tree/master/docker-swarm-secrets) 資料夾底下，\n\n主要只會用到 [docker-stack.yml](https://github.com/twtrubiks/docker-swarm-tutorial/blob/master/docker-swarm-secrets/docker-stack.yml) 這個檔案，這個範例是從 [Docker 基本教學 - 從無到有 Docker-Beginners-Guide](https://github.com/twtrubiks/docker-tutorial) 修改過來的，\n\n修改了 api/django_rest_framework_tutorial/[settings.py](https://github.com/twtrubiks/docker-swarm-tutorial/blob/master/docker-swarm-secrets/api/django_rest_framework_tutorial/settings.py) 這個檔案，修改如下\n\n```python\n\ndef secret_path(name):\n    path = '/run/secrets/{}'.format(name)\n    if not os.path.isfile(path):\n        raise Warning(name)\n    return path\n\n\ndef secret(name, strip=True):\n    with open(secret_path(name), 'r') as f:\n        val = f.read()\n        if strip:\n            val = val.strip()\n        return val\n\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.postgresql_psycopg2',\n        'NAME': 'postgres',\n        'USER': 'postgres',\n        'PASSWORD': secret('my_password'),\n        'HOST': 'db',\n        'PORT': 5432,\n    }\n}\n```\n\n目的是去讀取路徑中的 `/run/secrets/\u003csecret_name\u003e` 檔案。（ 我們會將 secrets 名稱設定為 my_password ）。\n\n在 Docker 17.05 或更早的版本，secrets 路徑總是會存在 `/run/secrets/` 資料夾裡，\n\n在 Docker 17.06 之後，可以指定路徑（ 沒指定默認路徑也是 `/run/secrets/` ）。\n\n前面說過了，`docker stack` 強制規定一定要使用 image，這邊大家可以自己 build，然後 push 到 [docker hub](https://hub.docker.com/)，\n\n也可以直接使用我幫大家做好的 [twtrubiks/my_swarm_secrets_demo](https://hub.docker.com/r/twtrubiks/my_swarm_secrets_demo/):wink:\n\n接著來看 [docker-stack.yml](https://github.com/twtrubiks/docker-swarm-tutorial/blob/master/docker-swarm-secrets/docker-stack.yml)\n\n```yml\nversion: '3.1'\nservices:\n\n    db:\n      image: postgres\n      environment:\n        POSTGRES_PASSWORD_FILE: /run/secrets/my_password\n      ports:\n        - \"5432:5432\"\n      networks:\n        - backend\n      volumes:\n        - pgdata:/var/lib/postgresql/data/\n      secrets:\n        - my_password\n\n    web:\n      image: twtrubiks/my_swarm_secrets_demo\n      ports:\n        - \"8000:8000\"\n      networks:\n        - backend\n      deploy:\n          replicas: 4\n          update_config:\n              parallelism: 2\n          restart_policy:\n              condition: on-failure\n      secrets:\n        - my_password\n      depends_on:\n        - db\n\nvolumes:\n    api_data:\n    pgdata:\n\nnetworks:\n  backend:\n\nsecrets:\n    my_password:\n        external: true\n```\n\n解釋幾個名詞，\n\n版本使用 `3.1` 是避免遇到 secrets Additional property secrets is not allowed 這個錯誤訊息。\n\n`POSTGRES_PASSWORD_FILE` 這個是讀取我們創造的 secrets，\n\n`secrets` 則是指定我們創造的 secrets，這邊還要提一個參數 `external`，\n\n當設定為 `true` 時，代表為外部資源，也就是他已經在 docker 中被定義了，\n\n所以當啟動時，不會再去創造他，如果找不到，則會顯示 `secret not found` 錯誤。\n\n詳細的說明可參考\n\n[https://docs.docker.com/compose/compose-file/#secrets](https://docs.docker.com/compose/compose-file/#secrets)\n\n[https://docs.docker.com/compose/compose-file/#external](https://docs.docker.com/compose/compose-file/#external)\n\n接下來就真的要佈署了:grin:\n\n在 vm1 manager 節點下，先建立 secret\n\n```cmd\necho \"password123yoyo\" | docker secret create my_password -\n```\n\n注意最後面有一個 `-`，代表輸入是從標準輸入讀取的。\n\n密碼你要打多少都可以，因為現在我們只需要知道 secrets name 就可以讀取敏感資訊了。\n\n可以使用 `docker secret ls` 查詢，會看到剛剛建立的 my_password\n\n![](https://i.imgur.com/kPwe1oU.png)\n\n開始佈署\n\n```cmd\ndocker stack deploy -c docker-stack.yml demo_secret\n```\n\n![](https://i.imgur.com/RS93Yfz.png)\n\n執行 `docker stack services demo_secret` 確認佈署狀態，\n\n![](https://i.imgur.com/be6cNyI.png)\n\n確定都佈署完成了之後，\n\n可以執行 `docker stack ps demo_secret` 查看分布在各主機的狀況，\n\n![](https://i.imgur.com/m61tm6s.png)\n\n在這邊我們隨便進入一個 container ，\n都可以找到 `/run/secrets/my_password` 這個檔案\n\n（ 原因是因為 `db` 以及 `web` 都有指定 secrets ）\n\n```cmd\ncat /run/secrets/my_password\n```\n\n![](https://i.imgur.com/4kKxWFn.png)\n\n從上圖可以發現，看到剛剛設定的密碼了:smile:\n\n接下來就是 migrate，隨便進去一個 web service 的 container migrate 即可，使用的指令如下，\n\n先查看 container id，並且進入 container\n\n```cmd\ndocker ps\ndocker exec -it \u003cContainer ID\u003e bash\n```\n\n![](https://i.imgur.com/daIIFT0.png)\n\n開始 migrate\n\n```cmd\npython manage.py makemigrations musics\npython manage.py migrate\n```\n\n![](https://i.imgur.com/5YkmSqQ.png)\n\n再建立一個 superuser\n\n```cmd\npython manage.py createsuperuser\n```\n\n接下來就可以正常使用了\n\n![](https://i.imgur.com/rxoEkG5.png)\n\n## 後記：\n\n如果你真的很有耐心的看到這邊，而且你也是第一次接觸這種分散式系統的人，相信你會覺得 Docker Swarm\n\n真的很棒，而且入門也不會很困難 :smile:\n\nDocker Swarm 可以玩得真的非常非常多，這篇只是一個基礎的介紹，有機會我再介紹其他的東西給大家 :kissing_closed_eyes:\n\n當然，分散式系統也有很多，像是文章開頭說的 [Kubernetes](https://kubernetes.io/) ( k8s ) 也可以玩玩看 ~\n\n如果你有想分享或是補充的，歡迎聯絡我，感謝閱讀到最後的你 ( 妳 ) :kissing_heart:\n\n## 執行環境\n\n* Mac\n* Python 3.6.2\n* windows 10\n\n## Reference\n\n* [https://docs.docker.com/](https://docs.docker.com/)\n* [http://www.haproxy.org/](http://www.haproxy.org/)\n* [An Introduction to HAProxy and Load Balancing Concepts](https://www.digitalocean.com/community/tutorials/an-introduction-to-haproxy-and-load-balancing-concepts)\n* [docker-swarm-visualizer](https://github.com/ManoMarks/docker-swarm-visualizer)\n* [Keepalived](http://www.keepalived.org)\n\n## Donation\n\n文章都是我自己研究內化後原創，如果有幫助到您，也想鼓勵我的話，歡迎請我喝一杯咖啡:laughing:\n\n![alt tag](https://i.imgur.com/LRct9xa.png)\n\n[贊助者付款](https://payment.opay.tw/Broadcaster/Donate/9E47FDEF85ABE383A0F5FC6A218606F8)\n\n## License\n\nMIT license\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwtrubiks%2Fdocker-swarm-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftwtrubiks%2Fdocker-swarm-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwtrubiks%2Fdocker-swarm-tutorial/lists"}