Go微服務 - 第五部分 - 在Docker Swarm中部署

第五部分: Go微服務 - 在Docker Swarm中部署

這一部分,咱們讓accountservice服務在本地部署的Docker Swarm集羣上運行,並探討容器編排的核心概念。java

本文處理下面的內容:node

  • Docker Swarm和容器編排。
  • 使用Docker將accountservice服務容器化。
  • 配置本地Docker Swarm集羣。
  • 以Swarm服務的方式部署accountservice服務。
  • 運行基準測試並蒐集度量值。

其實這一部分和Go語言沒有什麼直接關係,具體來講它是關於Docker以及Docker Swarm的。一樣但願你能喜歡這篇文章。linux

什麼是Docker編排(CONTAINER ORCHESTRATOR)

在開始實操以前,快速介紹一下容器編排的概念可能會有用。git

隨着應用程序變得愈來愈複雜,而且須要處理更高的負載,咱們不得不處理這樣的一個事實,咱們成千上萬的服務實例遍及大量物理硬件上。容器編排讓咱們把全部硬件看成單個邏輯實體看待。github

容器編排這篇文章總結以下:golang

容器編排: 經過抽象主機基礎設施,編排工具容許用戶將整個集羣看成單個部署目標看待。
abstracting the host infrastructure, orchestration tools allow users to treat the entire cluster as a single deployment target.

我本身不能很好的總結它 - 使用容器編排器,例如Kubernetes或Docker Swarm,能夠容許咱們在一個或多個可用的基礎設施上將咱們的軟件組件部署爲服務。 在Docker的狀況中 - Swarm模式是關於管理叫作swarm的Docker引擎集羣的。 Kubernetes使用了一種稍微不一樣的術語和關鍵抽象層次結構, 可是整體上來講概念大體相同。docker

容器編排器不只爲咱們處理服務的生命週期,還爲服務發現、負載均衡、內部尋址和日誌提供了機制。shell

Docker Swarm中的核心概念

在Docker Swarm中有三個概念須要介紹:windows

  • 節點(Node): 節點是Swarm中參與的Docker引擎實例。從技術上講,能夠將其視爲擁有本身CPU資源、內存、網絡接口的主機。 節點能夠是管理節點,也能夠是worker節點。
  • 服務(Service): 服務是執行在worker節點的東西,由容器映像和指示容器執行的命令定義的。服務能夠是複製的,也能夠是全局的。服務能夠視爲一種抽象,用於讓任意數量的容器造成一個能夠經過它的名字, 而無需知道環境內部的網絡拓撲狀況的狀況下在集羣內或集羣外訪問的邏輯服務。
  • 任務(Task e.g. container): 對全部實用手段而言,能夠認爲任務就是Docker容器。 Docker文檔定義任務就是承載Docker容器和在容器內運行的命令的一些東西。 管理器節點將任務賦予給(worker)節點,這些任務是在特定服務中指定的容器鏡像。

下圖展現了微服務景觀的一種可能(簡化版)部署,其中兩個節點運行了五個容器實例,抽象成兩個服務accountservice和quotes-service。瀏覽器

clipboard.png

源代碼

這一部分沒有對Go代碼進行任何修改,只是添加了一些新的文件,用於將服務運行在Docker上。代碼地址: https://github.com/callistaen...

將accountservice容器化

Docker安裝

Docker安裝,參考官網安裝指導

建立Dockerfile

Dockerfile是Docker用於構建docker容器映像的, 包含全部你但願包含的東西。讓咱們開始在/accountservice目錄下面建立一個Dockerfile吧。

FROM iron/base

EXPOSE 6767
ADD accountservice-linux-amd64 /
ENTRYPOINT ["./accountservice-linux-amd64"]

快速解釋:

  • FROM: 定義咱們將要開始構建咱們本身映像來源的基本映像。 iron/base是很是適合運行Go應用程序的映像。
  • EXPOSE: 定義咱們但願在Docker網絡內部暴露的能夠到達的端口號。
  • ADD: 添加一個文件accountservice-linux-amd64到容器文件系統的根目錄/。
  • ENTRYPOINT: 定義當Docker啓動這個映像容器時要運行的可執行文件。

爲另一種CPU架構/OS進行構建

如你所見,咱們在文件名後面添加了linux-amd64。固然咱們能夠隨意使用名字來指定Go語言可執行文件,可是我喜歡這樣的約定,將OS和目標CPU平臺放到可執行文件名中。我寫這個博客的時候,使用的是mac OS X。所以若是我只是直接在accountservice目錄下面運行go build來構建的話,會在同一個目錄下面產生一個accountservice可執行文件。可是這樣的文件在Docker容器中,底層OS是基於Linux的。所以,咱們在構建以前,須要設置一些環境變量, 這樣編譯器和連接器知道咱們在爲另外的OS、CPU架構進行構建, 咱們這裏的例子是linux。

