一 、前期準備
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 實現(xiàn)
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(觸發(fā)器)
需要安裝插件 Gitlab

image.png
點開高級 - 選擇 Filter branches by name

image.png
勾選 Filter branches by name - 填寫分支 - 生成 Secret token

image.png
(3)流水線配置

image.png

image.png
(4)配置憑據(jù)

image.png
(5)其它設置
1、直接在服務器上安裝 jenkins
# 從 jenkins 服務器 192.168.31.112 添加的任務發(fā)布到 Nginx 服務器 192.168.31.110
# 需要把公鑰拷貝到 192.168.31.110
# 如果執(zhí)行 docker 操作,還需要給 jenkins 用戶添加 docker 執(zhí)行權限
# 在 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 用戶身份執(zhí)行 shell,然后執(zhí)行 docker ps,可以查看 jenkins 是否有權限執(zhí)行 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" 或其他用戶名
# 如果不存在,需先創(chuàng)建用戶并指定 UID:
sudo useradd -u 1000 -m jenkins
# 將 UID 1000 的用戶加入 docker 組
sudo usermod -aG docker $(id -nu 1000)
# 查看 jenkins 是否有執(zhí)行 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 密鑰,發(fā)布到其它服務器的時候可以用 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 容器的默認網(wǎng)頁根目錄(/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 {
// 從代碼倉庫拉取代碼(假設代碼已經(jīng)提交到 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 憑證系統(tǒng)管理 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 管理憑據(jù)
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 # 設置環(huán)境變量
restart: always # 容器意外停止時自動重啟
6、CICD
將
web項目上傳到Gitlab倉庫之后,會觸發(fā)Jenkins執(zhí)行web項目下Jenkinsfile中定義的任務 ,然后瀏覽器訪問http://192.168.31.110:8081,即可查看頁面
Jenkins 執(zhí)行成功或者失敗,可以在這里查看日志

image.png