10x系列之Docker在Clay.io
【编者的话】近日,Clay.io的Zoli Kahan开始了“10X”系列博文的撰写。通过这个系列博文,Zoli将分享如何只使用一个很小的团队支撑Clay.io的大规模应用。本文是整个系列的第三篇,DockerOne接下来将会对整个系列文章进行翻译。
简介
在Clay,我们的部署过程非常有趣。真的!因为我们使用Docker。Docker是一个用于简化应用隔离与部署的容器化工具。其基本思路是,Docker会在一个虚拟的隔离环境中运行你的应用,这有点像虚拟机,但没有额外开销。你以一个“基础镜像”起步,然后使用一个Dockerfile描述如何创建一个“容器”。综述
我们的部署过程是这样的:
- 将所有要发布的代码合并到git的
master
分支 - 用
git tag
打上发布标签(比如 v1.0.0) - 构建Docker镜像(代码锁定)
- 用
docker tag
打上发布标签(比如 v1.0.0) - 将Docker镜像推送到registry
更新集群容器版本(零停机)
- 确认备用容器正在运行
- 升级主容器
- 等待新的主容器上线
- 升级备用容器
更新生产集群容器版本(零停机)
- (与上同)
这个过程确保了在过渡环境和生产环境中运行的是完全相同的代码,同时允许我们在发生错误时回滚到上一个Docker容器发布版本。
Clay.io的Dockerfile
这是来自我们的移动应用的一个示例Dockerfile(源码):FROM dockerfile/nodejs:latest
Install Git
RUN apt-get install -y git
Add source
ADD ./node_modules /opt/clay-mobile/node_modules
ADD . /opt/clay-mobile
WORKDIR /opt/clay-mobile
Install app deps
RUN npm install
CMD ["npm", "start"]
这个文件不言自明。它只是简单的从当前目录复制源码到容器中。环境变量将用于引入敏感的或动态的配置。重点说明一下:
npm start
实际上是在为生产环境编译并压缩代码:// package.json
{
"scripts": {
"build": "node_modules/gulp/bin/gulp.js build"
"start": "npm run build &&
./node_modules/pm2/bin/pm2 start ./bin/server.coffee
-i max
--name clay_mobile
--no-daemon
-o /var/log/clay/clay_mobile.log
-e /var/log/clay/clay_mobile.error.log",
}
}
这是因为我们需要使用生产环境变量重新构建静态文件。请访问我们的GitHub查看更多示例:github.com/clay.io。
Docker镜像的基本部署
在Clay,我们将镜像托管在docker registry上。因为Docker,部署我们的应用到过渡环境和生产环境中非常简单。整个过程(从未标记容器,到过渡环境,由Ansible自动完成)如下:
Local machine / Build server
docker build -t clay/mobile .
docker push clay/mobile
Staging / Production server
docker pull clay/mobile
docker run
--restart on-failure
-v /var/log/clay:/var/log/clay
-p 50000:3000
-e CLAY_MOBILE_HOST=XXXX
-e CLAY_API_URL=XXXX
-e FC_API_URL=XXXX
-e NODE_ENV=production
-e PORT=3000
--name mobile
-d
-t clay/mobile:VERSION
(注意:49,152 - 65,535端口通常用于私有应用)
零停机更新
你可能注意到在上述启动脚本中,我们使用PM2来处理集群多个服务器进程。PM2支持零停机更新,不过因为它存在于容器内,而我们从不在运行时修改容器内代码,所以我们没使用这个功能。PM2只是单纯的用于获取多个服务器的核心。零停机更新的关键点在于运行两个服务器进程。一个主进程和一个备用进程。我们通过给两个容器部署分配不同的端口实现这一点:
docker run ... -e PORT=50000 --name mobile
docker run ... -e PORT=50001 --name mobile-backup
HAProxy负责在主服务器宕机时将流量重分配到备用服务器上:
example haproxy.cfg
backend mobile
mode http
balance roundrobin
server app1 x.x.x.x:50000 check
server app1b x.x.x.x:50001 check backup
server app2 x.x.x.x:50000 check
server app2b x.x.x.x:50001 check backup
后续将有篇关于HAProxy的文章,介绍更多关于我们是如何使用HAProxy在服务器间进行负载均衡的详情。
以下部署过程将完全由Ansible自动完成:
- 确认备用健康容器状态(Ansible)
docker pull clay/mobile:v1.0.0
杀死主容器(网络请求自动重路由到备用服务器)
docker rm -f mobile
更新主容器,并重启
docker run ...
一旦主容器恢复,网络请求将移回到主服务器- 杀死并更新备用容器
docker rm -f mobile-backup && docker run ...
如果发生了任何错误,只要简单的恢复到上一个镜像版本:
docker run -t clay/mobile:v0.0.12
结语
如果你错过了之前的10x文章:可以点击下面的链接阅读:Architecture(中文翻译)
Logging(中文翻译)
原文:10x: Docker at Clay.io