深入解析阿里 PouchContainer 如何实现容器原地升级
PouchContainer 是阿里巴巴集团开源的高效、轻量级企业级富容器引擎技术,拥有隔离性强、可移植性高、资源占用少等特性。可以帮助企业快速实现存量业务容器化,同时提高超大规模下数据中心的物理资源利用率。已助力阿里巴巴集团实现在线业务 100% 容器化,双 11 容器规模达到百万级。
背景
阿里巴巴集团内部,容器使用方式有很大一部分是富容器模式,像这种基于传统虚拟机运维模式下的富容器,其中也有一定数量容器仍然是有状态的。有状态服务的更新和升级是企业内部频率很高的一个日常操作,对于以镜像为交付的容器技术来说,服务的更新和升级,对应的容器操作实际上是两步:旧镜像容器的删除,以及新镜像容器的创建。而有状态服务的升级,则要求保证新容器必须继承旧容器所有的资源,比如网络、存储等信息。下面给出两个实际的业务案例来直观阐述富容器业务发布场景需求:
客户案例一:某数据库业务,在第一次创建容器服务时,会将远程的数据下载到本地,作为数据库的初始数据。因为数据库初始化过程会比较长,所以在之后可能存在的服务升级过程中,新容器需要继承旧容器的存储数据,来降低业务发布的时间;
客户案例二:某中间件服务,业务采取服务注册的模式,即所有新扩容的容器 IP 必须首先注册到服务器列表中,否则新扩容业务容器不可用。在业务容器每次升级发布时,需要保证新容器继承旧容器 IP,否则会导致新发布的服务不可用。
现在很多企业都是使用 Moby(2017 年 Docker 更名为 Moby) 作为容器引擎,但 Moby 的所有 API 中并没有一个接口来对标容器升级这一操作。而组合 API 的方式,必然会增加很多 API 请求次数,比如需要请求容器的增删 API,需要请求 IP 保留的 API 等等,还可能增加升级操作失败的风险。
基于以上背景,PouchContainer 在容器引擎层面提供了一个 upgrade
接口,用于实现容器的原地升级功能。将容器升级功能下沉到容器引擎这一层来做,对于操作容器相关资源更加方便,并且减少很多 API 请求,让容器升级操作变得更加高效。
Upgrade 功能具体实现
容器底层存储介绍
PouchContainer 底层对接的是 Containerd v1.0.3 ,对比 Moby,在容器存储架构上有很大的差别,所以在介绍 PouchContainer 如何实现容器原地升级功能之前,有必要先简单介绍一下在 PouchContainer 中一个容器的存储架构:
对比 Moby 中容器存储架构,PouchContainer 主要不一样的地方:
PouchContainer 中没有了 GraphDriver 和 Layer 的概念,新的存储架构里引入了 Snapshotter 和 Snapshot,从而更加拥抱 CNCF 项目 containerd 的架构设计。Snapshotter 可以理解为存储驱动,比如 overlay、devicemapper、btrfs 等。Snapshot 为镜像快照,分为两种:一种只读的,即容器镜像的每一层只读数据;一种为可读写的,即容器可读写层,所有容器增量数据都会存储在可读写 Snapshot 中;
Containerd 中容器和镜像元数据都存储在 boltdb 中,这样的好处是每次服务重启不需要通过读取宿主机文件目录信息来初始化容器和镜像数据,而是只需要初始化 boltdb。
Upgrade 功能需求
每一个系统和功能设计之初,都需要详细调研该系统或功能需要为用户解决什么疼点。经过调研阿里内部使用容器原地升级功能的具体业务场景,我们对 upgrade
功能设计总结了三点要求:
数据一致性
灵活性
鲁棒性
数据一致性指 upgrade
前后需要保证一些数据不变:
网络:升级前后,容器网络配置要保持不变;
存储:新容器需要继承旧容器的所有 volume ;
Config:新容器需要继承旧容器的某一些配置信息,比如 Env, Labels 等信息;
灵活性指 upgrade
操作在旧容器的基础上,允许引入新的配置:
允许修改新容器的 cpu、memory 等信息;
对新的镜像,即要支持指定新的
Entrypoint
,也要允许继承旧容器的Entrypoint
;支持给容器增加新的 volume,新的镜像中可能会包含新的 volume 信息,在新建容器时,需要对这部分 volume 信息进行解析,并创建新的 volume。
鲁棒性是指在进行容器原地升级操作期间,需要对可能出现的异常情况进行处理,支持回滚策略,升级失败可以回滚到旧容器。
Upgrade 功能具体实现
Upgrade API 定义
首先说明一下 upgrade
API 入口层定义,用于定义升级操作可以对容器的哪些参数进行修改。如下 ContainerUpgradeConfig
的定义,容器升级操作可以对容器 ContainerConfig
和 HostConfig
都可以进行操作,如果在 PouchContainer github 代码仓库的 apis/types
目录下参看这两个参数的定义,可以发现实际上,upgrade
操作可以修改旧容器的所有相关配置。
// ContainerUpgradeConfig ContainerUpgradeConfig is used for API "POST /containers/upgrade".
// It wraps all kinds of config used in container upgrade.
// It can be used to encode client params in client and unmarshal request body in daemon side.
//
// swagger:model ContainerUpgradeConfigtype ContainerUpgradeConfig struct {ContainerConfig// host configHostConfig *HostConfig `json:"HostConfig,omitempty"`
}
Upgrade 详细操作流程
容器 upgrade
操作,实际上是在保证网络配置和原始 volume 配置不变的前提下,进行旧容器的删除操作,以及使用新镜像创建新容器的过程,如下给出了 upgrade
操作流程的详细说明:
首先需要备份原有容器的所有操作,用于升级失败之后,进行回滚操作;
更新容器配置参数,将请求参数中新的配置参数合并到旧的容器参数中,使新配置生效;
镜像
Entrypoint
参数特殊处理:如果新的参数中指定了Entrypoint
参数,则使用新的参数;否则查看旧容器的Entrypoint
,如果该参数是通过配置参数指定,而不是旧镜像中自带的,则使用旧容器的Entrypoint
作为新容器的Entrypoint
;如果都不是,最后使用新镜像中的Entrypoint
最为新创建容器的Entrypoint
。对新容器Entrypoint
这样处理的原因是为了保持容器服务入口参数的连续性。判断容器的状态,如果是 running 状态的容器,首先 stop 容器;之后基于新的镜像创建一个新的 Snapshot 作为新容器读写层;
新的 Snapshot 创建成功之后,再次判断旧容器升级之前的状态,如果是 running 状态,则需要启动新的容器,否则不需要做任何操作;
最后进行容器升级清理工作,删掉旧的 Snapshot,并将最新配置进行存盘。
Upgrade 操作回滚
upgrade
操作可能会出现一些异常情况,现在的升级策略是在出现异常情况时,会进行回滚操作,恢复到原来旧容器的状态,在这里我们需要首先定义一下 升级失败情况 :
给新容器创建新的资源时失败,需要执行回滚操作:当给新容器创建新的 Snapshot,Volumes 等资源时,会执行回滚操作;
启动新容器出现系统错误时,需要执行回滚操作:即在调用 containerd API 创建新的容器时如果失败则会执行回滚操作。如果 API 返回正常,但容器内的程序运行异常导致容器退出的情况,不会执行回滚操作。
如下给出了回滚操作的一个基本操作:
defer func() {if !needRollback {return}// rollback to old container.c.meta = &backupContainerMeta// create a new containerd container.if err := mgr.createContainerdContainer(ctx, c); err != nil {logrus.Errorf("failed to rollback upgrade action: %s", err.Error())if err := mgr.markStoppedAndRelease(c, nil); err != nil {logrus.Errorf("failed to mark container %s stop status: %s", c.ID(), err.Error())}}
}()
在升级过程中,如果出现异常情况,会将新创建的 Snapshot 等相关资源进行清理操作,在回滚阶段,只需要恢复旧容器的配置,然后用恢复后的配置文件启动一个新容器既可。
Upgrade 功能演示
使用
ubuntu
镜像创建一个新容器:
$ pouch run --name test -d -t registry.hub.docker.com/library/ubuntu:14.04 top
43b75002b9a20264907441e0fe7d66030fb9acedaa9aa0fef839ccab1f9b7a8f$ pouch ps
Name ID Status Created Image Runtime
test 43b750 Up 3 seconds 3 seconds ago registry.hub.docker.com/library/ubuntu:14.04 runc
将
test
容器的镜像升级为busybox
:
$ pouch upgrade --name test registry.hub.docker.com/library/busybox:latest top
test
$ pouch ps
Name ID Status Created Image Runtime
test 43b750 Up 3 seconds 34 seconds ago registry.hub.docker.com/library/busybox:latest runc
如上功能演示,通过 upgrade
接口,直接将容器的镜像替换为新的镜像,而其他配置都没有变化。
总结
在企业生产环境中,容器 upgrade
操作和容器扩容、缩容操作一样也是的一个高频操作,但是,不管是在现在的 Moby 社区,还是 Containerd 社区都没有一个与该操作对标的 API,PouchContainer 率先实现了这个功能,解决了容器技术在企业环境中有状态服务更新发布的一个痛点问题。PouchContainer 现在也在尝试与其下游依赖组件服务如 Containerd 保持紧密的联系,所以后续也会将 upgrade
功能回馈给 Containerd 社区,增加 Containerd 的功能丰富度。
深入解析阿里 PouchContainer 如何实现容器原地升级相关推荐
- 深度解析 PouchContainer 的富容器技术
PouchContainer 是阿里巴巴集团开源的高效.轻量级企业级富容器引擎技术,拥有隔离性强.可移植性高.资源占用少等特性.可以帮助企业快速实现存量业务容器化,同时提高超大规模下数据中心的物理资源 ...
- 技术解析系列 | PouchContainer 富容器技术
划重点 本文将从什么是富容器.富容器适用场景.富容器技术实现三个角度全方位向大家解释富容器技术,同时对富容器感兴趣的同学可以扫描文章末尾二维码参与关于富容器的技术讨论.本文作者 PouchContai ...
- 技术解析系列 | PouchContainer CRI的设计与实现
1. CRI简介 在每个Kubernetes节点的最底层都有一个程序负责具体的容器创建删除工作,Kubernetes会对其接口进行调用,从而完成容器的编排调度.我们将这一层软件称之为容器运行时(Con ...
- 源码解析 使用tomcat作为web容器时,用到的外观模式
源码解析 使用tomcat作为web容器时,接收浏览器发送过来的请求, tomcat会将请求信息封装成ServletRequest对象, 如下图①处对象. 但是大家想想ServletRequest是一 ...
- 阿里云宣布 Serverless 容器服务 弹性容器实例 ECI 正式商业化
1月2日,阿里云宣布弹性容器实例 ECI(Elastic Container Instance)正式商业化,ECI 是阿里云践行普惠的云计算理念,将 Serverless 和 Container 技术 ...
- 连续两年入选Gartner公共云容器,阿里云在边缘容器方面做了什么?
最近,Gartner发布了2020年公共云容器报告,阿里云连续两年成为唯一入选的中国企业.报告显示,阿里云容器服务在中国市场表现强劲,产品形态丰富,在 Serverless 容器.服务网格.安全沙箱容 ...
- 群辉默认DDNS功能解析阿里云-自定义服务商
前言 前不久买了个群辉NAS发现群辉DDNS不能解析阿里云,后来找了很多教程都是部署Docker或使用其他平台转发一下,然而这些平台还要注册,我就在想我自己可不可以实现不需要注册就可以使用的DDNS, ...
- 阿里云专有云容器服务弹性伸缩最佳实践
简介:阿里云专有云容器服务弹性伸缩最佳实践 1.容器服务弹性伸缩简介 本小节将基于使用原理对容器服务弹性伸缩进行简要的描述. 本实践基于K8s的业务集群运行在专有云上,对测试业务进行压力测试,主要基于 ...
- 《机器学习在线 解析阿里云机器学习平台》读书笔记
原文 最近读了阿里的<大数据之路-阿里巴巴大数据实践>,对于其机器学习平台也蛮感兴趣,正好阿里出了本新书<解析阿里云机器学习平台>,顺便读了下,感触也不少,结合最近团队机器学习 ...
最新文章
- VMware 修改虚拟机网络_虚拟机问题解决
- linux c++ 程序运行时间,总结UNIX/LINUX下C++程序计时的方法
- 敏捷毒药-敏捷中有损组织整体的负面实践
- leetcode 219. 存在重复元素 II(规定步长)
- MyReport报表引擎2.2.0.0新功能
- layout_gravity
- AtCoder Regular Contest 059
- Pytorch(3)-数据载入接口:Dataloader、datasets
- python win32ui_Python创建普通菜单示例【基于win32ui模块】
- java jdk安装与环境变量配置
- 查找最接近的元素c语言,查找最接近的元素
- 50.Linux/Unix 系统编程手册(下) -- 虚拟内存操作
- 数据结构C语言版稀疏矩阵实验报告,数据结构稀疏矩阵基本运算实验报告..doc
- Atitit 前端算法技术体系总结 目录 1. 3. Ui方面的算法 3	2 3.1. 软键盘算法 计算软键盘上下左右按键位置 3	2 3.2. Sprire生成随机位置算法 随机数算法 3
- 奥鹏秋季计算机基础,14秋季奥鹏东北师范大学计算机应用基础离线作业
- xserver源码分析
- 三维电子沙盘数字沙盘无人机倾斜摄影三维建模教程第45课
- 网易微专业 前端工程师 学习笔记
- 页面置换算法之 LRU算法
- Revit 参数说明
热门文章
- linux php-fpm优化 php-fpm.conf 重要参数详解
- deepin 安装 kvm-manager
- 5、Java Swing JButton:按钮组件
- win7删除控制面板中的JAVA”
- 1139 First Contact (30 分)【难度: 一般 / 知识点: 模拟】
- vector相关习题
- Redis的Set操作
- 计算机的组成_计算机网络的组成和分类
- android view使用方法,Android View构造方法第三参数使用方法详解
- RocketMQ入门到入土(一)新手也能看懂的原理和实战!