基于 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 权限

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

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

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

  • 容器内部查看初始密码

    docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
    xxxxxxxxxx
    
  • 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 进程。

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

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 &

输出以下日志表示成功连接 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

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 了,否则会造成端口冲突。

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

docker logs -f gitlab

image-20220713215703865

4、获取初始密码

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

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

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']]])

# 两者选其一即可

2、项目构建

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

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:自定义
    
  • 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:选项展示的数量
    
  • choice

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

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

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

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"
    }
    

上面是用户名/密码的方式与远程主机的通信,当然你也可以以 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

再次编辑 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文件

image-20220713222227158

重启以下 Gitlab 即可。

docker exec -it gitlab bash
gitlab-ctl restart

# 或 docker restart gitlab

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
    

    image-20220715101043532

  • 重启 Gitlab

    docker restart gitlab
    
  • 再次查看

    image-20220715102148482

  • 新建一个 tq 项目并克隆

    image-20220715102401647

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

    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

3、重启 Jenkins 服务

docker restaer 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

3、重启 Jenkins 服务

docker restart jenkins

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

<点击跳转至开头>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 基于Docker的Web系统架构设计是一种将应用程序和依赖项打包在容器中的方法,使其能够在不同的环境中快速部署和运行的系统架构。 首先,我们需要将Web系统拆分为多个模块,每个模块负责不同的功能。这些模块可以是前端、后端、数据库等。 接下来,我们使用Docker将每个模块打包为一个独立的容器。每个容器包含该模块所需的所有依赖项,例如软件库、环境变量等。 为了实现容器之间的通信以及对外部的访问,我们需要使用Docker网络或者Docker Compose进行配置。通过网络,不同容器可以进行通信,例如前端容器可以向后端容器发送请求。 此外,我们可以使用Docker Swarm或Kubernetes等容器编排工具进行管理和部署。它们可以实现容器的自动化扩展、负载均衡和故障恢复,确保Web系统的高可用性和稳定性。 最后,可以通过使用Docker镜像仓库来存储和管理容器镜像,方便团队成员共享和更新。 基于Docker的Web系统架构设计带来了很多好处。首先,它提供了一种轻量级、可移植的部署方式,可以简化系统的部署和迁移。其次,它允许我们使用容器隔离技术,将应用程序与底层操作系统解耦,提高了系统的安全性和可靠性。另外,通过使用容器编排工具,我们可以更好地管理和扩展系统,提高系统的可伸缩性和性能。 总而言之,基于Docker的Web系统架构设计使得系统的部署和运维更加灵活和高效,同时提供了更好的安全性和可扩展性。 ### 回答2: 基于Docker的Web系统架构设计是一种将应用程序及其依赖项打包为容器的集中管理方式。以下是具体的架构设计: 1. 容器化应用程序:将Web应用程序和其依赖项(例如数据库、消息队列等)打包为容器镜像。可以使用Dockerfile定义容器的运行环境和依赖项。 2. 容器编排:使用容器编排工具(如Docker Compose、Kubernetes)组织和管理多个容器。可以定义容器的数量、环境变量、网络设置等。 3. 高可用和负载均衡:使用容器编排工具的负载均衡功能,在多个容器之间均衡地分发用户请求。当某个容器出现故障时,负载均衡会将请求转发到其他正常的容器上。 4. 持久化数据:将容器与数据分离,使用外部存储服务(如数据库)存储应用程序的持久化数据。这样即使容器重启或被替换,数据仍然存在。 5. 安全性:通过在容器中限制权限和访问控制,加强系统的安全性。可以使用Docker提供的安全功能,如命名空间隔离、应用程序沙箱等。 6. 监控和日志:使用容器日志和监控工具来监控系统的性能和状态。可以使用ELK(Elasticsearch, Logstash, Kibana)等工具来收集和分析日志。 7. 部署和扩展:使用容器编排工具实现无缝的部署和扩展。可以通过简单地添加或删除容器实例来调整系统的规模,从而满足用户需求。 基于Docker的Web系统架构设计可以提供更高的可扩展性、灵活性和易管理性。容器化的应用程序能够快速部署、隔离和迁移,同时通过自动化的容器编排和负载均衡,可以实现高可用和负载均衡的架构。此外,容器化的架构还可以简化开发团队的协作,提高开发效率。 ### 回答3: 基于Docker的Web系统架构设计是一种基于容器化技术的系统设计方法。它将Web应用程序的不同组件打包成独立的容器,每个容器都包含了应用程序所需的所有依赖,包括操作系统、库文件和配置文件等。 首先,Docker容器可以根据不同的功能划分为多个微服务。每个微服务负责处理特定的业务功能,如用户管理、订单管理等。因为每个微服务都是独立运行在容器中的,因此它们可以并行处理多个请求,提高系统的效率和稳定性。 其次,容器之间可以通过Docker网络进行通信。在架构设计中,可以使用容器编排工具如Docker Compose或Kubernetes来协调和管理不同容器之间的通信和调度。通过容器网络,微服务之间的通信可以通过容器名称来实现,而无需关心具体的IP地址和端口。 另外,针对系统的数据存储,可以使用Docker卷来实现持久化存储。通过将数据卷挂载到容器中,可以确保数据不会随着容器的销毁而丢失。可以使用诸如Docker Volume、Docker NFS等技术来实现数据卷的管理和共享。 最后,通过持续集成和持续部署(CI/CD)的工作流程,可以实现对Web系统的自动化构建、测试和部署。可以使用持续集成工具如Jenkins或GitLab CI来自动构建和测试Docker镜像,然后通过容器编排工具将镜像部署到生产环境中。 总之,基于Docker的Web系统架构设计通过容器化技术的应用,实现了系统组件的隔离部署、灵活扩展和资源的高效利用。它提供了一种可靠、可伸缩和易于管理的系统架构,使得Web应用程序更加稳定和可靠。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云计算-Security

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值