大家好,我是专注于分享云原生与 DevOps 实战经验的技术博主。在团队协作开发中,你是否遇到过这样的困境:代码合并冲突频发、测试环境部署耗时费力、生产发布如履薄冰?这些问题背后,往往是缺乏一套自动化、标准化的软件交付流程。本文将为你带来一套从零到一的完整解决方案,通过整合 Docker、Kubernetes (K8S)、Jenkins 等核心工具,构建一个现代化的 CI/CD 流水线。无论你是刚接触容器化的新手,还是希望将现有项目进行云原生改造的开发者,都能从这篇实战指南中找到清晰的路径。我们将从最基础的 Docker 安装讲起,逐步深入到 Jenkins 流水线编排和 K8S 集群部署,最终实现代码提交到应用上线的全流程自动化。

1. 背景与核心概念:为什么需要 CI/CD 与容器化?

在深入动手之前,我们有必要理解这套技术栈要解决的根本问题,以及每个组件扮演的角色。这能帮助你在后续配置时,不仅知道“怎么做”,更明白“为什么这么做”。

1.1 传统软件交付的痛点与 DevOps 的兴起

在传统的软件开发模式中,开发、测试、运维团队往往各自为政。开发人员完成代码后,将程序打包成一个压缩包,附上一份可能已经过时的部署文档,扔给运维团队。运维人员则在生产服务器上手动安装依赖、配置环境、部署应用。这个过程充满了不确定性:开发环境能跑,测试环境可能就报错;测试环境通过了,生产环境又因为系统库版本不同而崩溃。这种“它在我机器上是好的”问题,严重拖慢了软件交付的速度和质量。

DevOps 文化正是为了打破这种壁垒而生,它强调开发(Dev)和运维(Ops)的紧密协作与自动化。而 CI/CD 是实现 DevOps 理念的关键技术实践。

1.2 CI/CD、Docker 与 Kubernetes 的核心价值

持续集成 (Continuous Integration, CI) :指开发人员频繁地(例如每天多次)将代码集成到共享主干。每次集成都通过自动化的构建和测试来验证,从而尽早发现集成错误。它的核心价值在于快速反馈,避免分支长期偏离主干导致的大量合并冲突。

持续交付/持续部署 (Continuous Delivery/Deployment, CD) :持续交付指在持续集成的基础上,将集成后的代码自动部署到更贴近真实环境的“类生产环境”。持续部署则更进一步,在通过所有测试后,自动将应用发布到生产环境。CD 的目标是让软件发布成为一个可预测、低风险、频繁进行的常规活动。

Docker :是实现环境一致性的基石。它将应用及其所有依赖(库、环境变量、配置文件)打包成一个标准化的单元——容器镜像。这个镜像可以在任何安装了 Docker 的机器上以完全相同的方式运行,彻底解决了“环境差异”问题。你可以把它理解为一个轻量级的、便携的软件集装箱。

Kubernetes (K8S) :当你的应用从单个容器扩展到成百上千个容器时,如何管理它们的生命周期、网络、存储和伸缩?Kubernetes 就是这个容器编排领域的王者。它负责容器的调度、部署、扩缩容、负载均衡和自愈,让你能像管理单个应用一样管理庞大的分布式系统。

Jenkins :是 CI/CD 流程的“大脑”和“指挥中心”。它是一个开源的自动化服务器,通过插件体系可以连接 Git、Maven、Docker、K8S 等几乎所有工具。我们通过编写 Jenkins Pipeline(流水线脚本),定义从代码拉取、编译、测试、构建镜像到部署的完整工作流。

简单来说,这套组合拳的工作流是:开发者提交代码到 Git -> Jenkins 被触发 -> 拉取代码、编译、运行测试 -> 通过后,使用 Docker 构建镜像 -> 将镜像推送到仓库 -> 最后通过 Kubernetes 将新版本应用滚动更新到集群中。整个过程无需人工干预,高效且可靠。

2. 环境准备与版本说明

工欲善其事,必先利其器。为了完成本次实战,你需要准备以下环境。我将以一台 Ubuntu 22.04 LTS 的云服务器或虚拟机作为演示环境,这也是目前最主流和稳定的选择之一。

