【行云流水线实践】基于“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命名

1 2Dockerfile # 标准版 3 4Dockerfile.kylinv10 # kylinv10 base 版本 5 6Dockerfile.oel22 # openeuler base 版本 7 8 9

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

首先是 Dockerfile

1 2ARG ARCH 3 4ARG BUILD_IMAGE 5 6ARG BASE_IMAGE 7 8FROM ${BUILD_IMAGE} as builder 9 10 11ARG ARCH 12 13ENV GOPATH=/go 14 15 16COPY go.mod go.mod 17 18COPY go.sum go.sum 19 20COPY main.go main.go 21 22COPY api/ api/ 23 24COPY controllers/ controllers/ 25 26COPY pkg/ pkg/ 27 28COPY vendor/ vendor/ 29 30 31# Build 32 33RUN CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=${ARCH} go build --mod=vendor -a -o manager main.go 34 35 36ARG ARCH 37 38ARG BASE_IMAGE 39 40FROM ${BASE_IMAGE} 41 42 43ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simple 44 45ENV DEFAULT_FORKS=50 46 47ENV DEFAULT_TIMEOUT=600 48 49ENV DEFAULT_GATHER_TIMEOUT=600 50 51ENV TZ=Asia/Shanghai 52 53ENV PYTHONWARNINGS=ignore::UserWarning 54 55 56WORKDIR / 57 58COPY --from=builder /manager . 59 60 61COPY inventory/ inventory/ 62 63COPY roles/ roles/ 64 65COPY etcd-restore.yml etcd-restore.yml 66 67COPY facts.yml facts.yml 68 69COPY requirements.txt requirements.txt 70 71COPY inventory.tmpl.ini inventory.tmpl.ini 72 73COPY ansible.cfg ansible.cfg 74 75 76RUN yum -y install kde-l10n-Chinese && \ 77 78 yum -y reinstall glibc-common && \ 79 80 localedef -c -f UTF-8 -i zh_CN zh_CN.UFT-8 && \ 81 82 echo 'LANG="zh_CN.UTF-8"' > /etc/locale.conf && \ 83 84 source /etc/locale.conf && \ 85 86 yum clean all 87 88 89ENV LANG=zh_CN.UTF-8 90 91ENV LC_ALL=zh_CN.UTF-8 92 93 94RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ 95 96 echo $TZ > /etc/timezone && \ 97 98 yum install python3 python3-devel sshpass openssh-clients -y && \ 99 100 yum clean all && \ 101 102 /usr/bin/python3 -m pip --no-cache-dir install pip==21.3.1 -U -i $PIP3_SOURCE && \ 103 104 /usr/bin/python3 -m pip --no-cache-dir install -r requirements.txt -i $PIP3_SOURCE 105 106 107USER root 108 109 110ENTRYPOINT ["/manager"] 111 112 113

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

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

再看dockerfile.kylinv10

1 2ARG BASE_IMAGE 3 4FROM ${BASE_IMAGE} 5 6 7ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simple 8 9ENV DEFAULT_FORKS=50 10 11ENV LANG=en_US.UTF-8 12 13ENV DEFAULT_TIMEOUT=600 14 15ENV DEFAULT_GATHER_TIMEOUT=600 16 17ENV TZ=Asia/Shanghai 18 19ENV PYTHONWARNINGS=ignore::UserWarning 20 21 22WORKDIR / 23 24COPY --from=jdos-etcd-restore-helper:latest /manager / 25 26 27COPY inventory/ inventory/ 28 29COPY roles/ roles/ 30 31COPY etcd-restore.yml etcd-restore.yml 32 33COPY facts.yml facts.yml 34 35COPY requirements.txt requirements.txt 36 37COPY inventory.tmpl.ini inventory.tmpl.ini 38 39COPY ansible.cfg ansible.cfg 40 41 42RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ 43 44 echo $TZ > /etc/timezone && \ 45 46 yum install python3 python3-devel python3-pip sshpass openssh-clients -y && \ 47 48 /usr/bin/python3 -m pip --no-cache-dir install pip==21.3.1 -U -i $PIP3_SOURCE && \ 49 50 /usr/bin/python3 -m pip --no-cache-dir install -r requirements.txt -i $PIP3_SOURCE 51 52 53USER root 54 55 56ENTRYPOINT ["/manager"] 57 58 59

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

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

再看Dockerfile.oel22

