有赞容器化实践

2020 年 3 月 11 日

有赞容器化实践

前言


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


有赞容器化的初衷


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



有赞环境


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



项目环境


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



持续交付


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


有赞容器化方案


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


网络


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


隔离性


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


内存问题


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



CPU 数的问题


因为我们有超卖的需求以及 kubernetes 默认也是采用 cpu share 来做 cpu 限制,虽然我们使用了 lxcfs,CPU 数还是不准的。jvm 以及很多 Java sdk 都会根据系统的 CPU 数来决定创建多少线程,导致 java 应用在线程数和内存使用上都比虚拟机多的多,严重影响运行,其他类型的应用也有类似的问题。


我们会根据容器的规格内置一个环境变量 NUMCPUS,然后比如 nodejs 应用就会按照这个变量来创建它的 worker 进程数。在解决 java 类应用的问题时,我们索性通过 LDPRELOAD 将 JVMActiveProcessorCount 函数覆盖掉,让它直接返回 NUMCPUS 的值[1]。


应用接入


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


  1. nodejs, python,php-soa 等用 supervisord 托管的应用,只需要在 git 仓库里提供 app.yaml 文件定义运行需要的 runtime 和启动命令即可。



  1. java 标准化启动的应用业务方无需改动

  2. 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] https://github.com/fabianenardon/docker-java-issues-demo


2020 年 3 月 11 日 22:19180

评论

发布
暂无评论
  • 认识容器:容器的基本操作和实现原理

    通过这一讲,你会对容器有了一个大致的认识,包括它的“形”,掌握一些基本的容器操作;还有它的“神”,也就是容器实现的原理。

    2020 年 11 月 16 日

  • 雪球的 Docker 实践

    雪球是一家涉足证券行业的互联网金融公司,成立于2010年,去年获得 C 轮融资。雪球的产品形态包括社区、行情、组合、交易等,覆盖沪深港美市场的各个品种。

  • 拉勾网基于 UK8S 平台的容器化改造实践

    拉勾网于2019年3月份开始尝试将生产环境的业务从UHost迁移到UK8S,截至2019年9月份,QA环境的大部分业务模块已经完成容器化改造,生产环境中,后台管理服务已全部迁移到UK8S,部分业务模块也已完成容器化。

  • 从 Docker 运维看知乎容器平台的优雅整合

    传统的部署是安装、配置和运行;而Docker的出现革命性地改变了传统模式,部署被简化为复制和运行两个步骤。因此,越来越多企业使用Docker提高分布式应用的构建与交付;但是与此同时,Docker带来了很多不可避免的挑战,其中运维需要克服的挑战尤为传统的部署是安装、配置和运行;而Docker的出现革命性地改变了传统模式,部署被简化为复制和运行两个步骤。因此,越来越多企业使用Docker提高分布式应用的构建与交付;但是与此同时,Docker带来了很多不可避免的挑战,其中运维需要克服的挑战尤为突出。知乎曾经在QCon上与大家首次分享Docker架构和经验,也即将在全球容器大会详细讲述容器平台的实战历程。本次InfoQ就在Docker整合入原有架构过程中,如何实现的Docker运维对知乎两位专家进行了采访。

  • dumb-init:一个 Docker 容器初始化系统

    容器化环境中,往往直接运行应用程序,而缺少初始化系统(如systemd、sysvinit等)。这可能需要应用程序来处理系统信号,接管子进程,进而导致容器无法停止、产生僵尸进程等问题。dumb-init旨在模拟初始化系统功能,避免上述问题的发生。

  • 干货 | 腾讯游戏是如何使用 Docker 的?

    腾讯第一季度的财报显示,腾讯游戏的收入占腾讯总营收的59.4%,很显然,腾讯游戏已经是腾讯最赚钱的部门,当然,腾讯也是国内最大的游戏发行商。游戏行业相对于其他行业来说特点非常明显,一是需要同时运营多款游戏,二是很多游戏的生命周期都很短。不管是从数量还是周期来看,游戏行业特殊的业务都为技术团队提出了更高的要求。腾讯游戏从2014年下半年开始就在生产环境中使用Docker,并取得了不错的成果。目前《我叫MT2》等多款重量级游戏都跑在容器中,且整体运行良好。在8月28日的CNUTCon全球容器技术大会上,腾讯游戏的高级工程师尹烨将会介绍腾讯游戏业务使用Docker的进展及收益,并从内核、网络、存储、运营等方面深入探讨腾讯游戏在实践过程中遇到的问题及解决方案,最后还会复盘反思Docker对于游戏业务的价值。本文是会前InfoQ记者对尹烨的采访。

  • LeetCode 题解:11. 盛最多水的容器,for 循环双指针,JavaScript,详细注释

    原题链接:https://leetcode-cn.com/problems/container-with-most-water/

    2020 年 8 月 22 日

  • 测试工程能力容器化改造方案

    随着容器时代的到来,开源社区中诞生了以Docker、Rocket为代表的优秀的容器引擎方案。本文旨在介绍通过容器技术对不同测试类型(应用层测试、中间层测试、内核测试、硬件驱动测试、编译测试)进行容器化改造的方案和收益,并通过具体实例的方式来展示容器化时代为软件测试带来的机遇。

  • 应用托管服务:Web 应用怎样在云上安家?

    能不能有一个平台服务,来帮我们解决所有的基础架构问题,让我们只需要专注于应用构建本身?这就是云上应用托管PaaS服务。

    2020 年 3 月 27 日

  • Docker 发布 1.2.0 版本,并宣布 DockerCon Europe

    Docker发布了1.2.0版本,其中包括为容器指定重启策略、容器权限的细粒度控制等特性。该公司还将于今年12月在阿姆斯特丹主持召开它在欧洲的第一次正式会议DockerCon Europe。

  • 数据中心的 Yarn on Docker 集群方案

    数据中心中的应用一般独立部署,为了保证环境隔离与方便管理,保证应用最大资源 数据中心中普遍存在如下问题: 1.主机资源利用率低 2.部署和扩展复杂 3.资源隔离无法动态调整 4.无法快速响应业务。

  • 白话容器基础(二):隔离与限制

    一个正在运行的Docker容器,是一个启用了多个Namespace的应用进程,它能够使用的资源量受Cgroups的限制。

    2018 年 9 月 5 日

  • Namespace 技术:内部创业公司应该独立运营

    今天我们来看,“看起来隔离的”技术Namespace,在内核里面是如何工作的。

    2019 年 8 月 7 日

  • 360 容器平台基于 Prometheus 的监控实践

    360近年来上线了容器云平台,给团队工作带来了一些便利,同时也给运维工作带来了很多挑战。

  • Docker 扁平化网络设计与实现

    众所周知,Docker容器跨主机互访一直是一个问题,Docker官方为了避免网络上带来的诸多麻烦,故将跨主机网络开了比较大的口子,而由用户自己去实现。目前Docker跨主机的网络实现方案也有很多种,主要包括端口映射、ovs、 fannel等。但是这些方案都无法满足TalkingData的需求,最后我们采取了自主研发扁平化网络插件,也就是说让所有的容器统统在大二层上互通。

  • Kubernetes 在有赞的实践

    本文介绍Kubernetes在有赞提升人和机器的效率的实践。

  • 容器资源可视化隔离的实现方法

    通常有一些业务已经习惯了在传统的物理机/虚拟机上使用top,free等命令来查看系统的资源使用情况

  • 经典案例复盘——运维专家讲述如何实现 K8S 落地

    运满满近年来业务飞速发展,对系统稳定性的要求越来越高,针对一些痛点开始实现 K8s 的落地。

  • 美团容器技术研发实践

    2018 年 12 月 18 日

