摘要

在现代软件开发中,持续集成(CI)和持续部署(CD)是提升开发效率、保证软件质量、实现快速交付的核心实践。本文将通过一个完整的实战案例,手把手带你搭建一套基于 Jenkins、GitLab、Kubernetes、Harbor 和钉钉的自动化CI/CD流水线,涵盖从代码提交、镜像构建、推送到应用部署、升级、回滚及结果通知的全过程。

我们本次实战将聚焦于图中 GitLab -> Jenkins -> Harbor -> Kubernetes -> 钉钉 这条主干道。而像SonarQube代码质量检查、自动化测试以及底层的Prometheus/Loki全方位监控体系,则是我们可以在此基础上进一步完善和探索的高级方向。

  • GitLab: 作为代码仓库,负责存储我们的应用源代码和Dockerfile。开发人员将代码推送到GitLab,触发整个CI/CD流程。

  • Jenkins: CI/CD的核心引擎。它负责拉取GitLab上的最新代码,执行构建任务(编译、打包、构建Docker镜像),并将构建产物(Docker镜像)推送到Harbor仓库,最后触发Kubernetes进行应用的部署或更新。

  • Harbor: 一个企业级的私有Docker镜像仓库,用于安全地存储和管理我们构建的Docker镜像。

  • Kubernetes (K8s): 容器编排平台,是我们的应用最终运行的环境。Jenkins通过kubectl命令与K8s集群交互,实现应用的部署、滚动更新和回滚。

  • 钉钉: 团队协作与通知工具。流水线执行成功或失败时,Jenkins会自动发送消息到指定的钉钉群,让团队成员第一时间了解构建状态。

第一章:基础环境准备

我们在一个独立的虚拟机上部署Jenkins

环境规划:

  • 主机名: jenkins211

  • IP地址: 10.0.0.211

  • 系统:Ubuntu22.04

步骤1:安装JDK
Jenkins是Java编写的,需要Java运行环境。我们选择JDK 17。

# 1. 下载并解压JDK
[root@jenkins211 ~]# ll
drwxr-xr-x 2 root    root     4096 Aug  2 12:13 jdk-17_linux-x64_bin.tar.gz
[root@jenkins211 ~]# tar xf jdk-17_linux-x64_bin.tar.gz -C /usr/local/

# 2. 配置环境变量
[root@jenkins211 ~]# cat > /etc/profile.d/jdk.sh <<'EOF'
#!/bin/bash
export JAVA_HOME=/usr/local/jdk-17.0.8
export PATH=$PATH:$JAVA_HOME/bin
EOF

# 3. 使环境变量生效并验证
[root@jenkins211 ~]# source /etc/profile.d/jdk.sh
[root@jenkins211 ~]# java -version

步骤2:安装 Jenkins
我们使用.deb包进行安装

# 1. 安装依赖(适用于Debian/Ubuntu,若为CentOS请使用yum install fontconfig)
[root@jenkins211 ~]# apt install fontconfig -y

# 2. 下载并安装Jenkins
[root@jenkins211 ~]# ll
drwxr-xr-x 2 root    root     4096 Aug  2 12:15 jenkins-v2.479.3/jenkins_2.479.3_all.deb
[root@jenkins211 ~]# dpkg -i jenkins_2.479.3_all.deb 

# 3. 修改Jenkins服务配置,使用root用户运行并指定JAVA_HOME
# 使用root是为了简化权限问题,生产环境建议使用专用用户并精细化授权
[root@jenkins211 ~]# vim /lib/systemd/system/jenkins.service
# --- 修改内容 ---
# User=jenkins
# Group=jenkins
User=root
Group=root
Environment="JAVA_HOME=/usr/local/jdk-17.0.8"
# --- 保存退出 ---

# 4. 重载配置并启动Jenkins
[root@jenkins211 ~]# systemctl daemon-reload
[root@jenkins211 ~]# systemctl restart jenkins.service
[root@jenkins211 ~]# systemctl enable jenkins.service
[root@jenkins211 ~]# ss -nltp | grep 8080

