有赞容器化实践

前言

容器化已经成为一种趋势,它能够解决不少运维中的痛点,好比效率、成本、稳定性等问题,而接入容器的过程当中每每也会碰到不少问题和不便。在有赞最开始作容器化是为了快速交付开发测试环境,在容器化的过程当中,咱们碰到过容器技术、运维体系适配、用户使用习惯改变等各类问题,本文主要介绍有赞容器化过程当中碰到的问题以及采起的方案。php

有赞容器化的初衷

在有赞同时会有不少个项目、平常在并行开发,环境的抢占问题严重影响了开发、测试和上线的效率,咱们须要给每一个项目提供一套开发联调(daily)、测试环境(qa),而且随着项目、平常的生命周期项目环境也会随着建立和销毁,咱们最先的容器化需求就是怎么解决环境快速交付的问题。前端

[有赞环境]java

上面是有赞大体的研发流程,在标准流程中咱们有四套稳定环境,分别是 Daily 环境、Qa 环境、预发环境和测试环境。咱们的开发、测试、联调工做通常并不会直接在稳定环境中进行,而是会拉一套独立的项目环境出来,随着代码通过开发、测试、预发验收最终发布到生产环境后再同步回 Daily/Qa 的稳定环境中。node

[项目环境]python

咱们提供了一套以最小的资源投入知足最大项目并行度的环境交付方案,在 Daily/Qa 稳定环境的基础上,隔离出N个项目环境,在项目环境里只须要建立该项目所涉及应用的计算资源,其它缺失的服务调用由稳定环境提供,在项目环境里,咱们大量使用了容器技术。git

[持续交付]github

后面咱们又在项目环境快速交付的解决方案的基础上实现了持续交付流水线,目前已经有超过 600 套项目/持续交付环境,加上 Daily/Qa 稳定环境,涉及计算实例四五千个,这些计算实例不管是 cpu 仍是内存使用率都是很是低的,容器化能够很是好的解决环境交付的效率问题,以及提升资源使用率来节省成本的投入。docker

有赞容器化方案

咱们的容器化方案基于 kubernetes(1.7.10)和 docker(1.12.6)、docker(1.13.1),下面介绍一下咱们在各个方面遇到的问题以及解决方案。后端

网络

有赞后端主要是 java 应用,采用定制的 dubbo 服务化方案,过程当中没法作到整个单元全量容器化,和原有集群在网络路由上互通也就成了刚需,因为咱们没法解决公有云上 overlay 网络和公有云网络的互通问题,因此一开始咱们放弃了 overlay 网络方案,采用了托管网络下的 macvlan 方案,这样既解决了网络互通的问题也不存在网络性能问题,可是也就享受不到公有云弹性资源的优点了。随着有赞多云架构的发展以及愈来愈多的云厂商支持容器 overlay 网络和 vpc 网络打通,弹性资源的问题才获得了缓解。api

隔离性

容器的隔离主要利用内核的 namespace 和 cgroup 技术,在进程、cpu、内存、IO等资源隔离限制上有比较好的表现,但其余方面和虚拟机相比存在着不少的不足,咱们在使用过程当中碰到最多的问题是容器里看到的 cpu 数和内存大小不许确,由于/proc文件系统没法隔离,致使容器里的进程"看到"的是物理机的 cpu 数以及内存大小。

内存问题

咱们的 java 应用会根据服务器的内存大小来决定 jvm 参数应该怎么配置,咱们是采用 lxcfs 方案来规避的。

CPU 数的问题

由于咱们有超卖的需求以及 kubernetes 默认也是采用 cpu share 来作 cpu 限制,虽然咱们使用了 lxcfs,CPU 数仍是不许的。jvm 以及不少 Java sdk 都会根据系统的 CPU 数来决定建立多少线程,致使 java 应用在线程数和内存使用上都比虚拟机多的多,严重影响运行,其余类型的应用也有相似的问题。 咱们会根据容器的规格内置一个环境变量 NUM_CPUS,而后好比 nodejs 应用就会按照这个变量来建立它的 worker 进程数。在解决 java 类应用的问题时,咱们索性经过 LD_PRELOAD 将 JVM_ActiveProcessorCount 函数覆盖掉,让它直接返回 NUM_CPUS 的值[1]。

应用接入

在容器化以前,有赞的应用已经所有接入到发布系统,在发布系统里已经标准化了应用的打包、发布流程,因此在应用接入方面成本仍是比较小的,业务方无需提供 Dockerfile。

  1. nodejs, python,php-soa 等用 supervisord 托管的应用,只须要在 git 仓库里提供 app.yaml 文件定义运行须要的 runtime 和启动命令便可。
  2. java 标准化启动的应用业务方无需改动
  3. java 非标准化的应用须要作标准化改造

镜像集成

