在云原生领域,无论使用哪种编排调度平台,Kubernetes,DockerSwarm,OpenShift等,业务都需要基于镜像进行交付,我们在内部实践“Source-to-image”和链式构建,总而总结出“OneBuild”模式。

其核心思想是:一处构建,多处使用。

问题

一般,我们会使用类似Jenkins CI系统来构建镜像,以满足持续集成,持续开发,持续交付等场景。事实上,如果我们在某一方面能够提升效率或者解决镜像交付实践。

长期来看,将能够带来不少的成本收益,并且对于平台来讲,这种收益是一种可度量收益。假设我们在当前交付(git)分支中,需要fix或者feature已经release分支的,如何进行?如果在已经交付给用户的镜像中存在漏洞,需要批量交付,如何进行?为了解决这些问题,我们的团队必须重新构建镜像,并且找出基本镜像,构建过程有那些依赖关系。然后基于这些成熟的流程和规范进行快速交付。

解决方案

Docker build是大家比较常用的镜像构建方法,并且在构建中只需要声明自己的Dockerfile即可,就可以实现快速构建。但是这并不满足大型企业实践以及快速交付。

所以需要一套规范且能够直接生产的流程,帮助在云原生下进行快速交付。下面我们讲结合行云平台进行“OneBuild”方法的实践。

悬衡而知乎,没规而知圆。因此,我们在团队的流水线建立和改造的过程中,尤其注重标准化。

包括dockerfile的命名和设计,构建代码的设计。由此新项目加入时,我们只需复制,然后做小工作量的改造即可。

行云Build

行云是JDT生产效率的标准化产品,是一个比较成熟的产品。用于支撑内部研发,测试,交付的平台。

Build是行云中一个子系统,用于研发过程中的持续集成,持续测试,持续构建等任务。

团队日常开发语言主要是以golang为主,并且在上线或交付制品中,也以Docker镜像为主。并且由于大多数时间,我们必须在真实的K8S环境中运行。

所以稳定的构建平台,高效,快速的构建,对我们的日常开发和交付都是至关重要,在构建中往往需要构建多版本镜像。所以围绕行云流水线,主要就是发掘功能,适配改造。

Dockerfile标准化

接下来,我们设计的流程,将会使用上一级构建的产品,对下级镜像进行快速装箱。

Dockerfile命名


Dockerfile # 标准版 Dockerfile.kylinv10 # kylinv10 base 版本 Dockerfile.oel22 # openeuler base 版本

下面我们继续看dockerfile中的细节。

首先是 Dockerfile


ARG ARCH ARG BUILD_IMAGE ARG BASE_IMAGE FROM ${BUILD_IMAGE} as builder ARG ARCH ENV GOPATH=/go COPY go.mod go.mod COPY go.sum go.sum COPY main.go main.go COPY api/ api/ COPY controllers/ controllers/ COPY pkg/ pkg/ COPY vendor/ vendor/ # Build RUN CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=${ARCH} go build --mod=vendor -a -o manager main.go ARG ARCH ARG BASE_IMAGE FROM ${BASE_IMAGE} ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simple ENV DEFAULT_FORKS=50 ENV DEFAULT_TIMEOUT=600 ENV DEFAULT_GATHER_TIMEOUT=600 ENV TZ=Asia/Shanghai ENV PYTHONWARNINGS=ignore::UserWarning WORKDIR / COPY --from=builder /manager . COPY inventory/ inventory/ COPY roles/ roles/ COPY etcd-restore.yml etcd-restore.yml COPY facts.yml facts.yml COPY requirements.txt requirements.txt COPY inventory.tmpl.ini inventory.tmpl.ini COPY ansible.cfg ansible.cfg RUN yum -y install kde-l10n-Chinese && \ yum -y reinstall glibc-common && \ localedef -c -f UTF-8 -i zh_CN zh_CN.UFT-8 && \ echo 'LANG="zh_CN.UTF-8"' > /etc/locale.conf && \ source /etc/locale.conf && \ yum clean all ENV LANG=zh_CN.UTF-8 ENV LC_ALL=zh_CN.UTF-8 RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ echo $TZ > /etc/timezone && \ yum install python3 python3-devel sshpass openssh-clients -y && \ yum clean all && \ /usr/bin/python3 -m pip --no-cache-dir install pip==21.3.1 -U -i $PIP3_SOURCE && \ /usr/bin/python3 -m pip --no-cache-dir install -r requirements.txt -i $PIP3_SOURCE USER root ENTRYPOINT ["/manager"]

