自定义构建环境
问题
在构建过程中,通常会遇到这样的问题:
- 默认构建环境中的 node 版本是 12, 而我需要 node 16
- 默认构建环境中的 java 版本是 1.8,而我需要 java 21
- 默认构建环境中的 go 版本是 1.16,而我需要的 go 1.20
我如何安装这些工具到我想要的目标版本?
答案
最佳答案:使用 Docker 作为我们得构建环境
Docker 环境
CODING 持续集成为您提供了默认构建环境,若默认环境中预装的 SDK 版本和命令行工具无法满足您的要求,还可以通过在持续集成中使用 Docker 构建环境来解决。你可以通过以下方式使用 Docker 构建环境:
- 使用指定 Registry 地址(默认为 Docker Hub)的 Docker 镜像
- CODING 官方提供的镜像,会内置 go 和 python3.9,所有的官方插件运行都会依赖 python,部分插件还会依赖 go
- 使用已托管至项目级制品库的 Docker 镜像
- 适用于项目层级的标准构建环境,保障项目内镜像安全,方便管理,通过项目令牌您也可以拉取其他项目的镜像。
- 使用 Dockerfile 脚本构建环境
全局使用 Docker 镜像
在「持续集成计划设置」->「流程配置」->「基础配置」->「图形化编辑器」-> 「开始」
「使用 CODING 官方提供的 Docker 镜像」,比如 Node.js 16:
对应的 Jenkinsfile
参考:
pipeline {
agent {
docker {
reuseNode 'true'
registryUrl 'https://coding-public-docker.pkg.coding.net'
image 'public/docker/nodejs:16-2022'
// 如果使用全局构建环境,构建步骤中又使用 docker,请增加下列这句 args
args '-v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker'
}
}
stages {
stage('检出代码') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: env.GIT_BUILD_REF]],
userRemoteConfigs: [[
url: env.GIT_REPO_URL,
credentialsId: env.CREDENTIALS_ID
]]])
}
}
stage('编译') {
steps {
sh 'node -v'
sh 'echo "npm run build"'
}
}
stage('docker build') {
steps {
sh 'docker pull nginx'
sh 'echo docker login'
sh 'echo docker build -t xxxx-docker.pkg.coding.net'
sh 'echo docker push xxxx-docker.pkg.coding.net'
}
}
}
}
适用场景:
- 您的构建依赖比较单一,很容易找到一个 docker 镜像为你所用。
- 您自己制作了一个大而全的 docker 镜像,里面安装了所有您需要的工具。
缺点:
- 您使用的镜像大部分情况下需要安装 git、python3.9、go,因为您使用的团队插件会以来 python,如果插件是 go 写的也还会依赖 go。
- 您使用 docker 需要将 docker.sock 和 docker cli 挂在到容器中。否则会出现 docker not found 的报错。
- 如果有使用构建计划缓存,也需要将缓存目录和宿主机目录进行映射。
阶段使用 Docker 镜像
在「持续集成计划设置」->「流程配置」->「基础配置」->「图形化编辑器」->「任意阶段」
「使用 CODING 官方提供的 Docker 镜像」,比如 openjdk 21:
对应的 Jenkinsfile
参考
pipeline {
agent any
stages {
stage('检出代码') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: env.GIT_BUILD_REF]],
userRemoteConfigs: [[
url: env.GIT_REPO_URL,
credentialsId: env.CREDENTIALS_ID
]]])
}
}
stage('JAVA 编译') {
// 该阶段的所有步骤都会在 openjdk:21-2024.03 镜像启动的容器中进行
agent {
docker {
reuseNode 'true'
registryUrl 'https://coding-public-docker.pkg.coding.net'
image 'public/docker/openjdk:21-2024.03'
}
}
steps {
sh 'java -version'
sh 'echo mvn package -s settings.xml'
}
}
stage('docker build') {
// 因为该构建计划使用的不是全局自定义构建环境,而是阶段自定义构建环境,所以该阶段会在宿主机执行
steps {
sh 'docker pull nginx'
sh 'echo docker login'
sh 'echo docker build -t xxxx-docker.pkg.coding.net'
sh 'echo docker push xxxx-docker.pkg.coding.net'
}
}
}
}
优点:
- 使用场景比较灵活,docker 镜像不依赖额外的内容(python,go),dockerhub 上随便找一个镜像一般都可以正常使用。
- 多个阶段可以分别使用不同的镜像,多个阶段可以组合使用,不声明自定义构建环境的阶段使用宿主机环境。
全局和阶段使用不同的 Docker 镜像
在「持续集成计划设置」->「流程配置」->「基础配置」->「图形化编辑器」->「开始阶段」->「任意阶段」
pipeline {
agent {
docker {
reuseNode 'true'
registryUrl 'https://coding-public-docker.pkg.coding.net'
image 'public/docker/nodejs:16-2022'
}
}
stages {
stage('检出代码') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: env.GIT_BUILD_REF]],
userRemoteConfigs: [[
url: env.GIT_REPO_URL,
credentialsId: env.CREDENTIALS_ID
]]])
}
}
stage('Node 编译') {
steps {
sh 'node -v'
sh 'echo npm run build'
sh 'mkdir build && cd build && echo 1 > 1.html && echo 2 > 2.html'
}
}
stage('上传到 cos') {
agent {
docker {
image 'tencentcom/tencentyun-coscmd'
reuseNode 'true'
registryUrl 'https://docker.io'
args "--entrypoint"
}
}
steps {
sh 'coscmd config -a AKIDyFLL8Eg0WwIWH0Auc9bWJzWxFMIutdkh -s xhJl4B7sTuAIF1c2IPM7hqqg3E6oMjuu -b ehuiban-1301308367 -r ap-shanghai'
sh 'coscmd upload -r build /'
}
}
}
}
制作自己的构建环境镜像
本章节以制作一个 java 21 的 docker 镜像 → 使用自建镜像作为构建环境。
创建 Dockerfile 如下:
FROM openjdk:21-bullseye
RUN cat <> /etc/apt/sources.list
deb https://mirrors.cloud.tencent.com/debian/ bullseye main non-free contrib
deb-src https://mirrors.cloud.tencent.com/debian/ bullseye main non-free contrib
deb https://mirrors.cloud.tencent.com/debian-security/ bullseye-security main
deb-src https://mirrors.cloud.tencent.com/debian-security/ bullseye-security main
deb https://mirrors.cloud.tencent.com/debian/ bullseye-updates main non-free contrib
deb-src https://mirrors.cloud.tencent.com/debian/ bullseye-updates main non-free contrib
deb https://mirrors.cloud.tencent.com/debian/ bullseye-backports main non-free contrib
deb-src https://mirrors.cloud.tencent.com/debian/ bullseye-backports main non-free contrib
EOF
RUN cat /etc/apt/sources.list
RUN apt-get update \
&& apt-get install -y autoconf cmake curl ftp git make mercurial openssl rsync tar unzip wget zip python3.9 python3-pip \
&& update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1
# Install Maven Version: 3.8.6
# https://maven.apache.org/docs/history.html
RUN curl --location --output /tmp/apache-maven.tar.gz https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.tar.gz \
&& tar xf /tmp/apache-maven.tar.gz -C /opt/ \
&& rm /tmp/apache-maven.tar.gz \
&& ln -s /opt/apache-maven-* /opt/apache-maven \
&& /opt/apache-maven/bin/mvn -version
ENV M2_HOME=/root/.m2
# Install Gradle Version: 6.9.2
# https://docs.gradle.org/current/userguide/compatibility.html
RUN curl --location --output /tmp/gradle.zip https://mirrors.cloud.tencent.com/gradle/gradle-6.9.2-bin.zip \
&& unzip -d /opt /tmp/gradle.zip \
&& rm /tmp/gradle.zip \
&& ln -s /opt/gradle-* /opt/gradle \
&& /opt/gradle/bin/gradle -version
# Update PATH for Java tools
ENV PATH="/opt/apache-maven/bin:/opt/gradle/bin:$PATH"
WORKDIR /root/workspace
Dockerfile 构建环境
若项目已经使用 Docker,建议将 Dockerfile
提交到代码库,用它作为持续集成构建环境。Dockerfile
示例代码:
FROM php:8.0-apache
RUN apt-get update \
&& apt-get install -y unzip
Jenkinsfile
:
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: env.GIT_BUILD_REF]],
userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]
])
}
}
stage('Use Docker') {
agent {
dockerfile {
filename 'Dockerfile' // 可选,自定义 Dockerfile 文件名
dir 'build' // 可选,Dockerfile 所在目录
additionalBuildArgs '--build-arg version=1.0.2' // 可选,docker build 自定义参数
}
}
stages {
stage('Test') {
steps {
sh 'php -v'
sh 'unzip -v'
}
}
}
}
}
}
若构建次数频繁,而不想将时间浪费在 docker build
过程上,那么可以通过使用 Jenkins Dockerfile 保存镜像用于下次构建,从而节省大量时间,详情请点击了解。
根节点工作空间
将自定义 Docker 用作构建环境时,可以选择是否使用根节点的工作空间。勾选该选项后,当前阶段的 Docker 容器会和流水线在同一台构建节点中运行,可以获取流水线工作空间下根目录保存的所有文件。
对应的 Jenkinsfile
参数为 reuseNode
,类型:Boolean,默认为 false:
pipeline {
agent {
docker {
registryUrl 'https://coding-public-docker.pkg.coding.net'
image 'public/docker/android:29'
}
}
stages {
// 代码被检出到 pipeline agent 的工作空间根目录下
stage('检出代码') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: env.GIT_BUILD_REF]],
userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]
])
}
}
stage('单元测试') {
agent {
dockerfile {
// 默认在当前节点工作空间根目录下找名为 「Dockerfile」的文件构建环境
filename 'Dockerfile'
// 如果 reuseNode 为 false,则无法找到之前检出到 pipeline agent 的工作空间根目录下的 Dockerfile
reuseNode true
}
}
steps {
sh 'npm run test:ci'
junit '*.xml'
}
}
}
}
常见问题
docker: command not found
在 Jenkins Docker 环境中执行 docker
命令时,需要挂载外部虚拟机的 docker socket,否则会报错:docker: command not found
pipeline {
agent {
docker {
image 'ecoding/php:8.0'
reuseNode 'true'
// 挂载外部虚拟机的 docker socket
args '-v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker'
}
}
stages {
stage('自定义阶段') {
steps {
sh 'php -v'
}
}
stage('构建 Docker 镜像') {
steps {
sh 'docker -v'
script {
docker.withRegistry("https://${env.CCI_CURRENT_TEAM}-docker.pkg.coding.net", "${env.CODING_ARTIFACTS_CREDENTIALS_ID}") {
//docker.build("foo:bar").push()
}
}
}
}
}
}
若希望在自定义构建节点中运行 Docker 命令,在节点中先行安装 Docker 服务即可开始使用。
自定义构建环境使用缓存
公共节点自定义版本(不推荐)
在持续集成中可自行下载安装软件的各种版本,如果官网下载较慢,我们亦提供了镜像服务以供下载。如需增加制品,欢迎提交至开源项目。
Go
stage('Go') {
steps {
// 建议设置「缓存目录」 /root/.cache/downloads
sh 'rm -rf /root/programs/go'
dir ('/root/.cache/downloads') {
sh 'wget -nc "https://coding-public-generic.pkg.coding.net/public/downloads/go-linux-amd64.tar.gz?version=1.17.3" -O go-linux-amd64-1.17.3.tar.gz | true'
sh 'tar -zxvf go-linux-amd64-1.17.3.tar.gz -C /root/programs'
}
sh 'go version'
}
}
Helm
stage('Helm') {
steps {
dir ('/root/.cache/downloads') {
sh 'wget -nc "https://coding-public-generic.pkg.coding.net/public/downloads/helm-linux-amd64.tar.gz?version=v3.7.1" -O helm-linux-amd64-v3.7.1.tar.gz | true'
sh "tar -zxvf helm-linux-amd64-v3.7.1.tar.gz -C \$HELM_BIN linux-amd64/helm --strip-components 1"
}
sh 'helm version'
}
}
kubectl
stage('kubectl') {
steps {
dir ('/root/.cache/downloads') {
sh 'wget -nc "https://coding-public-generic.pkg.coding.net/public/downloads/kubectl-linux-amd64?version=v1.22.4" -O kubectl-linux-amd64-v1.22.4 | true'
sh 'cp kubectl-linux-amd64-v1.22.4 /usr/local/bin/kubectl'
}
sh 'chmod +x /usr/local/bin/kubectl'
sh 'kubectl version --client'
}
}
Node.js
stage('Node.js') {
steps {
sh 'rm -rf /usr/lib/node_modules/npm/'
dir ('/root/.cache/downloads') {
sh 'wget -nc "https://coding-public-generic.pkg.coding.net/public/downloads/node-linux-x64.tar.xz?version=v16.13.0" -O node-v16.13.0-linux-x64.tar.xz | true'
sh 'tar -xf node-v16.13.0-linux-x64.tar.xz -C /usr --strip-components 1'
// sh 'wget -nc "https://coding-public-generic.pkg.coding.net/public/downloads/node-linux-x64.tar.xz?version=v14.18.2" -O node-v14.18.2-linux-x64.tar.xz | true'
// sh 'tar -xf node-v14.18.2-linux-x64.tar.xz -C /usr --strip-components 1'
// 更多版本:v12.22.7、v17.2.0
}
sh 'node -v'
}
}
PHP
pipeline {
agent {
docker {
reuseNode 'true'
registryUrl 'https://coding-public-docker.pkg.coding.net'
image 'public/docker/php:8.0'
// image 'public/docker/php:7.4' 以及 7.3、7.2、7.1、5.6
args '-v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker'
}
}
stages {
stage('安装依赖') {
steps {
// Possible values for ext-name:
// bcmath bz2 calendar ctype curl dba dom enchant exif fileinfo filter ftp gd gettext gmp
// hash iconv imap interbase intl json ldap mbstring mysqli oci8 odbc opcache pcntl pdo
// pdo_dblib pdo_firebird pdo_mysql pdo_oci pdo_odbc pdo_pgsql pdo_sqlite pgsql phar posix pspell
// readline recode reflection session shmop simplexml snmp soap sockets sodium spl standard
// sysvmsg sysvsem sysvshm tidy tokenizer wddx xml xmlreader xmlrpc xmlwriter xsl zend_test zip
sh 'apt-get update && apt-get install -y libbz2-dev'
sh 'docker-php-ext-install bz2'
sh 'php -i | grep bz2'
}
}
}
}
常见问题
安装 nodejs 报错,node: /lib/x86_64-linux-gnu/libm.so.6: version ‘GLIBC_2.27’; not found (required by node)
问题描述:
安装 nodejs 报错 node: /lib/x86_64-linux-gnu/libm.so.6: version 'GLIBC_2.27' not found (required by node)
。
原因:
这个错误表示默认构建环境系统的 glibc 版本低于 Node.js 所需要的版本。为了避免直接升级系统中的 glibc 或 Node.js 版本,我们建议使用 nodejs 镜像来指定构建环境。
解决方法:
指定阶段使用 nodejs 镜像的方式,比如 node 安装依赖阶段使用 nodejs:18 的版本。
参考资料
在阅读中是否遇到以下问题?*
您希望我们如何改进?*
如果您希望得到回复,请留下您的邮箱地址。