swarm

標籤:swarm

Swarm mode 上線 6 - 2| 升級陷阱

潮流特區
MacauYeah ・2025-04-14

上一期筆者就介紹寺過swarm的相容性,可以任意地刪除其中node、加入新的node,系統會自動同步各機狀態。今日,我們就來討論一下加減的流程吧。 實戰輪調流程 假設我們有5個 node,都為manager,各個 docker 版本都為28.0.4 ,我們將要關掉node 5 ubuntu 22,並加入node 6 ubuntu24,輪調流程如下 如果node5有vvip,login node 5,關掉vvip systemctl stop keepalived login node1, 把node5降為drain模式,變為worker,並從群集中刪除 docker node update availability drain node5 docker node demote node5 若然node5不是直接關機、刪除,只想好好地離開群集,可以 login node5, 在node5上預先執行 docker swarm leave docker node rm force node5 如果之前node5有好好地離開群集,而且狀態已經轉為down,那麼就不用quot;forcequot;了,用最保守的刪除指令就可以 docker node rm node5 login node1, 取得manager token docker swarm jointoken manager node5關機,新增node6,使用相容的ip段,或者使用node5的ip login node6, 加入群集,設定vvip docker swarm join token xxxx XX_IPXX_PORT systemctl stop keepalived 這陷阱這陷阱 偏我遇上 上述的操作,有一些可能的陷阱,筆者就剛好踩過,未來不知道會不會有官方保證 docker的版本需要相同,不同版本可能不能加入群集,例如 docker 28.0.4 不能加到 docker 27.5.1。 docker 27.2.x 不能加到 docker 27.5.1。 docker swarm,官方雖然宣稱支援不同版本共存,但這指的是已加入的node,在不解綁的情況下原機升級。 在swarm已有多版本共存的情況下,有一個node選擇完全脫離,它想再加入,也是會失敗的。可能這不是docker自身的限制,而是底層library的相容性問題。筆者在實測不同版本時,就得到這樣的error。docker credentials cannot check peer missing selected ALPN property

Swarm mode 上線 6 | OS升級前的準備

潮流特區
MacauYeah ・2025-04-08

如果大家一直有跟進安全更新,基本上每個一至兩個月,都會有OS kernel和Docker Engine Update。也許大家習慣還是以不變應萬變,但有些時候還是不可避免地遇到嚴重漏動,需要強制更新。那麼當我們在這個情況時,我們該如何做呢?在開始做之前,我們先測試一下Swarm的容錯率有多高。 官方就宣稱,只要swarm中,manager例下的數目沒有超過半數,就依然可以運行。這個部份,筆者相信大家一早就感受過。但筆者認為,在直正出意外的情況是,少於半數的manager倒下了,但其餘的manager又不幸要重啟,到底又些活著的manager,又可否成功重新啟動?所以下面就來做些測試。 測試1 測試REPO 初始化script initDockerCluster.sh 筆者在原本的教學中,就有一個3個manager node 2 worker node的範例,我們只要安裝ubuntu OS, packer, 並使用 # run setupMultipassWithFixIP.sh will install multipass and config fix ip .setupMultipassWithFixIP.sh # install packer, please refer to httpsgithub.commacauyeahubuntuPackerImageblobmainREADME.md packer init template.pkr.hcl packer build template.pkr.hcl # initialize docker cluster in multipass .initDockerCluster.sh 在上述的環境中,node21, node22, node23是manager, node24, node25則是worker。在全關的情況下,只要正常啟動兩台manager,worker就可以成功復活。 測試2 測試REPO 初始化script initDockerClusterLoopJoin.sh 筆者寫了另一個起始方案,會有5個manager node,而且依賴順序如下 node22 =gt; node21 node23 =gt; node22 node24 =gt; node23 node25 =gt; node24 node21 =gt; node22 # initialize docker cluster in multipass .initDockerClusterLoopJoin.sh 在上述的環境中,5台機也是manager。 initDockerClusterLoopJoin 的前半部份,它會建立順序依賴,即每一台機器,都經前一台機器進行加入的動作。而後半部份會把node21刪掉,並經multipass用一個全新的guest os重起,重新加入到。 在全關的情況下,只要正常啟動三台manager,它們都可以繼續運行。 這個測試的例子表明,即使原本作為依賴的機器死了,只要群齊中其餘多數manager仍然存在,它們也是可以復活的。更重要的是,即使最初引領一切的node21死掉了,什至是被刪掉重來,也是相安無事的。 結論 更新時,最保守的做法,是先加入新的manager,再除去舊有的manager。但這個做法下,manager的IP就不可避免地被改變。若然DNS或者防火牆沒有相應的自動化幫忙,先加入再替換就變得很痛苦了。 而上述的測試,其實代表了我們可以先暫停或移除舊有的manager,更新完後再接回去,這樣部份IP就可以重用。我們只要維持多於原本半數的manager活著,然後逐一替換或升級原有的機器,也不會有問題。即使在升級途中,其他manager不幸地斷線,重啟後它們還是有條件自行修復。我們也不需要顧及更新順序,只需想好Virtual IP的分配策略就足夠,其餘就像是單機升級一樣。

Swarm mode 上線 5 - load balancer | 還有那些事該考量?

潮流特區
MacauYeah ・2024-11-18

