测试环境docker化—容器集群编排实践

本文来自网易云社区html

做者:孙婷婷node


背景mysql

在前文《测试环境docker化—基于ndp部署模式的docker基础镜像制做》中已经详述了docker镜像制做及模块部署的过程,按照上述作法已能够搭建测试环境。可是在实践过程当中发现存在不少问题:git

  1. 在一台云主机上搭建多个模块,容易出现资源不足的状况(咱们在实验过程当中有台云主机好几回宕机,常常要删掉不用的镜像容器);web

  2. 部分模块之间须要相互调用,为方便部署多套环境简化配置修改,部署时须要肯定容器的ip地址;redis

  3. 手动敲命令一个个构建容器,n个模块就要敲n个构建指令,构建容易出错;sql

基于上述缘由,同时参考组内大神倪子的实践《细说Mammut大数据系统测试环境Docker迁移之路》,咱们也尝试了引入容器集群编排,来进一步优化测试环境docker化的过程。docker


容器集群搭建安全

为解决一台测试环境云主机可能支撑不了一套环境的问题,咱们考虑使用多台云主机组成一个容器集群,将多个deploy容器负载均衡的部署到多台云主机上,来实现环境的稳定和资源的合理利用。bash

要实现多主机的容器部署和分配,须要引入集群调度工具。目前业界比较主流的调度管理工具备Docker Swarm、Google Kubernetes 和 Apache Mesos(基于Marathon框架),其中目前已占领上风的是Kubernetes,成为容器编排管理的最佳实践工具。可是参考倪子的文章和介绍,我最终决定继续选择Swarm来进行实践。在Swarm的学习调研过程当中,我发现区别于倪子实践使用的Docker Swarm,docker1.12版本已经进一步推出了内置的简单易用的Swarm mode集群。老的Docker Swarm使用独立的外部KV存储(好比Consul、etcd、zookeeper),搭建独立运行的Docker主机集群,使用KV存储配置进行服务发现。新版的Swarm mode则将docker swarm包含到docker引擎中,并内置了服务发现工具,使得集群搭建进一步简化为直接使用docker swarm命令初始化一台主机做为manager,其余机器加入该swarm成为worker便可。具体命令以下(咱们的测试环境共使用3台云主机):

#将一台主机指定为manager,该命令会返回惟一一个集群惟一token,且该节点会同时做为manager和worker运行sudo docker swarm init --listen-addr 10.165.148.87:2377 --advertise-addr 10.165.148.87#在另两台主机上运行上述命令返回的join命令,便可加入该swarm集群sudo docker swarm join \
    --token SWMTKN-1-0cytn4js5b8jn0vibtk935y7jptqxv63ttiqui1qhi2uo07emx-cr80z41yz9v2tsn8vyxgy6k2u \    10.165.148.87:2377

以上命令即完成集群搭建,可经过sudo docker node ls命令查看集群中的节点。此后用户即可以经过manager节点操做整个集群,把多台Docker主机当作一台主机来部署容器服务和管理。


跨主机通讯

docker官方文档介绍,当咱们在一台主机上初始化一个swarm或者将一台云主机加入到一个swarm中时,该主机上将会默认建立两种新的网络:

  • 一种是名称为ingress的overlay型网络。ingress主要负责swarm集群中服务之间的负载均衡和服务发布。若用户在新建swarm service时未指定自定义的overlay网络,它会自动加入ingress。

  • 另外一个中名称为docker_gwbridge的bridge型网络。它是一个用于链接overlay型网络(包括ingress)和独立docker主机的物理网络的虚拟网桥。

备注:理论上docker_gwbridge是自动建立的,可是不知道为何我在实践过程当中没有找到docker_gwbridge,最后本身从新建立了该网络。若想自定义建立和设置docker_gwbridge,那么必须在初始化或者加入swarm前建立,不然以后建立的容器端口将没法成功映射至主机端口。

当咱们发布服务时,能够建立一个私有网络,实现跨主机之间的容器通讯。在Docker1.9版本以后,Dokcer给你们带来了一种原生的跨主机容器网络解决方案,该方案基于VXLAN的覆盖网技术、依靠独立的外部KV存储(好比Consul、etcd、zookeeper)来经过注册于同一存储的配置来实现“服务发现”和“DNS”解析,从而实现私有网络的跨主机通讯;同时在Docker1.12版本以后,咱们只要经过Swarm mode搭建集群,然后建立overlay网络,直接用“原生态”的swarm来发现进行通讯。

#若须要自定义建立docker_gwbridge或加入swarm后未发现docker_gwbridge,能够经过退出swarm后自定义建立;注意若想手动建立,必需要在加入swarm集群以前sudo docker network create --subnet 192.168.18.0/24 --opt com.docker.network.bridge.name=docker_gwbridge --opt com.docker.network.bridge.enable_icc=false --opt com.docker.network.bridge.enable_ip_masquerade=true docker_gwbridge#建立私有overlay网络,用于跨主机容器通讯,-- opt 指定网络安全模式sudo docker network create --driver overlay --subnet 192.168.47.0/24 --opt encrypted overlay-net

私有网络建立完成后,只需在建立容器服务时指定自定义网络,容器变会在建立时自动加入该网络,实现容器间通讯。

好了,如今容器之间能够互相访问了。可是每次容器启动的时候overlay都会动态分配一个虚拟IP地址,这样容器之间互相调用的时候就会须要在每次容器启动后再去容器中修改IP地址,当配置文件较多时修改起来会更加麻烦。熟悉docker engine的人必定知道link这个功能,Swarm mode则提供了一个相似的service discovery功能,它会将容器的虚拟IP映射到swarm的内置dns中,使用服务名称service name来做为域名。那么访问容器的IP则只须要访问服务名称,使得容器间通讯更加方便。