export GOOS=linux
go build -o accountservice-linux-amd64
export GOOS=darwin

上面使用-o標誌產生一個可執行二進制文件。 我一般寫一個小腳原本幫我執行一些可能須要重複執行的事情。

既然OS X和linux-based的容器都是運行在AMD64 CPU架構,由於咱們無需設置(並重置)GOARCH環境變量。 可是若是你爲32位OS構建或ARM處理器構建,就須要在構建以前恰當的設置GOARCH。

建立一個Docker映像

那麼如今能夠構建咱們第一個Docker映像來包含咱們的可執行文件。進入accountservice父級目錄, 應該是$GOPATH/src/github.com/callistaenterprise/goblog。

當構建Docker容器映像時,咱們一般使用[prefix]/[name]的命名約定來對其名字打標籤。我通常使用咱們的github用戶名作前綴, 例如eriklupander/myservicename。對於這個博客系列,咱們使用someprefix前綴。 在項目根目錄(eg: ./goblog)下面執行下面的命令來基於上面的Dockerfile來構建一個Docker映像。

  • 在goblog/accountservice目錄構建accountservice-linux-amd64可執行文件。
  • 構建Docker映像。
// 在goblog目錄執行構建Docker鏡像
docker build -t someprefix/accountservice accountservice/
Sending build context to Docker daemon  14.34kB
Step 1/4 : FROM iron/base
latest: Pulling from iron/base
ff3a5c916c92: Pull complete
43f18fea29ad: Pull complete
Digest: sha256:1489e9c1536af14937ac7f975b8529cbe335672b7b87dae36c6b385d3e4020c0
Status: Downloaded newer image for iron/base:latest
 ---> b438fe7f76e9
Step 2/4 : EXPOSE 6767
 ---> Running in 4246258b66c1
Removing intermediate container 4246258b66c1
 ---> 5113056caf24
Step 3/4 : ADD accountservice-linux-amd64 /
ADD failed: stat /var/lib/docker/tmp/docker-builder076553391/accountservice-linux-amd64: no such file or directory
AppledeMacBook-Pro-2:goblog apple$ docker build -t someprefix/accountservice accountservice/
Sending build context to Docker daemon  7.457MB
Step 1/4 : FROM iron/base
 ---> b438fe7f76e9
Step 2/4 : EXPOSE 6767
 ---> Using cache
 ---> 5113056caf24
Step 3/4 : ADD accountservice-linux-amd64 /
 ---> 7a21b55920e3
Step 4/4 : ENTRYPOINT ["./accountservice-linux-amd64"]
 ---> Running in 5b7115e2f89d
Removing intermediate container 5b7115e2f89d
 ---> 3e23a4268533
Successfully built 3e23a4268533
Successfully tagged someprefix/accountservice:latest

很好,咱們如今本地docker鏡像倉庫包含了名爲someprefix/accountservice的映像。 若是咱們想要運行多個節點或者想要共享咱們的鏡像, 咱們可使用docker push來將鏡像對其餘咱們當前Docker引擎提供的host以外的host拉取後可用。

而後咱們能夠直接經過命令行運行這個映像。

docker run --rm someprefix/accountservice
Starting accountservice
Seeded 100 fake accounts...
2018/05/16 02:57:37 Starting HTTP service at 6767

然而請注意,容器再也不是運行在你主機OS的localhost了。它如今位於它本身的網絡上下文,而且咱們不能直接從咱們的實際主機操做系統訪問。 固然有辦法修復,可是咱們先不深刻下去,咱們先對Docker Swarm進行局部設置,並部署accountservice。

咱們先使用Ctrl + C終止這個運行的鏡像。

配置單節點Docker Swarm集羣

本博客的一個目標就是咱們想讓咱們的微服務運行在容器編排上。 對於咱們不少人來講,通常意味着Kubernetes或Docker Swarm。 固然也有其餘編排器, 例如Apache Mesos和Apcera, 可是本文明確聚焦的是Docker 1.13的Docker Swarm上的。

當在你的開發計算機上配置單節點Docker Swarm集羣的時所需作的任務可能依賴於Docker自身怎麼安裝有關。 建議遵守Swarm Tutorial, 或者你可使用個人方式, 使用Docker Toolbox, Oracle Virtualbox和docker-machine, 是基於我同事Magnus lab-repo的關於服務發現的文章。

安裝VirtualBox

