持续交付系列(二):使用Docker、Mesos实现持续交付


【编者的话】本文主要介绍Mesos和Marathon的搭建以及如何完成整个持续交付过程,以及后续还可以做哪些改进和加强。整个系统搭建完成后,应用代码的改变会自动触发Jenkins构建流程,几秒钟后,改变就会通过Jenkins、Docker Hub和Marathon传递到Mesos中部署上线,是不是很酷?

第一部分中文翻译)我们介绍了如何Docker化一个Node.js应用,如何使用Fig部署Jenkins和Docker Registry,以及如何实现Node.js应用的持续集成。

本文是第二部分,将继续介绍Mesos和Marathon的搭建以及如何完成整个持续交付过程。

15.02_.11_diagram3_.jpg

如果你不了解Mesos或者Marathon,可以参考如下文章:文章1文章2文章3

现在,我们有了功能性开发和持续集成的环境,可以开始搭建Mesos集群了。

如下是包含系统所有部分的fig.yml文件。在之前配置好的Jenkins和Docker Registry基础之上,我们还有Mesos master、Mesos slave、Mesosphere Marathon和负责内部Mesos通信的Zookeeper。
# Zookeeper: -p 2181:2181 -p 2888:2888 -p 3888:3888
zookeeper:
image: jplock/zookeeper:3.4.5
ports:
- "2181"
master:
image: redjack/mesos-master:0.21.0
hostname: master
links:
- zookeeper:zookeeper
environment:
- MESOS_ZK=zk://zookeeper:2181/mesos
- MESOS_QUORUM=1
- MESOS_WORK_DIR=/var/lib/mesos
- MESOS_LOG_DIR=/var/log
ports:
- "5050:5050"
marathon:
#image: garland/mesosphere-docker-marathon
image: mesosphere/marathon
links:
- zookeeper:zookeeper
ports:
- "8080:8080"
# this image does not respect MARATHON_ env variables, so adding the params via command
command: --master zk://zookeeper:2181/mesos --zk zk://zookeeper:2181/marathon
slave:
image: redjack/mesos-slave:0.21.0
links:
- zookeeper:zookeeper
- master:master
environment:
- MESOS_MASTER=zk://zookeeper:2181/mesos
- MESOS_EXECUTOR_REGISTRATION_TIMEOUT=5mins
- MESOS_CONTAINERIZERS=docker,mesos
- MESOS_ISOLATOR=cgroups/cpu,cgroups/mem
- MESOS_LOG_DIR=/var/log
volumes:
- /var/run/docker.sock:/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
- /sys:/sys:ro
- mesosslace-stuff:/var/log
expose:
- "5051"
jenkins:
image: containersol/jenkins_with_docker
links: 
- marathon:marathon
volumes:
- jenkins-stuff:/var/jenkins_home
- .:/var/jenkins_data
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
ports: 
- "8081:8080"
registry:
image: registry
environment:
- STORAGE_PATH=/registry
volumes:
- registry-stuff:/registry
ports: 
- "5000:5000"

fig.yml不多做解释。所有环境参数都是参考Docker Hub上对应镜像的使用介绍。

Mesos slave容器还使用了挂载socket的技巧,不过不需要做别的,因为slave是用root用户运行的,有访问socket的权限。

要注意Jenkins容器连接到了Marathon。这就要求能够从Jenkins容器发送请求到Marathon容器里。我们在下一章介绍部署的时候会详细说明。

现在重启系统,可以看到系统开始运行:
$ fig up
Creating cddemo_registry_1...
Recreating cddemo_zookeeper_1...
Creating cddemo_master_1...
Creating cddemo_slave_1...
Recreating cddemo_marathon_1...
Creating cddemo_jenkins_1...

容器启动非常快,但是要等所有服务都上线大概花了30秒(在MacBook Air上的Ubuntu虚拟机里)。

Mesos在http://localhost:5050。如下截图里可以看到一个活动的slave。该slave在本次配置下没有暴露任何端口。
Screen-Shot-2015-02-28-at-18.08_.56_.png

http://localhost:8080可以访问Marathon。
Screen-Shot-2015-02-28-at-18.09_.14_.png

部署

最后一步是将我们用Marathon在Mesos上新构建的Docker镜像部署好。
15.02_.11_diagram4_.jpg

首先需要创建配置文件将应用安排到Marathon上,如下app_marathon.json:
{
"id": "app", 
"container": {
  "docker": {
    "image": "localhost:5000/containersol/nodejs_app:latest",
    "network": "BRIDGE",
    "portMappings": [
      {"containerPort": 8000, "servicePort": 8000}
    ]
  }
},
"cpus": 0.2,
"mem": 512.0,
"instances": 1
}

这里也有一些需要注意的地方。比如,没有提到健康检查,需要告诉Marathon应用运行和不运行的时间。

一旦我们发布了这个JSON文件,就可以在deploy.sh里添加最新的脚本,移除最近运行的应用,并且用新的镜像重新部署它。当然有更好的升级策略,不过不在这里讨论。
#!/bin/bash