步骤3:初始化 Jenkins

  1. 访问 Jenkins Web UI: http://IP:8080

  2. 获取初始密码并登录。

[root@jenkins211 ~]# cat /var/lib/jenkins/secrets/initialAdminPassword
417305a1be944bb38b8c217c01ba1040

安装插件为了后续操作顺利,我们直接使用准备好的插件包。这一步将极大地节省时间。

# 下载插件包
[root@jenkins211 ~]# ll
drwxr-xr-x 2 root    root     4096 Aug  2 12:13 jenkins-2.479.3-plugins.tar.gz

# 解压到Jenkins插件目录
[root@jenkins211 ~]# tar xf jenkins-2.479.3-plugins.tar.gz -C /var/lib/jenkins/plugins/

# 重启Jenkins使插件生效
# 可以在浏览器访问:http://IP:8080/restart
[root@jenkins211 ~]# systemctl restart jenkins.service


1.2 在K8s中部署GitLab(数据持久化)

我们将GitLab部署在Kubernetes集群中,并使用NFS来持久化其数据。

步骤1:准备NFS存储
在NFS服务器上(本例中是10.0.0.231),创建共享目录。

# 在NFS Server上执行
[root@worker231 ~]# mkdir -pv /yinzhengjie/data/nfs-server/case-demo/gitlab/{data,logs,conf}
# 请确保 /etc/exports 配置正确并已导出

步骤2:准备GitLab镜像
将GitLab镜像导入到本地Docker,并推送到Harbor私有仓库。

# 在任意一个K8s Node上执行
[root@worker233 ~]# ll
drwxr-xr-x 2 root   root   4096 Aug  2 12:13  gitlab-ce-v17.5.2.tar.gz
[root@worker233 ~]# docker load -i -gitlab-ce-v17.5.2.tar.gz
[root@worker233 ~]# docker tag gitlab/gitlab-ce:17.5.2-ce.0 harbor250..com/-devops/gitlab-ce:17.5.2-ce.0
[root@worker233 ~]# docker push harbor250..com/-devops/gitlab-ce:17.5.2-ce.0

步骤3:编写并应用K8s资源清单
创建一个Deployment来运行GitLab,并创建一个LoadBalancer类型的Service来暴露服务。

# 01-deploy-svc-gitlab.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-gitlab
spec:
  replicas: 1
  selector:
    matchLabels:
      apps: gitlab
  template:
    metadata:
      labels:
        apps: gitlab
    spec:
      volumes:
      - name: data
        nfs:
          server: 10.0.0.231
          path: /yinzhengjie/data/nfs-server/case-demo/gitlab/data
      - name: conf
        nfs:
          server: 10.0.0.231
          path: /yinzhengjie/data/nfs-server/case-demo/gitlab/conf
      - name: logs
        nfs:
          server: 10.0.0.231
          path: /yinzhengjie/data/nfs-server/case-demo/gitlab/logs
      containers:
      - name: c1
        image: harbor250..com/-devops/gitlab-ce:17.5.2-ce.0
        ports:
        - containerPort: 22
          name: ssh
        - containerPort: 80
          name: http
        - containerPort: 443
          name: https
        volumeMounts:
        - name: logs
          mountPath: /var/log/gitlab
        - name: data
          mountPath: /var/opt/gitlab
        - name: conf
          mountPath: /etc/gitlab
---
apiVersion: v1
kind: Service
metadata:
  name: svc-gitlab
spec:
  type: LoadBalancer
  selector:
    apps: gitlab
  ports:
  - protocol: TCP
    port: 80
    name: http
  - protocol: TCP
    port: 443
    name: https
  - protocol: TCP
    port: 22
    name: sshd
# 在K8s Master上执行
[root@master231 02-jenkins]# kubectl apply -f 01-deploy-svc-gitlab.yaml

步骤4:获取GitLab初始密码并登录

# 等待Pod启动完成
[root@master231 02-jenkins]# kubectl get pods -l apps=gitlab -w

