本文为您介绍如何自定义构建环境。
前提条件
进入项目
1. 登录 CODING 控制台,单击团队域名进入 CODING 使用页面。
2. 进入目标项目后,选择左侧导航栏的持续集成。
公共节点自定义版本
Go
stage('Go') {steps {// 建议设置「缓存目录」 /root/.cache/downloadssh '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.6args '-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 zipsh 'apt-get update && apt-get install -y libbz2-dev'sh 'docker-php-ext-install bz2'sh 'php -i | grep bz2'}}}}
Docker 环境
CODING 持续集成为您提供了默认构建环境,若默认环境中预装的 SDK 版本和命令行工具无法满足您的要求,还可以通过在持续集成中使用 Docker 构建环境来解决。您可以通过以下方式使用 Docker 构建环境:
CODING 官方提供的镜像。
使用已托管至项目级制品库的 Docker 镜像。
适用于项目层级的标准构建环境,保障项目内镜像安全,方便管理,通过项目令牌您也可以拉取其他项目的镜像。
使用指定 Registry 地址(默认为 Docker Hub)的 Docker 镜像。
使用 Dockerfile 脚本构建环境。
CODING Docker 镜像
在持续集成计划设置 > 流程配置 > 基础配置 > 图形化编辑器中,选择使用 CODING 官方 Docker 镜像,例如 Node.js 14:
对应的
Jenkinsfile
参考:pipeline {agent {docker {reuseNode 'true'registryUrl 'https://coding-public-docker.pkg.coding.net'image 'public/docker/nodejs:14'}}stages {stage('Test') {steps {sh 'node --version'}}}}
项目制品库 Docker 镜像
以下内容以配置了进程管理工具 pm2 的 Node.js 12 环境为例,分步骤演示如何将自建镜像推送至制品仓库以及使用自建镜像作为构建环境。
步骤一:构建 Docker 镜像
1. 新建目录,创建 Dockerfile 如下:
# 指定 node.js 版本为 node 12,默认从 Docker Hub 上拉取FROM node:12# 安装 pm2RUN npm install pm2 -gCOPY . .# 设置容器启动时的命令CMD [ "pm2-runtime", "start" ]
2. 运行指令
docker build -t pm2-test .
;-t
指定镜像名称。Step 1/4 : FROM node:12...Step 2/4 : RUN npm install pm2 -g...Step 3/4 : COPY . ....Step 4/4 : CMD [ "pm2-runtime", "start" ]---> Running in 46cc5081cb4fRemoving intermediate container 46cc5081cb4f---> 5f8335fa91d4Successfully built 5f8335fa91d4Successfully tagged pm2-test:latest
步骤二:推送镜像到 CODING 制品库
1. 进入 CODING 制品库,选择已有制品库或新建制品库,输入密码后单击生成个人令牌作为凭据。
2. 复制后在终端输入命令进行登录。
3. 按照操作指引提示,为本地镜像打标签。
docker tag pm2-test ******/test-dd/test/pm2-test
4. 推送您的 docker 镜像到 CODING 制品库。
docker push ******/test-dd/test/pm2-testThe push refers to repository [******************/test-dd/test/pm2-test]809e73e276b8: Pushed9159d4abedcd: Pushed...latest: digest: sha256:ccecda5071e60593d1be44ea27d4ec5b35f6a5f6872fb9 size: 2634
5. 推送成功后可以在镜像列表找到您的镜像。
步骤三:在持续集成中使用镜像作为构建环境
进入持续集成设置 > 流程配置,选择使用项目内的 Docker 镜像,选择对应制品库和镜像。
指定地址的 Docker 镜像
Docker 镜像为必填项,需要填入您的镜像名称。Registry 地址需填写的格式为不带路径的 URL 地址,例如:
正确:https://codes-farm-docker.pkg.coding.net
错误:https://codes-farm-docker.pkg.coding.net/laravel-demo/laravel-docker/
若拉取私有镜像,需录入凭据后填写 Registry 认证凭据 ID。
对应的 Jenkinsfile:
pipeline {agent {docker {image 'node:14-alpine'reuseNode 'true'}}stages {stage('Test') {steps {sh 'node --version'}}}}
Dockerfile 构建环境
若项目已经使用 Docker,建议将
Dockerfile
提交到代码库,用它作为持续集成构建环境。Dockerfile
示例代码:FROM php:8.0-apacheRUN apt-get update \\&& apt-get install -y unzip
Jenkinsfile
:pipeline {agent anystages {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 保存镜像用于下次构建,从而节省大量时间,请参见 保存 Dockerfile 镜像。在阶段中使用 Docker
Jenkinsfile 参考:
pipeline {agent nonestages {stage('Back-end') {agent {docker {image 'maven:3-alpine'reuseNode 'true'}}steps {sh 'mvn --version'}}stage('Front-end') {agent {docker {image 'node:14-alpine'reuseNode 'true'}}steps {sh 'node --version'}}}}
多个 Docker 后台
自动化测试往往需要临时的基础设施(例如 MySQL、Redis、Elasticsearch)。那么创建一个桥接网络,在其中启动多个 Docker 后台,测试完毕自动删除。
node {stage("检出") {checkout([$class: 'GitSCM',branches: [[name: GIT_BUILD_REF]],userRemoteConfigs: [[url: GIT_REPO_URL,credentialsId: CREDENTIALS_ID]]])}stage('准备数据库') {sh 'docker network create bridge1'sh(script:'docker run --net bridge1 --name mysql -d -e "MYSQL_ROOT_PASSWORD=my-secret-pw" -e "MYSQL_DATABASE=test_db" mysql:5.7', returnStdout: true)sh(script:'docker run --net bridge1 --name redis -d redis:5', returnStdout: true)}docker.image('ecoding/php:8.0').inside("--net bridge1 -v \\"${env.WORKSPACE}:/root/code\\" -e 'APP_ENV=testing' -e 'DB_DATABASE=test_db'" +" -e 'DB_USERNAME=root' -e 'DB_PASSWORD=my-secret-pw' -e 'DB_HOST=mysql' -e 'REDIS_HOST=redis'" +" -e 'APP_KEY=base64:tbgOBtYci7i7cdx5RiFE3KZzUkRtJfbU3lbj5uPdL8U='") {sh 'composer install'stage('单元测试') {sh 'XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-html storage/reports/tests/ --log-junit storage/test-results/junit.xml --coverage-text tests/'junit 'storage/test-results/junit.xml'codingHtmlReport(name: '测试覆盖率报告', path: 'storage/reports/tests/')}}}
根节点工作空间
将自定义 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 的工作空间根目录下的 DockerfilereuseNode true}}steps {sh 'npm run test:ci'junit '*.xml'}}}}
执行 Docker 命令
在 Jenkins Docker 环境中执行
docker
命令时,需要挂载外部虚拟机的 docker socket,否则会报错:docker: command not found
。pipeline {agent {docker {image 'ecoding/php:8.0'reuseNode 'true'// 挂载外部虚拟机的 docker socketargs '-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 服务即可开始使用。