视频信息 #

DockerCon 16 - Thinking Inside the Container - A Continuous Delivery Story
by Maxfield Stewart, Riot Games

https://www.youtube.com/watch?v=YViFZBoKqjg

http://v.qq.com/x/page/h03148603la.html

League Legends #

  • 67 millions player/ month, 27 m/daily, 7.5 m at peak.
  • 1.25 Milions Build / Year
  • 10 - 14 k containers / week
  • 120 build jobs / hour

A Containerized Build Farm #

Jenkins → (Docker API) → Swarm → (Docker API) → Build Hosts → (Docker API) → DryDock

Jenkins 还会直接通过SSH连接Build Host

每一个Build Host都是 CentOS 7.2/Docker 1.10.3 + cAdvisor + Docker-GC + Container Metrics, 4 core/32GB RAM/120GB LVS

Story Time #

两年前,2013,在一个 Jenkins 服务器上,运行3500+ unique build jobs ,换句话说就是每小时 650+ 个build。90+ Build slave

EngineersTicket(s)Build Team

实际上基本都被Ticket埋了……

我们到底想要什么? #

  • 团队必须有快速行动的能力
  • 产品必须拥有自己的技术栈
  • 配置可以像代码一样,希望需求方可以用code定义环境

曾经考虑过很多种方案: Packer, Vagrant, Openstack, AWS EC2, Azure, vmware

2014年的时候,突然docker出现了,由于团队太过繁忙,没有意识到这个东西的重要性。直到有一天,有一个ticket出现说,你们能够在build环境中部署Docker么?如果可以就太赞了。

第一反应,会觉得WTF,又有一个新的东西想部署了?但是turns out, it’s great。

Jenkins Primer #

Jenkins 是主从结构,在 Jenkins 眼中,其它的从构建主机是各种label而已,比如 Win32 + Java + TeamA,或者 CentOS7 + Java + TeamB

而开发人员在写构建需求的时候,只需要label上自己所需的环境:Win32 + Java + TeamA之类的即可,Jenkins会根据这些Label决定如何调度构建任务

Docker Container as Jenkins Slave #

现在 Jenkins 上估计有很多 Docker 的插件了,但是在1-2年前什么都没有,需要找出一种办法让 Jenkins 以为容器就是 Build Slave,而且还可以让开发人员提供 Dockerfile 的途径,并且可以扩展。

后来通过google在Docker Hub上找到了一个Dockerfile,可以让容器启动后模拟 Jenkins Build Slave。基本上是构建一个包括了 ssh, jdk, git, jenkins的容器

容器非常臃肿 #

由于他们构建了一个肥镜像,前面几层还好,最后一层构建开发人员所需的镜像时,非常臃肿。

Provisioning and Plugins #

  • Docker Plugin: <中选>
  • Mesos Plugin:
  • Kubernetes Plugin:

Jenkins Docker Plugin UI非常基本,URL, Docker Image, 容器选项等等。

然后设法用Groovy做了个结合二者API的脚本。现在开发人员可以直接提供Dockerfile,然后Jenkins自动识别构建。

We Created a Monster #

Garbage In-Gabage out Paradigm

不是所有开发人员都理解这种构架,所以有的时候开发人员提供的Dockerfile,或许本地构建没问题,但是在 Jenkins 构建 Slave 上会出问题,然后 Jenkins 会非常尽职的去努力工作,也就是创建很多的容器去满足这个需求,最后面对的是巨大的docker rmi的job。

We Need to Ispect Our Containers #

“Infrastructure as Code” Managing Servers in the Cloud

最开始是手动检查Docker Image,很快就意识到这是错误的做法。于是创建了个脚本 ./harbormaster ,使用Go写的,非常简单,就是检查这个Image是不是满足各种需求,比如ssh啊之类的。

But it needs to Scale #

所有这些最开始会只在一个Docker Host上跑,因为Docker Plugins只支持一个Docker API。当时就在想,要是有一个办法,可以使用一个Docker API 然后它理解负载均衡任务调度之类的事情,然后它去控制一群服务器多好。恰好这个时候Docker Swarm 0.1发布了,所以他们立即开始进行尝试,他们第一次试用的时间估计是Swarm 0.2