发现更多内容

架构师训练营第 1 期 - 第二周课后练习

Anyou Liu

极客大学架构师训练营

交易所开发,数字货币交易所平台搭建源码

WX13823153201

架构师训练营 1 期 - 第二周作业(vaik)

行之

信息获取的四个层级,看看你在哪一级?

boshi

学习 正确阅读 信息需求

第二周学习总结

饭桶

架构师训练营第二周课后作业

Gosling

极客大学架构师训练营

第二周作业

饭桶

架构师训练营第二周学习总结

Gosling

极客大学架构师训练营

TensorFlow 篇 | TensorFlow 2.x 分布式训练概览

Alex

tensorflow keras 分布式训练

在用户现场,你需要注意的几件事情

boshi

项目管理 实施 需求分析

基础框架第二周总结「架构师训练营第 1 期」

天天向善

基础框架

一个草根的日常杂碎(9月24日)

刘新吾

社会百态 生活随想 日常杂碎

第二周作业

icydolphin

极客大学架构师训练营

如果编程语言是一门武功绝学

C语言与CPP编程

c++ 编程 程序员人生 程序人生 编程语言

极客时间架构师培训 1 期-第2周总结

Kaven

LeetCode题解:590. N叉树的后序遍历,递归,JavaScript,详细注释

Lee Chen

LeetCode 前端进阶训练营

flutter 中的video player对比学习

Daniel

最新整理国内知名大厂7篇Java岗面试真题,奥利给!

Java架构师迁哥

开放的是金融服务 必须确保持牌经营

CECBC区块链专委会

金融 银行

程序员陪娃漫画系列——修空调

孙苏勇

程序员人生 陪伴 漫画

用于门牌号码检测的深度学习

计算机与AI

学习 分类

基础框架第二周作业「架构师训练营第 1 期」

天天向善

设计原则

2020.09.21-2020.09.27 学习总结

icydolphin

极客大学架构师训练营

架构师训练营 Week2 - 课后作业

依赖倒置原则 接口隔离原则

架构师训练营 Week2 框架设计- 学习总结SOLID

区块链+跨境贸易:让跨境数据高效共享可信

CECBC区块链专委会

区块链 跨境贸易 跨境电子商务

理解依赖倒置原则

林杭戴

极客大学架构师训练营

第二周学习总结

林杭戴

极客大学架构师训练营

第二周作业

追风

极客大学架构师训练营

第2周 框架设计总结

bearlu

第二周作业

华美而火锅

有赞容器化实践-InfoQ