VirtualBox是一款開源的虛擬機軟件。若是使用Windows或OS X系統安裝Docker Swarm, 須要安裝這個軟件。

下載地址: http://download.virtualbox.or...

安裝Boot2Docker

boot2docker是一個專爲Docker而設計的輕量級Linux髮型包,解決Windows或者OS X用戶不能安裝Docker的問題。 Boot2Docker徹底運行於內存中,24M大小,啓動僅5-6秒。

下載地址: https://github.com/boot2docke...

建立Swarm管理器

Docker Swarm集羣至少包含一個Swarm管理器和零到多個Swarm worker。 這裏爲了簡單起見,咱們只使用一個Swarm管理器 - 這裏最少一個。在這節以後,重要的是你須要讓Swarm Manager啓動並運行起來。

咱們這裏的例子,使用docker-machine並製做一個虛擬linux機器運行在咱們的Swarm管理器的VirtualBox。 這裏咱們使用"swarm-manager-1"來標示這個管理器。 你也能夠參看官方文檔看如何建立Swarm。

咱們使用下面的命令來初始化docker-machine主機,並標示其爲swarm-manager-1做爲swarm-manager-1節點相同的swarm節點的ip地址。

docker $(docker-machine config swarm-manager-1) swarm init --advertise-addr $(docker-machine ip swarm-manager-1)

若是咱們須要建立多節點的Swarm集羣,咱們將確保存儲上面命令產生的鏈接token, 稍後若是咱們須要添加額外節點到swarm中。

建立一個覆蓋網絡(CREATE AN OVERLAY NETWORK)

Docker的覆蓋網絡是一種當咱們給Swarm添加相似"accountservice"到上面的時候使用的一種機制,這樣它能訪問在同一個Swarm集羣中的其餘容器,而無需知道實際的集羣拓撲結構。
使用下面的命令建立一個網絡:

docker network create --driver overlay my_network

這裏咱們給網絡起名爲my_network。

部署AccountService服務

幾乎都已就緒,如今讓咱們開始部署咱們本身的"accountservice"來做爲一個Swarm服務吧。docker service create命令接收不少參數,但的確也不瘋狂。 下面是咱們發佈"accountservice"的命令:

docker service create --name=accountservice --replicas=1 --network=my_network -p=6767:6767 someprefix/accountservice

下面是參數的快速解釋:

  • name: 爲咱們的服務賦予一個邏輯名稱。 這個名字也是集羣中其餘服務用於定址該服務所使用的名字。 所以另一個服務想要調用accountservice, 那個服務只須要作一個GET請求: http://accountservice:6767/accounts/10001便可。
  • replicas: 咱們服務想要的實例數目。若是咱們Docker Swarm集羣是多節點的, swarm引擎將自動在這些節點之間進行分佈。
  • network: 這裏咱們告訴服務綁定咱們剛纔建立的覆蓋網絡名。
  • p: 映射, [內部端口號]:[外部端口號]。 這裏咱們使用6767:6767, 可是若是咱們使用6767:80,那麼咱們在外部調用的時候就要經過端口號80進行服務訪問。注意這是一種可讓咱們服務從集羣外部能夠到達的一種機制。一般來講,你無需對外暴露服務。而一般,咱們會使用邊界服務器(例如: 反向代理),這樣能夠有一些路由規則,而且能夠有安全配置,這樣外部消費者不能到達你的服務,除非你使用一種自願的方式。
  • someprefix/accountservice: 這個參數指定了咱們但願容器運行的映像的名字。在咱們這個例子中是咱們在建立容器的時候指定的標籤。 注意!若是咱們要運行多節點集羣,咱們須要將咱們的映像推送到Docker倉庫中,例如推送到公共(免費)的Docker Hub服務上。 固然咱們也能夠設置私有docker倉庫,或者付費來保持鏡像免費。

就是這樣了。運行下面的命令來看咱們的服務是否成功啓動了。

> docker service ls
ID            NAME               REPLICAS  IMAGE                      
ntg3zsgb3f7a  accountservice     1/1       someprefix/accountservice

很甜美。 咱們如今可使用curl或經過瀏覽器來查詢咱們的API。惟一須要知道的就是前面是Swarm的公網IP。即使咱們在不少節點的swarm中爲咱們的服務只運行了一個實例, 覆蓋網絡和Docker Swarm容許咱們請求任意的swarm主機基於端口號來訪問服務。也就是說,兩個服務在外部不能使用同一端口號暴露。 他們內部端口號能夠相同, 可是對外來講必須惟一。

不管如何,請記住咱們以前保存的環境變量ManagerIP的值。

> echo $ManagerIP
192.168.99.100

若是已經改變了終端會話,能夠從新導出它。

