【行云流水线实践】基于“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的对于中大型组织或者有快速交付需求的团队来讲,是非常有帮助的。

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

作者:京东科技 王晓飞

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/115416.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[JavaWeb]——过滤器filter与拦截器Interceptor的使用、执行过程、区别

🌈键盘敲烂,年薪30万🌈 目录 一、过滤器filter 概念介绍: 过滤器的使用: 过滤器的执行流程: 应用场景(登录校验): 二、拦截器Interceptor 概念介绍: 拦截器的使用&#xff1…

ios原生分享

什么是 ios 系统的原生分享呢,如下图所示 具体使用系统UIActivityViewController,完整代码如下: -(void)shareAny:(NSString *)text url:(NSString *)_url imagePath:(NSString *)_imagePath {NSLog("shareAny, text:%, url:%, imagePa…

FRI及相关SNARKs的Fiat-Shamir安全

1. 引言 本文主要参考: Alexander R. Block 2023年论文 Fiat-Shamir Security of FRI and Related SNARKsAlbert Garreta 2023年9月在ZK Summit 10上分享 ZK10: Fiat-Shamir security of FRI and related SNARKs - Albert Garreta (Nethermind) 评估参数用的Sage…

甲方自建ERP这事靠不靠谱?来听听读过中欧商学院的老板怎么说

李总自建ERP开发团队的失败案例,投入三年,花了五六百万,做出来的东西,远不如免费开源的Odoo软件。Odoo有强大的技术平台,有无穷的功能插件。李总现身说法:“早知道有Odoo,何必瞎折腾&#xff0c…

SAP IDOC 开发入门

1, 基本概念 IDOC技术在早起版本的R/3系统就已经集成了,不过国内真正用起来还是05年以后了,其实IDOC是很强大的,在主数据和一些业务数据同步方面,几乎不需要做任何开发就可以配置完成,例如BD11,BD13这些事…

3 Spring底层概念介绍

BeanDefinition BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点。比如: class,表示Bean类型 scope,表示Bean作用域,单例或原型等 lazyInit:表示Bean是否是懒加载 initM…

2.Docker基本架构简介与安装实战

1.认识Docker的基本架构 下面这张图是docker官网上的,介绍了整个Docker的基础架构,我们根据这张图来学习一下docker的涉及到的一些相关概念。 1.1 Docker的架构组成 Docker架构是由Client(客户端)、Docker Host(服务端)、Registry(远程仓库)组成。 …

C语言实现 1.在一个二维数组中形成 n 阶矩阵,2.去掉靠边元素,生成新的 n-2 阶矩阵;3.求矩阵主对角线下元素之和:4.以方阵形式输出数组。

矩阵形式: 1 1 1 1 1 2 1 1 1 1 3 2 1 1 1 4 3 2 1 1 5 4 3 2 1 完整代码: /*编写以下函数 1.在一个二维数组中形成如以下形式的 n 阶矩阵: 1 1 1 1 1 2 1 1 1 1 3 2 1 1 1 4 3 2 1 1 5 4 3 2 1 2.去掉…

【Vue3+Vite+bwip-js库】 生成DataMatrix码

前提条件 已存在的vue3vite架构前端项目对二维码分类有一定的了解 生成的码的样式如下&#xff08;DataMatrix&#xff09; 该二维码容量如下 详情见&#xff1a;DataMatrix介绍 Vue3Vite 导入 bwip-js生成DataMatrix 1. 安装 npm install bwip-js --save2. 引入使用 <…

基于STC12C5A60S2系列1T 8051单片机A/D转换器应用

基于STC12C5A60S2系列1T 8051单片机A/D转换器应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍STC12C5A60S2系列1T 8051单片机A/D转换器介绍STC12C5A60S2系列1T 805…

xlua源码分析(二)lua Call C#的无wrap实现

xlua源码分析&#xff08;二&#xff09;lua Call C#的无wrap实现 上一节我们主要分析了xlua中C# Call lua的实现思路&#xff0c;本节我们将根据Examples 03_UIEvent&#xff0c;分析lua Call C#的底层实现。例子场景里有一个简单的UI面板&#xff0c;面板中包含一个input fie…

3.线性神经网络-3GPT版

#pic_center R 1 R_1 R1​ R 2 R^2 R2 目录 知识框架No.1 线性回归基础优化算法一、线性回归1、买房案例2、买房模型简化3、线性模型4、神经网络5、损失函数6、训练数据7、参数学习8、显示解9、总结 二、 基础优化算法1、梯度下降2、学习率3、小批量随机梯度下降4、批量大小5、…

Qt 中model/View 架构 详解,以及案例实现相薄功能

model/View 架构 导读 ​ 我们的系统需要显示大量数据,比如从数据库中读取数据,以自己的方式显示在自己的应用程序的界面中。早期的 Qt 要实现这个功能,需要定义一个组件,在这个组件中保存一个数据对象,比如一个列表。我们对这个列表进行查找、插入等的操作,或者把修改…

HNU程序设计 练习五-函数

1.小熊买糖果 【问题描述】 小熊去到商店&#xff0c;选择了一种它非常喜欢的糖果&#xff0c;其单价为 k 元&#xff0c;假定商店里有无穷多的这种糖果。 它的父亲允许它花费任意多的10元硬币和一个 r 元硬币去购买&#xff0c;但不能找零&#xff0c;请帮助小熊确定它能购买…

EMC Unity存储系统如何查看SSD的使用寿命

为什么要写这个博客&#xff1f; 客户对老的EMC unity的存储系统要扩容&#xff0c;如何确定SSD磁盘是全新的还是拆机二手的&#xff1f;很多时候客户还有一个奇葩的要求&#xff0c;就是要和5年前的磁盘PN一致&#xff0c;甚至要求固件版本一致&#xff0c;最关键的还要求是全…

Leetcode刷题详解——反转链表

1. 题目链接&#xff1a;206. 反转链表 2. 题目描述&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1…

【java学习—十二】io流(1)

文章目录 1. 主要内容2. File类3. 练习题4. Java IO原理 1. 主要内容 java.io.File 类的使用&#xff08;计算机操作系统中的文件和文件夹&#xff09; IO原理及流的分类。 IO即input和output。 流的解释&#xff1a;     比如&#xff1a;通过程序把图片放到某一个文件…

pycharm 断点调试python Flask

以flask框架为例&#xff0c;其启动命令为 python app.py runserver 后面需要拼接runserver 点击开始断点 参考&#xff1a;https://www.cnblogs.com/bigtreei/p/14742015.html

Mac -- zsh-最新全网超详细的个性化终端(Terminal)颜色及vim颜色配置(亲测可行)

转自 Mac -- zsh-最新全网超详细的个性化终端(Terminal)颜色及vim颜色配置(亲测可行)_mac zsh-CSDN博客 以下都是苹果 设置&#xff0c;这是简化版的&#xff0c;详细的看我引用的 个性化终端颜色背景设置 显示检查器 打开终端&#xff0c;鼠标在终端中&#xff0c;右击&…

[PyTorch][chapter 60][强化学习-2-有模型学习2]

前言&#xff1a; 前面我们讲了一下策略评估的原理,以及例子. 强化学习核心是找到最优的策略&#xff0c;这里 重点讲解两个知识点&#xff1a; 策略改进 策略迭代与值迭代 最后以下面环境E 为例&#xff0c;给出Python 代码 。 目录&#xff1a; 1&#xff1a; 策略改进 2&…