上述dockerfile中,分为两个阶段构建,第一个阶段builder构建出需要的二进制。这与正常的dockerfile相同。

唯一不同的是,我们讲构建镜像和base镜像进行了参数化,这也使得当变更构建镜像和base镜像,我们只需要在构建时控制参数即可。

再看dockerfile.kylinv10


ARG BASE_IMAGE FROM ${BASE_IMAGE} ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simple ENV DEFAULT_FORKS=50 ENV LANG=en_US.UTF-8 ENV DEFAULT_TIMEOUT=600 ENV DEFAULT_GATHER_TIMEOUT=600 ENV TZ=Asia/Shanghai ENV PYTHONWARNINGS=ignore::UserWarning WORKDIR / COPY --from=jdos-etcd-restore-helper:latest /manager / COPY inventory/ inventory/ COPY roles/ roles/ COPY etcd-restore.yml etcd-restore.yml COPY facts.yml facts.yml COPY requirements.txt requirements.txt COPY inventory.tmpl.ini inventory.tmpl.ini COPY ansible.cfg ansible.cfg RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ echo $TZ > /etc/timezone && \ yum install python3 python3-devel python3-pip sshpass openssh-clients -y && \ /usr/bin/python3 -m pip --no-cache-dir install pip==21.3.1 -U -i $PIP3_SOURCE && \ /usr/bin/python3 -m pip --no-cache-dir install -r requirements.txt -i $PIP3_SOURCE USER root ENTRYPOINT ["/manager"]

发现了什么?在dockerfile.kylinv10中少了builder这一步,COPY --from=jdos-etcd-restore-helper:latest 是从一个指定的临时镜像中直接做了拷贝。这就直接复用了第一步dockerfile中构建出的产物。效率提升比较明显。

在dockerfile设计中,COPY是可以从一个指定的镜像中,copy指定的文件的。

再看Dockerfile.oel22


ARG BASE_IMAGE FROM ${BASE_IMAGE} ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simple ENV DEFAULT_FORKS=50 ENV LANG=en_US.UTF-8 ENV DEFAULT_TIMEOUT=600 ENV DEFAULT_GATHER_TIMEOUT=600 ENV TZ=Asia/Shanghai ENV PYTHONWARNINGS=ignore::UserWarning WORKDIR / COPY --from=jdos-etcd-restore-helper:latest /manager / COPY inventory/ inventory/ COPY roles/ roles/ COPY etcd-restore.yml etcd-restore.yml COPY facts.yml facts.yml COPY requirements.txt requirements.txt COPY inventory.tmpl.ini inventory.tmpl.ini COPY ansible.cfg ansible.cfg RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ echo $TZ > /etc/timezone && \ yum install python3 python3-devel python3-pip sshpass openssh-clients -y && \ /usr/bin/python3 -m pip --no-cache-dir install pip==21.3.1 -U -i $PIP3_SOURCE && \ /usr/bin/python3 -m pip --no-cache-dir install -r requirements.txt -i $PIP3_SOURCE USER root ENTRYPOINT ["/manager"]

是不是与dockerfile.kylinv10的思路非常相似,事实上,这两个文件已经可以合并了(内部为了向后兼容,没有合并这两个文件)。

脚本标准化

还需要在行云流水线中将shell脚本进行固化,与dockerfile进行配合。


