• 基于 Docker CICD 的 Master Slave 架构应用


    original
    Author:rab
    Gitlab 版本:15.1.2
    Jenkins 版本:2.332.3



    背景

    企业在高并发构建场景下,Jenkins 是存在性能瓶颈的,我记得之前写过一篇文章关于 Jenkins 内存溢出的问题,感兴趣的大佬们可以去看看《记一次 Jenkins 构建内存溢出的解决方案》。由此可见,Jenkins 确实存在一定性能瓶颈的。因此,我们可以部署一套高性能的 CD Master Slave 架构,在构建时,对项目指定 Jenkins node 节点进行构建,从而缓解单台 Jenkins 服务的压力,从而提升构建效率。

    一、规划

    1.1 主机规划

    HostServerVersion备注
    192.168.56.131(2C/4G/30G)Jenkins2.332.3Jenkins-master
    192.168.56.132(2C/4G/30G)Jenkins2.332.3Jenkins-slave
    192.168.56.133(2C/4G/30G)Gitlab15.1.2code server

    :至少需要两台 Jenkins 服务器,slave 可有多台。由于我本地服务器资源限制,这里暂且使用“一主一从”的架构模式。

    1.2 部署方式

    本次采用 Docker 容器化部署,实现基于 Docker 的完整 CICD 流程。

    二、部署

    2.1 Jenkins

    两台 Jenkins 服务器均操作

    2.1.1 基础部署及配置

    1、创建 Jenkins 工作目录

    mkdir -p /home/data/jenkins
    useradd jenkins
    chown jenkins.jenkins /home/data/jenkins
    
    # 注意
    # 如果不赋予jenkins用户权限,则容器无法启动。
    # 如果不赋予jenkins用户权限,需执行 777 权限
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、运行 Jenkins 容器

    docker run -itd \
           --privileged=true  \
           --name jenkins \
           --restart=always \
           -p 8080:8080 \
           -p 50000:50000 \
           -v /home/data/jenkins:/var/jenkins_home \
           -v /var/run/docker.sock:/var/run/docker.sock \
           -v /etc/localtime:/etc/localtime \
           -e JAVA_OPTS=-Duser.timezone=Asia/Shanghai jenkins/jenkins:2.332.3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    浏览器 URL 访问测试:http://192.168.56.131:8080/

    3、查询初始密码,并输入初始密码

    • 容器内部查看初始密码

      docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
      xxxxxxxxxx
      
      • 1
      • 2
    • docker logs -f jenkins 动态查看(高亮部分即为初始密码)

      qq

    4、选择推荐插件安装/稍后安装都可以

    新手选择 选择推荐插件安装 即可

    image-20220712095206659

    5、根据提示设置新的用户名密码即可登录

    image-20220712115206751

    6、插件安装

    官方插件下载地址:https://plugins.jenkins.io/

    在系统管理——>插件管理

    image-20220712115258437

    如何安装插件?

    image-20220712115535801

    2.1.2 Master Slave 配置

    当两台 Jenkins 服务器都配置完成后,接下来就是部署 master-slave 架构了。

    1、定义远程 Jenkins Slave 的工作目录

    mkdir /var/jenkins_home
    
    # 注意:这个目录有什么用?
    # 如果你的 master 与 slave 是以 ssh 密钥方式通信,则相关的密钥文件(~/.ssh/*)必须存放于该目录下,否则无法在 Slave 运行agent 进程。用户名/密码方式则无该要求
    # 你的java二进制命令也必须存放于该目录下的./jak/bin/,否则找不到 java 指令(你写在profile里也不行啊,因为master找的是绝对路径),则无法在 Slave 运行agent 进程。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、132 服务器部署 JDK 环境

    tar xzf jdk-8u202-linux-x64.tar.gz -C /var/jenkins_home
    mv /var/jenkins_home/jdk-8u202-linux-x64 /var/jenkins_home/jdk
    
    • 1
    • 2

    3、在 131 服务器上添加 Jenkins slave 节点

    image-20220712104021413

    4、点击 Create 后继续以下配置

    image-20220712105306471

    如何添加主机密钥凭证?

    image-20220712104801894

    扩展(可选)

    当然你也可以启动 java web 的方式来实现

    image-20220712122952377

    在管理节点选择对应的 slave

    image-20220712125413146

    具体如下:

    image-20220712125825174

    点击【Launch】获取 JNLP 文件(jenkins-agent.jnlp),会下载到你本地。
    点击图片中 agent.jar ,jar 包会下载到你本地。
    分别上传 jenkins-agent.jnlp、agent.jar 到你的 jenkins-node1 节点的。

    复制上图启动命令:连接 Master

    echo "7dd1168f19c1d6d37917209e74de67501b816e40d3cd507def381f81243893da" > secret-file
    
    nohup java -jar agent.jar -jnlpUrl http://192.168.56.131:8080/computer/jenkins%2Dnode1/jenkins-agent.jnlp -secret @secret-file -workDir "/home/data/jenkins" &> ./agent.out &
    
    • 1
    • 2
    • 3

    输出以下日志表示成功连接 master

    image-20220712132015388

    5、配置完成后,手动点击启动 agent 进程

    观察输出日志,看到 succeefull 字眼说明启动成功。

    当然,你也可以去 slave 节点查看 Java 进程。

    image-20220712121736945

    6、最终可在 master 节点管理处看到已在线的 slave 节点

    image-20220712113543694

    至此,Jenkins 的 master slave 架构部署完成!

    2.2 Gitlab

    1、创建持久化目录

    mkdir -p /home/data/gitlab
    
    • 1

    2、运行 Gitlab 容器

    docker run -itd \
        --privileged=true \
        --name=gitlab \
        --restart=always \
        -p 443:443 \
        -p 80:80 \
        -p 2022:22 \
        -v /home/data/gitlab/conf:/etc/gitlab \
        -v /home/data/gitlab/log:/var/log/gitlab \
        -v /home/data/gitlab/data:/var/opt/gitlab \
        -v /etc/localtime:/etc/localtime \
        gitlab/gitlab-ce:15.1.2-ce.0
        
    # 注意,如果你的宿主机的 ssh 端口为默认的 22,则此处的映射就不能再是 22 了,否则会造成端口冲突。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、初始化需等待一定时间,可查看日志来跟踪此过程

    docker logs -f gitlab
    
    • 1

    image-20220713215703865

    4、获取初始密码

    密码文件将在 24 小时后的第一次重新配置运行中自动删除。

    docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
    
    • 1

    5、登录验证

    http://192.168.56.131/

    image-20220713215904364

    可成功登录,登录后可修改初始密码(zhurs@123)。

    image-20220713220213119

    至此,Gitlab 部署完成!接下来的工作就是创建项目库。

    image-20220716101825718

    三、验证

    3.1 Master Slave 架构可用性测试

    1、创建一个流水线工程项目

    下图的 label 标签就是我们添加 Jenkins slave 节点时指定的标签名

    image-20220712135850705

    2、看看输出控制台

    image-20220712135657664

    3.2 CICD 整体测试

    此处以 Java 后端为例进行演示。

    3.2.1 Gitlab 新建源码项目

    image-20220715111457949

    3.2.2 Jenkins 编写 Jenkinsfile

    1、Jenkins 如何 clone Gitlab 远程代码?

    在Jenkins 流水线语法,进行片段生成。

    image-20220715111659073

    填写 git 仓库地址(项目源码地址)

    添加 git 仓库凭证(目的是为了 Jenkins 能与 Gitlab 通信)— 点击 ADD 添加凭证

    image-20220715110418098

    添加凭证方式

    • 用户名/密码形式

      这种方式对应 gitlab 的 http

      image-20220715112351505

    • ssh 密钥形式

      这种方式对应 gitlab 的 ssh

      Jenkins 上传私钥:

      image-20220715113827647

      Gitlab 上传公钥:

      image-20220715120725542

    点击生成 jenkinsfile 语句

    image-20220715121804333

    # SSH密钥
    checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: 'git-pull', url: 'ssh://git@192.168.56.133:2022/root/tq.git']]])
    
    # Http用户名/密码
    checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-root-user', url: 'http://192.168.56.133/root/tq.git']]])
    
    # 两者选其一即可
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、项目构建

    mvn clean package -Dmaven.test.skip=true -P test
    
    • 1

    3、选项参数

    同样用 Jenkins 自带流水线代码片段生成器来生成

    实现的选项参数功能:

    • 自动获取 Gitlab 远程仓库分支(gitParameter);
    • 项目构建列表(extendedChoice);
    • 项目构建环境(choice);
    • 项目构建后选择是否启动(booleanParam).
    • gitParameter

      该参数类型可自动获取远程 Gitlab 仓库的源码项目的所有分支或标签。
      
      gitParameter (name: 'BRANCH_TAG', type: 'PT_BRANCH_TAG', branchFilter: 'origin/(.*)', defaultValue: 'main', selectedValue: 'DEFAULT', sortMode: 'DESCENDING_SMART', description: '选择分支或标签')
      
      # name:自定义
      # defaultValue:自定义
      # description:自定义
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • extendedChoice

      该参数类型为选项参数,支持多选。
      
      extendedChoice(name: 'JOB', description: '选择需要发布的项目', multiSelectDelimiter: ',', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_CHECKBOX', value: 'all,project-1,project-2,project-3', visibleItemCount: 10)
      
      # name:自定义
      # description:自定义
      # multiSelectDelimiter:分隔符 -- 自定义
      # value:自定义,并以英文状态下逗号分割
      # visibleItemCount:选项展示的数量
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    • choice

      该参数类型也是为选项参数,但仅支持单选。
      
      choice(name: 'ENV', choices: ['test', 'pro'], description: 'test:测试构建,pro:正式构建')
      
      # name:自定义
      # choices:自定义(可写多个)
      # description:自定义
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • booleanParam

      该参数类型为布尔类型,只有两种情况 true 或 false。
      
      booleanParam(name: 'START', defaultValue: 'false', description: '是否构建完成后启动项目?是则勾选,否则需手动启动项目。')
      
      # name:自定义
      # defaultValue:默认为 false (或true)
      # description:自定义
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • text

      该参数类型文本类型。
      
      text defaultValue: 'project-1,project-2,project-3',name: 'ALL_PROJECT_LIST'
      
      # name:自定义
      # defaultValue:自定义
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    4、配置远程主机信息

    同样用 Jenkins 自带流水线代码片段生成器来生成

    构建成功后,jar 包如何发布远程测试/生产服务器?

    • withCredentials: Bind credentials to variables 方法生成加密信息

      image-20220715131611863

      该方法支持多种方式加密,根据实际情况选择。我本次采用的是 Username and password (separated)

      image-20220715130614089

    • 远程测试/生产服务器配置信息

      上面生成的用户名/密码的加密信息就是用于下图中来做变量替换的,如下图中远端服务器用户名/密码都是明文形式,不安全。

      image-20220715131348001

    • 最终配置如下

      withCredentials([usernamePassword(credentialsId: 'remote-host', passwordVariable: 'PassWord', usernameVariable: 'UserName')]){
          def remote = [:]
          remote.name = "$Jarnname"
          remote.host = "$Host"
          remote.user = "$UserName"
          remote.password = "$PassWord"
          remote.port = 22
          remote.allowAnyHosts = true
          //在远程测试/生产服务器执行命令(可选)
          sshCommand remote: remote, command: "sudo mv ${ProJect}/$Jarnname  ${ProJect}/${Jarnname}.\$(date +%Y%m%d_%H:%M)"
          //部署jar包(必选)
          //如果into不添加具体路径,默认发布到远程服务器的家目录下
          sshPut remote: remote, from: "${WORKSPACE}/${ProJect}/target/$Jarnname", into: "./${ProJect}/", override: true
          //在远程测试/生产服务器执行命令(可选)
          sshCommand remote: remote, command: "sudo chown root.root ${ProJect}/$Jarnname"
          sshCommand remote: remote, command: "sudo cp -f ${ProJect}/$Jarnname /opt/$ENV/${ProJect}/$Jarnname"
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

    上面是用户名/密码的方式与远程主机的通信,当然你也可以以 SSH 用户密钥的方式,可参考我前面的博文《Jenkins Pipeline 密钥实现远程部署》

    5、流水线后操作

    流水线是否执行成功,我们可以通过钉钉或邮件等其他形式通知,具体配置看我前面的博文《Jenkins Pipeline 配置钉钉消息通知》

    6、编写完 Jenkinsfile 之后执行构建

    当然,Jenkins 需要安装一些额外的插件,这里不再赘述。

    image-20220721142741602

    如上图构建成功,当然流水线代码较多,我没有写在上面,遇到问题的朋友可以私我,我们一起交流解决。

    至此,一套 Jenkins Master Slave 架构部署完成。

    四、FAQ

    4.1 SSH 问题

    启动 jenkins slave 时输出日志信息:

    No entry currently exists in the Known Hosts file for this host. Connections will be denied until th
    
    • 1

    再次编辑 Jenkins slave 选择下图红色框选项即可。

    image-20220712111708967

    4.2 无法启动 agent

    当我们 jenkins-node1 配置完成后,Jenkins-master 会通过 ssh 连接远程 slave,并自动为我们在 slave 节点启用一个 agent 进程(remoting.jar),所以要保证远程 slave 具备 JDK 环境。在 1.1.2 小结 已进行了说明。

    4.3 Gitlab 用户头像无法显示

    1、现象

    image-20220713222428057

    2、解决方案

    原因是因为GitLab默认使用了Gravatar的头像,而Gravatar目前是被墙的。所以访问不了,解决问题的办法就是更换其URL为国内的某个镜像URL。

    vim /home/data/gitlab/data/gitlab-rails/etc/gitlab.yml
    
    ...
    plain_url: http://sdn.geekzu.org/avatar/%{hash}?s=%{size}&d=identicon
    ssl_url: https://sdn.geekzu.org/avatar/%{hash}?s=%{size}&d=identicon
    ...
    
    # 其实也就是修改容器里的/var/opt/gitlab/*/gitlab.yml文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    image-20220713222227158

    重启以下 Gitlab 即可。

    docker exec -it gitlab bash
    gitlab-ctl restart
    
    # 或 docker restart gitlab
    
    • 1
    • 2
    • 3
    • 4

    image-20220713223041147

    在看看,头像已经正常显示了。

    image-20220713223310224

    也可自定义自己的头像:

    image-20220713225042146

    4.4 Gitlab 502 报错

    1、现象

    image-20220714003018565

    2、解决方案

    这个一般是你服务器性能出现问题,稍等片刻或重启 Gitlab 即可解决。

    4.5 Git 克隆报错

    1、git clone 时提示如下错误

    提示无法解析这个主机名。

    image-20220715100731082

    上 Gitlab 看一下:不是主机IP,而是一串随机字符

    image-20220715100600850

    2、解决方案

    • 修改配置文件

      vim /home/data/gitlab/conf/gitlab.rb
      
      • 1

      image-20220715101043532

    • 重启 Gitlab

      docker restart gitlab
      
      • 1
    • 再次查看

      image-20220715102148482

    • 新建一个 tq 项目并克隆

      image-20220715102401647

      git clone ssh://git@192.168.56.133:2022/root/tq.git
      
      # 注意:ssh协议,其容器内部的22端口映射到了我的宿主机的2022端口了,所以clone时需改为2022端口。
      # 如下图:成功clone
      
      • 1
      • 2
      • 3
      • 4

      image-20220715102605206

    4.6 Jenkins 插件安装失败

    1、Jenkins 插件管理

    Jenkins 插件默认使用其官方源安装,因此在我们国内的话可能会安装失败,于是可以更换为国内源进行安装。

    国内源:

    https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
    http://mirror.xmission.com/jenkins/updates/update-center.json

    image-20220716123013773

    2、修改 Jenkins 服务器 default.json配置

    将其中的 updates.jenkins-ci.org/download 替换为 mirrors.tuna.tsinghua.edu.cn/jenkins

    某些 Jenkins 版本当中,是将 updates.jenkins.io/download 替换为 mirrors.tuna.tsinghua.edu.cn/jenkins

    然后,把 www.google.com 修改为 www.baidu.com

    vim /home/data/jenkins/updates/default.json
    
    # 全局替换
    :%s#updates.jenkins.io/download#mirrors.tuna.tsinghua.edu.cn/jenkins#g
    :%s#www.google.com#www.baidu.com#g
    
    # 或
    sed -i 's#updates.jenkins.io/download#mirrors.tuna.tsinghua.edu.cn/jenkins#g' default.json
    sed -i 's#www.google.com#www.baidu.com#g' default.json
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3、重启 Jenkins 服务

    docker restaer jenkins
    
    • 1

    ci.org/download替换为mirrors.tuna.tsinghua.edu.cn/jenkins`

    某些 Jenkins 版本当中,是将 updates.jenkins.io/download 替换为 mirrors.tuna.tsinghua.edu.cn/jenkins

    然后,把 www.google.com 修改为 www.baidu.com

    vim /home/data/jenkins/updates/default.json
    
    # 全局替换
    :%s#updates.jenkins.io/download#mirrors.tuna.tsinghua.edu.cn/jenkins#g
    :%s#www.google.com#www.baidu.com#g
    
    # 或
    sed -i 's#updates.jenkins.io/download#mirrors.tuna.tsinghua.edu.cn/jenkins#g' default.json
    sed -i 's#www.google.com#www.baidu.com#g' default.json
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3、重启 Jenkins 服务

    docker restart jenkins
    
    • 1

    如有错漏之处,敬请指正!

    <点击跳转至开头>

  • 相关阅读:
    python安装源码包
    基于密码芯片的 DDR 加速器的设计与实现
    基于Jeecgboot前后端分离的平台后端系统采用jenkins发布
    软考-软件工程
    RabbitMQ 基础操作
    分布式 | 几步快速拥有读写分离
    项目人力资源管理
    Java复习-20-接口(3)- 代理设计模式
    exceljs库实现excel表样式定制化
    基于标准库的STM32的外部中断EXTI
  • 原文地址:https://blog.csdn.net/IT_ZRS/article/details/125911853