11 基于 Docker 构建 Jenkins CI 平台
11.1 CI/CD概述
持续集成(Continuous Integration,Cl):代码合并、构建、部署、测试都在一起,不断地执行这个过程,并对结果反馈。
持续部署(Continuous Deployment,CD):部署到测试环境、预生产环境、生产环境。
持续交付(Continuous Delivery,CD):将最终产品发布到生产环境,给用户使用。

11.2 CI工作流程设计

CI 工作流程
拓展:
Git 代码版本管理系统
GitLab 基于Git做图形管理页面
GitHub 公共的代码管理仓库
| IP地址 | 主机名 | 角色 |
|---|---|---|
| 10.0.0.100 | harbor-ssh-server | Harbor 镜像仓库 |
| 10.0.0.101 | jenkins-ssh-server | Jenkins CICD |
| 10.0.0.102 | gitlab-ssh-server | GitLab 代码仓库 |
11.3 部署 GitLab
11.3.1 部署 GitLab
mkdir gitlab && cd gitlabdocker run -d \--name gitlab \-p 8443:443 \-p 9999:80 \-p 9998:22 \-v $PWD/config:/etc/gitlab \-v $PWD/logs:/var/log/gitlab \-v $PWD/data:/var/opt/gitlab \-v /etc/localtime:/etc/localtime \--restart=always \lizhenliang/gitlab-ce-zh:latest# 查看GitLab的容器日志$ docker logs -f gitlab
访问地址::http://<IP地址>:9999

初次会先设置管理员密码,然后登陆,默认管理员用户名root,密码就是刚设置的。

11.3.2 创建项目,提交测试代码
进入后先创建项目,提交代码,以便后面测试。
项目名称自定义:java-devops-demo

unzip devops-java-demo.zipcd devops-java-demogit init# 若无法正常推送到远程仓库,则将项目代码中的隐藏目录 .git 删除即可git remote add origin http://10.0.0.102:9999/root/java-devops-demo.gitgit add .# git config --global user.email "Your@example.com"# git config --global user.name "Your Name"git config --global user.email "zhongzhiwei@kubesphere.io"git config --global user.name "zhongzhiwei"git commit -m "all"$ git push origin masterUsername for 'http://10.0.0.102:9999': rootPassword for 'http://root@10.0.0.102:9999': [Gitlab root密码]
- GitLab 代码仓库中就有相应的代码
unzip devops-java-demo.zipcd devops-java-demogit init# 若无法正常推送到远程仓库,则将项目代码中的隐藏目录 .git 删除即可git remote add origin http://10.0.0.102:9999/root/java-devops-demo.gitgit add .# git config --global user.email "Your@example.com"# git config --global user.name "Your Name"git config --global user.email "zhongzhiwei@kubesphere.io"git config --global user.name "zhongzhiwei"git commit -m "all"$ git push origin masterUsername for 'http://10.0.0.102:9999': rootPassword for 'http://root@10.0.0.102:9999': [Gitlab root密码]

GitLab 代码项目仓库中就拥有该代码