核心环境清单:

  • 操作系统 :Ubuntu 22.04 LTS (x86_64)
  • 容器运行时 :Docker Engine 24.0+
  • 容器编排 :Kubernetes (使用 Minikube 搭建单节点集群,用于学习和测试)
  • CI/CD 服务器 :Jenkins 2.4xx (LTS 版本)
  • 构建工具 :OpenJDK 17, Maven 3.8+
  • 代码质量 :SonarQube (可选,用于静态代码分析)
  • 版本控制 :Git

重要说明 :本文提供的安装命令和配置在 Ubuntu 22.04 上测试通过。如果你使用 CentOS、Rocky Linux 或其他发行版,部分包管理命令(如 apt 需改为 yum dnf )和细节可能略有不同,请参考对应官方文档进行调整。所有涉及版本号的地方,请以安装时官方仓库提供的最新稳定版为准。

3. 基础环境搭建:从 Linux 到 Docker

我们的旅程从最基础的 Linux 操作和 Docker 安装开始。即使你是零基础,跟着步骤也能顺利完成。

3.1 Linux 基础与准备工作

首先,通过 SSH 连接到你的 Ubuntu 服务器。确保系统包列表是最新的。

# 更新软件包索引
sudo apt update

# 升级所有已安装的软件包(可选,但推荐)
sudo apt upgrade -y

# 安装一些常用的工具,如 Vim、curl、wget、net-tools
sudo apt install -y vim curl wget net-tools

接下来,我们需要安装 Java,因为 Jenkins 是基于 Java 开发的。

# 安装 OpenJDK 17 (Jenkins 推荐版本)
sudo apt install -y openjdk-17-jdk

# 验证安装
java -version
# 预期输出应包含 “openjdk version “17.0.x”

3.2 Docker 安装与配置

Docker 的安装非常 straightforward。我们将使用 Docker 官方提供的便捷脚本进行安装,这也是官方推荐的方式。

# 1. 卸载旧版本 Docker(如果存在)
sudo apt remove -y docker docker-engine docker.io containerd runc

# 2. 安装依赖包,允许 apt 通过 HTTPS 使用仓库
sudo apt install -y ca-certificates curl gnupg lsb-release

# 3. 添加 Docker 的官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 4. 设置 Docker 稳定版仓库
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 5. 更新 apt 包索引并安装 Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 6. 验证 Docker 安装是否成功
sudo docker run hello-world

如果看到 “Hello from Docker!” 的消息,说明 Docker 已经安装并运行成功。

配置 Docker 用户组(非常重要) :默认情况下,运行 Docker 命令需要 sudo 权限。为了方便,我们将当前用户加入 docker 用户组,这样以后就可以直接使用 docker 命令了。

# 将当前用户加入 docker 组
sudo usermod -aG docker $USER

# 重新登录或使用以下命令使组更改生效
newgrp docker

# 再次验证,此时应无需 sudo
docker run hello-world

配置 Docker 镜像加速器(国内用户必做) :从 Docker Hub 拉取镜像速度可能较慢,我们可以配置国内镜像加速器。

# 创建或修改 Docker 守护进程配置文件
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  “registry-mirrors”: [“https://docker.mirrors.ustc.edu.cn”, “https://hub-mirror.c.163.com”],
  “exec-opts”: [“native.cgroupdriver=systemd”],
  “log-driver”: “json-file”,
  “log-opts”: {
    “max-size”: “100m”
  },
  “storage-driver”: “overlay2”
}
EOF

# 重新加载配置并重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

# 检查加速器是否生效
docker info | grep -A 1 ‘Registry Mirrors’

3.3 Docker 核心概念与常用命令速查

安装完成后,我们快速过一下 Docker 最核心的概念和命令,为后续使用打下基础。

  • 镜像 (Image) :一个只读的模板,用于创建容器。例如 ubuntu:22.04 , nginx:alpine
  • 容器 (Container) :镜像的运行实例。你可以创建、启动、停止、删除容器。
  • 仓库 (Registry) :存放镜像的地方,如 Docker Hub。

常用命令:

# 镜像相关
docker pull nginx:alpine          # 拉取镜像
docker images                     # 列出本地镜像
docker rmi <image_id>            # 删除镜像

