二、 架构演进
1. Docker build机制
按照Docker官方文档给出的架构图,Docker主要分为Client,Host,Registry三个部分。
Docker按照C/S架构,通过Client与Host进行通信。Host作为后端,负责处理所有Client请求以及后端模块的调度及管理工作。Registry作为中心化的镜像仓库,存储所有需要保存的镜像。
此处,我们主要关注docker build命令。可以看到Host中Docker daemon模块负责接受和处理Client的命令请求。Docker daemon内部架构此处不做详细描述,只需要知道Docker daemon在接受到docker build命令之后,会启动一个create job去执行构建。在构建过程中,可能会需要到远程Regiestry中心镜像仓库拉取基础镜像(如果本地不存在的话)。在构建完成之后,Host会将构建好的镜像保存在本地的Repository中。
Docker daemon作为docker的服务端,由于需要系统的ROOT权限等要求,导致其不能天然地运行在另一个docker容器之中。这也为镜像构建云原生化提出了新的技术问题。
2. 初始态:Docker out of K8S
在Docker build机制的支持下,在最初阶段是通过在K8S外搭建构建机器做镜像的构建任务,其架构如下:
AppManager:是SREWorks的中心管控服务,负责与K8S底座交互,应用构建发布及生命周期管理等核心功能;在初始态,AppManager在需要执行镜像构建时,直接连接部署在K8S之外的某个ECS上Docker daemon来执行镜像构建。依然处于“On-Machine”的发展阶段。
这种方式的缺点包括但不限于:
• 安全性差:当这台ECS被劫持之后,恶意程序通过在镜像构建过程中注入非法代码,能够影响所有部署在云上的应用。
• 效率较低:当构建任务过多时,一起抢占ECS机器资源,会引起构建拥塞。
3. 过渡态:Docker out of Docker
Docker out of Docker,下面简称“DooD”,依然使用docker build机制的远程构建能力,每个执行构建任务的pod都连接到本地node的Docker daemon实现镜像构建。
通过DooD的方式,AppManager可以动态的在集群层面拉起pod去执行镜像构建任务,而不用再去跟集群外部服务打交道。镜像构建任务可以均匀的分布到每台node,避免构建拥塞。且DooD通过操作基础设施node节点,实现了一种“伪弹性构建”的能力。
DooD的缺点也是显而易见的:
• 实施成本高:需要人工为每台Node节点安装Docker daemon程序,并保证其正确运行。
• 安全性差:构建Pod有能力通过node节点Docker daemon进程影响其他Pod。
• 资源浪费:由于每台node节点都常置Docker daemon服务进程,不仅没有减少资源消耗,反而加重了资源浪费,这也是为什么称其为“伪弹性构建”。
4. 终态:Docker in Docker
Docker in Docker,下面简称“DinD”,与DooD是对应的,表示容器内client直接连接容器自身的Docker daemon进程来完成镜像构建任务。其架构如下:
DinD的架构,实现了按需拉起执行镜像构建任务的Pod,并在任务完成后及时归还Pod资源。构建任务的Pod也不再感知Node机器,所有管控及调度工作由K8S等云底座统一实现。
其优点包括:
• 弹性构建:所有构建Pod所需资源由K8S等云底座统一调度和回收。
• 安全可靠:构建Pod满足所有资源及权限管控要求,更加安全可控。
• 无服务器:Pod是容器化的,不再运行在ECS等机器之上。
• 快速交付:在集群层面完成构建任务调度,更加及时且可扩展。