11.4 部署 Harbor 镜像仓库
11.4.1 安装 Docker 和 Docker-Compose
范例:Ubuntu 20.04 部署 Docker 和 Docker-Compose 脚本
#!/bin/bash#Description: ubuntu20.04系统安装docker-compose编排工具COLOR="echo -e \\033[1;31m"END="\033[m"DOCKER_VERSION="5:20.10.21~3-0~ubuntu-focal"install_docker(){${COLOR}"开始安装 Docker....."${END}sleep 1apt updateapt -y install apt-transport-https ca-certificates curl software-properties-commoncurl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"apt update${COLOR}"Docker有以下版本:"${END}sleep 2apt-cache madison docker-ce${COLOR}"5秒后即将安装: docker-"${DOCKER_VERSION}" 版本....."${END}${COLOR}"如果想安装其它Docker版本,请按ctrl+c键退出,修改版本再执行"${END}sleep 5apt -y install docker-ce=${DOCKER_VERSION} docker-ce-cli=${DOCKER_VERSION}mkdir -p /etc/dockertee /etc/docker/daemon.json <<-'EOF'{"registry-mirrors": ["https://po13h3y1.mirror.aliyuncs.com","http://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com","http://f1361db2.m.daocloud.io"],"exec-opts": ["native.cgroupdriver=systemd"],"log-driver": "json-file","log-opts": {"max-size": "100m"},"storage-driver": "overlay2"}EOFsystemctl daemon-reloadsystemctl restart dockerdocker version && ${COLOR}"Docker 安装完成"${END} || ${COLOR}"Docker 安装失败"${END}}install_docker_compose(){${COLOR}"开始安装 Docker compose....."${END}sleep 1# curl -L https://github.com/docker/compose/releases/download/1.25.3/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose# chmod +x /usr/local/bin/docker-composecurl -L https://get.daocloud.io/docker/compose/releases/download/v2.13.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-composechmod +x /usr/local/bin/docker-composedocker-compose --version && ${COLOR}"Docker Compose 安装完成"${END} || ${COLOR}"Docker compose 安装失败"${END}}dpkg -s docker-ce &> /dev/null && ${COLOR}"Docker已安装"${END} || install_dockerdocker-compose --version &> /dev/null && ${COLOR}"Docker Compose已安装"${END} || install_docker_compose
范例:CentOS & Ubuntu 全系列部署 Docker 和 Docker-Compose 脚本
#!/bin/bash#Description:全系列系统安装 docker harbor镜像仓库DOCKER_VERSION="20.10.10"#DOCKER_VERSION="19.03.14"DOCKER_COMPOSE_VERSION=2.6.1#DOCKER_COMPOSE_VERSION=1.29.2DOCKER_COMPOSE_FILE=docker-compose-Linux-x86_64#HARBOR_NAME=`hostname -I|awk '{print $1}'`HARBOR_ADMIN_PASSWORD=123456HARBOR_IP=`hostname -I|awk '{print $1}'`COLOR_SUCCESS="echo -e \\033[1;32m"COLOR_FAILURE="echo -e \\033[1;31m"END="\033[m". /etc/os-releaseUBUNTU_DOCKER_VERSION="5:${DOCKER_VERSION}~3-0~${ID}-${UBUNTU_CODENAME}"color () {RES_COL=60MOVE_TO_COL="echo -en \\033[${RES_COL}G"SETCOLOR_SUCCESS="echo -en \\033[1;32m"SETCOLOR_FAILURE="echo -en \\033[1;31m"SETCOLOR_WARNING="echo -en \\033[1;33m"SETCOLOR_NORMAL="echo -en \E[0m"echo -n "$1" && $MOVE_TO_COLecho -n "["if [ $2 = "success" -o $2 = "0" ] ;then${SETCOLOR_SUCCESS}echo -n $" OK "elif [ $2 = "failure" -o $2 = "1" ] ;then${SETCOLOR_FAILURE}echo -n $"FAILED"else${SETCOLOR_WARNING}echo -n $"WARNING"fi${SETCOLOR_NORMAL}echo -n "]"echo}install_docker(){if [ $ID = "centos" -o $ID = "rocky" ];thenif [ $VERSION_ID = "7" ];thencat > /etc/yum.repos.d/docker.repo <<EOF[docker]name=dockergpgcheck=0#baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/7/x86_64/stable/EOFelsecat > /etc/yum.repos.d/docker.repo <<EOF[docker]name=dockergpgcheck=0#baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/8/x86_64/stable/baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/8/x86_64/stable/EOFfiyum clean all${COLOR_FAILURE} "Docker有以下版本"${END}yum list docker-ce --showduplicates${COLOR_FAILURE}"5秒后即将安装: docker-"${DOCKER_VERSION}" 版本....."${END}${COLOR_FAILURE}"如果想安装其它Docker版本,请按ctrl+c键退出,修改版本再执行"${END}sleep 5yum -y install docker-ce-$DOCKER_VERSION docker-ce-cli-$DOCKER_VERSION \|| { color "Base,Extras的yum源失败,请检查yum源配置" 1;exit; }elsedpkg -s docker-ce &> /dev/null && $COLOR"Docker已安装,退出" 1 && exitapt update || { color "更新包索引失败" 1 ; exit 1; }apt -y install apt-transport-https ca-certificates curl software-properties-common || \{ color "安装相关包失败" 1 ; exit 2; }curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -add-apt-repository "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable"apt update${COLOR_FAILURE} "Docker有以下版本"${END}apt-cache madison docker-ce${COLOR_FAILURE}"5秒后即将安装: docker-"${UBUNTU_DOCKER_VERSION}" 版本....."${END}${COLOR_FAILURE}"如果想安装其它Docker版本,请按ctrl+c键退出,修改版本再执行"${END}sleep 5apt -y install docker-ce=${UBUNTU_DOCKER_VERSION} docker-ce-cli=${UBUNTU_DOCKER_VERSION}fiif [ $? -eq 0 ];thencolor "安装软件包成功" 0elsecolor "安装软件包失败,请检查网络配置" 1exitfimkdir -p /etc/dockertee /etc/docker/daemon.json <<-'EOF'{"registry-mirrors": ["https://po13h3y1.mirror.aliyuncs.com","http://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com","http://f1361db2.m.daocloud.io"],"exec-opts": ["native.cgroupdriver=systemd"],"log-driver": "json-file","log-opts": {"max-size": "100m"},"storage-driver": "overlay2"}EOFsystemctl daemon-reloadsystemctl enable dockersystemctl restart dockerdocker version && color "Docker 安装成功" 0 || color "Docker 安装失败" 1echo 'alias rmi="docker images -qa|xargs docker rmi -f"' >> ~/.bashrcecho 'alias rmc="docker ps -qa|xargs docker rm -f"' >> ~/.bashrc}install_docker_compose(){if [ $ID = "centos" -o $ID = "rocky" ];then${COLOR_SUCCESS}"开始安装 Docker compose....."${END}sleep 1if [ ! -e ${DOCKER_COMPOSE_FILE} ];then#curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/${DOCKER_COMPOSE_FILE} -o /usr/bin/docker-composecurl -L https://get.daocloud.io/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m) -o /usr/bin/docker-composeelsemv ${DOCKER_COMPOSE_FILE} /usr/bin/docker-composefichmod +x /usr/bin/docker-composeelseapt -y install docker-composefiif docker-compose --version ;then${COLOR_SUCCESS}"Docker Compose 安装完成"${END}else${COLOR_FAILURE}"Docker compose 安装失败"${END}exitfi}docker info &> /dev/null && ${COLOR_FAILURE}"Docker已安装"${END} || install_dockerdocker-compose --version &> /dev/null && ${COLOR_FAILURE}"Docker Compose已安装"${END} || install_docker_compose
11.4.2 解压离线包部署
# https://github.com/goharbor/harbor/releases/download/v2.6.2/harbor-offline-installer-v2.6.2.tgz$ tar -zxvf harbor-offline-installer-v2.6.2.tgz$ cd harbor$ cp harbor.yml.tmpl harbor.yml$ vim harbor.ymlhostname: reg.kubesphere.comhttps: #先注释https相关配置harbor_admin_password: Harbor12345# 部署Harbor HTTP$ ./prepare$ ./install.sh