# 获取Pod名称
[root@master231 02-jenkins]# POD_NAME=$(kubectl get pods -l apps=gitlab -o jsonpath='{.items[0].metadata.name}')

# 从Pod日志或文件中获取初始密码
[root@master231 02-jenkins]# kubectl exec $POD_NAME -- cat /etc/gitlab/initial_root_password
TlDLGaLMsPw5VhotNNlLtYSos1pU9bhfQgHWL1YEFnQ=

# 访问测试 

用上一步的密码进行登录,用户名为: root 
修改密码:Sdms2018

使用root用户和获取到的密码,通过LoadBalancerEXTERNAL-IP访问GitLab,首次登录会要求修改密码。

第二章:代码准备与提交

现在,我们模拟开发人员,将一个Web应用项目推送到刚刚搭建好的GitLab中。

2.1 准备应用代码和Dockerfile

我们使用一个现成的静态网站项目作为示例。

# 在任意一台可以执行git命令的机器上
[root@harbor250.oldboyedu.com ~]#  unzip -yiliao.zip -d -yiliao-app
[root@harbor250.oldboyedu.com ~]#  cd -yiliao-app

在项目根目录下,创建一个Dockerfile,用于将此静态网站打包成Nginx镜像。

# Dockerfile
FROM harbor250..com/-xiuxian/apps:v1

MAINTAINER Jason Yin

LABEL school= \
      class=test

ADD . /usr/share/nginx/html

EXPOSE 80

WORKDIR /usr/share/nginx/html

2.2 在GitLab创建项目并推送代码

GitLab创建项目: 登录GitLab,创建一个名为yiliao的项目

推送代码到GitLab

# 在 -yiliao-app 目录下执行
[root@harbor250.oldboyedu.com code]# git init
[root@harbor250.oldboyedu.com code]# git remote add origin http://43.139.77.96/root/oldboyedu-yiliao.git
[root@harbor250.oldboyedu.com code]# git remote -v
origin	http://10.0.0.153/root/yiliao.git (fetch)
origin	http://10.0.0.153/root/yiliao.git (push)


# 添加远程仓库地址,请使用你的GitLab Service IP或域名
[root@harbor250.oldboyedu.com code]# git add .
[root@harbor250.oldboyedu.com code]# git commit -m 'k8s yiliao demo'
[root@harbor250.oldboyedu.com code]# git push origin master
...输入密码

当提示输入用户名和密码时,使用 root 和你新设置的密码。
GitLab项目仓库中看到已推送的代码

第三章:构建第一个CI/CD流水线(Freestyle)

3.1Jenkins连接K8s与Harbor

要让Jenkins能够操作K8s和Harbor,需要进行一些配置。

步骤1:安装Docker和kubectl

# 在Jenkins服务器(10.0.0.211)上执行
# 1. 安装Docker
[root@jenkins211 ~]#  ll
autoinstall-docker-docker-compose.tar.gz
[root@jenkins211 ~]# tar xf -autoinstall-docker-docker-compose.tar.gz
[root@jenkins211 ~]# ./install-docker.sh i

# 2. 安装kubectl
[root@jenkins211 ~]# wget http://192.168.21.253/Resources/Kubernetes/Project/DevOps/Jenkins/kubectl-1.23.17
[root@jenkins211 ~]# chmod +x kubectl-1.23.17
[root@jenkins211 ~]# mv kubectl-1.23.17 /usr/local/bin/kubectl

步骤2:配置凭证

# 在Jenkins服务器(10.0.0.211)上执行
# 1. 配置Harbor的hosts解析和证书(确保Jenkins可以访问Harbor)
[root@jenkins211 ~]# echo "IP harbor250..com" >> /etc/hosts
[root@jenkins211 ~]# scp -r user@ip:/etc/docker/certs.d/ /etc/docker/

# 2. 配置kubectl的认证文件(让Jenkins有权限操作K8s)
[root@jenkins211 ~]#  mkdir -p ~/.kube/
[root@jenkins211 ~]#  scp ip:/root/.kube/config ~/.kube/

# 3. 验证kubectl是否能连接到K8s集群
[root@jenkins211 ~]#  kubectl get nodes

