【Docker】Docker三劍客實踐之部署叢集

不洗碗工作室發表於2017-11-14

作者:不洗碗工作室 - Marklux
出處:marklux.cn/blog/55
版權歸作者所有,轉載請註明出處

前言

DOCKER技術在推出後掀起了一陣容器化技術的熱潮,容器化使得服務的部署變得極其簡易,這為微服務和分散式計算提供了很大的便利。

為了把容器化技術的優點發揮到極致,docker公司先後推出了三大技術:docker-machine,docker-compose,docker-swarm,可以說是幾乎實現了容器化技術中所有可能需要的底層技術手段。

在使用go語言實現了判題引擎並打包好docker映象後,就需要進行分散式判題的編寫,這次就讓我們手動實踐,嘗試使用docker的三大殺器來部署一個多機器構成的判題服務叢集。

三劍客簡介

docker-machine

docker技術是基於Linux核心的cgroup技術實現的,那麼問題來了,在非Linux平臺上是否就不能使用docker技術了呢?答案是可以的,不過顯然需要藉助虛擬機器去模擬出Linux環境來。

docker-machine就是docker公司官方提出的,用於在各種平臺上快速建立具有docker服務的虛擬機器的技術,甚至可以通過指定driver來定製虛擬機器的實現原理(一般是virtualbox)。

docker-compose

docker映象在建立之後,往往需要自己手動pull來獲取映象,然後執行run命令來執行。當服務需要用到多種容器,容器之間又產生了各種依賴和連線的時候,部署一個服務的手動操作是令人感到十分厭煩的。

dcoker-compose技術,就是通過一個.yml配置檔案,將所有的容器的部署方法、檔案對映、容器連線等等一系列的配置寫在一個配置檔案裡,最後只需要執行docker-compose up命令就會像執行指令碼一樣的去一個個安裝容器並自動部署他們,極大的便利了複雜服務的部署。

docker-swarm

swarm是基於docker平臺實現的叢集技術,他可以通過幾條簡單的指令快速的建立一個docker叢集,接著在叢集的共享網路上部署應用,最終實現分散式的服務。

相比起zookeeper等叢集管理框架來說,swarm顯得十分輕量,作為一個工具,它把節點的加入、管理、發現等複雜的操作都濃縮為幾句簡單的命令,並且具有自動發現節點和排程的演算法,還支援自定製。雖然swarm技術現在還不是非常成熟,但其威力已經可見一般。

淺談docker服務架構和遠端API

在正式使用docker技術部署叢集應用時,我們應該先來了解一下docker工作的一些底層原理,和docker遠端呼叫的API,這樣才能大體瞭解叢集究竟是如何運作的。

daemon

之前的docker入門文章中講過,docker的基礎服務,比如容器的建立、檢視、停止、映象的管理,其實都是由docker的守護程式(daemon)來實現的。

每次執行的docker指令其實都是通過向daemon傳送請求來實現的。

daemon的運作(通訊模式)主要有兩種,一種是通過unix套接字(預設,但只能在本地訪問到,比較安全),一種是通過監聽tcp協議地址和埠來實現(這個可以實現在遠端呼叫到docker服務)。

遠端API

除了通過遠端tcp協議訪問遠端主機上的docker服務外,docker還提供了一套基於HTTP的API,可以使用curl來實現操作遠端主機上的docker服務,這為開發基於WEB的docker服務提供了便利。

遠端docker使用示例

最終實現叢集的時候實際是使用docker的遠端呼叫來將不同的docker主機連線成一個整體的(通過tcp協議)。

我們不妨先來手動模擬嘗試一下docker服務的遠端呼叫吧。

首先需要在提供服務的主機上將docker的執行方式改為tcp,具體方法為修改/etc/default/docker中的DOCKER_OPTS為如下內容

-H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock複製程式碼

-H 後的引數是自己定義的要繫結的tcp地址和埠,成功繫結後重啟docker服務就可以在該埠訪問到docker的daemon服務。

不幸的是:

  • 在OSX平臺上,並沒有找到docker的daemon配置檔案
  • 在OSX平臺上,使用docker -H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock -d這樣的命令來嘗試以tcp的方式啟動docker daemon也是失敗的,並沒有任何作用
  • 目前推測除了Linux平臺上,其他平臺上的配置方法都不太一樣,但是在網路上暫時沒有找到解決方案,所以後面的操作我只能通過在本地建立多個docker-machine的方式來模擬實現遠端呼叫。

