CICD04 Jenkins容器化CICD实现及分布式构建, 流水线Pipeline ubuntu使用
2.14.3 案例: 基于 Docker 插件实现自由风格任务实现 Docker 镜像 制作
不如前面的直接脚本编写灵活
2.14.3.2 安装插件 docker-build-step
jenkins上安装 docker-build-step 插件
#选择jenkins使用的docker服务 #左侧系统管理,右侧系统配置,Docker Builder下Docker URL输入 unix:///var/run/docker.sock #unix://开头,后面套接字前面以对jenkins用户授权 #也可以配置成 tcp://localhost:2375 #点test测试,如报错可能是docker代理问题,把jenkins全局安全配置跨站请求伪造保护启动代理兼容 #注:sock是本地连接,如果要使用远程机器docker,输入 tcp://10.0.0.152:2375 #jenkins通过插件连接harbor,需要建一个凭据(使用的docker服务不用事先登录harbor) #jenkins左侧系统管理,右侧凭据管理,添加凭据,用户名密码类型,输入harbor用户名密码 #ID,描述输入 harbor-xiaoming-password #创建自由风格项目,输入git仓库,分支 #Build Steps下选执行shell,先进行编译 mvn clean package -Dmaven.test.skip=true #然后,Build Steps下选Execute Docker command,选create/build image #Build context folder(dockerfile路径) 填 $WORKSPACE #项目目录下,如果有子目录就往下写 #Tag of the resulting docker image(构建标签) 填 (后续要上传镜像) harbor.wang.org/example/$JOB_NAME:$BUILD_NUMBER #Build Steps下选Execute Docker command,选Push image #Name of the image to push (repository/image) 填 example/$JOB_NAME #Tag(标签) 填 $BUILD_NUMBER #Registry 填 harbor.wang.org #Docker registry URL 填 http://harbor.wang.org #Registry credentials(凭据) 选 上面创建的harbor凭据 #Build Steps下选执行shell,目标机器运行容器 #!/bin/bash REGISTRY=harbor.wang.org HOSTS=" 10.0.0.153 10.0.0.154" #目标服务器docker要允许远程连接 for i in $HOSTS;do #ssh root@$i docker rm -f $JOB_NAME #ssh root@$i docker run -d -p 80:8888 --name $JOB_NAME harbor.wang.org/example/$JOB_NAME:$BUILD_NUMBER docker -H $i rm -f $JOB_NAME || true docker -H $i run -d -p 80:8888 --name $JOB_NAME ${REGISTRY}/example/$JOB_NAME:$BUILD_NUMBER done #保存任务,并构建
3.1 Jenkins 分布式
agent通过标签来分来,master上的任务通过标签去找对应的agent执行
3.1.1.2 Jenkins 主从架构图
3.1.1.3 节点标签 Label
一个 Agent 上可添加多个标签,一个标签也可以添加至多个 Agent, 可以在作业中通过标签表达式实现Agent的过滤 标签名称不允许使用空白字符,也不允许使用标签表达式中预留的关键字,例如: !、&、|、<、>、) 和( 等 常用的标签纬度有如下几个 1.操作系统类型: Linux、Windows、MacOS 2.操作系统位数: 32bit、64bit 3.集成的工具链: jdk、Go、Python、Nodejs等 标签表达式(label expressions)支持如下操作符 (了解) 1.!expression:表达式条件取反 2.a && b:表达式间“与” 关系 3.a || b:表达式间“或” 关系 4.a -> b:表示如果满足a表达式,则同时必须满足b表达式,但是如果不满足a,则不要求满足b,等同于“!a || b” 示例: linux -> x64,意味着,如果操作系统为linux,则它也必须是x64的系统环境,如果不是 linux,则无要求必须是x64 5.a<->b:表示两个条件要么同时满足,要么同时都不满足,即等同于 “a && b || !a && !b” 6.(expression):表达式分组,常在需要改变操作符间的优先级顺序时使用
3.1.1.4 Jenkins Master 与 Agent之间的通信方式
3.1.1.5 Agent 分类
Agent 可以分为静态和动态两种
静态Agent: 长时间存在(服务方式启动)
动态Agent: 用完就销毁(容器方式运行)
3.1.2 实战案例: 基于 SSH 协议实现 Jenkins 分布式
#jenkins主机上安装插件 SSH Build Agents #agent程序基于java,jenkins会传jar包到agent机器进行启动。 #两台agent机器环境需要安装和jenkins相同版本的java [root@ubuntu ~]#apt update && apt -y install openjdk-11-jdk #创建agent是在jenkins主机系统管理下的节点和云管理中创建的 #点击New Node,节点名称填 jenkins-agent01,固定节点, create #Number of executors执行器,允许并发构建数,这里写 2(一般同cpu数量,最多为2倍cpu数量) #远程工作目录填 /var/lib/jenkins (最好和jenkins master的目录相同,会自动创建) #标签,可以写多个,空格隔开,jenkins根据标签分派任务,填 java agent01 linux #用法 选 只允许运行绑定到这台机器的Job (也就是匹配标签才执行) #启动方式选 Launch agents via SSH (走SSH协议) #主机 填 10.0.0.156 (可填能解析的域名) #Credentials 这里创建凭据,可以基于用户名密码 root/admin123 #(注:也可创基于SSH key验证的凭据SSH Username with private key,用户名root,填入私钥) #ID和描述填 jenkins-agent-root-password #选中前面创建的凭证 #Host Key Verification Strategy选Non veritying verification strategy(不用ssh验证yes) #可用性 这里可以选 尽量保持代理在线 #节点属性下工具位置可以安装工具,这里不安装 #保存 #jenkins系统管理下节点列表显示节点没×表示连接成功,会显示内存等信息 #可以看到agent机器上运行了java应用 #再创建另一个节点 #点击New Node,节点名称填 jenkins-agent02,复制现有节点jenkins-agent01, create #标签,可以写多个,空格隔开,jenkins根据标签分派任务,填 golang agent02 linux #主机 填 10.0.0.157 (可填能解析的域名) #保存 #在一台专门java编译的agent上安装mvn ]#apt install -y maven #jenkins master上创建任务测试agent #创建自由风格任务,git输入java项目地址,分支 #General下点限制项目的运行节点,标签表达式(选择机器标签)输入 java #Build Steps,执行shell bash -x /data/jenkins/scripts/spring-boot-helloworld.sh #保存 [root@jenkins scripts]#cat spring-boot-helloworld.sh #!/bin/bash APP_PATH=/data/spring-boot-helloworld HOST_LIST=" 10.0.0.153 10.0.0.154 " mvn clean package -Dmaven.test.skip=true for host in $HOST_LIST;do ssh root@$host killall -9 java &> /dev/null scp target/spring-boot-helloworld-*-SNAPSHOT.jar root@$host:${APP_PATH}/spring-boot-helloworld.jar #ssh root@$host "java -jar ${APP_PATH}/spring-boot-helloworld.jar --server.port=8888 &" ssh root@$host "nohup java -jar ${APP_PATH}/spring-boot-helloworld.jar --server.port=8888 &>/dev/null & "& done #把执行脚本拷贝到agent机器上保持一致 [root@jenkins scripts]#scp -r /data/ 10.0.0.156:/ [root@jenkins scripts]#scp -r /data/ 10.0.0.157:/ #别忘了把新的2台agent机器和目标机器做免ssh的key验证 #构建任务
#准备docker-compose环境 [root@ubuntu2204 ~]#apt update && apt -y install docker-compose [root@ubuntu2204 ~]#vim docker-compose.yaml version: '3.6' volumes: ssh_agent01_data: {} ssh_agent02_data: {} networks: jenkins_net: driver: bridge ipam: config: - subnet: 172.27.0.0/24 services: ssh-agent01: image: jenkins/ssh-agent:jdk11 hostname: ssh-agent01.wang.org #user: jenkins environment: TZ: Asia/Shanghai #JENKINS_AGENT_HOME: /home/jenkins JENKINS_AGENT_SSH_PUBKEY: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC5krPWvOcWvQTP++JNkdBACy46vKnpcnIrNuv85NFIVFOGsvnvAZHCp2DRjXS7Q0GngipZ27XyTF99SEZnxZbS01ZgRSqldYaSHt+1poj4YSB+0tdP9+FO7u3NNyQ7qZ3NB4OzT21SFHIWm3ToA0Yjen8o8V3Dk87GdhE1O+8mWBYGyEQVN8QNveMFvI0dArWDwFjO/7Fu5zDS1/B6Sx4TLNBCoPE0gJ/A02pcpdDXk7pDdeAwC3SIqpOj2IuuoAQA4fNue1sx18av6DHKdkONf+fzJAVRJc+hgIsxqv94bP28HElbyE+1pdj0KBVU8FIGGJvvfL5RC2bk8NwPCsjEwYReL3nWDYPqQTjL4CCGjM6dpAgiM1UyYdcIQ499PEq/JAshktFEKn8LaVXl7nigi09AOQyTZ9l7D7de2gwcnKL26sbZ3gaB1O1cj3RCp1HjFvFS75py9F8flBYVNooRu7zMn4lnbA5pojSJXPsVs+4I821BmuRSZDVbsWRG2r8= root@jenkins # SSH PRIVATE KEY and PUBLIC KEY 需要手动生成,利用private key 创建凭据,此处写入public key networks: jenkins_net: ipv4_address: 172.27.0.21 aliases: - ssh-slave01 - ssh-agent01 ports: - "22022:22" #restart: always ssh-agent02: image: jenkins/ssh-agent:jdk11 hostname: ssh-agent02.wang.org #user: jenkins environment: TZ: Asia/Shanghai #JENKINS_AGENT_HOME: /home/jenkins JENKINS_AGENT_SSH_PUBKEY: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC5krPWvOcWvQTP++JNkdBACy46vKnpcnIrNuv85NFIVFOGsvnvAZHCp2DRjXS7Q0GngipZ27XyTF99SEZnxZbS01ZgRSqldYaSHt+1poj4YSB+0tdP9+FO7u3NNyQ7qZ3NB4OzT21SFHIWm3ToA0Yjen8o8V3Dk87GdhE1O+8mWBYGyEQVN8QNveMFvI0dArWDwFjO/7Fu5zDS1/B6Sx4TLNBCoPE0gJ/A02pcpdDXk7pDdeAwC3SIqpOj2IuuoAQA4fNue1sx18av6DHKdkONf+fzJAVRJc+hgIsxqv94bP28HElbyE+1pdj0KBVU8FIGGJvvfL5RC2bk8NwPCsjEwYReL3nWDYPqQTjL4CCGjM6dpAgiM1UyYdcIQ499PEq/JAshktFEKn8LaVXl7nigi09AOQyTZ9l7D7de2gwcnKL26sbZ3gaB1O1cj3RCp1HjFvFS75py9F8flBYVNooRu7zMn4lnbA5pojSJXPsVs+4I821BmuRSZDVbsWRG2r8= root@jenkins # SSH PRIVATE KEY and PUBLIC KEY 需要手动生成,利用private key 创建凭据,此处写入:public key,和上面一样 networks: jenkins_net: ipv4_address: 172.27.0.22 aliases: - ssh-slave02 - ssh-agent02 ports: - "22122:22" #restart: always #把上面公钥对应的私钥.ssh/id_rsa,在jenkins master中创创建凭据 #jenkins系统管理下,凭据管理,Add Credentials #类型 SSH Username with private key,用户名(可能是jenkins启动用户)写 jenkins #Private Key填入私钥 #ID和描述写 jenkins-agent-ssh-privatekey #拉起容器 [root@ubuntu ~]#docker-compose up #起来了2个容器 [root@ubuntu ~]#docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b95d341fe35d jenkins/ssh-agent:jdk11 "setup-sshd" 11 minutes ago Up 11 minutes 0.0.0.0:22122->22/tcp, :::22122->22/tcp root_ssh-agent02_1 e5322fa9b0d0 jenkins/ssh-agent:jdk11 "setup-sshd" 11 minutes ago Up 11 minutes 0.0.0.0:22022->22/tcp, :::22022->22/tcp root_ssh-agent01_1 #jenkins系统管理,节点和云管理,创建新的agent #名称 jenkins-ssh-agent03, 固定节点 #远程工作目录(容器里面已经定义好了) /home/jenkins #标签 ssh #用法 尽可能使用 #启动方式 Launch agents via SSH #主机 10.0.0.156 #点高级,端口 22022 #Credentials凭据选前面创建的 jenkins-agent-ssh-privatekey #Host Key Verification Strategy选 Non verfiying verification strategy #保存,即可在从库列表看到节点对应状态 #jenkins系统管理,节点和云管理,创建新的agent,复制上面那个 #名称 jenkins-ssh-agent04, 复制现有节点jenkins-ssh-agent03 #点高级,端口 22122 #保存,即可在从库列表看到节点对应状态 #这两个镜像可能也有缺陷,比如没有maven,可以用他们作为父镜像,做子镜像 #jenkis执行任务测试这两个容器agent #标签表达式ssh,git通过http方式,执行命令hostname -I #注:如git用ssh失败,要先进容器,git clone手动信任主机,就能用这种方式了 #也可在jenkins系统管理/全局安全配置/Git Host Key Verification Configuration选No verification
Launch agent by connecting it to the controller 也称为 通过 Java Web 启动代理
此方式无需安装插件,即可实现
#jenkins系统管理/全局安全配置/代理 改成指定端口 50000
3.1.4.2 创建代理Agent节点
#jenkins系统管理/节点和云管理,创建节点 jenkins-jnlp-agent01,固定节点 #Number of executors 2 #远程工作目录 /var/lib/jenkins #标签 jnlp agent01 #用法 只允许运行绑定到这台机器的ob #启动方式 通过Java Web启动代理 #保存,点击该节点名称,有2条运行指令 Run from agent command line: (Unix)下 #在agent机器上执行上面2步,注意:要提前装java [root@ubuntu2204 ~]#apt update && apt -y install openjdk-11-jdk curl -sO http://10.0.0.152:8080/jnlpJars/agent.jar [root@ubuntu2204 ~]#ls -l agent.jar -rw-r--r-- 1 root root 1371733 1月 1 17:07 agent.jar #启动Agent [root@ubuntu2204 ~]#java -jar agent.jar -url http://10.0.0.152:8080/ -secret b3cb19d89c6d22a0a4457d01f2efaf10233a3b55779dcc0efa160e32c3201539 -name "jenkins-jnlp-agent01" -workDir "/var/lib/jenkins" ... INFO: Connected #jenkins从库列表看到节点对应状态 #jenkins系统管理/节点和云管理,创建另一个节点 jenkins-jnlp-agent02,复制上面的节点 #标签 jnlp agent02 #保存 #另一台agent机器同样执行从节点给出的2步 #验证,jenkins自由风格任务,标签表达式 jnlp
3.1.5.2 启动 Docker Compose 容器的 Jenkins Agent
#jenkins上先创建从节点jenkins-jnlp-agent01,方法同上 #远程工作目录(镜像定义的) /data/jenkins/ #记录生成创建命令中的秘钥,如下命令为 b3cb19d89c...01539 java -jar agent.jar -url http://10.0.0.152:8080/ -secret b3cb19d89c6d22a0a4457d01f2efaf10233a3b55779dcc0efa160e32c3201539 -name "jenkins-jnlp-agent01" -workDir "/var/lib/jenkins" #替换下面docker-compose中的JENKINS_SECRET #再生成一个从节点jenkins-jnlp-agent02,复制现有节点,方法同上 [root@ubuntu2204 ~]#cat docker-compose.yaml version: '3.6' volumes: agent01_data: {} slave02_data: {} networks: jenkins_net: driver: bridge ipam: config: - subnet: 172.27.0.0/24 services: agent01: image: jenkins/inbound-agent:alpine-jdk11 hostname: agent01.wang.org user: root environment: TZ: Asia/Shanghai JENKINS_URL: http://jenkins.wang.org:8080 JENKINS_AGENT_NAME: jenkins-jnlp-agent01 #指定和Jenkins的Agent的名称相同 JENKINS_AGENT_WORKDIR: /data/jenkins/ #秘钥用jenkins创节点给的命令中的秘钥 JENKINS_SECRET: 3aef4f69d569d9f3b48e2daf91c3a80b1c8d8bcb310462859950dacc1b202cbc # 此处的JENKINS_SECRET需要用创建agent时生成的Secret替代 volumes: - agent01_data:/data/jenkins/ networks: jenkins_net: ipv4_address: 172.27.0.11 aliases: - slave01 - agent01 #extra_hosts: # - "jenkins.wang.org:${JENKINS_HOST_IP}" #restart: always agent02: image: jenkins/inbound-agent:alpine-jdk11 hostname: agent02.wang.org user: root environment: TZ: Asia/Shanghai JENKINS_URL: http://jenkins.wang.org:8080 JENKINS_AGENT_NAME: jenkins-jnlp-agent02 #此处指定Jenkins的Agent的名称相同 JENKINS_AGENT_WORKDIR: /data/jenkins/ JENKINS_SECRET: fb52f831107fd9a7de8051ca8aa506dc4836056231d21aab7e82138febf83231 # SECRET is automatically generated by the master when adding agent02. volumes: - agent01_data:/data/jenkins/ networks: jenkins_net: ipv4_address: 172.27.0.12 aliases: - slave02 - agent02 #extra_hosts: # - "jenkins.wang.org:${JENKINS_HOST_IP}" #restart: always #拉起容器 [root@ubuntu ~]#docker-compose up #jenkins上节点列表查看,连接成功
这种用的很少, 性能一般。
3.1.6.1 准备 Docker Engine 主机
准备一台新的主机,安装 Docker Engine ,上此主机上运行Agent容器
[root@ubuntu2204 ~]#apt update && apt -y install docker.io #如果需要远程 Docker 连接,需要修配下面配置 [root@ubuntu2204 ~]#vim /lib/systemd/system/docker.service [Service] ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 [root@ubuntu2204 ~]#systemctl daemon-reload && systemctl restart docker.service #另一台机器上确认2375是否可以连接 ]#curl -s 10.0.0.156:2375/version
jenkins安装Docker插件
3.1.6.3 创建 Cloud
#jenkins系统管理下,Clouds创建new cloud #云名称 mydocker #Docker Cloud details下 Docker Host URI(docker主机地址) tcp://10.0.0.156:2375 #点击test查看能不能连上,点击Enabled,表示启用 #Docker Agent templates下, 点击添加模板 #Labels jnlp ,点Enabled #Name docker-jnlp-agent #Docker Image 镜像这里选走jnlp协议的,推荐 jenkins/inbound-agent:alpine-jdk11 #上面镜像小些,也可以jenkins/inbound-agent:jdk11 #Registry Authentication如果公司内网拉取要凭证,这里从互联网拉就不用选了 #点Container settings,Extra Hosts就是配/etc/hosts,可多个(如果公司有dns就不需要配这个) gitlab.wang.org:10.0.0.151 jenkins.wang.org:10.0.0.152 #因为主动找jenkins,需要对应的域名解析 #Remote File System Root(镜像定的) /home/jenkins #用法 只允许 #Connect method 这里选JNLP (这次用的是JNLP的方法) #Jenkins URL http://jenkins.wang.org:8080 #Pull strategy拉取策略(每次拉/拉一次有更新再拉/只在本地找) 这里选2 Pull once and update latest #别忘了系统管理/全局安全配置代理开50000端口 #再加一个模板(走SSH协议), 2个模板对应就是2个agent #Labels ssh ,点Enabled #Name docker-ssh-agent #Docker Image(基于ssh的镜像) jenkins/ssh-agent:jdk11 #点Container settings,Extra Hosts就是配/etc/hosts,可多个(如果公司有dns就不需要配这个) gitlab.wang.org:10.0.0.151 #Remote File System Root(镜像定的) /home/jenkins #用法 只允许 #Connect method 这里选SSH #SSH key 选Inject SSH key 自动注入ssh key就不用管了(也可以自己往里拷) #User写 jenkins (容器里jenkins账号运行) #点save,没有构建任务,那2个agent不会启动,执行结束也会删 #jenkins上用自由风格任务进行调用 #限制项目运行节点标签写 jnlp或者ssh,会自动显示1个cloud匹配 #注意:如果要mvn编译,还得基于该模板创建新的镜像,里面装maven 用docker插件通过云创建指定docker容器(云在哪,容器创建在哪) #在jenkins自由风格任务下,Build Steps选 Start/Stop Docker Containers #Action to choose选 Run container #Docker Cloud选择上面创建的云 mydocker #Docker Image这里写 wangxiaochun/pod-test:v0.1 #保存,构建,在连接的docker服务器上创建对应的容器
3.2.3 Pipeline 语法
当前 Jenkins 2.X 支持两种语法的流水线: 脚本式(命令式)和声明式 1.脚本式Scripted Pipeline语法 (老版本,淘汰) 2.声明式Declarative Pipeline语法 (新版,推荐)
3.2.3.2 脚本式流水线语法
node { stage('Source') { //git clone } stage('Build') { //mvn } stage('Test') { //mvn test } stage('Deploy') { // scp // java -jar } } #特点:最外层是node {}
3.2.3.3 声明式流水线语法
#声明式流水线是在"Pipeline plugin"的2.5版本添加到 Jenkins 流水线的 ,它在流水线子系统之上提供了 一种更简单,更常见的语法。 #所有有效的声明式流水线必须包含在一个 pipeline 块中, 比如: pipeline { /* insert Declarative Pipeline here */ }