# 支持shell语言代码的多行输入 cd / sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}') git_commit=${output.Download_Code.GIT_LAST_COMMIT_SHA1} build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ') image_tag="${env.GenerateNewVersion}-${git_commit:0:6}" echo "start build image - standard" new_image_repo="${IMAGE_REPO}" sudo docker build -t ${new_image_repo}:${image_tag} -f Dockerfile --build-arg ARCH="amd64" . sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}') sudo docker push ${new_image_repo}:${image_tag} echo "end to build image - standard" echo "amd64ImageName=${new_image_repo}:${image_tag}" > ./amd64_output # 重新命名一个新镜像,供下级dockerfile进行多阶段构建时直接copy sudo docker tag ${new_image_repo}:${image_tag} jdos-etcd-restore-helper:latest # 条件性选择构建基于kylinv10OS的镜像 if [[ -f Dockerfile.kylinv10 ]];then echo "start build image - security - kylin base" new_image_repo="${IMAGE_REPO}-kylinv10-amd64" sudo docker build -t ${new_image_repo}:${image_tag} -f Dockerfile.kylinv10 --build-arg ARCH="amd64" . sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}') sudo docker push ${new_image_repo}:${image_tag} echo "end to build image - security - kylin base" echo "amd64KylinImageName=${new_image_repo}:${image_tag}" >> ./amd64_output fi # 条件性选择构建基于欧拉OS的镜像 if [[ -f Dockerfile.oel22 ]];then echo "start build image - security - openeuler22 base" new_image_repo="${IMAGE_REPO}-openeuler22-amd64" sudo docker build -t ${new_image_repo}:${image_tag} -f Dockerfile.oel22 --build-arg ARCH="amd64" . sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}') sudo docker push ${new_image_repo}:${image_tag} echo "end to build image - security - openeuler22 base" echo "amd64Oel22ImageName=${new_image_repo}:${image_tag}" >> ./amd64_output fi # 清理builder镜像,避免产生none垃圾镜像。 sudo docker rmi jdos-etcd-restore-helper:latest --force

提升

基于以上,构建时间从21min缩短至7min,构建效率提升66%。我们总结出“OneBuild”方法:即构建一次,多处使用的思路。

标准化的shell与dockerfile进行配合,能够做到一次构建,多处使用。提升了构建效率。

讨论

上述完整介绍了多个镜像构建的流程和设计规范,也说明“OneBuild”可以进行快速构建的优点。所以OneBuild的对于中大型组织或者有快速交付需求的团队来讲,是非常有帮助的。

并且对效率的提升是可以看得见的。

作者:京东科技 王晓飞

来源:京东云开发者社区 转载请注明来源

【行云流水线实践】基于“OneBuild”方法对镜像进行快速装箱的更多相关文章

  1. 基于SCRUM方法实践的西油计科党建设计与实现

    基于SCRUM方法实践的西油计科党建设计与实现 序言 所属课程 https://edu.cnblogs.com/campus/xnsy/2019autumnsystemanalysisanddesig ...

  2. 基于SCRUM方法实践的西油计科党建设计与实现-个人实践流程清单

    基于SCRUM方法实践的西油计科党建设计与实现 个人实践流程清单 一.Alpha版本冲刺个人在SCRUM团队任务清单: 时间 我这个三天做了什么 实际解决燃尽图项目数量 我遇到了什么问题 我下一个三天 ...

  3. 【敏捷研发系列】前端DevOps流水线实践

    作者:胡骏 一.背景现状 软件开发从传统的瀑布流方式到敏捷开发,将软件交付过程中开发和测试形成快速的迭代交付,但在软件交付客户之前或者使用过程中,还包括集成.部署.运维等环节需要进一步优化交付效率.因 ...

  4. Spring-Context之六:基于Setter方法进行依赖注入

    上文讲了基于构造器进行依赖注入,这里讲解基于Setter方法进行注入.在Java世界中有个约定(Convention),那就是属性的设置和获取的方法名一般是:set+属性名(参数)及get+属性名() ...

  5. 基于核方法的模糊C均值聚类

    摘要: 本文主要针对于FCM算法在很大程度上局限于处理球星星团数据的不足,引入了核方法对算法进行优化.  与许多聚类算法一样,FCM选择欧氏距离作为样本点与相应聚类中心之间的非相似性指标,致使算法趋向 ...

  6. 微服务架构 - 基于Harbor构建本地镜像仓库

    之前写过<搭建docker本地镜像仓库并提供权限校验及UI界面>文章,然后有同仁评论道这样做太复杂了,如果Harbor来搭建会更简单同时功能也更强大.于是抽时间研究了基于Harbor构建本 ...

  7. 基于 debian 操作系统的 docker 镜像,安装 vim

    基于 debian 操作系统的 docker 镜像,安装 vim,步骤: apt-get update apt-get install vim 注意: 直接运行步骤2,可能会报错: Reading p ...

  8. UCP规模估算方法介绍 基于UCP方法的软件项目成本估计及其应用方法,软件,项目,UCP方法,应用,项目估算及软件及应用,软件估算,项目成本,软件项目

    基于UCP方法的软件项目成本估计及其应用 UCP说明: UCP = 交易的UCP数 + Actor的UCP数,1.交易/Actor在估算时按复杂度分为简单.普通.复杂.主观类别,权重分别对应1.2.3 ...

  9. 基于“基于dockerhub的jetty镜像的ossfs镜像”部署war包,遇到的文件夹读写权限被限制的问题解决方案

    前提: “基于dockerhub的jetty镜像的ossfs镜像” 已经搭建好了. 部署准备: 1.本地打包:war包-->idea工具 mvn 打包. 2.本地sh脚本:compile_vps ...

  10. 基于点云的3ds Max快速精细三维建模方法及系统的制作方法 插件开发

                                 基于点云的3ds Max快速精细三维建模方法及系统的制作方法[技术领域][0001]本发明涉及数字城市三维建模领域,尤其涉及一种基于点云的3d ...

