写点什么

使用 Jenkins 和 Docker 确保构建环境和生产环境之间的对等

  • 2019-08-26
  • 本文字数:2541 字

    阅读完需:约 8 分钟

使用Jenkins和Docker确保构建环境和生产环境之间的对等

持续交付(CD)的核心原则之一是,测试需要在“类似生产”的环境中运行,以保证发布版本的稳定性。类似相同的环境可以减少“在我的机器上可以运行”之类的问题,并能轻松地在本地复现问题。我们可以避免由于平台差异引起的 bug,比如证书丢失或过期。


Docker 是实现这种对等性的最佳工具之一。它还允许我们将构建与 Jenkins 基础设施分离。比如,使用基于 Docker 的构建,我们无需担心预先安装在 Jenkins 代理上的 Java 版本。无论代理上安装了什么,构建都将使用我们指定的版本运行。尝试新的 JVM 版本如同变更 Docker 标签一样容易,可以让我们走地更快。


在本文中,我们将要学习如何使用Docker配置Jenkins,来确保构建环境与生产环境是相同的。我们还将学习如何通过在构建过程中共享缓存数据,来保持最小的构建时间。

Java 构建的简单概述

首先,从预先安装了 Docker 的 Jenkins 代理开始构建。该代理通过签出源代码编译的方式获取,并在预先安装了 JDK 的 Docker 容器中运行测试。然后,富 JAR 将在生产环境中运行在一个 Docker 镜像,该镜像具有和构建时相同的 Java 版本。


不幸的是,我们需要考虑很多细节才能解决这个问题。下面我们将深入地讨论这些细节。

使用 Docker 构建的详细指南

首先,需要预先安装一个带有 Docker 二进制文件的 Jenkins 代理。因为这是唯一的要求,所以这个代理可以在整个公司内共享,没有必要为每个团队都构建自己的代理。在本例中,klarna-jenkins-agent 是附带了 Docker 的通用代理。它还有一个 ID 为 11000 的 Jenkins 用户,该用户属于 ID 为 12000 的 Docker 组。


如果你想先看下结果,请阅读本文末尾部分,以了解此处讨论的完整 Jenkinsfile。


我们在 pipeline 的根目录处配置代理,以确保所有的 Docker 镜像都能在签出源代码的同一台机器上运行。


// Jenkinsfilepipeline {  agent { label ‘klarna-jenkins-agent’ }  stages { ... }}
复制代码


我们使用 amazonlinux-java-jdk:11 镜像来运行构建。考虑到安全性,镜像安装了 JDK 并使用非 root 帐户来运行。该步骤应该在同一代理(1,3)上运行,以便可以访问项目的源代码。


或者,如果集成测试需要 Docker,则可以安装 docker.sock(2)。


