docker 在乐视的实践之路
摘要:
现在docker 技术越来越火热,越来越多的公司开始使用docker技术,部署应用。这次分享主要是讲如何充分利用 docker 技术,实现代码到线上环境的部署。 以及在使用docker 中遇到的问题和困扰。
背景:
我们是在14年开始研究并使用docker,最开始主要想利用docker 解决组件化和服务的上线问题。现在慢慢演化成一个提供服务从代码环境到线上部署的一套解决方案。现在这套系统在内部我们称之为Harbor。
实战之路:
1.0 版本:
我们第一版采用docker-registry搭建了私有的镜像仓库,并使用python开发的命令行模式,对docker 主机和容器进行管理,使用APP->Service->Container 和主机集群的概念. 一个APP 下对应多个Service, 多个Service 组成一个App, 一个Servier对应多个容器,每个Server 都有对应的配置。
配置信息包括: 内存,名称,业务描述,镜像, 容器数量,export端口,环境变量等等。 提供基本的部署,删除容器,查看容器,添加主机集群等功能。可以将App部署在不同的主机集群中。
1.0 的架构比较简单, 我们在每个docker 主机上安装上一个python 写的agent 代理,专门向etcd 中注册容器和主机的信息,提供服务发现功能。
命令行工具在部署时候,根据etcd 中的信息,同时根据每个App 的配置采用不同的策略,通过调用docker的api将容器部署在不同的物理机或者虚拟机上。
部署策略保证同一个APP 下的多个容器尽量分散在不同的主机上,防止主机宕机,造成服务不可用。同时根据主机剩余可分配容器内存的概念,保证一个主机不会过量部署容器。
app - service –container 逻辑:
1.0结构如下:
1.0 版本 基本上能解决应用容器的快速部署,但是有很多缺陷:
- 用户或者开发人员需要直接写Dockerfile,自己通过docker build命令制作docker 镜像。 需要培训DockerFile语法,学习成本比较高。
- 用户的代码中加入了跟Docker有关的逻辑,比如Dockerfile,Volume。污染了用户或者开发人员的代码
- 镜像名称和版本定义没有统一的规范,而且存在镜像名称一样的风险。
- 没有可视化的操作界面,App 和容器数量到达一定规模,出现问题就不好排查。
- 不支持应用服务的灰度升级
- Server 升级时,需要先修改Server的配置信息,比如镜像版本,环境变量, export端口等等,一旦修改失败,想回退到上一版本,必须提前手工备份配置文件。
我们推广一段时间后,在1.0 基础上推出 1.5 版本:
1.5 版本在1.0 结构基础上,保留了App-Service-Container 概念,同时我们主要做了以下改善:
- 推荐用户或者开发人员,代码管理使用git。
- 使用Jenkins ,将用户和开发人员的代码与Jenkins 做关联,用户一旦在对应分支上提交代码或者打tag 会触发Jenkins相应的job自动构建镜像。实现了代码到镜像的自动构建。
- 使用tornado 搭建了一套可视化的web 服务,同时提供restapi接口。Web 界面集成了私有镜像仓库的镜像列表查询,和单个镜像版本查看的功能。 利用 web 界面上,用户和开发人员可以很方便的创建一个APP,并关联一个镜像。
- 提供统一的基础镜像,只需要用户提供一个Dockerfile 和start.sh 的脚本,前者用来定义运行环境,后者用来定义容器启动后所执行的操作,保证容器启动,服务也启动。
- 网络方面使用macvlan。
- 用户资源隔离,每个用户只能看到自己的容器和App, Service资源。
1.5 版本在一定程度上解决了代码到线上环境部署的问题,用户可以很直观的看到自己的App和容器资源。以及每个容器的运行状况。但是我们在内部推广的过程中,发现存在了很多不尽人意的地方:
- 必须向用户或者开发人员培训Docker, Jenkins的使用,Harbor 的使用,每一个系统或者技术的推广会耗费很大的精力去说明。
- 依然存在镜像名称冲突的风险
- 依然需要用户写dockerfile,将docker 的逻辑放在代码环境中,在一定程度上污染了代码。
- Jenkins个人感觉比较重,在查看镜像构建过程时,需要登录到Jenkins系统中去查看。
- App, Service 没有版本概念,无法做到基于版本的快速升级和回滚。
- 不能提供很好的进入容器的方法,用户只能在知道ip地址和密码后,通过ssh方式连接。
- macvlan需要专门给物理机划分vlan,需要专门的网络环境。
- 没有很好的应用资源隔离和共享机制,用户A创建的App或者容器资源,只能用户A看到,其他的用户无法查看,如果这时用户A离职,则需要人工的去转移资源。
2.0 版本 构建私有云环境。
2.0 在上一版本的基础上提出新的一些思路,整体的思路就是按照公有云的思想去构建私有云,并负责应用的开发到上线的整个生命周期:
- 用户资源隔离和成员管理,用户A的 APP应用或者主机集群资源可以通过添加成员的方式,来协助管理用户A的资源。也可以通过转移owner 的方式来转移资源的使用权。体现一种团队协作的概念。
- 去掉之前的Service 概念,改为AppGroup -> App ->Version->Container 的概念,一个Group 下包含多个App 应用,每个应用有多个版本 Version, 每个Version 可以包含多个Container.
每个应用版本包含了:镜像版本,描述,环境变量,export 端口,volume 映射,和其他高级配置(ssh,webssh密码)。每个容器都是根据版本的信息去创建。所以能很方便的实现容器的升级和回滚。 - 在原有docker-registry做了修改,加上权限的概念,防止创建相同的镜像名。并使用namespace,一个namespace下可以有多个镜像。在逻辑上可以表明这一组镜像的某种关联性。比如一个部门可以创建一个namespace,这个部门的镜像都放在这个namespace下。
- 公有集群和私有集群的概念,集群我们指的是一组docker 主机,物理机和虚拟机都可。公有集群对所有的用户开放,用户和开发人员可以将自己的App 应用部署在这些公有的集群上。 用户和开发人员可以随便创建自己的私有集群,并添加docker主机。应用可以部署在自己的集群中,实现私有集群的自我管理。公有集群网络方面可以使用macvlan和NAT模式。而私有集群,我们现在只给用户提供NAT方式,主要是方便开发人员和业务部门的接入。
- 提供Docker 环境一键部署的功能。业务部门分配下的主机资源可以很方便的部署docker 以及相关组件环境。
- 抛弃Jenkins,自己实现镜像构建。整合到一个界面中。 抛弃繁琐的Jenkins配置,用户和开发人员只需要在页面上选择所要创建镜像的基础镜像,输入git地址,分支名,镜像名,以及在界面上书写镜像构建脚本和镜像启动脚本即可。 同时在git库中,设定好系统给定的web hook url。当下一次提交代码后,会自动触发构建任务,并在页面中展示实时的构建过程。镜像版本强制使用: git tag + commit 号+ 配置变更数目 来命名,这一能方便用户和开发人员定位镜像版本和git的commit做关联。
下图展示的是我们镜像相关的操作:
构建日志:
镜像版本列表:
如何创建镜像:
镜像构建脚本:
服务启动脚本:
-
镜像分为基础镜像和业务镜像。基础镜像即包括我们提供的最基础的镜像(我们只提供了几个基本的基础镜像),也包括业务部门在我们提供基础镜像基础上修改的自己业务的基础镜像。 业务部门可以创建自己的基础镜像,下面的业务可以继承这个基础镜像。
如图:
- 支持应用的灰度上线, 开发人员或者业务部门在创建完新的app 版本后,可以 选择特定的容器进行升级,最终测试通过后,即可全部升级。
- 支持容器通过webssh 和ssh 两种方式访问。若不想通过ssh 访问容器资源,可以直接通过web的方式,访问容器内部资源,实现bug调试以及问题查询。
- 自动接入负载均衡, 智能负载均衡系统,我们使用nginx 实现,使用go 和etcd 实现nginx 配置自动下发。
- 支持事件操作记录,包括集群,镜像,应用的操作事件,方便以后的问题追踪,下图是应用的事件记录:
- 支持快速查看应用部署的拓扑结构,如下图:
第一层表示的是应用名,第二层表示的是应用所部署到的集群名称,第三层表示的应用的版本,第四层表示的是容器名称和运行状态. 用户可以在这里直接点击特定集群,创建特定版本的容器,具反馈,这是最受业务部门喜爱的功能之一。
2.0 版本在架构上 比1.5 版本上做了很大的改动,首先我们使用分层设计。
- 基础设施层面 docker 主机或者虚拟机,并安装用go 写的一个服务发现代理,go-registerd。
- 数据层包括etcd和数据库,消息队列以及docker-registry镜像仓库。 服务发现代理专门向etcd 中注册容器和主机信息。
- 执行层 主要包括异步任务处理:harbor-compute ,获取消息队列中的任务,执行比如容器的创建,删除,电源操作,镜像构建,上传等任务。可以处理大量的容器和镜像操作请求,镜像构建我们提供专门的服务器去提供镜像构建的操作,镜像构建完后,自动push到私有镜像仓库中。
- 调度层 marine,提供api接口,主要负责每个应用的容器部署调度,镜像构建的调度,以及集群,主机管理等等。当一个App需要创建容器时,根据所选的集群资源使用情况,以及容器数量等其他的配置进行资源决策,决定每个容器应该创建在哪个主机上,生成对应的任务,投放到消息队列中。
- 用户层,分为面向用户的开放系统:polaris和面向管理员的资源管理系统:ursa。
整体架构如下:
2.0 版本 从15年11月份上线以来,已经陆续创建了上百个应用,200多个镜像,几百台主机,每天构建镜像400多次,平均每天容器销毁和创建100余次。镜像容量在100G左右。
Harbor 基本上在乐视云计算有限公司内部成为了一个开放的容器平台,主机的添加,镜像的构建,应用容器的扩容,升级,回滚,现在已经完全实现开发人员和业务部门的自主管理。
开发人员和业务部门的学习成本由原来需要学习docker,Jenkins,harbor 变为单纯学习如何使用harbor 即可,而且省去了大量的旧有上线部署和配置手册,只需要学习如何升级容器即可。
下一步的任务:
随着社区容器编排系统越完善,我们也正研究kubernetes 和mesos, 也正充分借鉴开源社区的一些设计思路和理念
自我介绍:
张杰, 东北大学 软件工程
乐视云计算有限公司 云计算高级研发工程师, 容器私有云负责人,4年技术团队管理经验, 对新技术有着强烈的好奇心。
qq:695160664