一 、前期准备
1、安装 Gitlab
点击查看安装教程
2、安装 Jenkins
点击查看安装教程
3、部署 Docker Harbor
点击查看安装教程
4、
程序 | ip |
---|---|
Docker + Nginx | 192.168.31.110 |
Gitlab | 192.168.31.111 |
Jenkins | 192.168.31.112 |
DockerHarbor | 192.168.31.113 |
二、CICD 实现
1、配置 Gitlab
可以切换到中文:点击头像 - Preferences - Localization - Language - Save changes
(1) 新建 git 仓库,地址: http://192.168.31.111/root/helloworld.git
(2)Admin - Setting - Network
image.png
(3)Outbound requests - 勾选 Allow requests to the local network from webhooks and integrations
image.png
(4)选择项目 - Settings - Webhooks
image.png
(5)Add new webhook - URL 和 Secret token 都从 Jenkins Triggers 中获取
image.png
{E1458EE8-9E84-4015-B0AD-8FADE422DC60}.png
2、配置 Jenkins
(1) 新建任务 - 输入任务名称 - 选择流水线 - 确定
image.png
(2)点击刚刚新建的任务 - 配置 - Triggers
(触发器)
需要安装插件 Gitlab
image.png
点开高级 - 选择 Filter branches by name
image.png
勾选 Filter branches by name - 填写分支 - 生成 Secret token
image.png
(3)流水线配置
image.png
image.png
(4)配置凭据
image.png
(5)其它设置
1、直接在服务器上安装 jenkins
# 从 jenkins 服务器 192.168.31.112 添加的任务发布到 Nginx 服务器 192.168.31.110
# 需要把公钥拷贝到 192.168.31.110
# 如果执行 docker 操作,还需要给 jenkins 用户添加 docker 执行权限
# 在 Jenkins 服务器上以 jenkins 用户生成密钥:
sudo -u jenkins ssh-keygen -t ed25519 -f /var/lib/jenkins/.ssh/id_ed25519
# 查看公钥内容
sudo -u jenkins cat /var/lib/jenkins/.ssh/id_ed25519.pub
# 将公钥拷贝到目标服务器
sudo -u jenkins ssh-copy-id -i /var/lib/jenkins/.ssh/id_ed25519.pub root@192.168.31.110
# 以 jenkins 用户身份执行 shell,然后执行 docker ps,可以查看 jenkins 是否有权限执行 docker ps
sudo -u jenkins bash
# 检查 Jenkins 用户所属组
id jenkins
# 将 Jenkins 用户添加到 docker 用户组
sudo usermod -aG docker jenkins
# 重启 Jenkins 服务
sudo systemctl restart jenkins
# 重启 Docker 服务:
sudo systemctl restart docker
2、通过 docker 安装 jenkins
# 获取宿主机的 docker 组 GID
getent group docker | cut -d: -f3
# 在宿主机运行以下命令,确认 UID 1000 的用户是否存在:
id -nu 1000 # 应返回 "jenkins" 或其他用户名
# 如果不存在,需先创建用户并指定 UID:
sudo useradd -u 1000 -m jenkins
# 将 UID 1000 的用户加入 docker 组
sudo usermod -aG docker $(id -nu 1000)
# 查看 jenkins 是否有执行 docker ps 的权限
[root@jenkins ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9acb30a66cc7 jenkins/jenkins:lts "/usr/bin/tini -- /u…" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp, 0.0.0.0:50000->50000/tcp, [::]:50000->50000/tcp jenkins
[root@jenkins ~]# docker exec -it 9acb30a66cc7 bash
jenkins@9acb30a66cc7:/$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9acb30a66cc7 jenkins/jenkins:lts "/usr/bin/tini -- /u…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp, 0.0.0.0:50000->50000/tcp, [::]:50000->50000/tcp jenkins
# 1. 在 Jenkins 容器内生成 SSH 密钥,发布到其它服务器的时候可以用 ssh 连接
# 进入 Jenkins 容器
docker exec -it jenkins bash
# 生成 SSH 密钥对
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" # 无密码
# 2. 将公钥复制到目标服务器
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@target-server
3、配置 DockerHarbor,新建项目
image.png
4、web 项目内容
web 项目一共三个文件,所有内容如下
(1)index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView Test</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
(2)Dockerfile 文件
# 使用官方的 Nginx 镜像作为基础镜像
FROM nginx:latest
# 将当前目录下的所有文件复制到 Nginx 容器的默认网页根目录(/usr/share/nginx/html)
COPY . /usr/share/nginx/html
# 暴露 Nginx 服务的默认端口 80
EXPOSE 80
(3)Jenkinsfile 文件
pipeline {
agent any
environment {
// 定义 Docker 相关变量
DOCKER_REGISTRY = "cicd.ddzhixu.com:443"
IMAGE_NAME = "helloworld/helloworld"
TIMESTAMP = "${new Date().format('yyyyMMdd_HHmmss', TimeZone.getTimeZone('Asia/Shanghai'))}" // 默认 UTC 时间,更改为 CST 时间为:年月日-时分秒
DEPLOY_SERVER = "root@192.168.31.110" // 目标服务器地址
DEPLOY_DIR = "/root" // 目标服务器上的部署目录
}
stages {
stage('Checkout') {
steps {
// 从代码仓库拉取代码(假设代码已经提交到 Git 仓库)
git credentialsId: 'fa1644ee-7237-4388-8c95-11764b542803', url: 'http://192.168.31.111/root/helloworld.git', branch: 'main'
}
}
stage('Build Docker Image') {
steps {
// 构建 Docker 镜像,镜像标签格式为:仓库地址/镜像名:时间戳
sh """
docker build -t ${DOCKER_REGISTRY}/${IMAGE_NAME}:${TIMESTAMP} .
"""
}
}
stage('Login to Docker Harbor') {
steps {
// 使用 Jenkins 凭证系统管理 Docker Harbor 的用户名和密码
withCredentials([usernamePassword(credentialsId: '64cad706-930f-457b-9756-f468ea96c570', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASSWORD')]) {
sh '''
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USER}" --password-stdin cicd.ddzhixu.com:443
'''
}
}
}
stage('Push Docker Image') {
steps {
// 将构建好的 Docker 镜像推送到 Docker Harbor
sh """
docker push ${DOCKER_REGISTRY}/${IMAGE_NAME}:${TIMESTAMP}
"""
}
}
stage('Deploy to Server') {
steps {
script {
def IMAGE_TAG = "${DOCKER_REGISTRY}/${IMAGE_NAME}:${TIMESTAMP}"
// 使用 sshagent 管理凭据
sshagent(['ac999135-8dd0-434f-ade1-773921ac78d4']) {
// 更新目标服务器上的 helloworld.yaml 文件
sh """
ssh -v ${DEPLOY_SERVER} "
cd ${DEPLOY_DIR} &&
sed -i 's|image:.*|image: ${IMAGE_TAG}|' helloworld.yaml
"
"""
// 在目标服务器上拉取最新镜像并启动服务
sh """
ssh ${DEPLOY_SERVER} "
cd ${DEPLOY_DIR} &&
ls -l && # 打印当前目录文件列表,用于调试
docker compose -f helloworld.yaml pull &&
docker compose -f helloworld.yaml up -d
"
"""
}
}
}
}
}
post {
success {
echo "Pipeline completed successfully with image tag: ${DOCKER_REGISTRY}/${IMAGE_NAME}:${TIMESTAMP}"
}
failure {
echo "Pipeline failed"
}
}
}
5、服务器 192.168.31.110
(1)/root 目录下添加 helloworld.yaml 文件,内容如下
version: '3.8' # 使用 Docker Compose 的版本
services:
helloworld: # 服务名称
image: cicd.harbor.com:443/helloworld/helloworld:20250419_122044
container_name: helloworld # 容器名称
ports:
- "8081:80" # 将容器的 80 端口映射到主机的 8081 端口
environment:
- NODE_ENV=production # 设置环境变量
restart: always # 容器意外停止时自动重启
6、CICD
将
web
项目上传到Gitlab
仓库之后,会触发Jenkins
执行web
项目下Jenkinsfile
中定义的任务 ,然后浏览器访问http://192.168.31.110:8081
,即可查看页面
Jenkins 执行成功或者失败,可以在这里查看日志
image.png