# 容器相关
docker run -d -p 80:80 --name my-nginx nginx:alpine  # 运行容器 (-d 后台, -p 端口映射)
docker ps                         # 查看运行中的容器
docker ps -a                      # 查看所有容器(包括已停止的)
docker stop <container_id>       # 停止容器
docker start <container_id>      # 启动已停止的容器
docker rm <container_id>         # 删除容器
docker logs <container_id>       # 查看容器日志
docker exec -it <container_id> /bin/bash # 进入容器内部

# 构建镜像 (需要 Dockerfile)
docker build -t my-app:1.0 .

4. Jenkins 安装与基础配置

Jenkins 将作为我们自动化流水线的中枢。我们将把它安装在同一台服务器上。

4.1 安装 Jenkins

Jenkins 提供了稳定的 Debian/Ubuntu 仓库,安装非常方便。

# 1. 添加 Jenkins 仓库的密钥
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \
  /usr/share/keyrings/jenkins-keyring.asc > /dev/null

# 2. 添加 Jenkins 仓库
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
  https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
  /etc/apt/sources.list.d/jenkins.list > /dev/null

# 3. 更新并安装 Jenkins
sudo apt update
sudo apt install -y jenkins

# 4. 启动 Jenkins 并设置开机自启
sudo systemctl start jenkins
sudo systemctl enable jenkins

# 5. 检查 Jenkins 状态
sudo systemctl status jenkins

如果状态显示为 active (running) ,说明 Jenkins 服务已成功启动。

4.2 初始化 Jenkins

Jenkins 默认运行在 8080 端口。我们需要配置服务器的安全组或防火墙,允许访问该端口。

# 如果使用 UFW 防火墙(Ubuntu 默认)
sudo ufw allow 8080
sudo ufw status verbose

在浏览器中访问: http://<你的服务器IP地址>:8080 。 你会看到 “Unlock Jenkins” 页面,需要输入初始管理员密码。这个密码在服务器的日志文件中。

# 获取初始管理员密码
sudo cat /var/lib/jenkins/secrets/initialAdminPassword

将输出的密码粘贴到浏览器中,点击“继续”。

接下来,选择“安装推荐的插件”。Jenkins 会自动安装一套最常用的插件,包括 Git、Pipeline 等,这个过程可能需要几分钟。

插件安装完成后,会提示你创建第一个管理员用户。 强烈建议创建一个新用户 ,而不是继续使用初始的 admin 账户。填写用户名、密码、全名和邮箱后,点击“保存并完成”。

最后,配置 Jenkins URL,一般保持默认的 http://<你的IP>:8080 即可,点击“保存并完成”。至此,Jenkins 安装初始化完毕。

4.3 安装必备插件并配置工具

进入 Jenkins 主面板后,我们需要安装一些本次实战必需的插件。

  1. 点击左侧菜单 “Manage Jenkins” -> “Plugins” -> “Available plugins”。
  2. 在搜索框中搜索并勾选以下插件:
    • Docker Pipeline :用于在 Pipeline 中与 Docker 交互。
    • Kubernetes :用于连接 K8S 集群(如果使用 Jenkins Agent 在 K8S 中运行)。
    • GitHub Integration Git :用于从 Git 仓库拉取代码。
    • Pipeline: GitHub Groovy Libraries :增强 Pipeline 功能。
    • SonarQube Scanner (可选):用于集成 SonarQube 代码分析。
  3. 点击“Install without restart”,等待安装完成。

接下来,配置全局工具。点击 “Manage Jenkins” -> “Tools”。

  • JDK :添加一个 JDK 安装,命名为 “openjdk-17”,JAVA_HOME 路径通常为 /usr/lib/jvm/java-17-openjdk-amd64
  • Maven :添加一个 Maven 安装,命名为 “maven-3.8”,可以勾选“自动安装”。
  • Git :确保 Git 可执行文件路径正确,通常是 /usr/bin/git

保存配置。

5. Kubernetes (Minikube) 单机集群搭建

在生产环境中,Kubernetes 集群通常由多台机器组成。为了学习和测试,我们使用 Minikube 在单机上快速搭建一个功能完整的 K8S 集群。

5.1 安装 kubectl 和 Minikube

kubectl 是操作 Kubernetes 集群的命令行工具。

# 安装 kubectl
curl -LO “https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl”
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version --client --output=yaml

接下来安装 Minikube。Minikube 需要虚拟机驱动,我们使用 Docker 作为驱动,这也是最轻便的方式。