假設我們在192.168.1.123這臺主機上開啟了docker服務,監聽了2375埠,那麼我們就可以在同一網段的其他主機上(比如192.168.1.233)通過docker -H tcp://192.168.1.123:2345 <command>的方式呼叫到該主機上的docker服務。

比如

docker -H tcp://192.168.1.123:2345 ps
docker -H tcp://192.168.1.123:2345 images
docker -H tcp://192.168.1.123:2345 run ...複製程式碼

最終swarm構建叢集的時候,就是通過這樣的遠端服務呼叫來排程各個節點的。

叢集和分散式運算

在正式開始實踐叢集之前,我們有必要了解究竟什麼是叢集,什麼是分散式計算。

首先,這兩者有一個共同點,就是他們都是使用了多個服務節點的,通俗的說,就是要用到多臺伺服器協同工作(不一定是實體,也可能是虛擬機器)。

而兩者的區別在於:

  • 叢集是多臺機器執行同一個業務,每次根據排程演算法尋找最合適的節點來執行該業務
  • 分散式計算是將一個業務拆分成多個獨立的部分,由多臺機器共同協作完成

叢集的優點在於,當業務的需要的資源比較大時,可以避免由一個伺服器去獨自承擔壓力,而且即便有一個節點當機了,業務仍然可以繼續正常執行。這有點類似於負載均衡。

分散式的優點則是在計算上,可以協同多臺機器發揮計算的威力,進行需要超高效能的運算。

構建叢集

說現在我們正式開始構建叢集。

使用docker-machine建立節點

由於實體機器的缺乏以及在osx上無法正常開啟tcp的docker服務,我們基於docker-machine來建立多個虛擬機器,作為叢集中的節點。

執行下面的命令就可以建立一個新的docker-machine虛擬機器manager1

docker-machine create --driver virtualbox manager1複製程式碼

在建立了虛擬機器後,可以使用docker-machine env manager1來檢視虛擬機器manager1的相關資訊,包括IP地址等

現在我們繼續執行命令建立worker1worker2兩個節點,使用docker-machine ls命令可以檢視到所有正在工作的虛擬機器:

docker-machine ls
NAME       ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
manager1   -        virtualbox   Running   tcp://192.168.99.100:2376           v17.06.1-ce   
worker1    -        virtualbox   Running   tcp://192.168.99.101:2376           v17.06.1-ce   
worker2    -        virtualbox   Running   tcp://192.168.99.102:2376           v17.06.1-ce複製程式碼

建立docker machine後,可以通過docker-machine ssh manager1 <command>的方式來訪問虛擬機器,執行指令。

建立swarm叢集

初始化一個swarm叢集的命令為:

docker swarm init --listen-addr <MANAGER-IP>:<PORT> --advertise-addr <IP>複製程式碼

--listen-addr引數是管理者節點的docker服務所在的IP:PORT,也就是說,可以通過這個組合訪問到該節點的docker服務。

--advertise-addr是廣播地址,也就是其他節點加入該swarm叢集時,需要訪問的IP

現在我們在manager1節點裡建立swarm網路,執行

docker-machine ssh manager1 docker swarm init --listen-addr 192.168.99.100:2377 --advertise-addr 192.168.99.100複製程式碼

返回響應:

Swarm initialized: current node (23lkbq7uovqsg550qfzup59t6) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-c036gwrakjejql06klrfc585r \
    192.168.99.100:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.複製程式碼

這樣便建立了一個swarm叢集,並且manager1節點目前是以管理者的身份加入在節點中的。

現在我們把worker1worker2兩個節點加入到swarm叢集中去,分別在兩個節點的虛擬機器中執行docker swarm join --token ..即可:

docker-machine ssh worker1 docker swarm join --token \
    SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-c036gwrakjejql06klrfc585r \
    192.168.99.100:2377
This node joined a swarm as a worker.複製程式碼
docker-machine ssh worker2 docker swarm join --token \
    SWMTKN-1-3z5rzoey0u6onkvvm58f7vgkser5d7z8sfshlu7s4oz2gztlvj-c036gwrakjejql06klrfc585r \
    192.168.99.100:2377
This node joined a swarm as a worker.複製程式碼

