【行云流水线实践】基于“OneBuild”方法对镜像进行快速装箱
在云原生领域,无论使用哪种编排调度平台,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”方法对镜像进行快速装箱的更多相关文章
- 基于SCRUM方法实践的西油计科党建设计与实现
基于SCRUM方法实践的西油计科党建设计与实现 序言 所属课程 https://edu.cnblogs.com/campus/xnsy/2019autumnsystemanalysisanddesig ...
- 基于SCRUM方法实践的西油计科党建设计与实现-个人实践流程清单
基于SCRUM方法实践的西油计科党建设计与实现 个人实践流程清单 一.Alpha版本冲刺个人在SCRUM团队任务清单: 时间 我这个三天做了什么 实际解决燃尽图项目数量 我遇到了什么问题 我下一个三天 ...
- 【敏捷研发系列】前端DevOps流水线实践
作者:胡骏 一.背景现状 软件开发从传统的瀑布流方式到敏捷开发,将软件交付过程中开发和测试形成快速的迭代交付,但在软件交付客户之前或者使用过程中,还包括集成.部署.运维等环节需要进一步优化交付效率.因 ...
- Spring-Context之六:基于Setter方法进行依赖注入
上文讲了基于构造器进行依赖注入,这里讲解基于Setter方法进行注入.在Java世界中有个约定(Convention),那就是属性的设置和获取的方法名一般是:set+属性名(参数)及get+属性名() ...
- 基于核方法的模糊C均值聚类
摘要: 本文主要针对于FCM算法在很大程度上局限于处理球星星团数据的不足,引入了核方法对算法进行优化. 与许多聚类算法一样,FCM选择欧氏距离作为样本点与相应聚类中心之间的非相似性指标,致使算法趋向 ...
- 微服务架构 - 基于Harbor构建本地镜像仓库
之前写过<搭建docker本地镜像仓库并提供权限校验及UI界面>文章,然后有同仁评论道这样做太复杂了,如果Harbor来搭建会更简单同时功能也更强大.于是抽时间研究了基于Harbor构建本 ...
- 基于 debian 操作系统的 docker 镜像,安装 vim
基于 debian 操作系统的 docker 镜像,安装 vim,步骤: apt-get update apt-get install vim 注意: 直接运行步骤2,可能会报错: Reading p ...
- UCP规模估算方法介绍 基于UCP方法的软件项目成本估计及其应用方法,软件,项目,UCP方法,应用,项目估算及软件及应用,软件估算,项目成本,软件项目
基于UCP方法的软件项目成本估计及其应用 UCP说明: UCP = 交易的UCP数 + Actor的UCP数,1.交易/Actor在估算时按复杂度分为简单.普通.复杂.主观类别,权重分别对应1.2.3 ...
- 基于“基于dockerhub的jetty镜像的ossfs镜像”部署war包,遇到的文件夹读写权限被限制的问题解决方案
前提: “基于dockerhub的jetty镜像的ossfs镜像” 已经搭建好了. 部署准备: 1.本地打包:war包-->idea工具 mvn 打包. 2.本地sh脚本:compile_vps ...
- 基于点云的3ds Max快速精细三维建模方法及系统的制作方法 插件开发
基于点云的3ds Max快速精细三维建模方法及系统的制作方法[技术领域][0001]本发明涉及数字城市三维建模领域,尤其涉及一种基于点云的3d ...
随机推荐
- Valine评论插件因为LeanCloud国内域名解析问题无法正常使用的解决方法
近日,LeanCloud 国内域名解析存在问题,Valine评论插件的评论内容都储存在LeanCloud,使用Valine评论插件的个人博客的评论及阅读数会显示失败. 关于 LeanCloud 国内域 ...
- MAUI Blazor项目中如何添加一个返回服务,并支持安卓返回键
前言 MAUI Blazor中,安卓项目的返回键体验很不好,只能如同浏览器一样返回上一页.但很多时候,我们想让他返回的上一页,不一定就是实际上的上一页.而且也想让返回键去支持一些事件,按下返回键触发, ...
- 通配符SSL证书自动续签自动部署方案
最开始接触 https 的时候一直是使用的 阿里云和腾讯云的免费 SSL证书,免费的SSL证书用了几年后,慢慢的部署https证书的项目越来越多,时间久了发现每个网站都需要一个 SSL证书,每个SSL ...
- java读取txt文件解决乱码问题
说明:由于txt文件有bom和不同的编码方式,导致导入数据时产生乱码,以下代码完美解决乱码问题. 参考他人代码,结合自己的业务加工完成,费了大半天功夫完成,希望对大家有点用处. 废话不多说,直接上代码 ...
- 医疗知识图谱问答 ——Neo4j 基本操作
前言 说到问答机器人,就不得不说一下 ChatGPT 啦.一个预训练的大预言模型,只要是人类范畴内的知识,似乎他回答得都井井有条,从写文章到写代码,再到解决零散琐碎的问题,不光震撼到我们普通人,就百度 ...
- ACl与ACL实验
ACl与ACL实验 ACL 1,ACL概述及 产生的背景 ACL: access list 访问控制列表 2,ACL应用 ACL两种应用: 应用在接口的ACL-----过滤数据包(原目ip地址,原目 ...
- Java 设计模式实战系列—单例模式
本文首发公众号:小码A梦 单例模式是设计模式中最简单一个设计模式,该模式属于创建型模式,它提供了一种创建实例的最佳方式. 单例模式的定义也比较简单:一个类只能允许创建一个对象或者实例,那么这个类就是单 ...
- 关于API数据接口获取商品的数据的说明
获取商品数据已经成为许多应用程序的重要组成部分.为了实现这一目标,许多公司和技术开发者使用API数据接口来获取相关数据.本文将详细介绍如何使用API数据接口获取商品数据,并使用Python作为编程 ...
- 快手商品详情API接口如何使用
使用快手开的API接口获取商品详情,可按照以下步骤进行: 1.注册账号并创建应用 注册开发者账号,并在账号后台中创建一个应用,获得AppKey和AppSecret等信息.这些信息是使用API接口访问快 ...
- springboot打包与依赖包分离
前言: springboot项目部署时,需要本地打包成一个jar放到服务器进行部署(使用jenkins自动打包部署同理),部署包里包含了其它所有依赖包,整个包会比较大,小则几M,大则几十上百. 正文: ...