3.2 创建并配置Freestyle项目

新建任务: 在Jenkins首页,点击 "New Item",输入项目名称 test-yiliao,选择 "Freestyle project",点击 "OK"。

源码管理(Source Code Management):

选择 "Git"。

Repository URL: 填入你的GitLab项目地址,如 http:/ip/root/-yiliao.git

Credentials: 点击 "Add" -> "Jenkins",添加GitLab的用户名和密码凭证。

3.编写shell脚本
pwd
ls -l
4.点击立即构建
5.查看日志 

3.构建(Build Steps):

点击 "Add build step",选择 "Execute shell"。

这里是CI/CD的核心逻辑:拉取代码后,构建镜像、推送镜像、然后部署到K8s。

首次部署脚本:

#!/bin/bash

IMAGE_NAME="harbor250..com/-cicd/yiliao:v0.1"

echo "Step 1: Building Docker image..."
docker build -t ${IMAGE_NAME} .

echo "Step 2: Logging into Harbor..."
docker login -u admin -p Harbor12345 harbor250..com

echo "Step 3: Pushing image to Harbor..."
docker push ${IMAGE_NAME}

echo "Step 4: Deploying to Kubernetes..."
# 检查Deployment是否存在,不存在则创建
kubectl get deployment deploy-yiliao &>/dev/null
if [ $? -ne 0 ]; then
  echo "Deployment not found, creating new deployment and service..."
  cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-yiliao
spec:
  replicas: 3
  selector:
    matchLabels:
      apps: yiliao
  template:
    metadata:
      labels:
        apps: yiliao
    spec:
      containers:
      - name: c1
        image: ${IMAGE_NAME}
---
apiVersion: v1
kind: Service
metadata:
  name: svc-yiliao
spec:
  type: LoadBalancer
  selector:
    apps: yiliao
  ports:
    - protocol: TCP
      port: 80
EOF
else
  echo "Deployment found, skipping creation."
fi

echo "Step 5: Verifying deployment status..."
kubectl get pods -o wide -l apps=yiliao
kubectl get svc svc-yiliao

保存并立即构建(Save & Build Now):

确保Harbor中已存在 cicd 这个项目。

点击 "Build Now",观察左侧 "Build History" 中的构建过程。

点击构建号,进入 "Console Output" 查看详细日志

访问验证:

从构建日志或 kubectl get svc svc-yiliao 中获取服务的EXTERNAL-IP

查看构建信息日志部分内容如下:
+ kubectl get pods -o wide -l apps=yiliao
NAME                            READY   STATUS    RESTARTS   AGE     IP             NODE        NOMINATED NODE   READINESS GATES
deploy-yiliao-9f765b8d8-688hn   1/1     Running   0          2m22s   10.100.2.59    worker233   <none>           <none>
deploy-yiliao-9f765b8d8-6ztrf   1/1     Running   0          2m22s   10.100.2.58    worker233   <none>           <none>
deploy-yiliao-9f765b8d8-bkb2n   1/1     Running   0          2m22s   10.100.1.204   worker232   <none>           <none>
+ kubectl get svc svc-yiliao
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
svc-yiliao   LoadBalancer   10.200.208.97   10.0.0.154    80:33356/TCP   2m22s
+ kubectl describe svc svc-yiliao
+ grep Endpoints
Endpoints:                10.100.1.204:80,10.100.2.58:80,10.100.2.59:80
Finished: SUCCESS

在浏览器中访问 http://IP,可以看到医疗网站的首页。

第四章:实现自动化升级与回滚

4.1 参数化构建实现版本升级

当代码更新后,我们需要构建一个新版本的镜像并更新到K8s中。使用参数化构建可以让我们灵活地指定版本号。

修改代码: 在本地代码库中,修改index.html文件,例如添加一行醒目的标题。然后提交并推送到GitLab。

配置参数化构建:

在Jenkins任务配置页面,勾选 "This project is parameterized"。

点击 "Add Parameter",选择 "String Parameter"。

Name: version

Default Value: v0.2