容器镜像咱们分了三层,依次为 stack 层(os),runtime 层(语言环境),应用层(业务代码和一些辅助agent),应用以及辅助 agent 由 runit 来启动。因为咱们的配置尚未彻底分离,在应用层目前仍是每一个环境独立打包,镜像里除了业务代码以外,咱们还会根据业务的语言类型放一些辅助的 agent。咱们一开始也想将各类 agent 拆成多个镜像,而后每一个 pod 运行多个容器,后来由于解决不了 pod 里容器的启动顺序(服务启动有依赖)问题,就把全部服务都扔到一个容器里去运行了。

咱们的容器镜像集成过程也是经过 kubernetes 来调度的(会调度到指定的打包节点上),在发布任务发起时,管控系统会在集群中建立一个打包的 pod,打包程序会根据应用类型等参数编译代码、安装依赖,而且生成 Dockerifile,而后在这个 pod 中使用 docker in docker 的方式来集成容器镜像并推送到仓库。 为了加速应用的打包速度,咱们用 pvc 缓存了 python 的 virtualenv,nodejs 的 node_modules,java 的 maven 包等文件。另外就是 docker 早的版本里,Dockerfile ADD 指令是不支持指定文件属主和分组的,这样会带来一个问题就是须要指定文件属主时(咱们的应用是以 app 帐号运行的)须要多运行一次 RUN chown,这样镜像也就多了一层数据,因此咱们打包节点的 docker 版本采用了官方比较新的 ce 版本,由于新版本支持 ADD --chown 特性。

负载均衡(ingress)

有赞的应用内部调用有比较完善的服务化和 service mesh 方案,集群内的访问不用过多考虑,负载均衡只须要考虑用户和系统访问的 http 流量,在容器化以前咱们已经自研了一套统一接入系统,因此在容器化负载均衡上咱们并无完整按照 ingress 的机制来实现 controller,ingress 的资源配置是配在统一接入里的,配置里面转发的 upstream 会和 kubernetes 里的 service 关联,咱们只是作了一个 sync 程序 watch kube-api,感知 service 的变化来实时更新统一接入系统中 upstream 的服务器列表信息。

容器登陆和调试

在容器化接入过程当中开发会反馈是控制台比较难用,虽然咱们优化了屡次,和 iterm2 等的体验仍是有所不足,最终咱们仍是放开了项目/持续交付环境这种须要频繁登录调试的 ssh 登录权限。 另一个比较严重的问题是,当一个应用启动后健康检查有问题会致使 pod 一直在从新调度,而在开发过程当中开发确定是但愿看到失败现场的,咱们提供了调试发布模式,让容器不作健康检查。

日志

有赞有专门的日志系统,咱们内部叫天网,大部分日志以及业务监控数据都是经过 sdk 直接打到天网里去了,因此容器的标准输出日志仅仅做为一种辅助排查问题的手段。咱们容器的日志收集采用的是 fluentd,通过 fluentd 处理后按照天网约定的日志格式打到 kafka,最终由天网处理进入 es 作存储。

灰度发布

咱们涉及到灰度发布的流量主要包含三部分:

  1. 用户端的 http 访问流量
  2. 应用之间的 http 调用
  3. 应用之间的 dubbo 调用 首先,咱们在入口的统一接入上统一打上灰度须要用的各类维度的标签(好比用户、店铺等),而后须要对统一接入、http client 以及 dubbo client 作改造,目的是让这些标签可以在整个调用链上透传。咱们在作容器灰度发布时,会发一个灰度的 deployment,而后在统一接入以及灰度配置中心配置灰度规则,整个链路上的调用方都会感知这些灰度规则来实现灰度发布。

标准环境容器化

标准环境的出发点

  1. 和项目环境相似,标准稳定环境中的 daily,qa,pre 以及 prod 中超过一半运行在低水位的服务器的资源很是浪费。
  2. 由于成本考虑 daily,qa,pre 里都是以单台虚拟机运行的,这样一旦须要发布稳定环境将会形成标准稳定环境和项目环境的短暂不可用。
  3. 虚拟机交付速度比较慢,使用虚拟机作灰度发布也比较复杂。
  4. 虚拟机每每会存在几年甚至更长的时间,运行过程当中操做系统以及基础软件版本的收敛很是麻烦。

标准环境容器化推动

通过以前项目/持续交付的上线和迭代,大部分应用自己已经具有了容器化的条件。不过对于上线来讲,须要整个运维体系来适配容器化,好比监控、发布、日志等等。目前咱们生产环境容器化准备基本完成,生产网已经上了部分前端 nodejs 应用,其余应用也在陆续推进中,但愿之后能够分享更多生产环境中的容器化经验。

结束语

以上是有赞在容器化上的应用,以及在容器化过程当中碰到的一些问题和解决方案,咱们生产环境的容器化还处于开始阶段,后面还会碰到各类个样的问题,但愿可以和你们互相学习,后面可以有更多的经验分享给你们。

参考文献

[1] github.com/fabianenard…

相关文章
相关标签/搜索