stage ('Compile & Test') {  agent {    docker {      image 'docker-registry.klarna/amazonlinux-java-jdk:11'      label 'klarna-jenkins-agent' // 1      args '-v /var/run/docker.sock:/var/run/docker.sock -u 11000:12000' // 2      reuseNode true // 3    }   }  steps {    sh './gradlew build'  } }
复制代码


如果项目需要,也可以在自定义的 Docker 镜像中运行构建。该过程,仅需指定要使用的 Dockerfile 即可,而无需指定镜像:


 agent {    docker {      filename 'MyDockerfile.build'      ...    }  }
复制代码


镜像将会缓存在代理上,只有当 Dockerfile 的内容发生变更时,镜像才会重新生成。

提高性能

现在我们已经运行了一个基本的构建,我们可以通过在运行之间共享 Gradle 缓存来提高性能。


我们为 Gradle 缓存准备了一个“home”。在将它挂载之前,必须先创建一个.gradle_home 文件夹(4),才能确保 Jenkins 用户可以对其进行写入。否则,该文件夹将由 Docker 创建,只有 root 帐户才有权访问它。


pipeline {  environment {    GRADLE_USER_HOME = "/home/jenkins/.gradle_home"  }  stages {    stage (‘Setup’) {      steps { sh 'mkdir /home/jenkins/.gradle_home || true' // 4    }   } }
复制代码


最后一步,我们修改 docker args 部分,以挂载新创建的文件夹。完整的 args 参数如下所示:


args '-v /var/run/docker.sock:/var/run/docker.sock -u 11000:12000 -v /home/jenkins/.gradle_home:/home/jenkins/.gradle_home'
复制代码


Jenkinsfile 的最终版本如下:


pipeline {    agent { label 'klarna-jenkins-agent' }    stages {      environment {        GRADLE_USER_HOME = "/home/jenkins/.gradle_home"      }      stages {        stage ('Setup') {          steps { sh 'mkdir /home/jenkins/.gradle_home || true' // 4        }         stage ('Compile & Test') {          agent {            docker {              image 'docker-registry.klarna/amazonlinux-java-jdk:11'              // alternatively, build a docker image by specifying a Dockerfile              // filename 'MyDockerfile.build'              label 'klarna-jenkins-agent' // 1              // assuming uid(jenkins)=11000 and gid(docker)=12000              args '-v /var/run/docker.sock:/var/run/docker.sock -u 11000:12000 -v /home/jenkins/.gradle_home:/home/jenkins/.gradle_home'              reuseNode true // 3            }           }          steps {            sh './gradlew build'          }         }      }    }  }
复制代码


Jenkinsfile


或者,我们也可以使用名为 volumes 的 Docker 作为 Gradle 缓存,但是 volume 文件夹由容器内的 root 拥有,如果我们使用非 root 用户运行构建,则会使设置变得更加复杂。

好处

除了可以获得相同的构建和生产环境之外,还有其他一些好处:


  1. 不需要为每个团队或项目维护一个定制的 Jenkins 代理。只需一个 Docker 通用代理就足够了。

  2. 不受 Jenkins 代理上的 Java 版本限制。

  3. 如果项目在 pipeline 的特定步骤中需要一些自定义的软件,我们可以为它创建一个 Dockerfile,而无需创建自定义的代理,并受那些预先安装在代理上的软件的约束。如果以后可能会切换到其他构建工具上,我们也有很多选择。

  4. 升级到下一个 JDK 版本很容易。只需将 Jenkinsfile 中的标签 11 替换为 12 即可。我们甚至可以将构建参数化来验证兼容性。

结论

我们需要付出一些努力才能确保构建环境和生产环境是相同的,并且花费的这些时间是值得的,因为它增强了我们对发布的信心。


使用 Docker 能够使用我们将 Jenkins 代理从构建环境中解耦出来,从而使我们能够精确地控制构建所需的 Java、Node 或 Python 版本,而不需要在代理上预先安装什么。通过使用公司中的标准化组件,可以减少长期维护。


原文链接:


https://engineering.klarna.com/ensuring-parity-between-build-and-production-environments-using-jenkins-and-docker-2695f758b549


2019-08-26 10:2115074
用户头像

发布了 299 篇内容, 共 194.4 次阅读, 收获喜欢 597 次。

关注

评论

发布
暂无评论
发现更多内容

探索大模型训练与多模态数据处理

百度开发者中心

人工智能 图像 大模型训练

OurBMC技术委员会2023年四季度例会顺利召开

OurBMC

技术委员会 工作汇报 四季度例会

Wireshark中的http协议包分析

小齐写代码

Palworld幻兽帕鲁世界参数修改最佳实践(Ubuntu)

天翼云开发者社区

云计算 最佳实践 云服务器

迎龙年接新春,来华为手机里寻找祥龙

最新动态

Gas Hero Coupon NFT 概览与数据分析

Footprint Analytics

区块链 加密货币 NFT

推动海外云手机发展的几个因素

Ogcloud

云手机 海外云手机 云手机海外版 国外云手机

【教程】Python代码混淆工具,Python源代码保密、加密、混淆

雪奈椰子

测试开发+人工智能大礼包,让你在假期实现弯道超车

测试人

软件测试

“祥龙守神州,舞瑞中国年”,京东超市携手王牌驼喜迎新春

科技热闻

浅谈LocalCache | 京东云技术团队

京东科技开发者

使用SD-WAN进行企业网络升级的必要性

Ogcloud

SD-WAN SD-WAN组网 SD-WAN服务商

全新 Amazon S3 Express One Zone 高性能存储类服务,震撼发布!

亚马逊云科技 (Amazon Web Services)

大文件上传原理及实现方案 | 京东物流技术团队

京东科技开发者

OurBMC大咖说 | OurBMC,共创国产软硬件开源发展新纪元

OurBMC

大咖说 软硬件开源 BMC技术全栈

淘宝/天猫商品详情API:返回值参数详解及商业逻辑实现

Noah

IT工单治理野史:由每周最高150+治理到20+ | 京东物流技术团队

京东科技开发者

Kubeadmiral 开源编程挑战 —— 我觉得不错

miraclejzd

字节跳动 Kubernetes 云原生 Kubeadmiral

通义灵码——灵动指间,快码加编,你的智能编码助手

阿里巴巴云原生

阿里云 云原生

自动化测试,有最佳实践吗?

老张

软件测试 自动化测试

部署Palworld幻兽帕鲁服务器最佳实践(Ubuntu)

天翼云开发者社区

云计算 最佳实践 服务器 云服务器

OurBMC 社区 SIG 建设月报(2023 年 10 月)

OurBMC

SIG月报 SIG进展

100%中奖、会员回馈礼…星河会员新春福利到!

飞桨PaddlePaddle

百度 飞桨 飞桨AI 飞桨星河社区

这篇深入浅出贴 助你早日实现Stable diffusion自由

京东科技开发者

OurBMC运营委员会2023年下半年度例会顺利召开

OurBMC

运营委员会 工作汇报 首次例会

OpenSPG新版发布:大模型知识抽取与快速知识图谱构建

百度开发者中心

人工智能 知识图谱 智能客服 大模型

假期想学习,送你测试开发+人工智能大礼包

霍格沃兹测试开发学社

玩转OurBMC第一期:社区操作指南-功能篇

OurBMC

玩转OurBMC 操作指南 基本功能

OurBMC社区首场Meetup成功举办,共建BMC产业生态

OurBMC

Meetup 汇聚智力 共建BMC

有了ERP和MES,还需要质量管理QMS系统吗?

万界星空科技

数字化 生产管理系统 mes 万界星空科技 QMS

【教程】一个比较良心的C++代码混淆器

使用Jenkins和Docker确保构建环境和生产环境之间的对等_语言 & 开发_Dumitru Postoronca_InfoQ精选文章