$ docker-compose psName Command State Ports-----------------------------------------------------------------------------------------------------------------harbor-core /harbor/entrypoint.sh Up (health: starting)harbor-db /docker-entrypoint.sh 96 13 Up (health: starting)harbor-jobservice /harbor/entrypoint.sh Up (health: starting)harbor-log /bin/sh -c /usr/local/bin/ ... Up (health: starting) 127.0.0.1:1514->10514/tcpharbor-portal nginx -g daemon off; Up (health: starting)nginx nginx -g daemon off; Up (health: starting) 0.0.0.0:80->8080/tcp,:::80->8080/tcpredis redis-server /etc/redis.conf Up (health: starting)registry /home/harbor/entrypoint.sh Up (health: starting)registryctl /home/harbor/start.sh Up (health: starting)
浏览器访问http://<IP地址>:80也可以修改主机的host文件将IP地址 域名进行绑定
默认用户名:admin
默认密码:Harbor12345

Harbor 的主界面

cat >> /etc/hosts <<EOF# KubeSphere Harbor Host BEGIN10.0.0.100 reg.kubesphere.com# KubeSphere Harbor Host ENDEOF
11.4.3 在 Jenkins 主机配置Docker可信任,如果是HTTPS需要拷贝证书
由于Harbor未配置https,还需要在docker配置可信任。
$ cat /etc/docker/daemon.json{"registry-mirrors": ["https://po13h3y1.mirror.aliyuncs.com","http://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com","http://f1361db2.m.daocloud.io"],"exec-opts": ["native.cgroupdriver=systemd"],"log-driver": "json-file","log-opts": {"max-size": "100m"},"storage-driver": "overlay2","insecure-registries": ["reg.kubesphere.com"]}
11.5 部署 Jenkins
11.5.1 准备JDK 和 Maven 环境
将二进制包上传到服务器并解压到工作目录,用于让Jenkins容器挂载使用。
# JDK Download:https://lupf.cn/articles/2022/02/19/1645283667689.html# Maven Download:https://dlcdn.apache.org/maven/maven-3/3.5.4/binaries/# wget https://dlcdn.apache.org/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz --no-check-certificatetar -zxvf jdk-8u45-linux-x64.tar.gzmv jdk1.8.0_45/ /usr/local/jdktar -zxvf apache-maven-3.5.4-bin.tar.gzmv apache-maven-3.5.4/ /usr/local/maven
修改Maven源:
# docker pull jenkins/jenkins:ltsdocker pull jenkins/jenkins:2.375.1-ltsdocker run -d --name jenkins -p 80:8080 -p 50000:50000 -u root \-v /opt/jenkins_home:/var/jenkins_home \-v /var/run/docker.sock:/var/run/docker.sock \-v /usr/bin/docker:/usr/bin/docker \-v /usr/local/maven:/usr/local/maven \-v /usr/local/jdk:/usr/local/jdk \-v /etc/localtime:/etc/localtime \--restart=always \--name jenkins jenkins/jenkins:2.375.1-lts# 查看Jenkins日志$ docker logs -f jenkins
访问地址:http://IP