随机推荐

  1. 快速切换 nodejs 的版本

    最近在开发一个常驻进程.定时任务统一调度系统,以应对开发在进程管理方面遇到的各种复杂问题. 组里开发项目,一般来说是一个人承包整个项目,包括调度器设计,还有后台系统.我还有一部分工作,是队列相关的信息 ...

  2. bzip2: (stdin) is not a bzip2 file.

    用tar -zxvf dir.tar.gz命令解压即可.

  3. [db2]缓冲池管理

    简介 缓冲池指的是从硬盘读取表和索引数据时,数据库管理器分配的用于高速缓存这些表和索引数据的内存区域.每个数据库都必须具有至少一个缓冲池,创建数据库时会自动创建一个名为IBMDEFAULTBP的缓冲池 ...

  4. 《CTFshow-Web入门》05. Web 41~50

    @ 目录 web41 题解 原理 web42 题解 原理 web43 题解 原理 web44 题解 原理 web45 题解 原理 web46 题解 原理 web47 题解 web48 题解 web49 ...

  5. 《SQL与数据库基础》15. 触发器

    目录 触发器 语法 示例-insert型触发器 示例-update型触发器 示例-delete型触发器 本文以 MySQL 为例 触发器 触发器是与表有关的数据库对象,指在 insert/update ...

  6. Go语言-Slice详解

    Go语言中的slice表示一个具有相同类型元素的可变长序列,语言本身提供了两个操作方法: 创建:make([]T,len,cap) 追加: append(slice, T ...) 同时slice支持 ...

  7. 《Hadoop3.X大数据开发实战(视频教学版)》新书来啦!

  8. 全景VR KRPano项目打包成安卓APP快速简易教程

    有时候,我们可能不想把我们制作的全景VR项目发布到网站上,而是想把它作为一个手机应用来使用或者分享.这样,我们就可以更好地保护我们的作品,也可以更方便地展示给客户或者朋友.本文将介绍一种简单的方法,让 ...

  9. 【matplotlib基础】--手绘风格

    Matplotlib 中有一个很有趣的手绘风格.如果不是特别严肃的分析报告,使用这个风格能给枯燥的数据分析图表带来一些活泼的感觉. 使用手绘风格非常简单,本篇主要手绘风格的效果以及如何配置中文的支持. ...

  10. 记一次 .NET 某电力系统 内存暴涨分析

    一:背景 1. 讲故事 前些天有位朋友找到我,说他生产上的程序有内存暴涨情况,让我帮忙看下怎么回事,最简单粗暴的方法就是让朋友在内存暴涨的时候抓一个dump下来,看一看大概就知道咋回事了. 二:Win ...