容器是什么?
上一篇文章(一个创业公司的容器化之路(一) - 容器化之前),我们简单说明了杏仁容器化之前的架构发展。今天我们就来谈谈容器。
2013 年 Docker 横空出世,到 2015 年已经渐渐进入大家的视野。容器当然不一定是 Docker,而且容器现在也是有标准的。但一说容器大家肯定会想到 Docker。所以我们这里说的容器,主要就是指 Docker。
容器到底是什么呢?顾名思义,容器就是用来装东西的。在这里它用来装的就是应用程序。容器的特点简单说就那么四点:
- 容器是自包含的,它打包了应用程序及其所有依赖,可以直接运行。以前应用程序的依赖管理一直是个大问题,即使像 RPM 、Maven、Ansible 等都能解决一部分问题,但并没有一个所有应用程序通用的标准机制,直到容器出现。
- 容器是可移植的,可以在几乎任何地方以相同的方式运行。这就可以确保应用在开发环境、测试环境、生产环境等都有完全一样的运行环境。
- 容器是互相隔离的,同一主机上运行的多个容器,不会互相影响。即一个容器中运行的应用程序,是访问不到其他容器的资源的(进程、网络、文件、用户等),除非配置为共享的资源。
- 容器是轻量级的,体现在容器的秒级启动,并且占用资源很少。
容器能做的很多事情,虚拟机也能做,那它们有什么区别呢?下面这张图是 Docker 官网的截图,很好的说明了两者的区别。
但最根本的差别,其实就是最后一点:轻量。很多人可能觉得这只是一个简单的差别,但其实不是。因为就是这一点使得容器可以成为一种 标准化的应用发布方式。
上个世纪 5、60 年代集装箱刚出现,看上去也只是简单的差别,也没有什么技术含量。但集装箱提供了一个标准化的物流方式,全球的海陆空运输、码头装卸等围绕集装箱形成了整个一个高效的物流体系。最终改变了世界贸易,促成了全球化。
所以容器这个标准化的应用发布方式,最终会影响上层的整个应用架构。最终围绕容器,会建立一套完整应用架构体系,带来革命性的改变。现在其实已经可以看到一点端倪了,Kubernetes 基本已经成为标准,不久前 Google 还发布了 Istio 这个 Service Mesh 工具,进一步把微服务的基础架构也抽象了出来。
容器编排是什么?
光有能装应用的容器还不够,如果还是人工管理那么多容器,那也发挥不出容器的优势。所以我们需要一个容器编排系统。容器编排能提供以下功能:
- 应用调度:应用部署、无缝升级、弹性扩展、自愈等。
- 资源管理:内存、CPU、存储空间、网络等。
- 服务管理:命名空间、负载均衡、健康检查等。
- 以及很多其他功能,如日志、监控、认证、授权等。
容器编排领域最主要的三个系统是 Docker Swarm、Kubernetes 以及 Marathon/Mesos。
Swarm 是 Docker 官方的方案,优点就是简单,缺点是太简单了。
然后是 Google 的 Kubernetes,也叫 K8s。Kubernetes 最近一年大放光彩,几乎统治了容器编排领域,就连 Docker 官方不久前也宣布了支持 Kubernetes 。它的优势就是有大厂支持,而且 Google 是把它作为战略来布局的,你可以把它想象成当年的 Android;它的社区也非常火爆。
技术上,Kubernetes 是一个集成的方案,设计非常优秀,可以说是分布式系统的设计典范,Google 在这方面毕竟有很深入的经验。缺点就是有点复杂,而且在今年之前它还是存在不少问题,包括性能问题、大版本的兼容性、部署复杂等,当然现在已经基本解决了。
Mesos 在 Docker 之前就有了,本身做的是分布式系统的资源管理,Mesos 很灵活,上面可以支持各种系统,包括 Spark 等。Marathon 则是基于 Mesos 实现了编排的功能。
我们是去年年中考虑容器化的,我们最后选择的方案是 Marathon/Mesos。原因一方面是之前 Jenkins 容器化已经用到了 Marathon/Mesos,有些经验。另一方面是该方案便于和当前的架构整合。Kubernetes 太过复杂,迁移的话,对架构改动太大。
杏仁的容器化
我们容器化之后的架构是这样的:
所有的应用都以容器的方式运行在 Mesos Slave 上,Mesos Master 统一管理 Mesos Slave 服务器。Marathon 通过 Mesos 调度容器,进行发布、升级、扩容等。Calico 是 Docker 的网络解决方案,实现了一个容器一个 IP 以及容器之间的互联。而右上角部分,我们基本保留了我们之前的微服务架构,只是用于服务发现和注册的 Consul Agent 替换成了 Registrator。
同时我们的 CI/CD 也相应的做了调整。
Jenkins 自身现在也是基于容器的,会在 Mesos Slave 的容器里进行编译和打包。应用会被打包成的 Docker 镜像,上传到我们的镜像仓库 Harbor 里。部署时,Jenkins 调用 Marathon 的接口进行部署,Marathon 则从 Mesos 申请资源。部署时 Mesos 会从 Harbor 下载相应的应用镜像并根据配置运行。
有了这套系统,我们创建应用、扩展应用就很简单了。创建应用时首先通过 Dockerfile 和 Jenkins 创建镜像,然后在 Marathon 界面上,只需要准备一个 Json 配置(也可以通过 Form 配置),指定资源、实例数、镜像、网络、健康检查、环境变量等,就可以很快上线一个新应用。
有时候我们要准备一个秒杀活动或者推送几百万用户,需要增加应用实例,也只要在 Marathon 界面调整一个数字就可以了。
除了容器编排和 CI/CD,还有两个很基础的东西,一个是基于 ELK 的统一日志平台、另一个是基于 Open-Falcon、StatsD、Graphite、Grafana 的 监控告警平台。大致结构如下,具体实现以后有机会再专门写文章介绍,这里就不详述了。
最终,我们的整个平台的组成是这样的:
容器化总结
到这里为止,这些就是杏仁目前的基础平台的架构。通过这套系统,我们提升了资源利用率,刚刚迁移到容器化环境的时候,我们只用了原来大约 6、70% 的云服务器。并且我们大大加强了我们的自动化运维的能力,完善了服务监控。
但是这套系统也存在不少问题。
- 新增服务器节点还是需要一些手工操作。
- 容器、环境等的配置都是分散在各处,缺乏有效的管理。
- 对有状态应用支持不好。
- 系统存在一些冗余,例如有 Zookeeper、有 Etcd 还有 Consul。
- 不支持自动扩容。
- 部分基础设施没有容器化。
未来我们会继续进化,也许等时机成熟了,也不排除会迁移到公有云的容器服务,或者自建 Kubernetes 集群。