compose部署

到此其实测试环境docker化的基本工做已经完成了,可是结合前文镜像制做的内容,咱们的测试环境部署须要至少1个compile容器+n个deploy容器,deploy容器中也可能有多个web服务,各个容器须要暴露port,添加各自的entry.sh,如果经过docker service create命令一个个建立,一不当心就会配置错误致使容器没法启动;配置多套环境的可复制性也会差不少。

一个简单的办法是使用compose进行容器编排,将各命令简化为只须要编写compose的yaml文件便可。Docker1.13版本以后增长了compose v3,在Swarm的基础上引入了stack对service镜像的管理和编排,使得容器服务的部署更加简单。compose v3的语法能够参考Compose file version 3 reference,注意其与v2有些许不一样。

咱们在项目部署中,考虑到compile容器须要先行建立,以便在deploy部署前完成项目代码的构建,咱们将整个测试环境的部署分割为3个yaml文件:

  • compose-compile.yaml:用于compile容器先行建立

  • compose-dependency.yaml:用于项目中依赖模块容器建立(好比zk、kafka、redis、mysql等)

  • compose-deploy.yaml:里面添加了项目各个模块的容器建立指令

咱们在搭建完swarm环境+准备好各配置文件后,因为compose同时能够自定义建立network,最终咱们仅须要三行命令便可建立一套测试环境:

#生成dependency应用,该应用中包含项目部署所须要的相关依赖,包括kafka、zk等 sudo docker stack deploy --with-registry-auth -c ./compose-dependency.yaml antispamdependency#生成compile应用,建立antispamcompile-compile服务完成项目编译sudo docker stack deploy --with-registry-auth -c ./compose-compile.yaml antispamcompile#生成antispam应用,该应用中包含各模块部署的相关服务sudo docker stack deploy --with-registry-auth -c ./compose-deploy.yaml antispam


测试环境docker自动部署

在完成compile和deploy镜像的制做后,能够将镜像保存在蜂巢,以方便部署环境时拉取。同时为保证每一个deploy容器在建立后能自动拉取compile容器中构建好的编译模块进行模块部署,咱们为各个功能模块编写了相应的entry.sh并保存在网易git仓库中,entry.sh文件实现相应的构建模块拉取、部分配置修改和模块启动。同时在deploy镜像中内置一个inter-entry.sh,该脚本用于deploy启动时拉取entry项目,并经过容器启动参数运行相应的entry.sh文件。

inter-entry.sh文件内容以下:

#!/bin/bashgit clone ssh://git@xxxx:22222/hzsuntingting/xxx-docker-entries.git /usr/local/docker-entry/xxx-docker-entries/echo $1chmod 777 /usr/local/docker-entry/xxx-docker-entries/entries/$1/usr/local/docker-entry/xxx-docker-entries/entries/$1

同时docker-entries项目中保存了compile编译项目须要的build.xml和容器编排须要的yaml文件,这样项目测试环境docker化只须要增长一个docker-entries项目,该项目目录结构以下:

最终,在搭建完swarm环境和准备好文件后,一个项目使用docker部署的流程以下图所示:

  1. 主机下载各依赖模块的镜像建立相应的依赖模块的容器;

  2. 修改被部署项目的接口调用配置为docker服务的service name,例如部分模块须要调用zk,而docker部署环境中zk的service name为dependency_zookeeper,则直接将调用ip改成该服务名便可;

  3. 主机下载compile镜像建立compile容器,容器在git拉取项目代码和docker-entries(里面含有build.xml),进行项目构建打包,并httpServer等待其余模块拉取;

  4. 主机下载deploy镜像建立各deploy容器,容器内置的inter-entry.sh运行在git拉取docker-entries;

  5. 各deploy模块拉取docker-entries后,根据容器启动的entrypoint参数运行相应的entry.sh,到compile容器中拉取相应的构建模块,解压,修改配置并启动。


总结

到此,测试环境docker化的自动化部署过程基本完成,组内成员已可实现用几行命令即完成一套环境的部署工做。可是在实践过程当中,还有不少须要优化的地方,例如:目前各跨主机容器之间的文件共享采用的是起一个简单的httpServer+wget的方式以及git的方式替代,必需要指定肯定的路径,在脚本编写过程当中须要仔细比对,容易出错,若实现跨主机的文件共享则会避免更多错误问题。同时,查看网上资料,Swarm mode集群会折损系统约50%的性能,后续替换为k8s来实践,确定为更有利于测试环境来完成异常测试等对系统稳定和性能要求比较高的测试。


例行一坑,让你们少走弯路~

1. 指定主机为manager时,若机器有多个ip地址,需在其后加参数“--advertise-addr 10.165.148.87 ”,不然会报错

2. 建立overlay网络时能够用subnet参数指定用于网络的子网,若是不指定,swarm会自动选择一个子网,可是根据官网的描述这个自动指定的子网可能会引发container通讯的问题

3.compose的yaml编写时,volumes中type:volume须要版本在3.2及以上,不然会返回services.compile.volumes.0 must be a string

4.在一开始从蜂巢拉取镜像的时候报错以下,缘由是其余主机节点无权限,须要经过--with-registry-auth参数来增长权限。

unable to pin image hub.c.163.com/neteaseqa2017/compile to digest: errors:
denied: requested access to the resource is denied
unauthorized: authentication required



网易云容器服务为用户提供了无服务器容器,让企业可以快速部署业务,轻松运维服务。容器服务支持弹性伸缩、垂直扩容、灰度升级、服务发现、服务编排、错误恢复及性能监测等功能,  点击可免费试用

   

   

网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区


相关文章:
【推荐】 微服务监控探索
【推荐】 接口文档神器Swagger(下篇)

相关文章
相关标签/搜索