【行云流水线实践】基于“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 ARCHARG BUILD_IMAGEARG BASE_IMAGEFROM ${BUILD_IMAGE} as builderARG ARCHENV GOPATH=/goCOPY go.mod go.modCOPY go.sum go.sumCOPY main.go main.goCOPY api/ api/COPY controllers/ controllers/COPY pkg/ pkg/COPY vendor/ vendor/# BuildRUN CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=${ARCH} go build --mod=vendor -a -o manager main.goARG ARCHARG BASE_IMAGEFROM ${BASE_IMAGE}ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simpleENV DEFAULT_FORKS=50ENV DEFAULT_TIMEOUT=600ENV DEFAULT_GATHER_TIMEOUT=600ENV TZ=Asia/ShanghaiENV PYTHONWARNINGS=ignore::UserWarningWORKDIR /COPY --from=builder /manager .COPY inventory/ inventory/COPY roles/ roles/COPY etcd-restore.yml etcd-restore.ymlCOPY facts.yml facts.ymlCOPY requirements.txt requirements.txtCOPY inventory.tmpl.ini inventory.tmpl.iniCOPY ansible.cfg ansible.cfgRUN 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 allENV LANG=zh_CN.UTF-8ENV LC_ALL=zh_CN.UTF-8RUN 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_SOURCEUSER rootENTRYPOINT ["/manager"]
上述dockerfile中,分为两个阶段构建,第一个阶段builder构建出需要的二进制。这与正常的dockerfile相同。
唯一不同的是,我们讲构建镜像和base镜像进行了参数化,这也使得当变更构建镜像和base镜像,我们只需要在构建时控制参数即可。
再看dockerfile.kylinv10
ARG BASE_IMAGEFROM ${BASE_IMAGE}ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simpleENV DEFAULT_FORKS=50ENV LANG=en_US.UTF-8ENV DEFAULT_TIMEOUT=600ENV DEFAULT_GATHER_TIMEOUT=600ENV TZ=Asia/ShanghaiENV PYTHONWARNINGS=ignore::UserWarningWORKDIR /COPY --from=jdos-etcd-restore-helper:latest /manager /COPY inventory/ inventory/COPY roles/ roles/COPY etcd-restore.yml etcd-restore.ymlCOPY facts.yml facts.ymlCOPY requirements.txt requirements.txtCOPY inventory.tmpl.ini inventory.tmpl.iniCOPY ansible.cfg ansible.cfgRUN 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_SOURCEUSER rootENTRYPOINT ["/manager"]
发现了什么?在dockerfile.kylinv10中少了builder这一步,COPY --from=jdos-etcd-restore-helper:latest 是从一个指定的临时镜像中直接做了拷贝。这就直接复用了第一步dockerfile中构建出的产物。效率提升比较明显。
在dockerfile设计中,COPY是可以从一个指定的镜像中,copy指定的文件的。
再看Dockerfile.oel22
ARG BASE_IMAGEFROM ${BASE_IMAGE}ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simpleENV DEFAULT_FORKS=50ENV LANG=en_US.UTF-8ENV DEFAULT_TIMEOUT=600ENV DEFAULT_GATHER_TIMEOUT=600ENV TZ=Asia/ShanghaiENV PYTHONWARNINGS=ignore::UserWarningWORKDIR /COPY --from=jdos-etcd-restore-helper:latest /manager /COPY inventory/ inventory/COPY roles/ roles/COPY etcd-restore.yml etcd-restore.ymlCOPY facts.yml facts.ymlCOPY requirements.txt requirements.txtCOPY inventory.tmpl.ini inventory.tmpl.iniCOPY ansible.cfg ansible.cfgRUN 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_SOURCEUSER rootENTRYPOINT ["/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进行多阶段构建时直接copysudo docker tag ${new_image_repo}:${image_tag} jdos-etcd-restore-helper:latest# 条件性选择构建基于kylinv10OS的镜像if [[ -f Dockerfile.kylinv10 ]];thenecho "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_outputfi# 条件性选择构建基于欧拉OS的镜像if [[ -f Dockerfile.oel22 ]];thenecho "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_outputfi# 清理builder镜像,避免产生none垃圾镜像。sudo docker rmi jdos-etcd-restore-helper:latest --force
提升
基于以上,构建时间从21min缩短至7min,构建效率提升66%👊。我们总结出“OneBuild”方法:即构建一次,多处使用的思路。
标准化的shell与dockerfile进行配合,能够做到一次构建,多处使用。提升了构建效率。
讨论
上述完整介绍了多个镜像构建的流程和设计规范,也说明“OneBuild”可以进行快速构建的优点。所以OneBuild的对于中大型组织或者有快速交付需求的团队来讲,是非常有帮助的。
并且对效率的提升是可以看得见的。
作者:京东科技 王晓飞
来源:京东云开发者社区 转载请注明来源
相关文章:
【行云流水线实践】基于“OneBuild”方法对镜像进行快速装箱 | 京东云技术团队
在云原生领域,无论使用哪种编排调度平台,Kubernetes,DockerSwarm,OpenShift等,业务都需要基于镜像进行交付,我们在内部实践“Source-to-image”和链式构建,总而总结出“OneBuild”模式。 其核心…...
软件开发必备神器!一文读懂10款热门看板工具推荐!
看板(Kanban)是一种流行的框架,用于实施敏捷和DevOps软件开发。它要求实时沟通每个人的能力,并全面透明地展示正在进行的工作。工作项目在看板上以可视化方式表示,使项目经理和所有团队成员可以随时查看每个工作的状态…...
怎样提取视频提取的人声或伴奏?
有些小伙伴们进行音视频创作时,可能会需要提取音频的人声或者是伴奏。这里给大家推荐一个音分轨人声分离软件,支持一键提取音频人声和一键提取伴奏功能,可批量导入文件同步提取,简单高效,是音视频创作者的不二选择&…...
SpringBoot概述
SpringBoot是Spring提供的一个子项目,用于快速构建Spring应用程序。 SpringFramework:核心功能SpringData:数据获取SpringSecurity:认证授权SpringAMQP:消息传递SpringCloud:服务治理 SpringBoot新特性&…...
深度学习框架TensorFlow.NET环境搭建1(C#)
测试环境 visual studio 2017 window10 64位 测试步骤如下: 1 新建.net framework控制台项目,工程名称为TensorFlowNetDemo,.net framework的版本选4.7.2,如下图: 2 分别安装TensorFlow.NET包(先装)和SciSharp.…...
Git客户端软件 Tower mac中文版特点说明
Tower mac是一款Mac OS X系统上的Git客户端软件,它提供了丰富的功能和工具,帮助用户更加方便地管理和使用Git版本控制系统。 Tower mac软件特点 1. 界面友好:Tower的界面友好,使用户能够轻松地掌握软件的使用方法。 2. 多种Git操…...
详解IPD需求分析工具$APPEALS
够让企业生存下去的是客户,所以,众多企业提出要“以客户为中心”,那如何做到以客户为中心?IPD中给出的答案是需求管理。 需求管理流程,是IPD(集成管理开发)体系中的四大支撑流程之一࿰…...
318. 最大单词长度乘积
这道题求没有重复字母的两个字符串的最大长度乘积 重点在于怎么判断两个字符串没有重复字母 题目中只有小写字母,最多26个,于是想到使用26位二进制数来代表每一个字符串 有哪个字母就在对应位置设1 这个转换使用的是num | 1 << (c-a); 对字符串中的…...
.NET Core 中插件式开发实现
在 .NET Framework 中,通过AppDomain实现动态加载和卸载程序集的效果;但是.NET Core 仅支持单个默认应用域,那么在.NET Core中如何实现【插件式】开发呢? 一、.NET Core 中 AssemblyLoadContext的使用 1、AssemblyLoadContext简…...
并查集模版以及两道例题
💯 博客内容:并查集 😀 作 者:陈大大陈 🚀 个人简介:一个正在努力学技术的准C后端工程师,专注基础和实战分享 ,欢迎私信! 💖 欢迎大家:这里是C…...
英飞凌TLF35584规格书中文
官网: 英飞凌TLF35584QVVS2 TLF35584_SPI: 1 Overview2 Block Diagram3 Pin Configuration3.1 Pin Assignment - PG-VQFN-48 4 General Product Characteristics4.1 Absolute Maximum Ratings 绝对最大额定值4.2 Functional Range4.3 Thermal Resistance…...
【教3妹学编程-算法题】最大单词长度乘积
3妹:哇,今天好冷啊, 不想上班。 2哥:今天气温比昨天低8度,3妹要空厚一点啊。 3妹 : 嗯, 赶紧把我的羽绒服找出来穿上! 2哥:哈哈,那倒还不至于, 不过气温骤降&…...
遇到python程序是通过sh文件启动的,如何调试
说明 下载的源码总会遇到这样启动的: 并且发现shell文件内容很多,比较复杂,比如: 解决方案 这时候想要调试,可以通过端口连接的方式调试,具体方法如下: 在vscode调试按钮中添加远程附加调试…...
应用系统集成-Spring Integration
应用系统集成-Spring Integration 图1 EIP 消息系统模式全景图。 Spring Integration 是系统集成的一个实现框架,提供了对EIP核心概念:Endpoint、Message、Channel、Router、Translator的抽象及相关框架实现,使得基于Spring Integration进行…...
亚马逊与TEMU平台欧代英代如何注册?注册欧代/英代流程及注意事项
亚马逊与TEMU平台欧代英代如何注册?注册欧代/英代流程及注意事项 亚马逊平台的商家的产品,由于受到欧盟商品安全新法规市场监管法规欧盟要求所有标有CE标志的商品,都要拥有欧盟境内的欧代作为商品合规的联系方式(也称为负责人)。由于英国脱离…...
【嵌入式开发工具】STM32+Keil实现软件工程搭建与开发调试
本篇文章介绍了使用Keil来对STM32F103C8芯片进行初始工程搭建,以及开发与工程调试的完整过程,帮助读者能够在实战中体会到Keil这个开发环境的使用方法,了解一个嵌入式工程从无到有的过程,并且具备快速搭建一个全新芯片对应最小软件…...
python 去除图像中的框
最近在做图像标注,会出现以下的图片,需要去除其中的边框。 1.思路 人工标注画框的范围P,并使用标注工具在画框上画一个点A。获取点A的坐标和颜色。在范围P内,将与点A颜色相似的每一个点x的颜色,替换为点x上下&#…...
企业邀约媒体的方式方法?-(快速精准)
传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 快速而精确地邀约媒体通常需要有计划和策略性的方法。以下是一些方法,可以帮助企业有效地邀请媒体: 1. 媒体列表构建:首先,建立一个精心筛…...
旅游业为什么要选择VR全景,VR全景在景区旅游上有哪些应用
引言: VR全景技术的引入为旅游业带来了一场变革。这项先进技术不仅提供了前所未有的互动体验,还为景区旅游文化注入了新的生机。 一.VR全景技术:革新旅游体验 1.什么是VR全景技术? VR全景技术是一种虚拟现实技术&am…...
搭建第一个区块链网络与一键部署WeBASE步骤
官网 搭建第一个区块链网络 — FISCO BCOS v2 v2.9.0 文档 (fisco-bcos-documentation.readthedocs.io) 一键部署 — WeBASE v1.5.5 文档 (webasedoc.readthedocs.io) 步骤 默认如MySQL、Python、java等依赖已经引入 1.创建操作目录, 下载安装脚本 创建操作目录 cd ~ &a…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