export ManageIP=`docker-machine ip swarm-manager-0`

下面curl請求API:

> curl $ManagerIP:6767/accounts/10000
{"id":"10000","name":"Person_0"}

很是不錯,成功了。

部署一個可視化工具

使用docker的命令行API來檢查Swarm的狀態是徹底可行的(docker service ls), 可是使用更加圖形化的呈現,看起來更有意思。 例如可視化的有Docker Swarm Visualizer, 咱們一樣能夠像部署剛纔accountservice服務同樣的方式部署這個可視化服務工具。 這樣咱們能夠有另一種方式來查看咱們的集羣拓撲結構。 也能夠用於確保集羣中咱們是否讓某個服務暴露到給定端口號。

咱們能夠從預烘培的容器鏡像來安裝visualizer, 就一行命令:

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

這樣咱們就能夠經過8000端口來訪問它。直接經過http://$ManagerIP:8000, 記住剛纔的ManagerIP的值。

使人沸騰的內容!

我也開發了一個小的Swarm可視化器,叫作dvizz, 使用的是Go語言、Docker Remote API和D3.js產生圖形。 一樣可使用下面的命令安裝這個服務:

docker service create \
   --constraint node.role==manager \
   --replicas 1 --name dvizz -p 6969:6969 \
   --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
   --network my_network \
   eriklupander/dvizz

直接訪問http://$ManagerIP:6969, 能夠看到相似的展現:

看起來有點潦草, 可是不要太認真,它仍是很是有趣的, 看看塗上蹦蹦跳跳、上下縮放服務器、隨意拖放每一個節點。

添加其餘服務,例如quotes-service

微服務領域如今只有一個服務(咱們廣泛存在的accountservice)。 下面咱們部署一個前面提到的Spring Boot類型的微服務"Quotes-service", 這個微服務我已經放在公共的Docker倉庫中,能夠直接部署它。

docker service create --name=quotes-service --replicas=1 --network=my_network eriklupander/quotes-service

若是使用docker ps來列舉運行的Docker容器,咱們可能會看到它已經啓動了(或正在啓動中)。

> docker ps
CONTAINER ID    IMAGE                       COMMAND                 CREATED         STATUS                           PORTS                                           NAMES
98867f3514a1    eriklupander/quotes-service "java -Djava.security"  12 seconds ago  Up 10 seconds (health: starting) 8080/tcp

注意這裏咱們沒有導出這個服務的端口映射,意味着它不能從集羣外部訪問,只有內部經過內部端口8080訪問。 咱們會在後面第七部分服務發現和負載均衡中來集成這個服務。

若是你已經在集羣中添加了dvizz服務,你會看到圖中會多出一個quotes-service。

copyall.sh腳本

要簡化事情,咱們能夠添加一個shell腳原本幫咱們作從新構建和從新部署的自動化工做。在goblog的根目錄下面,建立一個copyall.sh文件:

#!/bin/bash
export GOOS=linux
export CGO_ENABLED=0

cd accountservice;go get;go build -o accountservice-linux-amd64;echo built `pwd`;cd ..

export GOOS=darwin

docker build -t someprefix/accountservice accountservice/

docker service rm accountservice
docker service create --name=accountservice --replicas=1 --network=my_network -p=6767:6767 someprefix/accountservice

這個腳本設置了GOOS環境變量,這樣咱們能夠安全的爲Linux/AMD64架構構建靜態連接二進制文件, 而後運行一些docker命令來從新構建映像文件以及從新部署到Swarm服務裏邊。 能夠節約時間,而且少輸入不少字母。

Go語言項目的構建,我不在本文中深刻介紹。 我的認爲,我喜歡shell腳本的簡潔,雖然我本身也常用gradle插件,而且也知道一個好的ol的make也是至關流行。

佔用空間和性能

從如今起,全部的基準測試和蒐集CPU/內存度量將用於Docker Swarm中部署的服務。 這意味着以前的文章結果和如今開始以後的結果不可比。

CPU使用和內存使用將使用Docker stats蒐集,同時咱們會使用以前使用的Gatling測試。

若是你本身運行負載測試, 那麼在第二部分引入的要求依然適用。 請注意,須要修改baseUrl參數爲Swarm Manager節點的IP, 例如:

mvn gatling:execute -Dusers=1000 -Dduration=30 -DbaseUrl=http://$ManagerIP:6767

總結

到目前爲止,咱們已經學到如何在本地啓動Docker Swarm領域(只有一個節點), 以及如何打包和部署咱們的accountservice微服務做爲Docker Swarm的服務。

下一節,咱們會給咱們的微服務添加心跳檢查。

參考連接

相關文章
相關標籤/搜索