1 2ARG BASE_IMAGE 3 4FROM ${BASE_IMAGE} 5 6 7ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simple 8 9ENV DEFAULT_FORKS=50 10 11ENV LANG=en_US.UTF-8 12 13ENV DEFAULT_TIMEOUT=600 14 15ENV DEFAULT_GATHER_TIMEOUT=600 16 17ENV TZ=Asia/Shanghai 18 19ENV PYTHONWARNINGS=ignore::UserWarning 20 21 22WORKDIR / 23 24COPY --from=jdos-etcd-restore-helper:latest /manager / 25 26 27COPY inventory/ inventory/ 28 29COPY roles/ roles/ 30 31COPY etcd-restore.yml etcd-restore.yml 32 33COPY facts.yml facts.yml 34 35COPY requirements.txt requirements.txt 36 37COPY inventory.tmpl.ini inventory.tmpl.ini 38 39COPY ansible.cfg ansible.cfg 40 41 42RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ 43 44 echo $TZ > /etc/timezone && \ 45 46 yum install python3 python3-devel python3-pip sshpass openssh-clients -y && \ 47 48 /usr/bin/python3 -m pip --no-cache-dir install pip==21.3.1 -U -i $PIP3_SOURCE && \ 49 50 /usr/bin/python3 -m pip --no-cache-dir install -r requirements.txt -i $PIP3_SOURCE 51 52 53USER root 54 55 56ENTRYPOINT ["/manager"] 57 58 59

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

脚本标准化

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

1 2# 支持shell语言代码的多行输入 3 4 5cd / 6 7 8sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}') 9 10 11git_commit=${output.Download_Code.GIT_LAST_COMMIT_SHA1} 12 13build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ') 14 15image_tag="${env.GenerateNewVersion}-${git_commit:0:6}" 16 17 18echo "start build image - standard" 19 20new_image_repo="${IMAGE_REPO}" 21 22sudo docker build -t ${new_image_repo}:${image_tag} -f Dockerfile --build-arg ARCH="amd64" . 23 24sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}') 25 26sudo docker push ${new_image_repo}:${image_tag} 27 28echo "end to build image - standard" 29 30echo "amd64ImageName=${new_image_repo}:${image_tag}" > ./amd64_output 31 32 33# 重新命名一个新镜像,供下级dockerfile进行多阶段构建时直接copy 34 35sudo docker tag ${new_image_repo}:${image_tag} jdos-etcd-restore-helper:latest 36 37 38# 条件性选择构建基于kylinv10OS的镜像 39 40if [[ -f Dockerfile.kylinv10 ]];then 41 42 echo "start build image - security - kylin base" 43 44 new_image_repo="${IMAGE_REPO}-kylinv10-amd64" 45 46 sudo docker build -t ${new_image_repo}:${image_tag} -f Dockerfile.kylinv10 --build-arg ARCH="amd64" . 47 48 sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}') 49 50 sudo docker push ${new_image_repo}:${image_tag} 51 52 echo "end to build image - security - kylin base" 53 54 echo "amd64KylinImageName=${new_image_repo}:${image_tag}" >> ./amd64_output 55 56fi 57 58 59# 条件性选择构建基于欧拉OS的镜像 60 61if [[ -f Dockerfile.oel22 ]];then 62 63 echo "start build image - security - openeuler22 base" 64 65 new_image_repo="${IMAGE_REPO}-openeuler22-amd64" 66 67 sudo docker build -t ${new_image_repo}:${image_tag} -f Dockerfile.oel22 --build-arg ARCH="amd64" . 68 69 sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}') 70 71 sudo docker push ${new_image_repo}:${image_tag} 72 73 echo "end to build image - security - openeuler22 base" 74 75 echo "amd64Oel22ImageName=${new_image_repo}:${image_tag}" >> ./amd64_output 76 77fi 78 79 80# 清理builder镜像,避免产生none垃圾镜像。 81 82sudo docker rmi jdos-etcd-restore-helper:latest --force 83 84 85

提升

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

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

讨论

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

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

作者:京东科技 王晓飞

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

点赞
收藏

评论区

加载中...

相关推荐

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

mysql中like用法

like的通配符有两种%(百分号):代表零个、一个或者多个字符。\(下划线):代表一个数字或者字符。1\.name以"李"开头wherenamelike'李%'2\.name中包含"云",“云”可以在任何位置wherenamelike'%云%'3\.第二个和第三个字符是0的值wheresalarylike'\00%'4\

2018云原生技术实践峰会CNBPS 重新定义云原生

!(https://oscimg.oschina.net/oscnet/ae5825ad14864f01837f7fe38f4e45f0.jpg)9月20日,2018云原生技术实践峰会(CloudNativeBestPracticesSummit)在北京悠唐皇冠假日酒店成功落幕。本次大会是云原生技术实践联盟(CNBPA)和灵雀云联合主办

2019 年 CNCF 中国云原生调查报告

!头图.jpg(https://ucc.alicdn.com/pic/developerecology/6db0c465111b4d9a96eb1ffe85c00e7a.jpg)中国72%的受访者生产中使用Kubernetes在CNCF,为更好地了解开源和云原生技术的使用,我们定期调查社区。这是第三次中国云原生调查,以中文进行

FLV文件格式

1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.