修改构建脚本以支持升级:
我们将脚本逻辑修改为:如果Deployment已存在,则使用 kubectl set image 命令来触发滚动更新。

#!/bin/bash
set -e # 任何命令失败则立即退出

VERSION=${version} # 从参数化构建中获取版本号
IMAGE_NAME="harbor250..com/-cicd/yiliao:${VERSION}"

echo ">>> Building and Pushing Version: ${VERSION}"
docker build -t ${IMAGE_NAME} .
docker login -u admin -p Harbor12345 harbor250..com
docker push ${IMAGE_NAME}

echo ">>> Updating Kubernetes Deployment..."
# 直接使用set image命令进行滚动更新
kubectl set image deployment/deploy-yiliao c1=${IMAGE_NAME} --record

echo ">>> Verifying Update Status..."
# 增加--timeout来等待更新完成
kubectl rollout status deployment/deploy-yiliao --timeout=120s

kubectl get pods -o wide -l apps=yiliao
kubectl describe svc svc-yiliao | grep Endpoints

带参数构建: 返回项目页面,点击 "Build with Parameters",输入新版本号(如v0.2),点击构建。

4.2 实现版本回滚

回滚的本质是重新部署一个旧的、稳定的版本。

  1. 克隆现有任务: 在Jenkins首页,找到 test-yiliao 任务,从左侧菜单选择 "Clone"。新任务命名为 rollback-yiliao。

  2. 修改回滚任务配置:

    • 也设置为参数化构建,参数同样是 version。

    • 修改 "Execute shell" 的内容,简化为只执行更新命令。这样我们可以指定任何一个存在于Harbor中的旧版本号来进行回滚。

#!/bin/bash
set -e

VERSION=${version}
IMAGE_NAME="harbor250..com/-cicd/yiliao:${VERSION}"

echo "!!! Rolling back to version: ${VERSION} !!!"

# 检查Harbor中是否存在该镜像Tag (可选,但推荐)
# 此处需要docker-registry-cli等工具,或调用Harbor API,为简化暂略

kubectl set image deployment/deploy-yiliao c1=${IMAGE_NAME} --record

echo ">>> Verifying Rollback Status..."
kubectl rollout status deployment/deploy-yiliao --timeout=120s
echo "Rollback to ${VERSION} completed."

执行回滚: 点击 rollback-yiliao 任务的 "Build with Parameters",输入你想回滚到的版本号(如v0.1),执行构建。刷新网页,页面应该已经回到旧版本。

第五章:Pipeline as Code

Freestyle项目UI操作繁琐,且配置无法版本化。Pipeline(尤其是Jenkinsfile)是更现代、更强大的选择。

5.1 编写第一个Pipeline脚本

  1. 新建Pipeline任务: 创建一个新任务,选择 "Pipeline" 类型,命名为 yiliao-pipeline

  2. 编写Pipeline脚本: 在配置页面的 "Pipeline" -> "Script" 区域,粘贴以下脚本。

