標題: 部署docker swarmjava
這部分,咱們啓動咱們的accountservice,運行在本地的docker swarm集羣中.同時討論幾個容器部署的重要概念
這篇博客主要講一下幾點:node
其實寫完這一章,我發現這一章和go沒有關係.但但願你喜歡.linux
在實踐開始以前,一個容器部署的簡單介紹:
當一個應用愈來愈複雜,而且開始有更高的負載,將會有成百個服務在不少硬件上運行.容器部署讓咱們在一個節點上管理咱們的硬件
一篇文章上總結的:git
抽象主機的基礎結構,部署工具容許用戶在一個部署目標上控制整個集羣.
這總結的很好.用kubernetes或者docker swarm這種容器部署工具來部署咱們的各個服務在不一樣的節點上.對於docker來講,swarm模式管理docker engine的集羣.kubernetes用一種稍微不一樣的抽象方法,可是總體概念上是一致的.
容器部署不只控制咱們服務的生命週期,也提供其餘服務,例如:服務發現,負載均衡,內部地址和日誌.github
在docker swarm中,有三個核心概念:spring
下圖展現一個簡單的微服務框架.兩個服務accountservice和quotes-service抽象爲兩個節點,運行在五個容器的實例中.docker
![圖片上傳中...]json
這部分沒有改go方面的代碼.
cker.你能夠獲得這一章完整的代碼api
git checkout P5
你須要安裝docker.我用的是docker toolbox 和vitualbox.可是你能夠直接用docker.瀏覽器
一個dockerfile能夠當作是你想建立什麼樣的docker鏡像的配方.讓咱們在accountservice文件夾中建立文件Dockerfile:
FROM iron/base EXPOSE 6767 ADD accountservice-linux-amd64 / ENTRYPOINT ["./accountservice-linux-amd64"]
解釋:
咱們的文件名字包含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鏡像,包含咱們的執行文件.去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集羣包括至少一個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進Docker swarm服務中.這個docker服務命令有不少參數設置,但不要怕.這裏咱們來部署accountservice
docker service create --name=accountservice --replicas=1 --network=my_network -p=6767:6767 someprefix/accountservice ntg3zsgb3f7ah4l90sfh43kud
快速看一下這些參數
讓咱們看看咱們的服務是否運行了
> 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
我也作了一個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
只有一個服務的微服務不能看出微服務的全貌.讓咱們部署一個基於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
咱們來作一個腳本幫助咱們編譯和部署.在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來下降.
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.