基於go的微服務搭建(五) - 部署docker swarm

標題: 部署docker swarmjava

這部分,咱們啓動咱們的accountservice,運行在本地的docker swarm集羣中.同時討論幾個容器部署的重要概念
這篇博客主要講一下幾點:node

  • docker swarm和容器部署
  • 用docker做爲容器運行accountservice
  • 創建一個本地的docker swarm集羣
  • 將accountservice做爲swarm服務部署
  • 基測和結果

其實寫完這一章,我發現這一章和go沒有關係.但但願你喜歡.linux

什麼是容器部署


在實踐開始以前,一個容器部署的簡單介紹:
當一個應用愈來愈複雜,而且開始有更高的負載,將會有成百個服務在不少硬件上運行.容器部署讓咱們在一個節點上管理咱們的硬件
一篇文章上總結的:git

抽象主機的基礎結構,部署工具容許用戶在一個部署目標上控制整個集羣.

這總結的很好.用kubernetes或者docker swarm這種容器部署工具來部署咱們的各個服務在不一樣的節點上.對於docker來講,swarm模式管理docker engine的集羣.kubernetes用一種稍微不一樣的抽象方法,可是總體概念上是一致的.
容器部署不只控制咱們服務的生命週期,也提供其餘服務,例如:服務發現,負載均衡,內部地址和日誌.github

docker swarm核心概念


在docker swarm中,有三個核心概念:spring

  • 節點: 一個節點就是一個docker engine的實例.理論上講,他是一個擁有cpu資源,內存和網絡接口的主機.一個節點能夠是一個manager節點或者worker節點.
  • 服務: 服務就是worker節點上運行的指令.一個服務能夠是複製的或者全局的.一個服務能夠抽象的當作是任意數量的容器組成的邏輯上的服務.這個服務能夠用它的名字來調用,而不須要知道它內部的網絡結構.
  • 任務: 一個任務能夠是docker容器,docker文件定義任務爲:擁有並運行docker容器和指令.manager節點分發任務給worker節點的服務.

下圖展現一個簡單的微服務框架.兩個服務accountservice和quotes-service抽象爲兩個節點,運行在五個容器的實例中.docker

![圖片上傳中...]json

代碼


這部分沒有改go方面的代碼.
clipboard.png
cker.你能夠獲得這一章完整的代碼api

git checkout P5

容器化咱們的accountservice


docker安裝


你須要安裝docker.我用的是docker toolbox 和vitualbox.可是你能夠直接用docker.瀏覽器

建立dockerfile


一個dockerfile能夠當作是你想建立什麼樣的docker鏡像的配方.讓咱們在accountservice文件夾中建立文件Dockerfile:

FROM iron/base

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

解釋:

  • FROM-定義咱們的基礎鏡像.咱們會在這個鏡像上開始.iron/base是一個能夠運行go程序的小巧的鏡像
  • EXPOSE-定義一個端口,做爲外部請求的端口
  • ADD-增長一個文件accountservice-linux-amd64到root(/)目錄下
  • ENTRYPOINT-定義啓動哪個程序,當docker開啓這個鏡像容器

不一樣操做系統下的編譯


咱們的文件名字包含linux-amd64.咱們能夠叫他任何名字,可是我喜歡把操做系統和cpu型號放進執行文件名字中.我用的是mac OSX 系統.因此我若是直接編譯go的執行文件,用go build的話,這產生一個執行文件在同一個文件夾中.然而這個執行文件不能再docker上運行,由於docker容器的環境是linux.所以,咱們須要設定一些環境參數,這樣咱們的編譯器才知道咱們要給其餘的系統或者cpu環境編譯文件.
在goblog/accountservice文件夾下面運行:

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

-o表示產生二進制執行文件.我常常用腳本文件自動作這些東西(後面會有)
由於OS X和linux容器都在AMD64 cpu架構上,咱們不須要設置GOARCH參數.可是你若是用32位系統,或者ARM處理器,你要設置GOARCH參數