// yiliao-pipeline script
pipeline {
    agent any // 在任何可用的agent上执行

    environment {
        // 定义全局环境变量
        HARBOR_URL = 'harbor250..com'
        HARBOR_PROJECT = '-cicd'
        APP_NAME = 'yiliao'
        DEPLOYMENT_NAME = 'deploy-yiliao'
        // 使用Jenkins内置的BUILD_ID作为版本号,确保唯一性
        IMAGE_TAG = "v${env.BUILD_ID}" 
    }

    stages {
        stage('1. Pull Code') {
            steps {
                echo 'Pulling code from GitLab...'
                // 使用之前创建的GitLab凭证ID
                git credentialsId: 'your-gitlab-credentials-id', url: 'http://<GITLAB_EXTERNAL_IP>/root/-yiliao.git'
            }
        }
        
        stage('2. Build Image') {
            steps {
                script {
                    // 拼接完整的镜像名称
                    def fullImageName = "${HARBOR_URL}/${HARBOR_PROJECT}/${APP_NAME}:${IMAGE_TAG}"
                    echo "Building image: ${fullImageName}"
                    sh "docker build -t ${fullImageName} ."
                }
            }
        }
        
        stage('3. Push Image') {
            steps {
                script {
                    def fullImageName = "${HARBOR_URL}/${HARBOR_PROJECT}/${APP_NAME}:${IMAGE_TAG}"
                    echo "Pushing image: ${fullImageName}"
                    // 推荐使用 withCredentials 来安全地处理密码
                    withCredentials([usernamePassword(credentialsId: 'your-harbor-credentials-id', passwordVariable: 'HARBOR_PASS', usernameVariable: 'HARBOR_USER')]) {
                        sh "docker login -u '${HARBOR_USER}' -p '${HARBOR_PASS}' ${HARBOR_URL}"
                        sh "docker push ${fullImageName}"
                    }
                }
            }
        }
        
        stage('4. Deploy to K8s') {
            steps {
                script {
                    def fullImageName = "${HARBOR_URL}/${HARBOR_PROJECT}/${APP_NAME}:${IMAGE_TAG}"
                    echo "Deploying image ${fullImageName} to Kubernetes..."
                    sh "kubectl set image deployment/${DEPLOYMENT_NAME} c1=${fullImageName} --record"
                    sh "kubectl rollout status deployment/${DEPLOYMENT_NAME} --timeout=120s"
                }
            }
        }
    }
}

注意:

  • 使用environment块来定义变量,使脚本更清晰。

  • 使用withCredentials是处理敏感信息(如密码)的最佳实践。

5.2 终极形态:Jenkinsfile

将Pipeline脚本存储在代码仓库中(即Jenkinsfile),是"Pipeline as Code"的最佳实践。

  1. 创建Jenkinsfile: 在你的-yiliao-app项目根目录下,创建一个名为 Jenkinsfile 的文件,内容就是上面的Pipeline脚本。然后提交并推送到GitLab。

  2. 修改Pipeline任务配置:

    • 回到yiliao-pipeline任务的配置页面。

    • 在 "Pipeline" 部分,将 "Definition" 从 "Pipeline script" 修改为 "Pipeline script from SCM"。

    • SCM: 选择 "Git"。

    • Repository URL: 填入GitLab项目地址。

    • Credentials: 选择GitLab凭证。

    • Script Path: 保持默认的 Jenkinsfile 即可。

  3. 构建: 保存配置后,Jenkins会自动拉取代码,并执行项目根目录下的Jenkinsfile文件来运行流水线

第六章:锦上添花,集成钉钉通知

最后一步,我们将构建结果通过钉钉机器人实时通知给团队。

6.1 配置钉钉机器人与Jenkins插件

  1. 创建钉钉机器人: 在你的钉钉群中,选择 "智能群助手" -> "添加机器人" -> "自定义",获取Webhook地址,并记下安全设置中的关键词(例如"Jenkins")。

  2. Jenkins配置:

    • 确保已安装 DingTalk 插件。

    • 进入 "Manage Jenkins" -> "System",找到 "钉钉" 配置区。

    • 点击 "新增钉钉",填入一个ID(如 my-dingtalk-robot)、Webhook地址和关键词

6.2 在Pipeline中加入通知逻辑

我们使用 post 指令块,它可以在Pipeline执行完成后根据结果(成功、失败等)执行特定操作。

修改Jenkinsfile,在pipeline的顶层加入post块:

pipeline {
    // ... agent, environment, stages ...

    post {
        success {
            script {
                def successMessage = """### ✅ [${env.JOB_NAME}] Jenkins 任务成功
- **任务状态**: **成功 (SUCCESS)**
- **镜像版本**: `${IMAGE_TAG}`
- **构建编号**: #${env.BUILD_NUMBER}
- **完成时间**: ${new Date().format("yyyy-MM-dd HH:mm:ss")}
- **详情链接**: [点击查看构建详情](${env.BUILD_URL})

> 由 CI/CD 流水线自动触发。"""

                dingtalk (
                    robot: 'my-dingtalk-robot', // Jenkins中配置的机器人ID
                    text: [successMessage], 
                    type: 'MARKDOWN'
                )
            }
        }
        failure {
            script {
                def failureMessage = """### 🚨 [${env.JOB_NAME}] Jenkins 任务失败
- **任务状态**: **失败 (FAILURE)**
- **构建编号**: #${env.BUILD_NUMBER}
- **失败链接**: [点击查看失败日志](${env.BUILD_URL})

> 请相关同学尽快检查问题!"""
                
                dingtalk (
                    robot: 'my-dingtalk-robot', // Jenkins中配置的机器人ID
                    text: [failureMessage],
                    type: 'MARKDOWN'
                )
            }
        }
    }
}