# 安装 Minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# 启动 Minikube 集群,使用 Docker 驱动
minikube start --driver=docker

# 检查集群状态
minikube status

如果输出显示 host , kubelet , apiserver 都是 Running 状态,说明集群启动成功。

5.2 验证 K8S 集群并部署示例应用

让我们验证一下集群,并部署一个简单的 Nginx 应用。

# 查看集群节点(应该只有一个 minikube 节点)
kubectl get nodes

# 查看所有命名空间下的 Pod
kubectl get pods -A

# 部署一个 Nginx Deployment
kubectl create deployment nginx-demo --image=nginx:alpine

# 将 Deployment 暴露为 NodePort 类型的 Service
kubectl expose deployment nginx-demo --type=NodePort --port=80

# 查看 Service,获取访问端口
kubectl get svc nginx-demo
# 输出中会有一个端口,例如 80:3xxxx/TCP,后面的 3xxxx 就是 NodePort

# 使用 minikube 生成访问 URL
minikube service nginx-demo --url

复制最后命令输出的 URL 到浏览器,你应该能看到 Nginx 的欢迎页面。这证明你的 K8S 集群工作正常。

6. 实战:构建完整的 CI/CD 流水线

现在,所有基础设施都已就位。我们将创建一个简单的 Spring Boot 应用,并为其打造一个完整的 CI/CD 流水线。流程如下:代码推送至 Git -> Jenkins 自动构建 -> 运行单元测试 -> 静态代码检查(SonarQube)-> 构建 Docker 镜像 -> 推送至镜像仓库 -> 更新 K8S 部署。

6.1 准备示例项目与 Git 仓库

首先,在本地或服务器上创建一个简单的 Spring Boot 项目。这里我们使用 Spring Initializr 快速生成。

# 使用 curl 从 start.spring.io 生成项目
curl https://start.spring.io/starter.zip -o demo-app.zip \
  -d type=maven-project \
  -d language=java \
  -d bootVersion=3.1.5 \
  -d baseDir=cicd-demo \
  -d groupId=com.example \
  -d artifactId=cicd-demo \
  -d name=cicd-demo \
  -d description=Demo+project+for+CI/CD \
  -d packageName=com.example.cicd \
  -d packaging=jar \
  -d javaVersion=17 \
  -d dependencies=web

unzip demo-app.zip -d .
cd cicd-demo

项目结构大致如下:

cicd-demo/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/com/example/cicd/
│   │   │   └── CicdDemoApplication.java
│   │   └── resources/
│   │       └── application.properties
│   └── test/
│       └── java/com/example/cicd/
│           └── CicdDemoApplicationTests.java

我们添加一个简单的 REST 接口和对应的测试。

文件: src/main/java/com/example/cicd/HelloController.java

package com.example.cicd;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping(“/hello”)
    public String sayHello() {
        return “Hello from CI/CD Pipeline!”;
    }
}

文件: src/test/java/com/example/cicd/HelloControllerTest.java

package com.example.cicd;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(HelloController.class)
public class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testHelloEndpoint() throws Exception {
        mockMvc.perform(get(“/hello”))
                .andExpect(status().isOk())
                .andExpect(content().string(“Hello from CI/CD Pipeline!”));
    }
}

接下来,在项目根目录创建两个关键文件: Dockerfile Jenkinsfile

文件: Dockerfile

# 使用 OpenJDK 17 作为基础镜像
FROM openjdk:17-jdk-slim AS builder

# 设置工作目录
WORKDIR /app

# 将 Maven 包装器和 pom.xml 复制到镜像中
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .

# 下载项目依赖(利用 Docker 缓存层,如果 pom.xml 未改变,则跳过)
RUN ./mvnw dependency:go-offline -B

# 复制源代码并打包
COPY src src
RUN ./mvnw clean package -DskipTests

