标题: 部署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.