:::warning Jenkins 是类似于 Docker in Docker 的模式
:::
# 获取Jenkins的管理员密码$ docker exec -it jenkins cat /var/jenkins_home/secrets/initialAdminPassword2f9c8ca73c98418182bd1af7a19a37ca
Jenkins 使用安装推荐的插件

11.5.2 安装插件
管理Jenkins→系统配置→管理插件→搜索git/pipeline/blue ocean,选中点击安装。默认从国外网络下载插件,会比较慢,建议修改国内源:
$ docker exec -it jenkins /bin/bashcd /opt/jenkins_home/updates# sed -i 's/https:\/\/updates.jenkins.io\/download/http:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' /var/lib/jenkins/updates/default.json# sed -i 's/https:\/\/www.google.com/https:\/\/www.baidu.com/g' /var/lib/jenkins/updates/default.jsonsed -i 's/https:\/\/updates.jenkins.io\/download/http:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' /opt/jenkins_home/updates/default.jsonsed -i 's/https:\/\/www.google.com/https:\/\/www.baidu.com/g' /opt/jenkins_home/updates/default.json$ docker restart jenkins
11.6 发布测试
11.6.1 创建项目并配置
New ltem → Pipeline → This project is parameterized → String Parameter
- Name: Branch #变量名,下面脚本中调用
- Default Value: master #默认分支
- Description: 发布的代码分支 #描述