# 第二阶段:运行阶段
FROM openjdk:17-jdk-slim
WORKDIR /app
# 从构建阶段复制打好的 jar 包
COPY --from=builder /app/target/*.jar app.jar
# 暴露端口
EXPOSE 8080
# 启动应用
ENTRYPOINT [“java”, “-jar”, “/app/app.jar”]

文件: Jenkinsfile (声明式流水线)

pipeline {
    agent any // 使用任何可用的 Jenkins Agent

    tools {
        maven ‘maven-3.8’ // 使用在 Jenkins 全局工具中配置的 Maven
        jdk ‘openjdk-17’   // 使用在 Jenkins 全局工具中配置的 JDK
    }

    environment {
        // 定义环境变量,请根据实际情况修改
        DOCKER_REGISTRY = ‘your-dockerhub-username’ // 或私有仓库地址
        DOCKER_IMAGE_NAME = “cicd-demo”
        KUBE_CONFIG = credentials(‘k8s-config’) // 在 Jenkins 中配置的 K8S kubeconfig 凭据 ID
    }

    stages {
        stage(‘Checkout’) {
            steps {
                // 从 Git 仓库拉取代码
                git branch: ‘main’, url: ‘https://github.com/your-username/your-repo.git’
            }
        }

        stage(‘Build & Unit Test’) {
            steps {
                // 清理、编译并运行单元测试
                sh ‘mvn clean compile’
                sh ‘mvn test’
            }
            post {
                always {
                    // 无论成功失败,都归档测试报告(可选)
                    junit ‘target/surefire-reports/*.xml’
                }
            }
        }

        stage(‘SonarQube Analysis’) {
            steps {
                // 使用 SonarQube Scanner 进行代码质量分析
                withSonarQubeEnv(‘sonarqube-server’) { // ‘sonarqube-server’ 是在 Jenkins 系统配置中定义的 SonarQube 服务器名称
                    sh ‘mvn sonar:sonar’
                }
            }
        }

        stage(‘Build Docker Image’) {
            steps {
                script {
                    // 构建 Docker 镜像,标签使用构建编号
                    dockerImage = docker.build(“${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${BUILD_NUMBER}”)
                }
            }
        }

        stage(‘Push Docker Image’) {
            steps {
                script {
                    // 登录 Docker 仓库(需先在 Jenkins 中添加 Docker Hub 用户名密码凭据,ID 为 ‘dockerhub-cred’)
                    docker.withRegistry(‘https://index.docker.io/v1/’, ‘dockerhub-cred’) {
                        dockerImage.push()
                        // 同时打上 latest 标签
                        dockerImage.push(‘latest’)
                    }
                }
            }
        }

        stage(‘Deploy to K8S’) {
            steps {
                script {
                    // 使用 kubectl 配置更新 K8S 部署
                    // 假设我们有一个 deployment.yaml 文件在仓库中
                    sh “““
                        # 设置 kubectl 配置(从凭据中读取)
                        echo “\$KUBE_CONFIG” > /tmp/kubeconfig.yaml
                        export KUBECONFIG=/tmp/kubeconfig.yaml

                        # 使用 sed 替换 deployment.yaml 中的镜像标签
                        sed -i ‘s|IMAGE_PLACEHOLDER|${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${BUILD_NUMBER}|g’ k8s/deployment.yaml

                        # 应用部署
                        kubectl apply -f k8s/deployment.yaml

                        # 检查部署状态
                        kubectl rollout status deployment/cicd-demo -n default
                    “““
                }
            }
        }
    }

    post {
        success {
            echo ‘Pipeline succeeded! The new version is now deployed.’
            // 可以在这里添加通知,如发送邮件、Slack 消息等
        }
        failure {
            echo ‘Pipeline failed! Check the logs for details.’
        }
    }
}

文件: k8s/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cicd-demo
  namespace: default
  labels:
    app: cicd-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: cicd-demo
  template:
    metadata:
      labels:
        app: cicd-demo
    spec:
      containers:
      - name: cicd-demo
        image: IMAGE_PLACEHOLDER # Jenkinsfile 中的 sed 命令会替换这里
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: “256Mi”
            cpu: “250m”
          limits:
            memory: “512Mi”
            cpu: “500m”
---
apiVersion: v1
kind: Service
metadata:
  name: cicd-demo-service
spec:
  selector:
    app: cicd-demo
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: NodePort

将以上所有文件提交到你的 Git 仓库(如 GitHub、GitLab 或 Gitee)。

6.2 在 Jenkins 中配置流水线任务

  1. 创建 Pipeline 任务 :在 Jenkins 首页点击“新建任务”,输入任务名称(如 cicd-demo-pipeline ),选择“流水线”,点击“确定”。
  2. 配置流水线 :在任务配置页面,滚动到“流水线”部分。
    • 定义 :选择“Pipeline script from SCM”。这告诉 Jenkins 从源代码仓库中读取 Jenkinsfile
    • SCM :选择 “Git”。
    • Repository URL :填写你的 Git 仓库地址。
    • Credentials :如果你的仓库是私有的,需要添加一个“用户名与密码”类型的凭据,包含你的 Git 账号信息。
    • 分支 */main
    • 脚本路径 :保持默认的 Jenkinsfile
  3. 添加必要的凭据
    • Docker Hub 凭据 :进入 “Manage Jenkins” -> “Credentials” -> “System” -> “Global credentials” -> “Add Credentials”。选择“Username with password”,输入你的 Docker Hub 用户名和密码,ID 设为 dockerhub-cred
    • Kubeconfig 凭据 :同样位置,添加一个“Secret file”类型的凭据,上传你的 ~/.kube/config 文件(从 Minikube 环境复制),ID 设为 k8s-config
    • SonarQube Token (如果使用):添加一个“Secret text”类型的凭据,填入从 SonarQube 获取的 Token,ID 设为 sonarqube-token 。并在 “Manage Jenkins” -> “Configure System” 中添加 SonarQube 服务器配置。
  4. 保存并运行 :点击“保存”,回到任务页面,点击“立即构建”。Jenkins 会开始执行流水线,你可以在“阶段视图”中实时看到每个阶段的执行状态和日志。