if [ -z "${1}" ]; then
version="latest"
marathon="localhost"
else
version="${1}"
marathon=${MARATHON_PORT_8080_TCP_ADDR}
fi

# destroy old application
curl -X DELETE -H "Content-Type: application/json" http://${marathon}:8080/v2/apps/app 

# I know this one is ugly. But it works for now.
sleep 1

# these lines will create a copy of app_marathon.json and update the image version
cp -f app_marathon.json app_marathon.json.tmp
sed -i "s/latest/${version}/g" app_marathon.json.tmp

# post the application to Marathon
curl -X POST -H "Content-Type: application/json" http://${marathon}:8080/v2/apps -d@app_marathon.json.tmp

最后一步是将deploy.sh添加到Jenkins的配置中并运行构建。
Screen-Shot-2015-02-28-at-19.18_.17_.png

成功构建之后,可以看到应用运行在Marathon上:
Screen-Shot-2015-02-28-at-19.21_.59_.png

http://localhost:31000可以访问我们自己的应用:
Screen-Shot-2015-02-28-at-19.23_.29_.png

现在可以试着改变应用并且触发Jenkins去构建build。几秒钟后,这个改变就会通过Jenkins、Docker Hub和Marathon传递到Mesos里!

改进

要想改进这个系统有两个大方向:添加更多的功能以及提升搭建质量(deepening the quality of the setup)。可能的扩展有很多,我们只列了几个例子:
  • 将HelloWorld示例扩展为一个标准Web应用
  • 多语言支持
  • 多层次的自动化测试(单元测试、系统测试、性能测试等等。)
  • 用Git hook自动触发Jenkins build
  • 部署到公有云里,比如GCE、AWS等
  • 在多主机上运行
  • HAProxy搭建
  • 用Jmeter实现负载模拟下的自动扩展
  • 部署一个基于微服务的系统
  • 使用Flocker做持久化存储
  • 使用Weave作为网络容器
  • 使用Consul实现自动服务发现
  • 添加系统监控
  • 添加集中式日志


我的下一步想使系统可以面向外部用户,添加HAProxy和自动扩展的能力,如下图所示:
15.02_.11_diagram5_.jpg

最后的话

一开始搭建这个系统主要是想帮助开发和运维人员学习如何在持续交付领域使用Docker和Mesos。在几个月的过程中我发现完整的系统很复杂,很难解释,更难搭建和使用。
我们请Marta marszal创建了本文的图表,以让文章更容易理解。

如果有改进本示例系统的建议,请一定告诉我们。本文的图表也可以随意下载和使用,不过请注明出处。CD_with_Mesos_Docker

所有资源都可以在GitHub上找到。
===========================
译者介绍
崔婧雯,现就职于VMware,高级软件工程师,负责桌面虚拟化产品的质量保证工作。曾在IBM WebSphere业务流程管理软件担任多年系统测试工作。对虚拟化,中间件技术有浓厚的兴趣。

原文链接:Continuous Delivery with Docker on Mesos in less than a minute – Part 2(翻译:崔婧雯 校对:李颖杰)

6 个评论

这个系列visualization做的不错。之前对Mesos一直停留在理论层,看了这个深入透彻地理解了不少!再次感谢!
mesos-slave启动的时候有问题,各种异常。不知道大家有没有遇到这情况
我看到网上也有此问题讨论:https://www.mail-archive.com/user@mesos.apache.org/msg01863.html

I0320 06:47:28.592039 1 logging.cpp:172] INFO level logging started!
I0320 06:47:28.593437 1 main.cpp:142] Build: 2014-11-22 05:29:57 by root
I0320 06:47:28.593533 1 main.cpp:144] Version: 0.21.0
I0320 06:47:28.593590 1 main.cpp:147] Git tag: 0.21.0
I0320 06:47:28.593636 1 main.cpp:151] Git SHA: ab8fa655d34e8e15a4290422df38a18db1c09b5b
Failed to create a containerizer: Could not create DockerContainerizer: Failed to execute 'docker version': exited with status 127
docker run --name slave2 --link zookeeper:zookeeper --link master:master -e MESOS_MASTER=zk://zookeeper:2181/mesos -e MESOS_EXECUTOR_REGISTRATION_TIMEOUT=5mins -e MESOS_CONTAINERIZERS=docker,mesos -e MESOS_ISOLATOR=cgroups/cpu,cgroups/mem -e MESOS_LOG_DIR=/var/log -v /var/run/docker.sock:/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v /sys:/sys:ro -v /data/ic/mesosslave-stuff:/var/log -p 5051:5051 --privileged redjack/mesos-slave:0.21.0

MESOS_CONTAINERIZERS=docker,mesos 去掉 docker能正常启动,但是不能创建实例
直接执行一下docker version看看有没有报错
我也遇到这个问题了,你后来是如何处理的呀?
hplong

hplong 回复 Jzako

宿主机上执行docker version执行没有错,他这个看起来是在容器里面执行docker命令不行。

要回复文章请先登录注册