11.6.2 Pipeline 脚本
初始化Pipeline 脚本范例:
pipeline {agent anystages {stage('1.拉取代码') {steps {echo '拉取代码'}}stage('2.代码编译') {steps {echo '代码编译'}}stage('3.部署代码') {steps {echo '部署代码'}}}}

结果看板

最终的Jenkinsfile Pipeline示例
#!/usr/bin/env groovy// 定义镜像仓库地址def registry = "reg.kubesphere.com"def project = "welcome"def app_name = "demo"// 需要 Groovy Postbuild Jenkins 插件def image_name = "${registry}/${project}/${app_name}:${Branch}-${BUILD_NUMBER}"// GitLab的地址def git_address = "http://10.0.0.102:9999/root/java-devops-demo.git"// 连接Harbor的用户名和密码def docker_registry_auth = "d5c0e5c2-5a39-496e-86ae-697a448f5b84"// 连接GitLab的用户名和密码def git_auth = "6d59e843-034f-4531-8705-d7f6c1f40b23"pipeline {agent anystages {stage('拉取代码') {steps {checkout ([$class: 'GitSCM', branches: [[name: "${Branch}"]], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_address}"]]])}}stage('代码编译') {steps {sh """pwdJAVA_HOME=/usr/local/jdkPATH=$JAVA_HOME/bin:/usr/local/maven/bin:$PATHjava -versionmvn clean package -Dmaven.test.skip=truels -alhR"""}}stage('构建镜像') {steps {withCredentials([usernamePassword(credentialsId: "${docker_registry_auth}",passwordVariable: "password",usernameVariable: "username")]) {sh """echo 'FROM lizhenliang/tomcat:latestLABEL maintainer zhongzhiwei <zhongzhiwei@kubesphere.io>RUN rm -rf /usr/local/tomcat/webapps/*ADD target/*.war /usr/local/tomcat/webapps/ROOT.war' > Dockerfiledocker build -t ${image_name} .docker login -u ${username} -p '${password}' ${registry}docker push ${image_name}"""}}}stage('部署到Docker') {steps {sh """docker rm -f tomcat-java-demo | truedocker container run -d --name tomcat-java-demo -p 18080:8080 ${image_name}"""}}}}
使用阿里云Maven镜像加速 **/usr/local/maven/conf/settings.xml**
cat settings.xml<?xml version="1.0" encoding="UTF-8"?><!--Licensed to the Apache Software Foundation (ASF) under oneor more contributor license agreements. See the NOTICE filedistributed with this work for additional informationregarding copyright ownership. The ASF licenses this fileto you under the Apache License, Version 2.0 (the"License"); you may not use this file except in compliancewith the License. You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing,software distributed under the License is distributed on an"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANYKIND, either express or implied. See the License for thespecific language governing permissions and limitationsunder the License.--><!--| This is the configuration file for Maven. It can be specified at two levels:|| 1. User Level. This settings.xml file provides configuration for a single user,| and is normally provided in ${user.home}/.m2/settings.xml.|| NOTE: This location can be overridden with the CLI option:|| -s /path/to/user/settings.xml|| 2. Global Level. This settings.xml file provides configuration for all Maven| users on a machine (assuming they're all using the same Maven| installation). It's normally provided in| ${maven.conf}/settings.xml.|| NOTE: This location can be overridden with the CLI option:|| -gs /path/to/global/settings.xml|| The sections in this sample file are intended to give you a running start at| getting the most out of your Maven installation. Where appropriate, the default| values (values used when the setting is not specified) are provided.||--><settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"><!-- localRepository| The path to the local repository maven will use to store artifacts.|| Default: ${user.home}/.m2/repository<localRepository>/path/to/local/repo</localRepository>--><!-- interactiveMode| This will determine whether maven prompts you when it needs input. If set to false,| maven will use a sensible default value, perhaps based on some other setting, for| the parameter in question.|| Default: true<interactiveMode>true</interactiveMode>--><!-- offline| Determines whether maven should attempt to connect to the network when executing a build.| This will have an effect on artifact downloads, artifact deployment, and others.|| Default: false<offline>false</offline>--><!-- pluginGroups| This is a list of additional group identifiers that will be searched when resolving plugins by their prefix, i.e.| when invoking a command line like "mvn prefix:goal". Maven will automatically add the group identifiers| "org.apache.maven.plugins" and "org.codehaus.mojo" if these are not already contained in the list.|--><pluginGroups><!-- pluginGroup| Specifies a further group identifier to use for plugin lookup.<pluginGroup>com.your.plugins</pluginGroup>--></pluginGroups><!-- proxies| This is a list of proxies which can be used on this machine to connect to the network.| Unless otherwise specified (by system property or command-line switch), the first proxy| specification in this list marked as active will be used.|--><proxies><!-- proxy| Specification for one proxy, to be used in connecting to the network.|<proxy><id>optional</id><active>true</active><protocol>http</protocol><username>proxyuser</username><password>proxypass</password><host>proxy.host.net</host><port>80</port><nonProxyHosts>local.net|some.host.com</nonProxyHosts></proxy>--></proxies><!-- servers| This is a list of authentication profiles, keyed by the server-id used within the system.| Authentication profiles can be used whenever maven must make a connection to a remote server.|--><servers><!-- server| Specifies the authentication information to use when connecting to a particular server, identified by| a unique name within the system (referred to by the 'id' attribute below).|| NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are| used together.|<server><id>deploymentRepo</id><username>repouser</username><password>repopwd</password></server>--><!-- Another sample, using keys to authenticate.<server><id>siteServer</id><privateKey>/path/to/private/key</privateKey><passphrase>optional; leave empty if not used.</passphrase></server>--></servers><!-- mirrors| This is a list of mirrors to be used in downloading artifacts from remote repositories.|| It works like this: a POM may declare a repository to use in resolving certain artifacts.| However, this repository may have problems with heavy traffic at times, so people have mirrored| it to several places.|| That repository definition will have a unique id, so we can create a mirror reference for that| repository, to be used as an alternate download site. The mirror site will be the preferred| server for that repository.|--><mirrors><!-- mirror| Specifies a repository mirror site to use instead of a given repository. The repository that| this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used| for inheritance and direct lookup purposes, and must be unique across the set of mirrors.|<mirror><id>mirrorId</id><mirrorOf>repositoryId</mirrorOf><name>Human Readable Name for this Mirror.</name><url>http://my.repository.com/repo/path</url></mirror>--><!--<mirror><id>nexus</id><mirrorOf>*</mirrorOf><url>http://maven.aliyun.com/nexus/content/groups/public/</url></mirror><mirror><id>nexus-public-snapshots</id><mirrorOf>public-snapshots</mirrorOf><url>http://maven.aliyun.com/nexus/content/repositories/snapshots/</url></mirror><mirror><id>nexus-public-snapshots1</id><mirrorOf>public-snapshots1</mirrorOf><url>https://artifacts.alfresco.com/nexus/content/repositories/public/</url></mirror>--><mirror><id>central</id><mirrorOf>central</mirrorOf><name>aliyun maven</name><url>https://maven.aliyun.com/repository/public</url></mirror></mirrors><!-- profiles| This is a list of profiles which can be activated in a variety of ways, and which can modify| the build process. Profiles provided in the settings.xml are intended to provide local machine-| specific paths and repository locations which allow the build to work in the local environment.|| For example, if you have an integration testing plugin - like cactus - that needs to know where| your Tomcat instance is installed, you can provide a variable here such that the variable is| dereferenced during the build process to configure the cactus plugin.|| As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles| section of this document (settings.xml) - will be discussed later. Another way essentially| relies on the detection of a system property, either matching a particular value for the property,| or merely testing its existence. Profiles can also be activated by JDK version prefix, where a| value of '1.4' might activate a profile when the build is executed on a JDK version of '1.4.2_07'.| Finally, the list of active profiles can be specified directly from the command line.|| NOTE: For profiles defined in the settings.xml, you are restricted to specifying only artifact| repositories, plugin repositories, and free-form properties to be used as configuration| variables for plugins in the POM.||--><profiles><!-- profile| Specifies a set of introductions to the build process, to be activated using one or more of the| mechanisms described above. For inheritance purposes, and to activate profiles via <activatedProfiles/>| or the command line, profiles have to have an ID that is unique.|| An encouraged best practice for profile identification is to use a consistent naming convention| for profiles, such as 'env-dev', 'env-test', 'env-production', 'user-jdcasey', 'user-brett', etc.| This will make it more intuitive to understand what the set of introduced profiles is attempting| to accomplish, particularly when you only have a list of profile id's for debug.|| This profile example uses the JDK version to trigger activation, and provides a JDK-specific repo.<profile><id>jdk-1.4</id><activation><jdk>1.4</jdk></activation><repositories><repository><id>jdk14</id><name>Repository for JDK 1.4 builds</name><url>http://www.myhost.com/maven/jdk14</url><layout>default</layout><snapshotPolicy>always</snapshotPolicy></repository></repositories></profile>--><!--| Here is another profile, activated by the system property 'target-env' with a value of 'dev',| which provides a specific path to the Tomcat instance. To use this, your plugin configuration| might hypothetically look like:|| ...| <plugin>| <groupId>org.myco.myplugins</groupId>| <artifactId>myplugin</artifactId>|| <configuration>| <tomcatLocation>${tomcatPath}</tomcatLocation>| </configuration>| </plugin>| ...|| NOTE: If you just wanted to inject this configuration whenever someone set 'target-env' to| anything, you could just leave off the <value/> inside the activation-property.|<profile><id>env-dev</id><activation><property><name>target-env</name><value>dev</value></property></activation><properties><tomcatPath>/path/to/tomcat/instance</tomcatPath></properties></profile>--></profiles><!-- activeProfiles| List of profiles that are active for all builds.|<activeProfiles><activeProfile>alwaysActiveProfile</activeProfile><activeProfile>anotherAlwaysActiveProfile</activeProfile></activeProfiles>--></settings>
11.6.3 添加凭证
- 添加字符参数