6.3 验证部署结果

流水线执行成功后,我们可以验证应用是否已部署到 K8S 集群。

# 查看 Deployment 状态
kubectl get deployment cicd-demo

# 查看 Pod 状态
kubectl get pods -l app=cicd-demo

# 查看 Service 并获取访问端口
kubectl get svc cicd-demo-service

# 使用 minikube 访问服务
minikube service cicd-demo-service --url

访问输出的 URL,并在后面加上 /hello 路径,你应该能看到 “Hello from CI/CD Pipeline!” 的响应。

7. 常见问题与排查思路

在搭建和运行过程中,你可能会遇到一些问题。这里列出一些常见问题及其解决方法。

问题现象 可能原因 排查思路与解决方案
Docker 命令需要 sudo 当前用户未加入 docker 用户组。 执行 sudo usermod -aG docker $USER 重新登录 或执行 newgrp docker
Jenkins 无法启动或 8080 端口无法访问 1. Jenkins 服务未启动。
2. 防火墙/安全组未开放 8080 端口。
3. 端口被占用。
1. sudo systemctl status jenkins 检查状态。
2. 检查 sudo ufw status 或云服务器安全组规则。
3. `sudo netstat -tlnp
Pipeline 拉取 Git 代码失败 1. 仓库地址错误。
2. 凭据无效或权限不足。
3. 网络问题。
1. 检查仓库 URL。
2. 在 Jenkins 凭据页面重新配置 Git 凭据。
3. 在 Jenkins 服务器上手动执行 git clone 测试连通性。
Maven 构建失败 1. pom.xml 依赖错误。
2. 网络问题无法下载依赖。
3. JDK 版本不匹配。
1. 检查 Jenkins 控制台输出,看具体错误信息。
2. 配置 Maven 镜像仓库 ( settings.xml )。
3. 确认 Jenkins 全局工具中配置的 JDK 版本与项目要求一致。
Docker 构建镜像失败 1. Dockerfile 语法错误。
2. 基础镜像拉取失败。
3. 构建上下文路径不对。
1. 在本地使用 docker build -t test . 测试 Dockerfile
2. 检查网络或配置 Docker 镜像加速器。
3. 确保 docker build 命令在正确的目录下执行。
推送镜像到仓库失败 1. 未登录 Docker 仓库。
2. 凭据错误。
3. 镜像标签命名不符合仓库规则。
1. 确认 Jenkins 中配置了正确的 Docker 仓库凭据。
2. 在服务器上手动 docker login 测试。
3. 镜像名通常为 username/repository:tag
kubectl 部署失败 1. kubeconfig 文件错误或过期。
2. 没有对应命名空间的权限。
3. deployment.yaml 文件语法错误。
1. 检查 Jenkins 中上传的 kubeconfig 文件内容是否正确(可用 kubectl get nodes 测试)。
2. 检查 RBAC 权限。
3. 使用 kubectl apply --dry-run=client -f deployment.yaml 验证 YAML 语法。
Pod 一直处于 Pending CrashLoopBackOff 状态 1. 集群资源不足。
2. 镜像拉取失败。
3. 应用启动失败(如端口冲突、配置错误)。
1. kubectl describe pod <pod-name> 查看详细事件。
2. kubectl logs <pod-name> 查看容器日志。
3. minikube ssh 进入节点,用 docker ps docker logs 进一步排查。
SonarQube 扫描失败 1. SonarQube 服务器未启动或无法访问。
2. Token 无效。
3. 项目配置(如 sonar-project.properties )缺失。
1. 确认 SonarQube 服务 ( http://<ip>:9000 ) 可访问。
2. 检查 Jenkins 中配置的 SonarQube Token 凭据。
3. 在项目根目录添加正确的 sonar-project.properties 文件。

8. 最佳实践与工程建议

掌握了基础流程后,以下建议能帮助你将这套流水线应用到更严肃的生产环境中。

  1. 使用 Jenkins Shared Library :当你有多个项目使用相似的流水线时,将公共逻辑(如构建、推送镜像、部署)抽取到 Shared Library 中,可以极大减少 Jenkinsfile 的重复和维护成本。
  2. Pipeline 代码化与版本控制 :始终将 Jenkinsfile 放在项目根目录,并随代码一起进行版本控制。这是“Pipeline as Code”的核心,保证了流水线定义的可追溯性和可重复性。
  3. 细粒度的权限与凭据管理 :不要在 Jenkinsfile 中硬编码密码或密钥。始终使用 Jenkins 的凭据管理功能,并通过 credentials() 方法在流水线中引用。为不同项目或团队配置不同的 Jenkins 角色和权限。
  4. 构建高效的 Docker 镜像
    • 使用多阶段构建 :如示例所示,可以显著减小最终镜像体积。
    • 合理利用缓存 :将不经常变动的层(如依赖安装)放在 Dockerfile 前面。
    • 使用非 root 用户运行容器 :在 Dockerfile 中创建专用用户,增强安全性。
    • 选择合适的基础镜像 :优先选择官方、轻量级(如 -slim , -alpine )的镜像。
  5. Kubernetes 部署策略
    • 使用 Deployment 而非直接创建 Pod Deployment 提供了声明式更新、回滚和副本管理。
    • 配置资源请求和限制 :为每个容器设置 requests limits ,避免资源竞争,帮助调度器做出最佳决策。
    • 使用 ConfigMap Secret 管理配置 :将应用配置与镜像分离,提高灵活性。
    • 实现健康检查 :配置 livenessProbe readinessProbe ,让 K8S 能感知应用状态,实现自愈。
  6. 流水线稳定性与监控
    • 添加超时和重试机制 :在 Pipeline 的 options 块中设置 timeout ,对可能失败的步骤(如网络请求)添加重试逻辑。
    • 实施人工审批门禁 :在部署到生产环境前,通过 input 步骤加入人工确认环节。
    • 集成通知机制 :在流水线的 post 阶段,根据成功或失败状态,集成邮件、Slack、钉钉等通知。
    • 监控流水线性能 :关注构建时长,优化慢步骤。定期清理旧的构建记录和 Docker 镜像,释放磁盘空间。
  7. 安全考虑
    • 定期更新基础镜像和依赖 :扫描镜像中的漏洞,使用 docker scan 或集成 Trivy、Clair 等工具到流水线中。
    • 最小权限原则 :为 Jenkins Agent、Docker Daemon、K8S ServiceAccount 分配完成任务所需的最小权限。
    • 保护敏感数据 :绝不将密码、密钥等写入日志或代码。使用 K8S Secret 或专业的密钥管理服务。

从 Docker 容器化到 Kubernetes 编排,再到 Jenkins 自动化流水线,我们完成了一个现代云原生应用交付闭环的搭建。这套组合不仅能提升开发效率,更能保障交付质量与稳定性。技术的道路很长,下一步你可以探索 Helm 图表来管理更复杂的 K8S 应用,引入 Argo CD 实现 GitOps,或者搭建高可用的 Jenkins 集群。最重要的是,动手实践,将这套流程应用到你的实际项目中,并根据团队需求不断调整和优化。如果在实践中遇到任何问题,欢迎在评论区交流探讨。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