建立docker鏡像


如今咱們建立第一個docker鏡像,包含咱們的執行文件.去accountservice的上層文件夾,就是$GOPATH/src/github.com/callistaenterprise/goblog.
對於docker鏡像,咱們常常用一個前綴來標註名字.我常常用個人github名字做爲前綴,例如eriklupander/myservicename.這裏,我用someprefix做爲前綴.執行下面的命令來建立Docker鏡像:

> docker build -t someprefix/accountservice accountservice/

Sending build context to Docker daemon 13.17 MB
Step 1/4 : FROM iron/base
 ---> b65946736b2c
Step 2/4 : EXPOSE 6767
 ---> Using cache
 ---> f1147fd9abcf
Step 3/4 : ADD accountservice-linux-amd64 /
 ---> 0841289965c6
Removing intermediate container db3176c5e1e1
Step 4/4 : ENTRYPOINT ./accountservice-linux-amd64
 ---> Running in f99a911fd551
 ---> e5700191acf2
Removing intermediate container f99a911fd551
Successfully built e5700191acf2

好了,咱們有啦一個someprefix/accountservice鏡像.若是咱們要在多節點下運行或者分享鏡像,咱們能夠用docker push來使咱們的鏡像被別的主機pull.
咱們如今運行鏡像:

> docker run --rm someprefix/accountservice
Starting accountservice
Seeded 100 fake accounts...
2017/02/05 11:52:01 Starting HTTP service at 6767

然而,咱們的容器不是在你的主機系統下運行,他運行在本身的網絡中,咱們不能直接從咱們的主機來請求他.有辦法來解決這個問題,但如今咱們放一放,咱們繼續組建咱們的docker swarm和部署accountservice.

建立單節點Docker swarm集羣


一個docker swarm集羣包括至少一個swarm manager和零到多個swarm worker.個人例子會包含一個swarm manager.這節事後,你會有一個swarm manager運行.
你能夠參考別的文章來看如何運行swarm.下面這條命令初始化docker主機爲swarm-manager-1做爲一個swarm節點,同時讓swarm-manager-1節點地址和主機同樣

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

若是咱們要建立多節點的swarm集羣,咱們要把這條命令產生的join-token記錄下來,這樣咱們能夠加入其餘的節點到這個swarm中.

建立網絡


一個docker網絡的用處是,當咱們想請求同一個swarm集羣上的其餘的容器,並不須要知道真實的集羣分佈.

docker network create --driver overlay my_network

my_network是咱們的網絡名稱

部署accountservice


如今咱們要部署咱們的accountservice進Docker swarm服務中.這個docker服務命令有不少參數設置,但不要怕.這裏咱們來部署accountservice

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

快速看一下這些參數

  • -name:給服務的名字.這也是集羣中其餘服務請求咱們的名字.因此另外一個服務來請求accountservice的話,這個服務只須要Get請求http://accountservice:6767/accounts/10000
  • -replicas: 咱們服務的實例數量.若是咱們有多節點的docker swarm集羣,swarm engine會自動分發實例到不一樣的節點上.
  • -network: 這裏咱們告訴咱們的服務用剛剛咱們建立的網絡my_network
  • -p: 映射[內部端口]:[外部端口].這裏咱們用6767:6767.若是咱們用6767:80,從外部請求要用80端口.注意這部分使咱們的服務能夠被外界請求.大多數狀況,你不該該讓你的服務暴露給外界.你應該用一個EDGE-server(例如反向代理),包括路由機制和安全檢查,因此外界不能隨意請求你的服務
  • someprefix/accountservice: 指明咱們想讓容器運行哪個鏡像.

讓咱們看看咱們的服務是否運行了

> docker service ls