再次构建任务。无论成功还是失败,钉钉群都会收到通知。

CI/CD 流程总结:从代码到部署的全景图

我们已经成功搭建并实践了一套完整的CI/CD自动化流水线。现在,让我们将整个流程串联起来,形成一个清晰的、端到端的视图。

第一阶段:一次性环境搭建

  1. 部署核心服务:

    • 安装并初始化 Jenkins 服务器,作为CI/CD的调度中心。

    • 在 Kubernetes 集群中部署 GitLab,作为代码版本控制系统。

    • 准备好 Harbor 私有镜像仓库,用于存储构建产物。

  2. 打通连接:

    • 在 Jenkins 服务器上安装 docker 和 kubectl 客户端工具。

    • 配置 Jenkins 对 Kubernetes 的访问权限(通过kubeconfig文件)。

    • 配置 Jenkins 对 Harbor 的网络访问和认证(通过hosts解析和certs证书)。

  3. 配置凭证与工具:

    • 在 Jenkins 中创建并管理访问 GitLab 和 Harbor 所需的凭证。

    • 配置 钉钉 机器人,并在 Jenkins 中添加其Webhook,为自动化通知做准备。

第二阶段:自动化CI/CD工作流 (The Automated Workflow)

这是日常开发中持续、自动运行的循环。

1. 触发 (Trigger): 开发人员提交代码

  • 动作: 开发人员将本地开发完成的应用代码、Dockerfile 以及 Jenkinsfile 推送到 GitLab 仓库。

  • 结果: 这是整个自动化流程的起点。

2. 拉取 (Pull): Jenkins获取代码

  • 动作: Jenkins 被触发(通过Webhook或手动点击),启动Pipeline任务。流水线的第一个阶段是从 GitLab 拉取最新的源代码。

3. 构建 (Build): 创建Docker镜像

  • 动作: Jenkins 使用项目中的 Dockerfile,执行 docker build 命令,将应用打包成一个全新的Docker镜像。

  • 结果: 生成一个带有唯一版本标签(例如 v1.2.3 或 v_build-5)的镜像,这是一个不可变的、可发布的单元。

4. 推送 (Push): 存储构建产物

  • 动作: Jenkins 使用预设的凭证登录到私有镜像仓库 Harbor,并将刚刚构建好的新版本镜像推送上去。

  • 结果: 构建产物被安全、集中地存储起来,可供后续任何环境的部署使用。

5. 部署 (Deploy): 更新线上服务

  • 动作: Jenkins 通过 kubectl 命令连接到 Kubernetes 集群,指令其更新目标应用(Deployment)所使用的镜像为 Harbor 中的新版本。

  • 结果: Kubernetes 收到指令,开始进行应用的发布。

6. 发布 (Rollout): K8s执行滚动更新

  • 动作: Kubernetes 自动执行“滚动更新”策略。它会逐个创建运行新镜像的Pod,并在新Pod准备就绪后,平滑地销毁旧版本的Pod。

  • 结果: 应用在用户无感知的情况下完成了版本升级,实现了零停机部署。

7. 通知 (Notify): 反馈流程结果

  • 动作: Jenkins 流水线执行完毕。根据最终是成功还是失败,调用钉钉插件,将预设好的Markdown格式消息发送到团队 钉钉 群。

  • 结果: 团队成员能够即时、清晰地了解到每一次构建和部署的状态,快速响应可能出现的问题。