传统 Java 网站如何实现容器化?看看 Cars.com 如何玩转 Docker!

背景



Cars.com 是美国的汽车门户网站,为用户提供各种购车相关的信息和资讯,类似于国内的汽车之家。


他们之前的技术栈是比较传统的 Java Web 结构:Java 7,  Websphere/Weblogic, Oracle Linux, IBM 硬件,Oracle 数据库 。开发语言包含 Java,NodeJs,Go。随着网站宣传的投入,Cars.com 的流量也变大了。


·      3000万访问者 / 月

·      470万车辆信息

·      每天处理200万张图片请求

·      每天服务端处理1亿次请求


问题来了,流量变大之后,传统的架构显得力不从心。同时,软件交付流程也成为了瓶颈,来看看他们的痛点。


痛点


·      两套操作系统和中间件

操作系统和中间件的选型不同,各自分别包含Websphere, Weblogic, Oracle Linux, Redhat Linux, AIX等等。


·      每套运行环境需要5份

包含开发者环境,功能测试环境,集成测试环境,性能测试环境,生产环境。


·      10个 Web 应用,100多个服务需要部署。


由于环境的差异性,上线流程的复杂性,导致 Cars.com 的团队经常碰到的问题是:为什么代码在这个环境能运行,在另外一个环境不行?久而久之为团队带来大量重复的定位环境问题的工作,严重影响了开发进度。

 

 Cars.com 总结了他们的诉求 – 实现不可变基础设施


·      统一上线流程。


·      具备实时扩展的能力,应对高峰期流量。


·      当服务出现问题,能够自动回滚,自动恢复。



使用 Docker 实现不可变基础设施


为什么选择 Docker?


·      提供一致性,可预期的环境。

使用 Docker 可以屏蔽环境的差异,解决维护5份环境的痛点。


·      实现微服务部署。

Cars.com 底层有100多个服务,服务如果不能单独部署,会有造成构建时间长,上线周期长,排除问题困难等问题。 实现微服务的独立部署,可以加速软件上线速度,降低问题排除难度。


·      秒级故障恢复。

Docker 作为服务的载体,具备快速销毁,快速上线,快速回滚的能力。一旦线上服务出问题,可以快速回滚到上一个版本。


·      实现蓝绿部署,金丝雀发布。

快速发布环境,让一部分用户体验某些新功能,待功能被快速验证得到积极的反馈之后,再进行大面积部署。


构建一个通用 Docker 镜像


为什么需要构建通用的 Docker 镜像?


·      公司内部有很多镜像,当有新的环境需要搭建时,要把镜像从仓库一个一个都拷贝到开发者的机器。


·      多语言开发团队,包括 JavaScript,Java,Go 等等,每种语言打包的镜像体积过大,导致镜像构建,下载速度慢,影响开发效率。


经过一系列实践,Cars.com 总结出来了通用镜像的方案:


·      采用 Alpine Linux 作为基础镜像

Alpine Linux 系统的文件大小非常小,可以达到5MB。


·      轻量级的容器


    - 删除 Package Manager 里面的所有Source。


    - 在软件安装完之后,删除安装包,删除没有用到的依赖,删除临时文件。


    - 剪裁官方镜像。剪裁 Node 镜像,Node 官方镜像最新版达到了649MB,他们将这个镜像缩减到55MB。JDK 缩减到122MB,Tomcat 从357MB 缩减到181MB。

 

在裁剪镜像大小的实践中,Artifactory 中的 Docker info 提供了帮助,可以在 Docker info 中看到每次打包的镜像 Layer 的实际大小,通过裁剪每层 Layer 的大小,最终达到缩小镜像的目的。



仓库的需求


每个团队都有管理包的需求,开发者要管理 Jar,War,静态文件,系统 Admin 要管理不同的 Linux 发行版,每种语言都用不同的包管理系统,维护这5,6种二进制包仓库非常麻烦,他们使用了 Artifactory 作为一站式包管理平台。理由:


·      本地搭建的仓库

大大提升所有语言构建,打包的速度。


·      支持 NPM modules,Docker 注册中心,Maven,Go。


·      支持 Linux 的包管理工具(RPM,Debian)。


·      和 Jenkins/Bamboo/MSBuild/TFS 等工具集成,收集构建信息。


·      元数据支持,并且提供 Rest API。


Cars.com 通过为 Docker 镜像,War 包设置元数据,使得任何包都可以通过 Artifactory Query Language  根据元数据,过滤出符合上线条件的包,打包到镜像里,部署到环境上。


封装 Docker API – PowerTrain


      为什么要封装Docker API?


·      需要即时响应快速上线,回滚,支持滚动升级,动态绑定端口。


·      保证开发者环境里能跑的应用,在生产环境里也能跑,实现不可变基础设施。


·      声明式配置管理。


PowerTrain 的配置文件 powertrain.mk 解决的问题是将不同环境中变化的部分,作为变量,存在文件里,当需要生成某个环境时,只需将需要的变量传递给 PowerTrain,即可获取对应环境所需的依赖,实现按需搭建环境。



PowerTrain 也封装了一些 Docker 的常用操作,例如 Docker build,pull,push 等等,在这基础之上增加的一些定制化的信息,来适应灵活的镜像构建和部署。利用 Docker 的轻量级部署特性,实现快速搭建环境,快速上线服务。PowerTrain 的具体的实现可以在 Carsdotcom 的 Github 上找到源代码。


持续集成流水线



·      开发提交代码到 Bitbucket。


·      Commit 触发 Jenkins 的 Webhook, 执行构建。


·      Jenkins 执行 PowerTrain build。


·      从 Artifactory 找到对应的 War 文件,基础镜像,构建出新的镜像。


·      快速搭建测试环境,使用 Docker 作为载体运行 war 包,进行测试(功能,接口,性能) 。


持续交付流水线



·      镜像通过测试,会升级到 Artifactory 的生产仓库。

·      通过 Jenkins 触发 PowerTrain 命令,部署到生产环境。


要部署到不同的环境,只需要执行不同的 powertrain.mk 文件,就能拉取不同的依赖,部署到不同的环境。


总结


Cars.com 通过一系列的实践,完成了从传统  Java Web 应用到容器化的转型。得到的收获:


·      使用 Docker 屏蔽之前5份环境的差异,实现一次构建,处处运行,大大减少运维中的重复性工作。使用  PowerTrain 的配置文件,让上线流程脚本化,实现不可变基础设施。


·      使用 Artifactory 作为多语言的本地仓库,大大提高获取第三方依赖,和管理自研件的效率。


·      剪裁 Docker 镜像,实现轻量级镜像发布,在突发流量到来时能够实现动态扩容,以及快速故障恢复。

作者;王青

目前任职 JFrog 中国首席架构师,之前在 IBM,HPE,爱奇艺,新浪,VIPKID 等公司做过研发和架构,是有十多年开发经验的互联网老兵,专注于软件生命周期管理,微服务架构,云原生应用,容器化等领域。

欢迎转载,但转载请注明作者与出处。谢谢!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值