太好了,咱們應該能夠curl或者用瀏覽器請求咱們的api.惟一要知道的就是咱們swarm的ip地址.即便咱們只運行一個服務實例,咱們的網絡和swarm也會須要咱們的服務外部端口,這意味着兩個服務不能用同一個外部端口.他們能夠有一樣的內部端口,但對於外部來講,swarm是一個總體.

> echo $ManagerIP
192.168.99.100

若是你換了terminal,你能夠從新導出:

> export ManagerIP=`docker-machine ip swarm-manager-0`

curl請求:

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

部署可視化


用docker的命令來查看swarm的狀態不容易看,一個圖形化的方法比較好.例如manomarks docker swarm visualizer能夠被部署爲一個Docker swarm的服務.這能夠給咱們提供咱們集羣分佈的圖形,同事確保咱們在集羣中外部暴露的服務可不能夠請求到.
初始化這個可視器在容器鏡像中

docker service create \
 --name=viz \
 --publish=8080:8000/tcp \
 --constraint=node.role==manager \
 --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
 manomarks/visualizer

這將在8000端口產生一個服務.讓咱們用瀏覽器瀏覽http://$ManagerIP:8000

clipboard.png

額外內容


我也作了一個swarm的可視化界面叫作dvizz,展現docker 遠程api和D3.js force圖.你能夠安裝她

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

瀏覽 http://$ManagerIP:6969

clipboard.png

加入quote-service

只有一個服務的微服務不能看出微服務的全貌.讓咱們部署一個基於spring boot的quotes-service.我把這個容器鏡像放在docker hub中的eriklupander/quotes-service.

> 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

注意,咱們沒有暴露一個外界端口給這個服務,因此咱們只能在集羣內部的端口8080內請求.咱們會集成這個服務在第七部分同時看一下服務探索和負載均衡.
若是你加入了dvizz,你應該能看到quotes-service和accountservice

copyall.sh腳本

咱們來作一個腳本幫助咱們編譯和部署.在root/goblog文件夾中,建立一個腳本文件叫作copyall.sh

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

cd accountservice; go get; go build -o accountservice-linux-amd64;echo build `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

這段腳本編譯執行文件,從新編譯docker鏡像,部署到docker swarm服務上.
我喜歡腳本的簡化,雖然有時我用gradle plugin.

性能


如今開始,全部的基測都在docker swarm上進行.這意味以前的結果不能用來和以後的比較
cpu使用率和內存使用會用 docker stats來收集.咱們也會用gatling測試.
若是你喜歡壓力測試,第二節的仍然能夠用,但須要改變-baseUrl參數

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

內存使用率

> docker stats $(docker ps | awk '{if(NR>1) print $NF}')

CONTAINER                                    CPU %               MEM USAGE / LIMIT    
accountservice.1.k8vyt3dulvng9l6y4mj14ncw9   0.00%               5.621 MiB / 1.955 GiB
quotes-service.1.h07fde0ejxru4pqwwgms9qt00   0.06%               293.9 MiB / 1.955 GiB

啓動後,包含linux和咱們accountservice的容器用5.6mb的內存,java開發的quotes-service用了300mb.雖然這能夠經過調整jvm來下降.

cpu和內存使用壓力測試


CONTAINER                                    CPU %               MEM USAGE / LIMIT   
accountservice.1.k8vyt3dulvng9l6y4mj14ncw9   25.50%              35.15 MiB / 1.955 GiBB

在1K req/s下,虛擬機中運行的swarm和在第二三節中的OS x系統相比,內存稍微升高,cpu大略相同.

性能


![圖片上傳中...]


延遲上升到4ms.這和直接運行有所升高,緣由有幾點.我認爲gatling測試經過橋接的網絡和swarm上的路由會有一些延遲.可是4ms的延遲也不錯.畢竟咱們從boltDB讀數據,序列化到json並輸出到HTTP.

總結


咱們學習如何啓動docker swarm和部署accountservice到swarm上.下一節,咱們會給咱們的微服務加入healthcheck.

相關文章
相關標籤/搜索