【Swarm】node
Swarm是Docker官方提供的一款集羣管理工具,其主要做用是把若干臺Docker主機抽象爲一個總體,而且經過一個入口統一管理這些Docker主機上的各類Docker資源。Swarm和Kubernetes比較相似,可是更加輕,具備的功能也較kubernetes更少一些。mysql
Swarm的基本架構以下圖所示,nginx
這個圖做爲一個總體實際上都處於一個所謂的集羣中,它可能對應了一到多臺的實際服務器。每臺服務器上都裝有Docker而且開啓了基於HTTP的DockerAPI。這個集羣中有一個SwarmManager的管理者,用來管理集羣中的容器資源。管理者的管理對象不是服務器層面而是集羣層面的,也就是說經過Manager,咱們只能籠統地向集羣發出指令而不能具體到某臺具體的服務器上要幹什麼(這也是Swarm的根本所在)。至於具體的管理實現方式,Manager向外暴露了一個HTTP接口,外部用戶經過這個HTTP接口來實現對集羣的管理。對於稍微大一點的集羣,最好是拿出一臺實際的服務器做爲專門的管理者,做爲學習而言,也能夠把管理者和被管理者放在一臺服務器上。正則表達式
下面就來說一下如何簡單地經過swarm搭建一個集羣算法
■ 安裝與簡單集羣創建sql
● 開啓帶有HTTPAPI的Docker服務docker
個人虛擬機環境是CentOS7的,Docker則是經過yum來安裝的。如要使用swarm,則必須讓Docker開放其HTTP的API。默認狀況下這個API沒有開啓,而開啓此API須要在啓動時加入-H參數。json
網上有的人說運行/usr/bin/docker的時候直接加,有的又說修改/etc/sysconfig/docker之類的文件,都不適用於我,多是因爲系統以及docker自己的版本的緣故。而個人正確姿式是修改/lib/systemd/system/docker.service這個文件中的參數,而且用systemctl來管理啓動docker服務。tomcat
上述這個文件的ExecStart很明顯是指出了docker的啓動參數,在第一行的後面直接加上:服務器
-H tcp://0.0.0.0:2375
(有些文章也指出對於CentOS6還須要加上-H unix:///var/run/docker.sock)修改完成以後別忘了運行一下systemctl daemon-reload刷新配置
而後再重啓/啓動Docker服務,此時經過netstat -ntlp能夠看到一個新開的2375端口,此乃默認的DockerHTTPAPI的端口。若是是一個集羣則須要注意集羣中全部相關的主機都記得要啓動帶這個端口的Docker服務。
● 沒有正確退出swarm集羣時引起的問題
退出swarm集羣用的命令是docker swarm leave,然而存在這樣一種狀況:沒有徹底退出swarm集羣時就關掉了Docker服務。隨後網絡環境變化了(主機的IP變了)。此時若再systemctl start docker將會報錯,經過systemctl status docker -l能夠查看完整的報錯信息,提示找不到老IP地址云云。其實這是啓動swarm時報的錯誤。
google了一下以後,發現比較方便的解決辦法是手動修改/var/lib/docker/swarm下面的docker-state.json和state.json兩個文件。把這兩個json文件中原來的老地址都改爲如今的新地址。應該就能夠順利啓動了。
● 建立小集羣
前面提到的Swarm Manager,其自己實際上是一個容器,其餘一些swarm的角色基本上也經過容器的方式來實現。Swarm源於Docker而基於Docker。可是Docker在剛安裝的時候是沒有swarm支持的,須要咱們docker pull swarm去DockerHub裏下載swarm的鏡像。這個鏡像自己不大,最新版的大概15MB左右,一下子就下載完了。
固然,若是是集羣的話那麼須要在全部相關的主機上都pull到這個鏡像。
第一步,創建一個集羣而且取得集羣標誌。Swarm支持自動發現功能,若是在一個網絡中存在多個集羣,那麼就須要每一個集羣都有一個區別於其餘集羣的標誌來防止混淆。這個標誌就是所謂的集羣token,在集羣創立之初就被指定且沒法更改。在被選爲管理者角色的服務器上運行命令:
docker run --rm swarm create
這個命令返回中帶有一串token字符串(以dfb4fb3a8767835d799ce429fb4d7c4d爲例),這個信息須要記錄下來,以後全部操做中都須要用到它來指出咱們對哪一個集羣操做。並且目前還沒找到如何查看一個既存集羣的token,因此必定要記錄一下。。
建立集羣事後實際上並無真的增長什麼Docker資源,仍然是一個空的集羣。
第二步,建立集羣獲取到集羣token以後,目前咱們手上拿着的仍是一個空集羣,接下來就往裏面加入節點主機吧。加入節點主機的方法是再各個節點主機上運行這條命令:
docker run -d swarm join --addr=192.168.1.102:2375 token://dfb4fb3a8767835d799ce429fb4d7c4d
其中--addr參數指出的是本主機的Docker服務的socket,天然,IP要和各個主機自身的IP一致。另外我嘗試了一下,若在本機指定addr爲localhost或者0.0.0.0之類的IP,最終是沒法正常工做的。因此即使是在管理者本機,也要老老實實寫出IP。完成後能夠在當前主機上docker ps看一下,應該能夠看到一個在運行中的swarm容器。這個容器扮演的角色就是向上和管理者容器通訊,向下管理所在本機的docker資源,所謂被管理主機的代理。
建立完後,能夠經過
docker run -d swarm list token://dfb4fb3a8767835d799ce429fb4d7c4d
來查看這個指定的集羣(由token指出)中存在哪些join進來的節點。須要注意的是,swarm join命令只是簡單的加入集羣的聲明,swarm並不會去驗證給出的地址和端口是否真的能夠訪問到一個Docker服務。對於沒有發現正常Docker服務的節點,將置狀態爲Pending而不是Healthy,這個狀態以及其餘節點相關信息怎麼看下面會說。
第三步,開啓管理者容器。上面創建了集羣框架,而且往集羣中加入了join節點(即被管理主機的代理),可是尚未出現管理者容器(管理主機的代理)。建立管理者容器的方法是在管理者主機上:
docker run -d -p 8888:2375 swarm manage token://dfb4fb3a8767835d799ce429fb4d7c4d
一樣,docker ps以後能夠看到管理容器。-p表名管理者容器作了一個端口映射。由於2375端口在本機上已經被Docker進程佔用(固然啓動時指定的端口不是默認的2375就另當別論了),而管理容器暴露的這個端口要提供出來,實現外界對集羣的管理,因此作了一個端口映射。這個8888,也能夠換成其餘任何合理的端口號。
有了管理容器,而且管理容器給出了8888端口做爲管理的入口,咱們就能夠運行如下這些命令了:
docker -H 192.168.1.101:8888 info docker -H 127.0.0.1:8888 ps docker -H 192.168.1.101:8888 images
因爲這個8888端口就能夠看作是一個網絡中的普通端口,在本機上訪問的話天然IP寫127.0.0.1也是能夠的。可是注意不能寫成localhost,否則會報錯。。
這三條命令,去掉-H參數的話就是通常的docker用來查看信息的命令。加上-H以後,好比-H 192.168.1.101:8888以後,其意義就變成了,查看一個集羣的相關信息。這個集羣是192.168.1.101的8888端口對應的管理容器所對應的那個集羣。
經過這幾條命令呈現出來的docker資源如容器和鏡像是不強調具體處於那臺主機上的,這就使得集羣的概念得以發揚光大。另外經過這個socket獲得的集羣的信息會把swarm自己除外。好比目前這個狀態經過-H xxx ps看到的容器列表應該是空的。由於咱們尚未讓集羣運行任何容器。可是docker ps會有swarm的容器顯示出來。若是想在-H的時候(所謂集羣視圖)也看到swarm容器信息能夠用ps -a。
順便,info命令的結果和普通的docker info命令結果不太同樣,最主要的是有了nodes這個字段。這個字段包含了各個節點的信息,包括前面提到的節點狀態等信息。
■ 集羣簡單使用
下面正式使用集羣來跑個容器試試看。其實和原生docker命令相比,就是多了個-H參數來指明一個集羣管理入口而已:
docker -H 127.0.0.1:8888 run -d -p 10022:22 --name swarmtest tomcatssh:v1
tomcatssh是我本地一個自定義的鏡像,和docker run相似的,其餘的不少命令如docker start/stop/rm等等也均可以經過集羣管理的入口來對集羣作出。
若是咱們的集羣中有多態機器用於跑容器,即有多個被管理主機的話,那麼經過這樣的方式啓動起來的容器會經過必定的策略選擇一臺合適的主機做爲真實的跑容器的平臺來運行容器。策略分紅好多種,默認是spread(這個字段在docker -H xxx info中的Strategy中有顯示),具體是指當集羣要運行一個新的容器,將會根據算法和收集到的各個被管理主機CPU,內存等信息進行智能的選擇,使得各個運行容器的主機儘可能均衡。
既然可以作到自動選擇一臺主機做爲容器運行的寄託,那麼天然也能夠恢復手動模式。這在swarm中就是所謂的filter功能。filter能夠分紅多種,
● 約束過濾器(Constraint Filter)
約束過濾器經過啓動Docker守護進程時指定的標籤label來查找合適的被管理主機。label是經過啓動參數的方式在啓動時被固定的:
--label datacenter=us-east1
這個參數加入到以前說過的docker.service,或者手動加在啓動docker的命令後面等等。
而在啓動容器時經過這樣的方式來指定過濾器:
docker -H 127.0.0.1:8888 run -e constraint:datacenter==us-east1 -d --name www-use1 nginx
-e後面跟過濾器,constraint指出了約束過濾器,後面的約束標籤支持==,!=兩種判斷,後面能夠寫字符串和正則表達式如us-east*。
● 親和過濾器(Affinity Filter)
親和過濾器以現有的某個容器爲基準,讓新容器運行在/不在已經運行了某個現有容器的主機上運行。
docker run -d -e --name db affinity:container!=www-use1 mysql
好比上面這條命令說的就是要根據mysql鏡像啓動一個名爲db的容器,可是這個容器不能在已經預www-use1容器運行的主機上運行。
● 端口過濾器
端口過濾器嚴格來講並非一個真的過濾器。。它只是在啓動容器時經過-p參數來申請對一個主機端口的使用權。若是一臺主機上這個端口正在被使用那麼天然是不能把容器放到這個主機上運行的。
除了上述三種,過濾器還有不少,能夠經過swarm manage --help或者去官網查。總的來講,過濾器是一種主動指定主機的手段,配合swarm自身的自動分配機制,能夠靈活地肯定一臺主機來運行容器。
若是當前集羣中swarm找不到一臺符合條件的主機來運行容器,那麼swarm會明確指出哪一個過濾器條件得不到知足,從而啓動容器失敗。
========================================================================================================
意識到,上面的swarm介紹竟然是老版本的!orz
如今的Docker(1.12版本之後的)都是帶了原生的swarm命令,也就是說不須要不須要進行復雜的swarm create之類的操做,僅須要簡單幾條命令便可。
【http://blog.csdn.net/candcplusplus/article/details/53836703】
■ 新版本上構建swarm集羣和節點
啓動一個swarm集羣十分簡單,只須要執行
docker swarm init --listen-addr 192.168.1.112:8888 --advertise-addr 192.168.1.112
兩個參數也很好懂,--listen-addr指出的是這個集羣暴露給外界調用的HTTPAPI的socket地址。這個就是相似於上面老版本中swarm manage時-p指定的端口。添加--advertise-addr參數的緣由是大多數狀況下咱們的主機都不僅有一張網卡。而一個swarm集羣須要辨明集羣所在的子網絡是哪張網卡的。
另外須要注意,在新版本的swarm下,manage節點自身也做爲被worker節點的一個,自動加入創建起來的swarm集羣中。
命令運行成功的話會提示一串相似於這樣的信息:
docker swarm join \ --token SWMTKN-1-2vndbzp43eff6vaiornhbafew242arz29qngrql0slqg4zmi4j-1hpha7vnelkbg4gg1d293qus4 \ 192.168.1.112:8888
這是在說明,通網絡下的被管理主機上,只要運行這串命令就能夠將該主機加入集羣。若是不當心忘了這個命令那麼能夠在manager上運行docker swarm join-token manager命令,隨時調取出這部分信息來看。我特地多建了兩臺虛擬機,裝上docker做爲被管理機器。爲方便下面稱管理者角色的機器爲A,另兩臺爲B、C。
在B、C上分別運行上面這個命令(有時能夠在命令後加上--listen-addr參數,倒不是說被管理主機也須要監聽,而是存在一些將被管理主機升級爲管理主機的場景)後,在A上執行命令:
docker node ls
能夠查看swarm各個節點的狀況。一樣的docker info 中也會多出Swarm: True以及一系列相關字段。docker node ls的返回相似於:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 2hzmnrb0vddow7jlr7zdx86s0 localhost.localdomain Ready Active 444w5u9i9tf8h1dmvp404tluy * localhost.localdomain Ready Active Leader 89z0l64mitjyhwijj6o0ps3m3 localhost.localdomain Ready Active
節點id後的星號聽說表示的是你當前鏈接着的節點。
因而,咱們就獲得了一個由三個節點組成的swarm小集羣。在這個集羣中有一個manager節點和三個worker節點(別忘了manager自己自動做爲worker一員加入集羣)。
相比較於以前還須要手動pull鏡像,而後敲好多docker run命令,新版本下整合到docker內部的swarm明顯就要好多了。然而咱們如今也只是搭建了一個小集羣,並無實質內容在其中運行。
■ 構建服務
說到實質內容,因爲swarm會自動地作一些如負載均衡,保持容器副本數量等工做,因此swarm對外提供的和k8s相似也是屬於一個「服務」的概念。
docker service create --replicas 1 --name swarmtest tomcatssh:v1
經過上面這個命令能夠建立一個服務(tomcatssh是我本身的鏡像)。--replicas參數指出但願保持這個服務始終有多少容器在運行,name參數指定的是服務的名字而非容器的名字,雖然二者最終會很像。
建立完成的服務能夠在manage節點上經過docker service ls命令查看,可能replicas是0/1,這表示服務仍在建立過程當中。稍等一下子就會變成1/1了。更加詳細的信息,則能夠經過docker service inspect --pretty swarmtest來查看。pretty參數使輸出更加友好,不加此參數的輸出是JSON格式的。
同時也能夠順便到各臺worker上去docker ps看下容器的運行狀況。通常狀況下再manager上會出現一個正在運行的容器,若是你停掉或者刪掉這個容器,那麼swarm會自動重啓它。
進一步的docker service ps swarmtest,能夠查看swarmtest這個Service的各個容器到底在哪一個節點上運行且運行狀態如何。好比我剛纔創建了一個replicas爲3的swarmtest服務,docker service ps swarmtest後的結果是:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR a6ubuiush8l821rncxkd231le \_ swarmtest.1 tomcatssh:v1 localhost.localdomain Shutdown Rejected 8 minutes ago "No such image: tomcatssh:v1" 3sk5cowp4bve0zklvydwdgwba swarmtest.2 tomcatssh:v1 localhost.localdomain Running Running 6 minutes ago 8tku51hecc6pza21urs5oz5zk swarmtest.3 tomcatssh:v1 localhost.localdomain Running Preparing 32 seconds ago
能夠看到,在要求啓動3個容器做爲swarmtest服務的支撐時,swarm分別試圖在集羣(僵硬的是我集羣中三個主機的主機名都是localhost.localdomain。。。意思一下吧,總之知道這裏雖然寫的同樣可是裏面是三臺不一樣的機子)中去啓動swarmtest.1,swarmtest.2以及swarmtest.3三個容器,能夠看到swarm.1視圖運行的主機上沒有tomcatssh:v1鏡像所以啓動失敗,swarm.2啓動成功,開始運行;swarm.3仍在準備中。能夠想到的是,由於swarm.1已經啓動失敗,因此swarm會繼續尋找機會啓動它,儘可能保證啓動服務時replicas爲3的要求。
另外服務還有一個重要的功能就是伸縮。經過命令:
docker service scale swarmtest=5
能夠將服務現有的replica爲3的狀態擴展到5,期間已經啓動的容器不受影響。
對於不須要的服務,能夠docker service rm swarmtest來刪除。刪除後全部節點上的相關容器都會被刪除。
對於一個服務來講,常會遇到的一件事是滾動更新,swarm爲咱們封裝了命令docker service update。只要給這個命令加上--image參數指定一個新鏡像,那麼該服務中的全部容器都會被更新成這個新鏡像的內容。但爲了保證可用性,必然不能同時更新全部容器。swarm就內置了一個滾動更新的機制,可讓咱們依次更新各個容器從而避免更新期間的不可用。在docker service create 的時候能夠指出--upgrade-delay參數,表示更新服務對應的任務或一組任務之間的時間間隔。時間間隔用數字和時間單位表示,m 表示分,h 表示時,因此 10m30s 表示 10 分 30 秒的延時。另外--update-parallelism參數標誌配置調度器每次同時更新的最大任務數量,默認狀況下此參數值爲1,即一個一個容器地更新。
在有了滾動更新的保障以後,再來執行docker service update,好比docker service update --image tomcatssh:v2 swarmtest,則swarm會自動地去按照滾動更新的策略更新各個容器(實際上就是把舊容器關停並啓動新容器)。在更新過程當中docker service ps swarmtest能夠查看更新的實時狀況,最終更新完成後這條命令看到的結果應該是相似於這樣子的:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR 5v3purlp28bg93ngkmp9x1dy9 swarmtest.1 tomcatssh:v2 worker1 Running Running 45 seconds ago 055xxourdnlsylmnjgwvs718t \_ swarmtest.1 tomcatssh:v1 worker1 Shutdown Shutdown 49 seconds ago 4b1am22wx1w0abo3ylxt7qcfe swarmtest.2 tomcatssh:v2 localhost.localdomain Running Running 11 seconds ago euyu700dikpqmgzq8hyoijvdq \_ swarmtest.2 tomcatssh:v1 worker2 Shutdown Shutdown 7 minutes ago efgfvp2wd0x655dy136qrt47y swarmtest.3 tomcatssh:v2 worker2 Running Running 7 minutes ago 1m7muogeuitfsllhcyu942ac1 \_ swarmtest.3 tomcatssh:v1 localhost.localdomain Shutdown Shutdown 32 seconds ago
過程當中,swarm先Shutdown了一臺節點上的老容器而且啓動新容器,若是新容器啓動成功後就再等10秒(建立service時指定的參數),而後開始操做下一臺。另外,若是操做一臺的過程當中發生錯誤致使新容器沒有正確運行起來,那麼更新任務會到此暫停,不會繼續往下。docker service update後面的--update-failure-action參數能夠指定是否要跳過錯誤。
■ 節點管理
以前全部的演示中,三個節點始終都保持着Active的可用性。Swarm管理器會自動根據算法將任務(啓停容器等)分配給Active的節點。
除了Active,其餘常見的可用性狀態還有Drain,處於Drain的節點不會被分配新任務,並且當前運行着的容器也都會被中止,swarm管理器則會在其餘節點上新建這些任務。
運行命令
docker node update --availability drain worker2
能夠手動將某個節點的可用性設置爲Drain,好比這裏將名爲worker2的節點設置爲drain了以後,能夠看到在docker service ps swarmtest中出現的新信息:
anrqum9q6zg0jw12ds5jnloyb swarmtest.3 tomcatssh:v2 localhost.localdomain Running Running 9 seconds ago efgfvp2wd0x655dy136qrt47y \_ swarmtest.3 tomcatssh:v2 worker2 Shutdown Shutdown 7 minutes ago
因爲worker2再也不接受任務並關停現有任務,因此swarmtest.3這個容器被轉移到了localhost(即manage節點所在)。docker node ls或者docker node inspect --pretty worker2就能夠看到起可用性的變動了。
若是使用docker node update再次將worker2的可用性設置爲active,那麼worker2節點就能夠再次獲取任務了(剛纔被轉移到localhost上的任務是不會有再轉回來的,因此worker2的任務只有在接下來的分配中得到)。總的來講,一個處於Active狀態的節點在這些狀況下可能收到新任務:當服務規模擴大時;滾動更新時;其餘節點被設置爲Drain而本節點須要擔當時;其餘節點上任務啓動失敗時。