前面介紹了 ingress network ,亦介紹了 proxy gateway 。能做到的基本都做到了,再來就是考量安全性的問題。因為加了 proxy gateway ,前述的例子是所有 service ,都放在同一個 yaml 檔中。好處是,所有相關的東西存放在同一個檔中, gateway ,背後的 service 都一眼看到。但壞處就是有其中一個 service 更新,都要改那個 yaml 檔。更大的問題是, stack deploy 的指令,不單只更新其中一個 service ,就連其他 service 都會自動取得最新 image 而 redeploy 。 對於一個緊密的系統來講,同步更新可能不是大問題。但對於一些預定排程發佈的系統可不能這樣因為副作用而更新了。如果你也有這樣的分開管理需求,可以參考下面做法,把 gateway service 及 upstream service 放在不同的檔案中,然後經過 external network把所有 service 串連起來。 # nginxstack.yaml, docker stack deploy c nginxstack.yaml nginx services httpgateway image httpgateway ports 80808080 deploy replicas 1 update_config delay 10s restart_policy condition onfailure # managerstack.yaml services managerhttp image bretfisherhttpenv networks nginx_default default deploy replicas 3 update_config delay 10s restart_policy condition onfailure placement constraints node.labels.zone==manager networks nginx_default external true # dmzstack.yaml services dmzhttp image bretfisherhttpenv networks nginx_default default deploy replicas 2 update_config delay 10s restart_policy condition onfailure placement constraints node.labels.zone==dmz networks nginx_default external true 這樣,不同 service 的維護人員,就可以獨自控制自己的檔案。在第一次發佈時,確認 nginxstack.yaml 先行發佈就可以了。對應的發佈指令是docker stack deploy c nginxstack.yaml nginx,它會自動産生一個 nginx_default (即 stack名字_default )的網絡。之後其他service,就可以經networks的設定找到它了。 services YOUR_SERVICE networks nginx_default default networks nginx_default external true 上述即使分離檔案,在安全性考量時還是有一個問題,就是 ingress network 的問題。試想一下,dmzhttp (Demilitarized Zone)原本被設定的原因,就是想限制某些訪問只能一些可以公開的服務。但因為經過 ingress network 之後,它們會在所有機器上開放這些 port。那就是,以下面的例子來講,若 dmzhttp 是公開的服務, intrahttp 是內部服務,即使用 intrahttp 使用不同的port 8889。但一經 swarm mode 預設的 ingress network ,在node.labels.zone==dmz的那些節點,還是可以訪問到 intrahttp 。 services dmzhttp image bretfisherhttpenv ports 88888888 deploy replicas 2 update_config delay 10s restart_policy condition onfailure placement constraints node.labels.zone==dmz intrahttp image bretfisherhttpenv ports 88898888 deploy replicas 3 update_config delay 10s restart_policy condition onfailure placement constraints node.labels.zone==intra 我們前述介紹的 proxy gateway ,其實已經有一定程度可以解決這個問題。因為 proxy gateway 是根據 http 協定中的 host header 去做分流。在邊界網絡進來的「合法」訪問,道理上會好好地經引導到我們的 dmzhttp 。不過網路的邪惡可容小看, proxy gateway 也會有被騙的一日。有特定能力的攻擊者,只需找到目標域名,還是可以接觸到 intrahttp 。 若要做進一步隔離,在這種情況下,我們可以在 dmz , intra 機器中各設定一套 swarm ,完全獨立,這是最安全的做法。但這樣做的管理成本就會變高,因為兩個網段都會有自己的 manager 節點,而且在 dmz 網段的 manager 節點也有被攻擊的可能。 若我們回到單一 swarm 的方向,可以修改各個 service 中的 port 和 deploy 。利用 post mode 中的「host」,配合 deploy mode 中的「global」,完全跳開 ingress network。 services dmzhttp image nginx ports target 80 published 8888 mode host deploy mode global update_config delay 1s restart_policy condition any placement constraints node.labels.zone==dmz intrahttp image bretfisherhttpenv ports target 8888 published 8888 mode host deploy mode global update_config delay 10s restart_policy condition onfailure placement constraints node.labels.zone==intra 上面的例子中, dmzhttp 會在所有 dmz 的機器中,每個節點只運行一份服務,而且直接使用該機的 8888 port ,外面不會再有 ingress network 的 存在。同樣地,intrahttp 會在 intra 的所有節點,運行一份服務,佔用它們的8888 。這兩個服務,即使使用一個 port ,swarm 也不會說有任何問題。因為它們不會經 ingress network 搶佔其他人的 8888。 可能會有讀者問,如果 host mode 這麼安全,為什麼預設會是 ingress network,那我們就要先了理清 ingress network 與 host mode 有有什麼分別?假設我們只運行一個service,它佔用8888。 功能ingress modehost mode replicas 數 同一個 service replicas 為任意數量,什至比節點的數目多 因為有 port 限制,每個節點最多只能運行一份 Virtual IP Virtual IP 任意在節點中跳轉也可以,因為 ingress 會自動找到對應的 service 所在的節點 Virtual IP必需要與 service 所在節點綁定,其他節點訪問不到 load balance 有 沒有 host mode 就像我們傳統在各自的節點上自行佈署自己的程序,各個節點只有一份。所以不會有自動 load balance 的效果,如果客戶端訪問固定的IP,就會得到是固定的接器接受請求。我們有需要,就要在前面加一個 Proxy Gateway 或 HA proxy 。 Virtual IP 也一樣, host mode 下需要好好地自動跟著 service 的生命期,不過幸運的是, Docker 預設己經有自動重啟 service 功能,即前文中的 restart_policy ,它在 host mode 下也適用。如果大家有配合 deploy 中的 global mode , Virtual IP 的並沒有實際變動。但如果沒有 global mode ,就要再想想辦法了。 最後考慮 load balance 的問題,如果進入點的 service 的真的不太消耗資源,沒有 load balance 也是可以的 ,但若超負荷,就必需要自建 proxy gateway 。經過進入點後,若我有背後的 service 就沒有所謂的 ingress 和 host mode 選擇。