在任何一個節點上執行docker node ls都可以檢視到當前整個叢集中的所有節點:

docker-machine ssh manager1 docker node ls
NAME     ACTIVE    DRIVER       STATE     URL                         SWARM   DOCKER    ERRORS
manager1   -       virtualbox   Running   tcp://192.168.99.100:2376           v1.12.3   
worker1    -       virtualbox   Running   tcp://192.168.99.101:2376           v1.12.3   
worker2    -       virtualbox   Running   tcp://192.168.99.102:2376           v1.12.3複製程式碼

建立跨主機網路

叢集建立完畢之後我們要做的就是在叢集上部署我們的服務。但是首先應該讓所有的節點處在一個共享的網路中,這樣當我們把服務部署在這個共享網路中,就相當於部署在整個叢集中了。

使用docker network ls可以檢視到當前主機所參與的所有網路:

docker-machine ssh manager1 docker network ls
NETWORK ID         NAME            DRIVER          SCOPE
764ff31881e5        bridge          bridge          local                  
fbd9a977aa03        host            host            local               
6p6xlousvsy2        ingress         overlay         swarm            
e81af24d643d        none            null            local複製程式碼

其中SCOPE為swarm,DRIVER為overlay的即為叢集節點中的共享網路。叢集建立後會有一個預設的ingress共享網路,現在我們來再建立一個:

docker-machine ssh manager1 docker network create --driver overlay swarm_test複製程式碼

在跨主機網路上部署服務

在叢集上部署應用,就是在共享網路上部署服務(service)

但首先要保證每個節點上都已經有所需的映象和環境了,這點便可以通過將同一份docker-compose配置檔案共享到每個主機上,使用docker-compose在每個節點上下載映象和搭建環境的工作。

由於judge_server的服務架構很簡單,就一個映象,所以我在這裡直接在每臺主機上把它pull下來就好了:

docker-machine ssh manager1 docker pull registry.cn-qingdao.aliyuncs.com/marklux/judge_server:1.0
docker-machine ssh worker1 docker pull registry.cn-qingdao.aliyuncs.com/marklux/judge_server:1.0
docker-machine ssh worker2 docker pull registry.cn-qingdao.aliyuncs.com/marklux/judge_server:1.0複製程式碼

接下來便是重頭戲,我們使用manager1節點,在共享網路上啟動我們的服務

docker service create --replicas 3 --name judge_swarm -p 8090:8090 --network=swarm_test registry.cn-qingdao.aliyuncs.com/marklux/judge_server:1.0複製程式碼

這個命令看起來是不是很像docker run?沒錯,swarm最終的目的就是把操作叢集變得像操作單一的docker服務端一樣簡單!

--replicas 用於指定服務需要的節點數量,也就是叢集的規模,這個值是彈性的,你可以在後續動態的更改它。

當服務中某個節點掛掉時,swarm將會搜尋叢集中剩餘的可用節點,頂替上去。也就是說,swarm會動態的排程,總是保持服務是由3個節點執行著的。

-p 用於暴露埠到宿主機,這樣我們就能訪問到了。

--network用於指定部署service的網路是哪一個

現在在manager1節點中使用docker service ls來檢視叢集中的服務:

docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                                       PORTS
kofcno637cmq        judge_swarm         replicated          3/3                 registry.cn-qingdao.aliyuncs.com/marklux/judge_server:1.0   *:8090->8090/tcp複製程式碼

現在我們嘗試在本地訪問192.168.99.100:8090/ping,就可以得到響應了,事實上,現在無論將ip換為worker1或者worker2的,響應的結果都是一樣,因為此時所有節點已經處在一個共同的叢集網路下了

經過大量的訪問測試,可以看到hostname是在變化著的,這說明每次請求,都由swarm動態的排程,選擇了不同的節點來進行處理。

遺留問題

至此叢集的部署已經完成,但是我們還遺留了幾個問題沒有解決:

  • 叢集節點的動態新增刪除不是很方便,這導致在web端管理判題服務機有一定的難度,當然可以通過docker的REMOTE API來實現,不過複雜度比較高
  • 叢集節點間的檔案同步不太好實現,可能需要自己寫指令碼同步或是使用rsync之類的服務來實現
  • swarm非常適合快速構建大量叢集來實現業務的處理,不過對於只有幾臺機器的情況而言,有些"殺雞用牛刀"的感覺

相關文章