- 添加 Harbor 私有镜像的凭证( 需要确保凭证的信息正确 )

- 添加 GitLab 私有代码仓库的凭证( 需要确保凭证的信息正确 )

- 使用 Jenkins 生成的ID号。

11.6.4 运行构建
- Jenkins 查看流水线的状态


- Harbor 镜像仓库的镜像上传状态

- 访问部署页面

11.7 Jenkins Pipeline
Jenkins Pipeline是一套插件,支持在Jenkins中实现集成和持续交付管道;
Pipeline通过特定语法对简单到复杂的传输管道进行建模;
- 声明式:遵循与
<font style="color:#E8323C;">Groovy</font>相同语法。<font style="color:#E8323C;">pipeline { }</font> - 脚本式:支持
Groovy大部分功能,也是非常表达和灵活的工具。node { }
Jenkins Pipeline的定义被写入一个文本文件,称为Jenkinsfile。
Jenkinsfile (Declarative Pipeline)pipeline {agent anystages {stage('Build') {steps {//}}stage('Test') {steps {//}}stage('Deploy') {steps {//}}}}

:::warning
- 在任何可用的代理上,执行流水线或它的任何阶段。
- 定义“Build”阶段。
- 执行与”Build”阶段相关的步骤。
- 定义”Test”阶段。
- 执行与”Test”阶段相关的步骤。
- 定义“Deploy”阶段。
- 执行与”Deploy”阶段相关的步骤。
:::

11.8 CI/CD收益
高效的CI/CD环境可以获得:
- 及时发现问题
- 大幅度减少故障率
- 加快迭代速度
- 减少时间成本