Putting It All Together #

开发人员用 Dockerfile 构建了一个镜像,扔给 Registry,并且通知 Harbor Master ,然后 Harbor Master 开始检查这个镜像,如果通过,会通知 Swarm Master 下达任务,Swarm Master 会调度任务到集群中的某个节点。节点开始从 Registry 下载任务。

听起来很美好,他们让开发人员尝试,可是现实很残酷。开发人员构建的镜像大约3GB左右,用了很久push到了registry后,测试并没有开始。原因是,Swarm 中的 Docker Host 同样需要很久去下载这个3GB的镜像,下载后才可能测试。所以开发人员抱怨说你这个东西不好用,提交了任务许久都没有开始测试。

Grovvy 写的 Jenkins 构建 Job #

内容很简单

1
2
3
4
node ('Awesome-Build-Label') {
git branch: "master", url: "git@github.com:maxfields2000/awesome.git"
sh "./buildme.sh"
}

Dockerception #

很快就出新的麻烦了,因为Docker很好用,于是大家开始都用Docker了。所以很快有人需要Docker in Docker。因为很多人希望能够用Jenkins测试构建Docker 镜像是否成功。

最终,他们独立出来了一个机器,称为DRYDOCK,然后所有那些需要构建Docker镜像的任务,都指向这个机器,这样就不会出现DIND的问题,而且也不会把Build Slave集群搞崩了。真出了什么问题,直接把这个机器的清空重新部署即可。

How do you actually build it #

http://engineering.riotgames.com
https://github.com/maxfields2000/dockerjenkins_tutorial

听起来很简单 #

举了两步画猫头鹰的例子:第一步花两个圆;第二步画剩下的部分……

两年前我们就开始使用Docker了,但是今天我们才来这里给大家演讲,显然中间发生了写什么事情,不然我们去年就来了。

Lesson 1 - Docker Isn’t “Simple” #

  • Dockerfile 的撰写需要有良好的系统管理知识背景

好多人的问题实际上是 Dockerfile 的书写问题,然后就转化为认为这东西不可能在 Docker 里构建。其实 Docker 用户都知道事实并非如此。他们的解决办法就是Teaching。

  • 用来构建 Docker Images 的 Docker Images 是 Dockerception
  • Docker “Voodoo and Black Magic” 问题

Lesson 2 - 容器 != 虚拟机 #

虽然看起来很像虚拟机,比如你可以在里面 apt-get install,但是Docker不是虚拟机。很多事情是不可以在里面做的。

  • 无法挂载远程文件系统
  • 容器不保存状态
  • 对于构建时和运行时有不同的规矩

Lesson 3 - Garbage Collection #

docker build → docker run → docker pull → volume

github: spotify/docker-gc

Lesson 4 - Maintenance/Failure #

  • Pull hosts on/offline

Docker 经常升级,当然我们都想使用最新的版本,所以这就必须涉及一个如何升级维护、上线下线服务的流程。

  • Update All Images
  • Rolling Restarts

Docker 和其它程序一样,会 Crash,所以需要一些机制去发现维护这些故障。

Lesson 5 - 到底怎么升级? #

升级一定要有计划,升级需要考虑很多细节,比如如果Swarm升级了,那么现有的使用Docker API的插件是否还会继续支持?一般悬。

Lesson 7 - Credentials & Security #

  • 什么应该放到 Base Image 里?
  • SSH key扔到registry里?
  • 源代码中的password?
  • 所有密码类的东西都用环境变量?

现有的做法是在 Jenkins Master 上存储所有 Credentials,然后通过它以环境变量的形式发送给测试部署环节,只需要确保 Jenkins Master 安全即可。目前还有别的方法,他们暂时采用的是这种办法。

我们成功了吗? #

  • Over 1200 New Build Jobs Created
  • 30% 的环境是容器
  • 构建环境变化、创建、修复的Ticket消失了
  • 我们不只再是 Build Team 了

因为他们所有的构建过程都自动化了,而构建环境都 Docker 化了,所以不再需要他们了。但是并不是说他们都被开了,而是都成为了开发团队的一部分,因为他们都成了 Docker 专家,帮助开发人员构建Docker镜像。