Jenkins-CICD持续集成自动化部署指南

Jenkins CI/CD 持续集成自动化部署完整指南

文档说明:本指南涵盖两套 Jenkins CI/CD 部署方案

  • 方案一:Docker 环境下的 Jenkins CI/CD
  • 方案二:Kubernetes 环境下的 Jenkins CI/CD

前置条件:假设 Docker 或 Kubernetes 环境已搭建完毕


目录

方案一:Docker 环境

  1. [Jenkins 安装部署](#Jenkins 安装部署)
  2. [Jenkins 初始配置](#Jenkins 初始配置)
  3. 配置凭据管理
  4. [创建 Pipeline 流水线](#创建 Pipeline 流水线)
  5. 完整项目实战

方案二:Kubernetes 环境

  1. [Jenkins 在 K8s 中部署](#Jenkins 在 K8s 中部署)
  2. [配置动态 Agent](#配置动态 Agent)
  3. [K8s 流水线配置](#K8s 流水线配置)
  4. [完整 K8s 项目实战](#完整 K8s 项目实战)

附录

  1. 常见问题与解决方案
  2. 最佳实践建议

方案一:Docker 环境

一、Docker环境-Jenkins 安装部署

1.1 架构图

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│                     Docker 环境 Jenkins CI/CD 架构                               │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│   开发人员                                                                       │
│      │                                                                          │
│      │ git push                                                                 │
│      ▼                                                                          │
│   ┌─────────────────┐                                                           │
│   │   Git 仓库       │ (GitHub/GitLab/Gitee)                                    │
│   │   源代码存储     │                                                          │
│   └────────┬────────┘                                                           │
│            │ Webhook 触发                                                        │
│            ▼                                                                    │
│   ┌─────────────────────────────────────────────────────────────────────────┐  │
│   │                        CI/CD 服务器                                      │  │
│   │  ┌─────────────────────────────────────────────────────────────────┐    │  │
│   │  │                      Jenkins 容器                                │    │  │
│   │  │                                                                 │    │  │
│   │  │  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐         │    │  │
│   │  │  │  拉取代码    │ →  │  编译构建    │ →  │  构建镜像    │         │    │  │
│   │  │  │  git clone  │    │  maven/npm  │    │  docker     │         │    │  │
│   │  │  └─────────────┘    └─────────────┘    └──────┬──────┘         │    │  │
│   │  │                                               │                │    │  │
│   │  └───────────────────────────────────────────────┼────────────────┘    │  │
│   └──────────────────────────────────────────────────┼─────────────────────┘  │
│                                                      │                        │
│                                          docker push │                        │
│                                                      ▼                        │
│   ┌─────────────────────────────────────────────────────────────────────────┐ │
│   │                        镜像仓库                                          │ │
│   │                 (Docker Hub / 阿里云 ACR / Harbor)                       │ │
│   └─────────────────────────────────────────────────────────────────────────┘ │
│                                                      │                        │
│                                          docker pull │                        │
│                                                      ▼                        │
│   ┌─────────────────────────────────────────────────────────────────────────┐ │
│   │                        生产服务器                                        │ │
│   │                                                                         │ │
│   │  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐                 │ │
│   │  │   Nginx     │ →  │  Backend    │ →  │  Database   │                 │ │
│   │  │   容器      │    │   容器       │    │   容器      │                 │ │
│   │  └─────────────┘    └─────────────┘    └─────────────┘                 │ │
│   └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

1.2 创建 Jenkins 目录结构

bash 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 命令说明:创建 Jenkins 所需的目录结构
# 
# 位置:在 CI/CD 服务器上执行
# ═══════════════════════════════════════════════════════════════════════════════

# 创建 Jenkins 主目录
# -p 参数:递归创建,如果父目录不存在也会一并创建
mkdir -p /home/jenkins/jenkins_home

# 目录说明:
# /home/jenkins/          → Jenkins 根目录
# /home/jenkins/jenkins_home/ → Jenkins 数据持久化目录
#   ├── jobs/            → 所有任务配置和构建历史
#   ├── plugins/         → 安装的插件
#   ├── users/           → 用户配置
#   ├── secrets/         → 密钥和凭据
#   └── workspace/       → 构建工作空间

# 设置目录权限
# Jenkins 容器默认以 UID 1000 运行
# chown 改变目录所有者
# 1000:1000 是 Jenkins 容器内的用户ID:组ID
chown -R 1000:1000 /home/jenkins/jenkins_home

# 举一反三:
# 如果使用 root 用户运行 Jenkins:
# chown -R root:root /home/jenkins/jenkins_home
# 
# 如果自定义用户:
# useradd -u 1001 jenkins_user
# chown -R 1001:1001 /home/jenkins/jenkins_home

1.3 创建 docker-compose.yml

bash 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 命令说明:创建 Jenkins 的 Docker Compose 配置文件
# ═══════════════════════════════════════════════════════════════════════════════

cd /home/jenkins

cat > docker-compose.yml << 'EOF'
# ═══════════════════════════════════════════════════════════════════════════════
# Jenkins Docker Compose 配置
# 
# 启动命令:docker compose up -d
# 停止命令:docker compose down
# 查看日志:docker compose logs -f jenkins
# ═══════════════════════════════════════════════════════════════════════════════

version: '3.8'
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ version:Compose 文件版本                                                    │
# │ 3.8 是当前推荐版本,支持大部分功能                                            │
# └─────────────────────────────────────────────────────────────────────────────┘

services:
  jenkins:
    image: jenkins/jenkins:lts-jdk17
    # ┌───────────────────────────────────────────────────────────────────────────┐
    # │ image:使用的 Docker 镜像                                                  │
    # │                                                                           │
    # │ 镜像选择说明:                                                             │
    # │ • jenkins/jenkins:lts        → LTS 长期支持版(推荐生产环境)              │
    # │ • jenkins/jenkins:lts-jdk17  → LTS 版 + JDK 17(推荐)                    │
    # │ • jenkins/jenkins:lts-jdk11  → LTS 版 + JDK 11                           │
    # │ • jenkins/jenkins:latest     → 最新版(不推荐生产使用)                    │
    # │                                                                           │
    # │ 举一反三:                                                                 │
    # │ 如果项目需要特定 JDK 版本:                                                │
    # │ • JDK 8 项目:jenkins/jenkins:lts-jdk8                                   │
    # │ • JDK 11 项目:jenkins/jenkins:lts-jdk11                                 │
    # │ • JDK 17 项目:jenkins/jenkins:lts-jdk17                                 │
    # └───────────────────────────────────────────────────────────────────────────┘

    container_name: jenkins
    # ┌───────────────────────────────────────────────────────────────────────────┐
    # │ container_name:自定义容器名称                                             │
    # │ 设置后可以用 docker logs jenkins 等命令直接操作                            │
    # └───────────────────────────────────────────────────────────────────────────┘

    restart: unless-stopped
    # ┌───────────────────────────────────────────────────────────────────────────┐
    # │ restart:重启策略                                                          │
    # │                                                                           │
    # │ 可选值:                                                                   │
    # │ • no            → 不自动重启(默认)                                       │
    # │ • always        → 总是重启(包括手动停止后 Docker 重启)                   │
    # │ • on-failure    → 只在非正常退出时重启                                     │
    # │ • unless-stopped → 除非手动停止,否则总是重启(推荐)                       │
    # └───────────────────────────────────────────────────────────────────────────┘

    privileged: true
    # ┌───────────────────────────────────────────────────────────────────────────┐
    # │ privileged:特权模式                                                       │
    # │                                                                           │
    # │ 作用:                                                                     │
    # │ • 容器获得宿主机的几乎所有权限                                              │
    # │ • 可以访问宿主机的设备(如 Docker socket)                                  │
    # │ • Jenkins 需要调用 Docker 命令来构建镜像                                   │
    # │                                                                           │
    # │ 安全提醒:                                                                 │
    # │ • 生产环境建议用更安全的 Docker-in-Docker 或 Docker-out-of-Docker 方案     │
    # │ • 或者不用 privileged,只挂载 Docker socket                               │
    # └───────────────────────────────────────────────────────────────────────────┘

    user: root
    # ┌───────────────────────────────────────────────────────────────────────────┐
    # │ user:容器运行的用户                                                       │
    # │                                                                           │
    # │ 说明:                                                                     │
    # │ • root → 以 root 用户运行(方便但不够安全)                                │
    # │ • 默认 Jenkins 用 uid 1000 运行                                           │
    # │ • 使用 root 是为了能操作 Docker socket                                     │
    # │                                                                           │
    # │ 举一反三(更安全的方式):                                                  │
    # │ # 不用 root,而是把 jenkins 用户加入 docker 组                             │
    # │ user: "1000:1000"                                                         │
    # │ # 宿主机上执行:                                                           │
    # │ # usermod -aG docker $(id -un 1000)                                       │
    # └───────────────────────────────────────────────────────────────────────────┘

    ports:
      - "8080:8080"
      - "50000:50000"
    # ┌───────────────────────────────────────────────────────────────────────────┐
    # │ ports:端口映射                                                            │
    # │                                                                           │
    # │ 格式:"宿主机端口:容器端口"                                                │
    # │                                                                           │
    # │ • 8080:8080  → Jenkins Web 界面端口                                       │
    # │               访问地址:http://服务器IP:8080                               │
    # │                                                                           │
    # │ • 50000:50000 → Jenkins Agent 通信端口(JNLP)                            │
    # │                 用于 Jenkins 主节点与从节点通信                            │
    # │                 如果只用单机 Jenkins 可以不开                              │
    # │                                                                           │
    # │ 举一反三:                                                                 │
    # │ • 如果 8080 被占用:- "9090:8080"  # 用 9090 访问                          │
    # │ • 如果用 Nginx 反代:- "127.0.0.1:8080:8080"  # 只允许本机访问             │
    # └───────────────────────────────────────────────────────────────────────────┘

    volumes:
      - ./jenkins_home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
      - /usr/bin/docker:/usr/bin/docker
    # ┌───────────────────────────────────────────────────────────────────────────┐
    # │ volumes:数据卷映射                                                        │
    # │                                                                           │
    # │ ./jenkins_home:/var/jenkins_home                                          │
    # │ → Jenkins 数据目录                                                        │
    # │ → 持久化所有 Jenkins 配置、任务、插件等                                    │
    # │ → 容器重建数据不丢失                                                       │
    # │                                                                           │
    # │ /var/run/docker.sock:/var/run/docker.sock                                 │
    # │ → Docker socket 文件                                                      │
    # │ → 让容器内的 Jenkins 可以调用宿主机的 Docker                               │
    # │ → 实现 Docker-out-of-Docker(DooD)模式                                   │
    # │ → 这样 Jenkins 可以执行 docker build、docker push 等命令                  │
    # │                                                                           │
    # │ /usr/bin/docker:/usr/bin/docker                                           │
    # │ → Docker 可执行文件                                                       │
    # │ → 让容器内可以使用 docker 命令                                             │
    # │                                                                           │
    # │ 举一反三(使用 Docker-in-Docker):                                        │
    # │ # 不挂载 socket,使用独立的 Docker 环境                                    │
    # │ image: docker:dind                                                        │
    # │ privileged: true  # DinD 必须特权模式                                     │
    # └───────────────────────────────────────────────────────────────────────────┘

    environment:
      - TZ=Asia/Shanghai
      - JAVA_OPTS=-Xmx2g -Xms512m -Djenkins.install.runSetupWizard=true
    # ┌───────────────────────────────────────────────────────────────────────────┐
    # │ environment:环境变量                                                      │
    # │                                                                           │
    # │ TZ=Asia/Shanghai                                                          │
    # │ → 设置时区为上海(北京时间)                                               │
    # │ → 确保日志、定时任务时间正确                                               │
    # │                                                                           │
    # │ JAVA_OPTS                                                                 │
    # │ → JVM 启动参数                                                            │
    # │ → -Xmx2g:最大堆内存 2GB                                                  │
    # │ → -Xms512m:初始堆内存 512MB                                              │
    # │ → -Djenkins.install.runSetupWizard=true:首次运行显示设置向导             │
    # │                                                                           │
    # │ 举一反三(根据服务器内存调整):                                            │
    # │ • 4GB 服务器:JAVA_OPTS=-Xmx1g -Xms256m                                   │
    # │ • 8GB 服务器:JAVA_OPTS=-Xmx2g -Xms512m                                   │
    # │ • 16GB 服务器:JAVA_OPTS=-Xmx4g -Xms1g                                    │
    # │                                                                           │
    # │ 跳过设置向导(自动化部署时):                                              │
    # │ -Djenkins.install.runSetupWizard=false                                    │
    # └───────────────────────────────────────────────────────────────────────────┘

    networks:
      - jenkins-network

networks:
  jenkins-network:
    driver: bridge
    # ┌───────────────────────────────────────────────────────────────────────────┐
    # │ networks:自定义 Docker 网络                                               │
    # │                                                                           │
    # │ driver: bridge                                                            │
    # │ → 桥接网络,同一网络内的容器可以互相通信                                    │
    # │                                                                           │
    # │ 为什么要自定义网络:                                                        │
    # │ • 网络隔离,更安全                                                         │
    # │ • 支持服务名 DNS 解析                                                      │
    # │ • 便于后续添加其他服务(如 SonarQube、Nexus)                              │
    # └───────────────────────────────────────────────────────────────────────────┘
EOF

echo "✅ docker-compose.yml 创建完成!"

1.4 启动 Jenkins

bash 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 命令说明:启动 Jenkins 容器
# ═══════════════════════════════════════════════════════════════════════════════

cd /home/jenkins

# 启动 Jenkins(后台运行)
# -d 参数:detached 模式,后台运行
docker compose up -d

# 查看启动状态
# ps 显示所有服务的状态
docker compose ps

# 查看 Jenkins 日志
# -f 参数:follow 实时跟踪日志输出
# 首次启动会显示初始管理员密码
docker compose logs -f jenkins

# 等待看到类似以下输出表示启动成功:
# Jenkins initial setup is required. An admin user has been created and a password generated.
# Please use the following password to proceed to installation:
# 
# a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
# 
# This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

# 获取初始密码的另一种方式
# exec 在运行中的容器内执行命令
# cat 读取文件内容
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

# 举一反三:
# 重启 Jenkins:docker compose restart jenkins
# 停止 Jenkins:docker compose stop jenkins
# 删除并重建:docker compose down && docker compose up -d
# 查看资源使用:docker stats jenkins

1.5 验证 Docker 命令可用

bash 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 命令说明:验证 Jenkins 容器内可以使用 Docker 命令
# ═══════════════════════════════════════════════════════════════════════════════

# 进入 Jenkins 容器
# exec:在容器中执行命令
# -it:交互式终端(-i 交互,-t 终端)
# bash:使用 bash shell
docker exec -it jenkins bash

# 在容器内执行 docker 命令
docker --version
# 输出类似:Docker version 24.0.7, build afdd53b

docker ps
# 应该能看到宿主机上运行的所有容器

# 退出容器
exit

# 如果 docker 命令不可用,检查:
# 1. 是否挂载了 /var/run/docker.sock
# 2. 是否挂载了 /usr/bin/docker
# 3. 权限是否正确

二、Docker环境-Jenkins 初始配置

2.1 访问 Jenkins

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 步骤详解:首次访问 Jenkins                                                        │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ 步骤1:浏览器访问                                                                │
│ ─────────────────────────────────────────────────────────────────               │
│ http://服务器IP:8080                                                            │
│                                                                                 │
│ 步骤2:解锁 Jenkins                                                              │
│ ─────────────────────────────────────────────────────────────────               │
│ • 页面显示「Unlock Jenkins」                                                    │
│ • 输入初始管理员密码(从日志或文件获取)                                          │
│ • 点击「Continue」                                                              │
│                                                                                 │
│ 步骤3:安装插件                                                                  │
│ ─────────────────────────────────────────────────────────────────               │
│ • 选择「Install suggested plugins」(安装推荐插件)                              │
│ • 等待插件安装完成(可能需要 5-15 分钟)                                         │
│                                                                                 │
│ 步骤4:创建管理员用户                                                            │
│ ─────────────────────────────────────────────────────────────────               │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ 用户名            │ admin(可自定义)                                       │  │
│ │ 密码              │ 设置强密码                                              │  │
│ │ 确认密码          │ 重复输入                                                │  │
│ │ 全名              │ Administrator                                          │  │
│ │ 邮箱              │ admin@example.com                                       │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 步骤5:配置 Jenkins URL                                                         │
│ ─────────────────────────────────────────────────────────────────               │
│ • Jenkins URL:http://服务器IP:8080/                                            │
│ • 如果有域名:http://jenkins.example.com/                                       │
│ • 点击「Save and Finish」                                                       │
│                                                                                 │
│ 步骤6:完成                                                                      │
│ ─────────────────────────────────────────────────────────────────               │
│ • 点击「Start using Jenkins」                                                   │
│ • 进入 Jenkins 主界面                                                           │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

2.2 安装必需插件

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 步骤详解:安装 CI/CD 所需插件                                                     │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ 入口:Dashboard → Manage Jenkins → Plugins → Available plugins                  │
│                                                                                 │
│ 必装插件列表:                                                                   │
│ ┌──────────────────────────┬────────────────────────────────────────────────┐  │
│ │ 插件名称                  │ 作用说明                                       │  │
│ ├──────────────────────────┼────────────────────────────────────────────────┤  │
│ │ Git                       │ Git 版本控制支持                               │  │
│ │ Git Parameter             │ Git 参数化构建(选择分支/标签)                │  │
│ │ Pipeline                  │ Pipeline 流水线支持(核心)                    │  │
│ │ Pipeline: Stage View      │ 流水线阶段可视化                               │  │
│ │ Docker Pipeline           │ Pipeline 中使用 Docker                        │  │
│ │ Docker                    │ Docker 构建支持                                │  │
│ │ SSH Agent                 │ SSH 密钥管理(远程部署)                       │  │
│ │ Publish Over SSH          │ SSH 远程执行命令(部署到服务器)               │  │
│ │ Credentials               │ 凭据管理(密码、密钥等)                       │  │
│ │ Credentials Binding       │ 在 Pipeline 中绑定凭据                        │  │
│ │ Blue Ocean                │ 现代化 UI 界面(可选但推荐)                   │  │
│ │ Workspace Cleanup         │ 构建前清理工作空间                             │  │
│ │ Timestamper               │ 日志添加时间戳                                 │  │
│ │ AnsiColor                 │ 控制台彩色输出                                 │  │
│ │ Build Timeout             │ 构建超时控制                                   │  │
│ │ Webhook Trigger           │ Webhook 触发构建                               │  │
│ │ Generic Webhook Trigger   │ 通用 Webhook 触发器                            │  │
│ └──────────────────────────┴────────────────────────────────────────────────┘  │
│                                                                                 │
│ 安装方法:                                                                       │
│ 1. 在搜索框搜索插件名                                                           │
│ 2. 勾选插件                                                                     │
│ 3. 点击「Install」                                                              │
│ 4. 等待安装完成                                                                 │
│ 5. 勾选「Restart Jenkins when installation is complete...」重启                │
│                                                                                 │
│ 举一反三(根据项目类型添加):                                                    │
│ • Maven 项目:Maven Integration                                                │
│ • Gradle 项目:Gradle                                                          │
│ • Node.js 项目:NodeJS                                                         │
│ • 代码质量:SonarQube Scanner                                                  │
│ • 通知:DingTalk、Slack Notification、Email Extension                          │
│ • Kubernetes 部署:Kubernetes、Kubernetes CLI                                  │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

2.3 配置全局工具

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 步骤详解:配置 JDK、Maven、Node.js 等构建工具                                     │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ 入口:Dashboard → Manage Jenkins → Tools                                        │
│                                                                                 │
│ 【配置 JDK】                                                                     │
│ ─────────────────────────────────────────────────────────────────               │
│ 点击「Add JDK」:                                                                │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Name             │ JDK17(自定义名称,Pipeline 中引用)                     │  │
│ │ JAVA_HOME        │ /opt/java/openjdk                                       │  │
│ │                  │ (Jenkins 镜像自带 JDK 的路径)                          │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 或者选择「Install automatically」自动安装:                                      │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Name             │ JDK17                                                   │  │
│ │ Install from     │ adoptium.net                                            │  │
│ │ Version          │ jdk-17.0.8+7                                            │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 【配置 Maven】                                                                   │
│ ─────────────────────────────────────────────────────────────────               │
│ 点击「Add Maven」:                                                              │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Name             │ Maven3(自定义名称)                                     │  │
│ │ Install auto     │ ☑ 勾选                                                  │  │
│ │ Version          │ 3.9.5                                                   │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 【配置 NodeJS】(前端项目需要)                                                   │
│ ─────────────────────────────────────────────────────────────────               │
│ 需先安装 NodeJS 插件                                                            │
│ 点击「Add NodeJS」:                                                            │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Name             │ Node18                                                  │  │
│ │ Install auto     │ ☑ 勾选                                                  │  │
│ │ Version          │ 18.18.0                                                 │  │
│ │ Global packages  │ yarn pnpm(可选,自动安装的全局包)                      │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 【配置 Docker】                                                                  │
│ ─────────────────────────────────────────────────────────────────               │
│ 点击「Add Docker」:                                                            │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Name             │ Docker                                                  │  │
│ │ Installation     │ Download from docker.com                                │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 保存配置:点击页面底部「Save」按钮                                               │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

三、Docker环境-配置凭据管理

3.1 凭据类型说明

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│                          Jenkins 凭据类型详解                                    │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  ┌──────────────────────────┬────────────────────────────────────────────────┐ │
│  │ 凭据类型                  │ 使用场景                                       │ │
│  ├──────────────────────────┼────────────────────────────────────────────────┤ │
│  │ Username with password    │ Git 仓库账号密码                               │ │
│  │                          │ Docker Registry 登录                           │ │
│  │                          │ 数据库连接                                      │ │
│  ├──────────────────────────┼────────────────────────────────────────────────┤ │
│  │ SSH Username with        │ SSH 密钥登录服务器                              │ │
│  │ private key              │ Git SSH 方式拉取代码                           │ │
│  ├──────────────────────────┼────────────────────────────────────────────────┤ │
│  │ Secret text              │ API Token                                      │ │
│  │                          │ 各种密钥字符串                                  │ │
│  ├──────────────────────────┼────────────────────────────────────────────────┤ │
│  │ Secret file              │ 配置文件                                       │ │
│  │                          │ 证书文件                                       │ │
│  │                          │ kubeconfig 文件                                │ │
│  ├──────────────────────────┼────────────────────────────────────────────────┤ │
│  │ Certificate              │ PKCS#12 证书                                   │ │
│  └──────────────────────────┴────────────────────────────────────────────────┘ │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

3.2 添加 Git 凭据

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 步骤详解:添加 Git 仓库凭据                                                       │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ 入口:Dashboard → Manage Jenkins → Credentials → System → Global credentials   │
│      → Add Credentials                                                          │
│                                                                                 │
│ 【方式一:用户名密码】(适用于 HTTPS 方式拉取代码)                               │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Kind             │ Username with password                                  │  │
│ │ Scope            │ Global(全局可用)                                       │  │
│ │ Username         │ your-git-username                                       │  │
│ │ Password         │ your-git-password 或 Access Token                       │  │
│ │ ID               │ git-credentials(自定义 ID,Pipeline 中引用)            │  │
│ │ Description      │ Git 仓库登录凭据                                        │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 📝 说明:                                                                        │
│ • GitHub/GitLab 建议使用 Personal Access Token 而不是密码                       │
│ • Token 权限只需要 repo 读取权限                                                │
│                                                                                 │
│ 【方式二:SSH 密钥】(适用于 SSH 方式拉取代码)                                   │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Kind             │ SSH Username with private key                           │  │
│ │ Scope            │ Global                                                  │  │
│ │ ID               │ git-ssh-key                                             │  │
│ │ Description      │ Git SSH 密钥                                            │  │
│ │ Username         │ git                                                     │  │
│ │ Private Key      │ Enter directly → 粘贴私钥内容                           │  │
│ │                  │ 包含 -----BEGIN RSA PRIVATE KEY----- 开头               │  │
│ │ Passphrase       │ 如果密钥有密码则填写                                     │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 📝 生成 SSH 密钥:                                                               │
│ ssh-keygen -t rsa -b 4096 -C "jenkins@example.com"                             │
│ # 然后把公钥(id_rsa.pub)添加到 Git 仓库的 Deploy Keys                         │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

3.3 添加 Docker Registry 凭据

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 步骤详解:添加 Docker 镜像仓库凭据                                                │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ 【阿里云 ACR 凭据】                                                              │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Kind             │ Username with password                                  │  │
│ │ Scope            │ Global                                                  │  │
│ │ Username         │ 阿里云账号(或 RAM 子账号)                              │  │
│ │ Password         │ ACR 仓库密码(在 ACR 控制台设置)                        │  │
│ │ ID               │ aliyun-acr-credentials                                  │  │
│ │ Description      │ 阿里云容器镜像仓库凭据                                   │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 【Docker Hub 凭据】                                                             │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Kind             │ Username with password                                  │  │
│ │ Scope            │ Global                                                  │  │
│ │ Username         │ Docker Hub 用户名                                       │  │
│ │ Password         │ Docker Hub Access Token(不是登录密码)                 │  │
│ │ ID               │ dockerhub-credentials                                   │  │
│ │ Description      │ Docker Hub 凭据                                         │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 【Harbor 私有仓库凭据】                                                          │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Kind             │ Username with password                                  │  │
│ │ Scope            │ Global                                                  │  │
│ │ Username         │ Harbor 用户名                                           │  │
│ │ Password         │ Harbor 密码                                             │  │
│ │ ID               │ harbor-credentials                                      │  │
│ │ Description      │ Harbor 私有仓库凭据                                     │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

3.4 添加服务器 SSH 凭据

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 步骤详解:添加生产服务器 SSH 登录凭据(用于远程部署)                              │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ ┌──────────────────┬────────────────────────────────────────────────────────┐  │
│ │ Kind             │ SSH Username with private key                           │  │
│ │ Scope            │ Global                                                  │  │
│ │ ID               │ prod-server-ssh                                         │  │
│ │ Description      │ 生产服务器 SSH 密钥                                      │  │
│ │ Username         │ root(或其他有部署权限的用户)                           │  │
│ │ Private Key      │ Enter directly → 粘贴私钥内容                           │  │
│ └──────────────────┴────────────────────────────────────────────────────────┘  │
│                                                                                 │
│ 📝 准备工作:                                                                    │
│                                                                                 │
│ # 在 Jenkins 服务器上生成密钥对(如果还没有)                                    │
│ ssh-keygen -t rsa -b 4096 -f ~/.ssh/jenkins_deploy_key -C "jenkins-deploy"     │
│                                                                                 │
│ # 将公钥添加到生产服务器                                                         │
│ ssh-copy-id -i ~/.ssh/jenkins_deploy_key.pub root@生产服务器IP                  │
│                                                                                 │
│ # 或手动复制公钥内容到生产服务器的 ~/.ssh/authorized_keys                        │
│ cat ~/.ssh/jenkins_deploy_key.pub                                               │
│                                                                                 │
│ # 然后将私钥内容粘贴到 Jenkins 凭据中                                            │
│ cat ~/.ssh/jenkins_deploy_key                                                   │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

四、Docker环境-创建 Pipeline 流水线

4.1 Pipeline 基本概念

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│                          Pipeline 流水线核心概念                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│   Pipeline 流程:                                                                │
│   ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐         │
│   │ Checkout│ → │  Build  │ → │  Test   │ → │  Push   │ → │ Deploy  │         │
│   │ 拉取代码 │   │ 编译构建 │   │ 单元测试 │   │ 推送镜像 │   │ 部署发布 │         │
│   └─────────┘   └─────────┘   └─────────┘   └─────────┘   └─────────┘         │
│                                                                                 │
│   Pipeline 语法类型:                                                            │
│   ┌──────────────────────────┬────────────────────────────────────────────────┐│
│   │ 声明式 (Declarative)      │ 结构清晰,推荐使用                             ││
│   │                          │ 以 pipeline { } 开头                          ││
│   ├──────────────────────────┼────────────────────────────────────────────────┤│
│   │ 脚本式 (Scripted)         │ 更灵活,学习成本高                             ││
│   │                          │ 以 node { } 开头                              ││
│   └──────────────────────────┴────────────────────────────────────────────────┘│
│                                                                                 │
│   关键术语:                                                                     │
│   • pipeline:整个流水线定义                                                     │
│   • agent:指定执行环境(节点/容器)                                            │
│   • stages:包含多个 stage 的集合                                               │
│   • stage:流水线的一个阶段                                                     │
│   • steps:stage 中要执行的具体步骤                                             │
│   • post:流水线或 stage 结束后的处理                                           │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

4.2 Pipeline 基础语法详解

groovy 复制代码
// ═══════════════════════════════════════════════════════════════════════════════
// Pipeline 完整语法示例(带详细注释)
// ═══════════════════════════════════════════════════════════════════════════════

pipeline {
    // ┌─────────────────────────────────────────────────────────────────────────────┐
    // │ agent:指定流水线在哪里执行                                                  │
    // │                                                                             │
    // │ 常用选项:                                                                   │
    // │ • agent any          → 任意可用节点                                         │
    // │ • agent none         → 不指定,每个 stage 单独指定                          │
    // │ • agent { label 'xxx' } → 指定标签的节点                                   │
    // │ • agent { docker { image 'maven:3.9' } } → Docker 容器中执行               │
    // └─────────────────────────────────────────────────────────────────────────────┘
    agent any
    
    // ┌─────────────────────────────────────────────────────────────────────────────┐
    // │ environment:定义环境变量                                                    │
    // │                                                                             │
    // │ 作用:                                                                       │
    // │ • 定义全局环境变量,所有 stage 都可以使用                                    │
    // │ • 可以引用凭据                                                              │
    // │ • 在 Pipeline 中用 ${ENV_NAME} 或 $ENV_NAME 引用                           │
    // └─────────────────────────────────────────────────────────────────────────────┘
    environment {
        // 普通环境变量
        PROJECT_NAME = 'my-project'
        
        // 从凭据获取(自动注入为环境变量)
        // credentials('凭据ID') 会自动处理不同类型的凭据
        DOCKER_CREDENTIALS = credentials('aliyun-acr-credentials')
        // 会自动生成:
        // DOCKER_CREDENTIALS_USR → 用户名
        // DOCKER_CREDENTIALS_PSW → 密码
    }
    
    // ┌─────────────────────────────────────────────────────────────────────────────┐
    // │ options:流水线选项配置                                                      │
    // └─────────────────────────────────────────────────────────────────────────────┘
    options {
        // 构建超时时间(超过则自动终止)
        timeout(time: 30, unit: 'MINUTES')
        
        // 日志添加时间戳
        timestamps()
        
        // 丢弃旧的构建,保留最近 10 次
        buildDiscarder(logRotator(numToKeepStr: '10'))
        
        // 禁止并行构建(同一 Job 同时只能运行一个)
        disableConcurrentBuilds()
        
        // 重试次数
        retry(2)
    }
    
    // ┌─────────────────────────────────────────────────────────────────────────────┐
    // │ parameters:参数化构建                                                       │
    // │                                                                             │
    // │ 作用:构建时可以选择/输入参数                                                │
    // │ 在 Pipeline 中用 params.PARAM_NAME 引用                                    │
    // └─────────────────────────────────────────────────────────────────────────────┘
    parameters {
        // 字符串参数
        string(name: 'BRANCH', defaultValue: 'main', description: '要构建的分支')
        
        // 选择参数
        choice(name: 'ENVIRONMENT', choices: ['dev', 'test', 'prod'], description: '部署环境')
        
        // 布尔参数
        booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: '是否跳过测试')
        
        // Git 分支参数(需要 Git Parameter 插件)
        gitParameter(name: 'GIT_BRANCH', 
                     branchFilter: 'origin/(.*)', 
                     type: 'PT_BRANCH',
                     defaultValue: 'main',
                     description: '选择分支')
    }
    
    // ┌─────────────────────────────────────────────────────────────────────────────┐
    // │ triggers:自动触发器                                                         │
    // └─────────────────────────────────────────────────────────────────────────────┘
    triggers {
        // 定时构建(cron 表达式)
        // 每天凌晨 2 点构建
        cron('0 2 * * *')
        
        // 轮询 SCM(检测代码变化)
        // 每 5 分钟检查一次
        pollSCM('H/5 * * * *')
        
        // Generic Webhook Trigger(推荐)
        // 配置 webhook URL:http://jenkins-url/generic-webhook-trigger/invoke?token=xxx
    }
    
    // ┌─────────────────────────────────────────────────────────────────────────────┐
    // │ stages:流水线阶段定义                                                       │
    // └─────────────────────────────────────────────────────────────────────────────┘
    stages {
        stage('Checkout') {
            steps {
                echo '拉取代码...'
                // checkout 从 SCM 拉取代码
                checkout scm
            }
        }
        
        stage('Build') {
            steps {
                echo '编译构建...'
                sh 'mvn clean package -DskipTests'
            }
        }
        
        stage('Test') {
            // when:条件执行
            when {
                // 只有参数 SKIP_TESTS 为 false 时才执行
                expression { return !params.SKIP_TESTS }
            }
            steps {
                echo '运行测试...'
                sh 'mvn test'
            }
        }
        
        stage('Deploy') {
            // 并行执行多个子阶段
            parallel {
                stage('Deploy to Dev') {
                    when {
                        expression { params.ENVIRONMENT == 'dev' }
                    }
                    steps {
                        echo '部署到开发环境...'
                    }
                }
                stage('Deploy to Prod') {
                    when {
                        expression { params.ENVIRONMENT == 'prod' }
                    }
                    // 需要人工确认
                    input {
                        message "确认部署到生产环境?"
                        ok "确认部署"
                    }
                    steps {
                        echo '部署到生产环境...'
                    }
                }
            }
        }
    }
    
    // ┌─────────────────────────────────────────────────────────────────────────────┐
    // │ post:流水线执行后的处理                                                     │
    // │                                                                             │
    // │ 条件:                                                                       │
    // │ • always   → 无论成功失败都执行                                             │
    // │ • success  → 只在成功时执行                                                 │
    // │ • failure  → 只在失败时执行                                                 │
    // │ • unstable → 不稳定时执行(如测试失败但构建成功)                            │
    // │ • changed  → 状态变化时执行(如上次失败这次成功)                            │
    // └─────────────────────────────────────────────────────────────────────────────┘
    post {
        always {
            echo '清理工作空间...'
            cleanWs()  // 需要 Workspace Cleanup 插件
        }
        success {
            echo '构建成功!'
            // 可以发送通知
        }
        failure {
            echo '构建失败!'
            // 可以发送告警
        }
    }
}

五、Docker环境-完整项目实战

5.1 Spring Boot 项目完整 Pipeline

groovy 复制代码
// ═══════════════════════════════════════════════════════════════════════════════
// Spring Boot 项目 CI/CD 完整 Pipeline
// 
// 功能:
// 1. 拉取代码
// 2. Maven 编译打包
// 3. 构建 Docker 镜像
// 4. 推送到镜像仓库
// 5. 远程部署到服务器
// ═══════════════════════════════════════════════════════════════════════════════

pipeline {
    agent any
    
    environment {
        // ┌─────────────────────────────────────────────────────────────────────────┐
        // │【改】根据实际情况修改以下配置                                             │
        // └─────────────────────────────────────────────────────────────────────────┘
        
        // 项目名称(用于镜像名等)
        PROJECT_NAME = 'my-backend'
        
        // 镜像仓库地址(阿里云 ACR 示例)
        REGISTRY = 'registry.cn-hongkong.aliyuncs.com'
        NAMESPACE = 'myproject'
        
        // 完整镜像名
        IMAGE_NAME = "${REGISTRY}/${NAMESPACE}/${PROJECT_NAME}"
        
        // 镜像标签(使用 BUILD_NUMBER 保证唯一)
        IMAGE_TAG = "${BUILD_NUMBER}"
        
        // 生产服务器信息
        PROD_SERVER = '47.96.xxx.xxx'
        DEPLOY_PATH = '/home/deploy/backend'
        
        // 凭据引用
        DOCKER_CRED = credentials('aliyun-acr-credentials')
    }
    
    options {
        timeout(time: 30, unit: 'MINUTES')
        timestamps()
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }
    
    parameters {
        gitParameter(name: 'BRANCH', 
                     branchFilter: 'origin/(.*)', 
                     defaultValue: 'main',
                     type: 'PT_BRANCH',
                     description: '选择要构建的分支')
        
        choice(name: 'ENVIRONMENT', 
               choices: ['dev', 'test', 'prod'], 
               description: '选择部署环境')
    }
    
    stages {
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段1:拉取代码
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Checkout') {
            steps {
                echo "========== 拉取代码 =========="
                echo "分支: ${params.BRANCH}"
                
                // checkout:从 Git 仓库拉取代码
                // 使用 Git 插件提供的 checkout 步骤
                checkout([
                    $class: 'GitSCM',
                    // 分支配置
                    branches: [[name: "${params.BRANCH}"]],
                    // 扩展配置
                    extensions: [
                        // 清理工作空间
                        [$class: 'CleanBeforeCheckout'],
                        // 克隆深度(1 表示只克隆最近一次提交,加快速度)
                        [$class: 'CloneOption', depth: 1, shallow: true]
                    ],
                    // 仓库配置
                    userRemoteConfigs: [[
                        // 【改】替换为你的 Git 仓库地址
                        url: 'https://github.com/yourname/your-project.git',
                        // 凭据 ID
                        credentialsId: 'git-credentials'
                    ]]
                ])
                
                // 显示最近一次提交信息
                sh 'git log -1 --pretty=format:"%h - %s (%an, %ar)"'
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段2:编译构建
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Build') {
            steps {
                echo "========== Maven 编译 =========="
                
                // sh:执行 Shell 命令
                // mvn clean package:清理并打包
                // -DskipTests:跳过测试(测试在下一阶段)
                // -Dmaven.repo.local=.m2/repository:指定本地仓库路径(加速缓存)
                sh '''
                    mvn clean package \
                        -DskipTests \
                        -Dmaven.repo.local=.m2/repository \
                        -Dfile.encoding=UTF-8
                '''
                
                // archiveArtifacts:归档构建产物
                // 将 JAR 包保存到 Jenkins,方便下载
                archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段3:单元测试
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Test') {
            steps {
                echo "========== 单元测试 =========="
                
                sh 'mvn test -Dmaven.repo.local=.m2/repository'
            }
            post {
                always {
                    // junit:发布测试报告(需要 JUnit 插件)
                    // allowEmptyResults:允许没有测试结果
                    junit allowEmptyResults: true, testResults: 'target/surefire-reports/*.xml'
                }
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段4:构建 Docker 镜像
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Build Docker Image') {
            steps {
                echo "========== 构建 Docker 镜像 =========="
                echo "镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
                
                // 构建 Docker 镜像
                // -t:指定镜像名称和标签
                // -f:指定 Dockerfile 路径(如果不在根目录)
                // .:构建上下文为当前目录
                sh """
                    docker build \
                        -t ${IMAGE_NAME}:${IMAGE_TAG} \
                        -t ${IMAGE_NAME}:latest \
                        -f Dockerfile \
                        .
                """
                
                // 显示构建的镜像
                sh "docker images | grep ${PROJECT_NAME}"
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段5:推送镜像到仓库
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Push Image') {
            steps {
                echo "========== 推送镜像 =========="
                
                // withCredentials:安全地使用凭据
                // usernamePassword:用户名密码类型的凭据
                // credentialsId:凭据 ID
                // usernameVariable/passwordVariable:注入的环境变量名
                withCredentials([usernamePassword(
                    credentialsId: 'aliyun-acr-credentials',
                    usernameVariable: 'DOCKER_USER',
                    passwordVariable: 'DOCKER_PASS'
                )]) {
                    sh """
                        # 登录镜像仓库
                        # echo 密码 | docker login --password-stdin 避免密码出现在日志
                        echo ${DOCKER_PASS} | docker login ${REGISTRY} \
                            --username=${DOCKER_USER} \
                            --password-stdin
                        
                        # 推送镜像(带版本号)
                        docker push ${IMAGE_NAME}:${IMAGE_TAG}
                        
                        # 推送 latest 标签
                        docker push ${IMAGE_NAME}:latest
                        
                        # 清理本地镜像(节省磁盘空间)
                        docker rmi ${IMAGE_NAME}:${IMAGE_TAG} || true
                        docker rmi ${IMAGE_NAME}:latest || true
                    """
                }
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段6:部署到服务器
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Deploy') {
            when {
                // 只有选择 prod 环境才执行
                expression { params.ENVIRONMENT == 'prod' }
            }
            steps {
                echo "========== 部署到生产服务器 =========="
                
                // sshagent:使用 SSH 凭据
                // 需要 SSH Agent 插件
                sshagent(['prod-server-ssh']) {
                    sh """
                        # SSH 远程执行命令
                        # -o StrictHostKeyChecking=no:不检查主机密钥(首次连接)
                        ssh -o StrictHostKeyChecking=no root@${PROD_SERVER} << 'ENDSSH'
                            # 进入部署目录
                            cd ${DEPLOY_PATH}
                            
                            # 登录镜像仓库
                            docker login ${REGISTRY} -u ${DOCKER_USER} -p ${DOCKER_PASS}
                            
                            # 拉取最新镜像
                            docker pull ${IMAGE_NAME}:${IMAGE_TAG}
                            
                            # 停止并删除旧容器
                            docker stop ${PROJECT_NAME} || true
                            docker rm ${PROJECT_NAME} || true
                            
                            # 启动新容器
                            docker run -d \\
                                --name ${PROJECT_NAME} \\
                                --restart unless-stopped \\
                                -p 8080:8080 \\
                                -e SPRING_PROFILES_ACTIVE=prod \\
                                -e TZ=Asia/Shanghai \\
                                -v /home/deploy/logs:/app/logs \\
                                ${IMAGE_NAME}:${IMAGE_TAG}
                            
                            # 清理旧镜像
                            docker image prune -f
                            
                            # 检查容器状态
                            docker ps | grep ${PROJECT_NAME}
ENDSSH
                    """
                }
            }
        }
    }
    
    post {
        always {
            echo "========== 清理工作空间 =========="
            cleanWs()
        }
        success {
            echo "✅ 构建成功!镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
            // 可以添加通知(钉钉、企业微信等)
        }
        failure {
            echo "❌ 构建失败!"
            // 可以添加告警通知
        }
    }
}

5.2 项目 Dockerfile 示例

dockerfile 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# Spring Boot 项目 Dockerfile
# 
# 文件位置:项目根目录/Dockerfile
# ═══════════════════════════════════════════════════════════════════════════════

# ─────────────────────────────────────────────────────────────────────────────────
# 阶段1:构建阶段(可选,如果 Jenkins 已经构建好 JAR 则跳过)
# ─────────────────────────────────────────────────────────────────────────────────
# FROM maven:3.9-eclipse-temurin-17 AS builder
# WORKDIR /build
# COPY pom.xml .
# COPY src ./src
# RUN mvn clean package -DskipTests

# ─────────────────────────────────────────────────────────────────────────────────
# 阶段2:运行阶段
# ─────────────────────────────────────────────────────────────────────────────────
FROM eclipse-temurin:17-jre-alpine
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ FROM:基础镜像                                                               │
# │                                                                             │
# │ 选择说明:                                                                   │
# │ • eclipse-temurin:17-jre-alpine → JRE 17 Alpine 版(推荐,体积小)          │
# │ • eclipse-temurin:17-jdk-alpine → JDK 17 Alpine 版(需要编译工具时用)      │
# │ • openjdk:17-jdk-slim           → OpenJDK 17 精简版                        │
# │ • amazoncorretto:17-alpine      → Amazon Corretto JDK                      │
# │                                                                             │
# │ Alpine 版本体积约 100MB,普通版本约 300MB+                                   │
# └─────────────────────────────────────────────────────────────────────────────┘

LABEL maintainer="your-email@example.com"
LABEL version="1.0"
LABEL description="My Spring Boot Application"
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ LABEL:镜像元数据                                                            │
# │ 用于记录镜像信息,可以通过 docker inspect 查看                                │
# └─────────────────────────────────────────────────────────────────────────────┘

# 设置时区
ENV TZ=Asia/Shanghai
RUN apk add --no-cache tzdata \
    && cp /usr/share/zoneinfo/${TZ} /etc/localtime \
    && echo "${TZ}" > /etc/timezone
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ 时区设置:                                                                   │
# │ • apk add:Alpine 的包管理器(类似 apt)                                    │
# │ • --no-cache:不缓存包索引(减小镜像体积)                                   │
# │ • tzdata:时区数据包                                                        │
# └─────────────────────────────────────────────────────────────────────────────┘

# 创建非 root 用户(安全最佳实践)
RUN addgroup -g 1000 appgroup \
    && adduser -u 1000 -G appgroup -D appuser
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ 创建普通用户:                                                               │
# │ • 不要用 root 运行应用(安全风险)                                           │
# │ • -g 1000:指定 GID                                                        │
# │ • -u 1000:指定 UID                                                        │
# │ • -G:指定所属组                                                            │
# │ • -D:不创建密码                                                            │
# └─────────────────────────────────────────────────────────────────────────────┘

WORKDIR /app
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ WORKDIR:设置工作目录                                                        │
# │ 后续命令都在此目录执行                                                       │
# └─────────────────────────────────────────────────────────────────────────────┘

# 复制 JAR 包
# 【改】替换为你的 JAR 包名称
COPY target/*.jar app.jar
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ COPY:复制文件                                                               │
# │ 从构建上下文复制到镜像中                                                     │
# │                                                                             │
# │ 如果使用多阶段构建:                                                         │
# │ COPY --from=builder /build/target/*.jar app.jar                            │
# └─────────────────────────────────────────────────────────────────────────────┘

# 创建日志目录并设置权限
RUN mkdir -p /app/logs \
    && chown -R appuser:appgroup /app

# 切换到非 root 用户
USER appuser

# 暴露端口
EXPOSE 8080
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ EXPOSE:声明容器端口                                                         │
# │ • 仅声明,不实际开放                                                         │
# │ • 运行时需要 -p 映射端口                                                     │
# │ • 可以暴露多个:EXPOSE 8080 8443 9090                                       │
# └─────────────────────────────────────────────────────────────────────────────┘

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
    CMD wget -q --spider http://localhost:8080/actuator/health || exit 1
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ HEALTHCHECK:健康检查                                                        │
# │                                                                             │
# │ 参数说明:                                                                   │
# │ • --interval=30s:每 30 秒检查一次                                          │
# │ • --timeout=3s:超时时间 3 秒                                               │
# │ • --start-period=60s:启动后等待 60 秒再开始检查                             │
# │ • --retries=3:连续失败 3 次标记为 unhealthy                                │
# │                                                                             │
# │ 需要 Spring Boot Actuator:                                                 │
# │ 添加依赖:spring-boot-starter-actuator                                      │
# │ 配置:management.endpoints.web.exposure.include=health                      │
# └─────────────────────────────────────────────────────────────────────────────┘

# 启动命令
ENTRYPOINT ["java", \
    "-XX:+UseContainerSupport", \
    "-XX:MaxRAMPercentage=75.0", \
    "-Djava.security.egd=file:/dev/./urandom", \
    "-jar", "app.jar"]
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ ENTRYPOINT:容器启动命令                                                     │
# │                                                                             │
# │ JVM 参数说明:                                                               │
# │                                                                             │
# │ -XX:+UseContainerSupport                                                    │
# │ → 启用容器支持(JDK 10+)                                                   │
# │ → JVM 会自动检测容器的 CPU 和内存限制                                        │
# │                                                                             │
# │ -XX:MaxRAMPercentage=75.0                                                   │
# │ → 最大使用容器内存的 75%                                                    │
# │ → 留 25% 给系统和其他进程                                                   │
# │                                                                             │
# │ -Djava.security.egd=file:/dev/./urandom                                     │
# │ → 使用非阻塞随机数生成器                                                    │
# │ → 加快启动速度                                                              │
# │                                                                             │
# │ 举一反三(其他常用参数):                                                    │
# │ -Xms512m -Xmx1024m        → 固定堆内存                                      │
# │ -XX:+UseG1GC              → 使用 G1 垃圾收集器                              │
# │ -XX:+HeapDumpOnOutOfMemoryError → OOM 时 dump 内存                         │
# │ -Dspring.profiles.active=prod → 激活 prod 配置                             │
# └─────────────────────────────────────────────────────────────────────────────┘

# 也可以用 CMD 方式(更灵活,可被 docker run 参数覆盖):
# CMD ["java", "-jar", "app.jar"]

方案二:Kubernetes 环境

六、K8s环境-Jenkins 部署

6.1 架构图

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│                   Kubernetes 环境 Jenkins CI/CD 架构                             │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│   开发人员                                                                       │
│      │                                                                          │
│      │ git push                                                                 │
│      ▼                                                                          │
│   ┌─────────────────┐                                                           │
│   │   Git 仓库       │ (GitHub/GitLab/Gitee)                                    │
│   └────────┬────────┘                                                           │
│            │ Webhook 触发                                                        │
│            ▼                                                                    │
│   ┌─────────────────────────────────────────────────────────────────────────┐  │
│   │                       Kubernetes 集群                                    │  │
│   │  ┌───────────────────────────────────────────────────────────────────┐  │  │
│   │  │                    jenkins 命名空间                                │  │  │
│   │  │  ┌─────────────────────────────────────────────────────────────┐  │  │  │
│   │  │  │  Jenkins Master Pod                                         │  │  │  │
│   │  │  │  • 管理界面                                                  │  │  │  │
│   │  │  │  • 调度任务                                                  │  │  │  │
│   │  │  │  • 配置管理                                                  │  │  │  │
│   │  │  └─────────────────────────────────────────────────────────────┘  │  │  │
│   │  │              │                                                    │  │  │
│   │  │              │ 动态创建                                           │  │  │
│   │  │              ▼                                                    │  │  │
│   │  │  ┌──────────┐ ┌──────────┐ ┌──────────┐                          │  │  │
│   │  │  │ Agent    │ │ Agent    │ │ Agent    │ ← 构建完成后自动销毁      │  │  │
│   │  │  │ Pod 1    │ │ Pod 2    │ │ Pod N    │                          │  │  │
│   │  │  │ (构建)   │ │ (构建)   │ │ (构建)   │                          │  │  │
│   │  │  └──────────┘ └──────────┘ └──────────┘                          │  │  │
│   │  └───────────────────────────────────────────────────────────────────┘  │  │
│   │                                                                         │  │
│   │  构建完成后直接部署到 K8s:                                              │  │
│   │  ┌───────────────────────────────────────────────────────────────────┐  │  │
│   │  │                    prod 命名空间                                  │  │  │
│   │  │  ┌──────────┐ ┌──────────┐ ┌──────────┐                          │  │  │
│   │  │  │ Nginx    │ │ Backend  │ │ Backend  │ ← 滚动更新                │  │  │
│   │  │  │ Ingress  │ │ Pod 1    │ │ Pod 2    │                          │  │  │
│   │  │  └──────────┘ └──────────┘ └──────────┘                          │  │  │
│   │  └───────────────────────────────────────────────────────────────────┘  │  │
│   └─────────────────────────────────────────────────────────────────────────┘  │
│                                                                                 │
│   K8s Jenkins 优势:                                                            │
│   • 动态 Agent:按需创建,用完即删,资源高效                                    │
│   • 弹性伸缩:高峰期自动扩容                                                    │
│   • 隔离性好:每个构建独立 Pod                                                  │
│   • 与 K8s 原生集成:直接 kubectl 部署                                         │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

6.2 创建命名空间和 RBAC

bash 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 命令说明:创建 Jenkins 专用命名空间
# 
# 前提:kubectl 已配置好,能连接到 K8s 集群
# ═══════════════════════════════════════════════════════════════════════════════

# 创建 Jenkins 命名空间
kubectl create namespace jenkins

# 验证创建成功
kubectl get namespace jenkins

6.3 创建 ServiceAccount 和权限

yaml 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 文件名:jenkins-rbac.yaml
# 作用:创建 Jenkins 服务账号和权限
# 
# 执行:kubectl apply -f jenkins-rbac.yaml
# ═══════════════════════════════════════════════════════════════════════════════

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins
  namespace: jenkins
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ ServiceAccount:服务账号                                                     │
# │ 作用:Pod 使用此账号访问 K8s API                                            │
# │ Jenkins 需要此账号来创建动态 Agent Pod                                      │
# └─────────────────────────────────────────────────────────────────────────────┘

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: jenkins-role
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ ClusterRole:集群角色(集群范围的权限)                                       │
# │ Jenkins 需要 ClusterRole 因为要在多个命名空间操作                            │
# └─────────────────────────────────────────────────────────────────────────────┘
rules:
  # Pod 相关权限(创建动态 Agent)
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["create", "delete", "get", "list", "watch", "patch"]
  - apiGroups: [""]
    resources: ["pods/log", "pods/exec"]
    verbs: ["get", "list", "create"]
  
  # Secret/ConfigMap 权限
  - apiGroups: [""]
    resources: ["secrets", "configmaps"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  
  # Deployment/Service 权限(部署应用)
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets", "statefulsets"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  
  # Ingress 权限
  - apiGroups: ["networking.k8s.io"]
    resources: ["ingresses"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: jenkins-role
subjects:
  - kind: ServiceAccount
    name: jenkins
    namespace: jenkins

6.4 创建持久化存储

yaml 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 文件名:jenkins-pvc.yaml
# 作用:创建持久化存储卷,保存 Jenkins 数据
# ═══════════════════════════════════════════════════════════════════════════════

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pvc
  namespace: jenkins
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
  storageClassName: standard
  # ┌───────────────────────────────────────────────────────────────────────────┐
  # │【改】根据你的 K8s 环境修改 storageClassName:                               │
  # │ • 阿里云 ACK:alicloud-disk-ssd                                           │
  # │ • AWS EKS:gp2 或 gp3                                                     │
  # │ • GKE:standard 或 premium-rwo                                            │
  # │ • 查看可用:kubectl get storageclass                                       │
  # └───────────────────────────────────────────────────────────────────────────┘

6.5 部署 Jenkins Master

yaml 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 文件名:jenkins-deployment.yaml
# 作用:部署 Jenkins Master
# ═══════════════════════════════════════════════════════════════════════════════

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins
  namespace: jenkins
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      serviceAccountName: jenkins
      securityContext:
        fsGroup: 1000
        runAsUser: 1000
      containers:
        - name: jenkins
          image: jenkins/jenkins:lts-jdk17
          ports:
            - name: http
              containerPort: 8080
            - name: agent
              containerPort: 50000
          resources:
            requests:
              cpu: "500m"
              memory: "1Gi"
            limits:
              cpu: "2000m"
              memory: "4Gi"
          env:
            - name: TZ
              value: "Asia/Shanghai"
            - name: JAVA_OPTS
              value: "-Xmx2g -Xms512m"
          volumeMounts:
            - name: jenkins-data
              mountPath: /var/jenkins_home
          livenessProbe:
            httpGet:
              path: /login
              port: 8080
            initialDelaySeconds: 90
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /login
              port: 8080
            initialDelaySeconds: 60
            periodSeconds: 10
      volumes:
        - name: jenkins-data
          persistentVolumeClaim:
            claimName: jenkins-pvc

---
apiVersion: v1
kind: Service
metadata:
  name: jenkins
  namespace: jenkins
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 8080
      targetPort: 8080
    - name: agent
      port: 50000
      targetPort: 50000
  selector:
    app: jenkins

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: jenkins-ingress
  namespace: jenkins
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: jenkins.example.com  # 【改】替换为你的域名
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: jenkins
                port:
                  number: 8080
bash 复制代码
# 应用所有配置
kubectl apply -f jenkins-rbac.yaml
kubectl apply -f jenkins-pvc.yaml
kubectl apply -f jenkins-deployment.yaml

# 查看部署状态
kubectl get all -n jenkins

# 获取初始密码
kubectl exec -n jenkins deployment/jenkins -- \
  cat /var/jenkins_home/secrets/initialAdminPassword

七、K8s环境-配置动态 Agent

7.1 安装 Kubernetes 插件

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 步骤:在 Jenkins 中安装 Kubernetes 插件                                          │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ 入口:Dashboard → Manage Jenkins → Plugins → Available plugins                  │
│                                                                                 │
│ 搜索并安装:                                                                     │
│ • Kubernetes                                                                    │
│ • Kubernetes CLI                                                                │
│ • Kubernetes Credentials                                                        │
│                                                                                 │
│ 安装后重启 Jenkins                                                               │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

7.2 配置 Kubernetes Cloud

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 步骤:配置 Kubernetes 云                                                         │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ 入口:Dashboard → Manage Jenkins → Clouds → New cloud → Kubernetes              │
│                                                                                 │
│ 【Kubernetes Cloud details】                                                     │
│ ┌──────────────────────────┬────────────────────────────────────────────────┐  │
│ │ Name                      │ kubernetes                                     │  │
│ │ Kubernetes URL            │ https://kubernetes.default.svc                 │  │
│ │ Kubernetes Namespace      │ jenkins                                        │  │
│ │ Credentials               │ 留空(使用 ServiceAccount)                    │  │
│ │ Jenkins URL               │ http://jenkins.jenkins.svc:8080               │  │
│ └──────────────────────────┴────────────────────────────────────────────────┘  │
│                                                                                 │
│ 点击「Test Connection」测试连接                                                  │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

八、K8s环境-完整 Pipeline

8.1 K8s 动态 Agent Pipeline

groovy 复制代码
// ═══════════════════════════════════════════════════════════════════════════════
// Kubernetes 动态 Agent 完整 Pipeline
// ═══════════════════════════════════════════════════════════════════════════════

pipeline {
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
metadata:
  labels:
    jenkins: agent
spec:
  serviceAccountName: jenkins
  containers:
  - name: jnlp
    image: jenkins/inbound-agent:latest-jdk17
    resources:
      limits:
        cpu: "500m"
        memory: "512Mi"
  - name: maven
    image: maven:3.9-eclipse-temurin-17
    command: ["cat"]
    tty: true
    volumeMounts:
    - name: maven-cache
      mountPath: /root/.m2/repository
  - name: docker
    image: docker:24-cli
    command: ["cat"]
    tty: true
    volumeMounts:
    - name: docker-sock
      mountPath: /var/run/docker.sock
  - name: kubectl
    image: bitnami/kubectl:latest
    command: ["cat"]
    tty: true
  volumes:
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock
  - name: maven-cache
    emptyDir: {}
'''
        }
    }
    
    environment {
        PROJECT_NAME = 'my-backend'
        REGISTRY = 'registry.cn-hongkong.aliyuncs.com'
        NAMESPACE = 'myproject'
        IMAGE_NAME = "${REGISTRY}/${NAMESPACE}/${PROJECT_NAME}"
        IMAGE_TAG = "${BUILD_NUMBER}"
        K8S_NAMESPACE = 'prod'
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout([
                    $class: 'GitSCM',
                    branches: [[name: 'main']],
                    userRemoteConfigs: [[
                        url: 'https://github.com/yourname/your-project.git',
                        credentialsId: 'git-credentials'
                    ]]
                ])
            }
        }
        
        stage('Build') {
            steps {
                container('maven') {
                    sh 'mvn clean package -DskipTests'
                }
            }
        }
        
        stage('Build Docker Image') {
            steps {
                container('docker') {
                    sh "docker build -t ${IMAGE_NAME}:${IMAGE_TAG} ."
                }
            }
        }
        
        stage('Push Image') {
            steps {
                container('docker') {
                    withCredentials([usernamePassword(
                        credentialsId: 'aliyun-acr-credentials',
                        usernameVariable: 'DOCKER_USER',
                        passwordVariable: 'DOCKER_PASS'
                    )]) {
                        sh """
                            echo \${DOCKER_PASS} | docker login ${REGISTRY} \
                                --username=\${DOCKER_USER} --password-stdin
                            docker push ${IMAGE_NAME}:${IMAGE_TAG}
                        """
                    }
                }
            }
        }
        
        stage('Deploy to K8s') {
            steps {
                container('kubectl') {
                    sh """
                        kubectl set image deployment/${PROJECT_NAME} \
                            ${PROJECT_NAME}=${IMAGE_NAME}:${IMAGE_TAG} \
                            -n ${K8S_NAMESPACE}
                        kubectl rollout status deployment/${PROJECT_NAME} \
                            -n ${K8S_NAMESPACE} --timeout=300s
                    """
                }
            }
        }
    }
    
    post {
        success { echo "✅ 部署成功!" }
        failure { echo "❌ 部署失败!" }
    }
}

九、常见问题与最佳实践

9.1 常见问题

问题 原因 解决方案
docker: command not found 未挂载 Docker socket 检查 volumes 配置
Agent 连接超时 Jenkins URL 配置错误 使用 http://jenkins.jenkins.svc:8080
kubectl 权限不足 RBAC 配置缺失 检查 ClusterRole 和 ClusterRoleBinding
PVC Pending StorageClass 不存在 kubectl get sc 查看可用存储类
构建慢 每次重新下载依赖 使用 PVC 或 emptyDir 缓存依赖

9.2 最佳实践

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│                             最佳实践建议                                         │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ 安全:                                                                           │
│ • 使用 Jenkins Credentials 存储敏感信息                                         │
│ • 使用 withCredentials 注入凭据                                                 │
│ • RBAC 最小权限原则                                                             │
│ • 使用非 root 用户运行容器                                                       │
│                                                                                 │
│ 性能:                                                                           │
│ • 缓存依赖(Maven .m2、npm node_modules)                                       │
│ • 使用多阶段 Docker 构建                                                        │
│ • 并行执行无依赖的阶段                                                          │
│ • 合理设置资源限制                                                              │
│                                                                                 │
│ 运维:                                                                           │
│ • 定期备份 jenkins_home                                                         │
│ • 配置构建失败通知                                                              │
│ • 使用 buildDiscarder 清理旧构建                                               │
│ • Jenkinsfile 纳入版本控制                                                      │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

十、完整项目示例

10.1 后端项目示例(Spring Boot)

项目结构
复制代码
my-backend/
├── src/
│   └── main/
│       ├── java/
│       └── resources/
│           └── application.yml
├── pom.xml
├── Dockerfile
└── Jenkinsfile
pom.xml(关键配置)
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>my-backend</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <properties>
        <java.version>17</java.version>
        <!-- 打包时生成的 JAR 名称 -->
        <finalName>app</finalName>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 健康检查(CI/CD 验证部署用) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
    
    <build>
        <finalName>${finalName}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
Dockerfile(后端)
dockerfile 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# Spring Boot 后端 Dockerfile
# 
# 多阶段构建:编译 + 运行分离,减小最终镜像体积
# ═══════════════════════════════════════════════════════════════════════════════

# ─────────────────────────────────────────────────────────────────────────────────
# 阶段1:构建阶段(如果在 Jenkins 中已构建,可跳过此阶段)
# ─────────────────────────────────────────────────────────────────────────────────
FROM maven:3.9-eclipse-temurin-17 AS builder

WORKDIR /build

# 先复制 pom.xml,利用 Docker 缓存加速
COPY pom.xml .
# 下载依赖(这一层会被缓存)
RUN mvn dependency:go-offline -B

# 复制源代码
COPY src ./src

# 打包(跳过测试,测试在 Jenkins 中单独执行)
RUN mvn clean package -DskipTests -B

# ─────────────────────────────────────────────────────────────────────────────────
# 阶段2:运行阶段
# ─────────────────────────────────────────────────────────────────────────────────
FROM eclipse-temurin:17-jre-alpine

LABEL maintainer="your-email@example.com"
LABEL app="my-backend"

# 设置时区
ENV TZ=Asia/Shanghai
RUN apk add --no-cache tzdata \
    && cp /usr/share/zoneinfo/${TZ} /etc/localtime

# 创建非 root 用户
RUN addgroup -g 1000 appgroup \
    && adduser -u 1000 -G appgroup -D appuser

WORKDIR /app

# 从构建阶段复制 JAR 包
COPY --from=builder /build/target/app.jar app.jar

# 如果 Jenkins 已经构建好 JAR,直接复制:
# COPY target/app.jar app.jar

# 创建日志目录
RUN mkdir -p /app/logs && chown -R appuser:appgroup /app

USER appuser

EXPOSE 8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
    CMD wget -q --spider http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", \
    "-XX:+UseContainerSupport", \
    "-XX:MaxRAMPercentage=75.0", \
    "-Djava.security.egd=file:/dev/./urandom", \
    "-jar", "app.jar"]
Jenkinsfile(后端完整 Pipeline)
groovy 复制代码
// ═══════════════════════════════════════════════════════════════════════════════
// Spring Boot 后端项目 - 完整 CI/CD Pipeline
// 
// 流程:拉取代码 → Maven 编译 → 单元测试 → 构建镜像 → 推送镜像 → 部署
// ═══════════════════════════════════════════════════════════════════════════════

pipeline {
    agent any
    
    // ┌─────────────────────────────────────────────────────────────────────────────┐
    // │ 环境变量配置                                                                 │
    // │【改】根据你的实际情况修改以下配置                                             │
    // └─────────────────────────────────────────────────────────────────────────────┘
    environment {
        // 项目信息
        PROJECT_NAME = 'my-backend'
        
        // 镜像仓库配置(阿里云 ACR 示例)
        REGISTRY = 'registry.cn-hongkong.aliyuncs.com'
        NAMESPACE = 'myproject'
        IMAGE_NAME = "${REGISTRY}/${NAMESPACE}/${PROJECT_NAME}"
        IMAGE_TAG = "${BUILD_NUMBER}"
        
        // 部署服务器配置
        PROD_SERVER = '47.96.xxx.xxx'    // 【改】生产服务器 IP
        DEPLOY_PATH = '/home/deploy'      // 【改】部署目录
    }
    
    // 构建选项
    options {
        timeout(time: 30, unit: 'MINUTES')
        timestamps()
        buildDiscarder(logRotator(numToKeepStr: '10'))
        disableConcurrentBuilds()
    }
    
    // 参数化构建
    parameters {
        gitParameter(
            name: 'BRANCH',
            branchFilter: 'origin/(.*)',
            defaultValue: 'main',
            type: 'PT_BRANCH',
            description: '选择要构建的分支'
        )
        choice(
            name: 'ENVIRONMENT',
            choices: ['dev', 'test', 'prod'],
            description: '选择部署环境'
        )
        booleanParam(
            name: 'SKIP_TESTS',
            defaultValue: false,
            description: '是否跳过单元测试'
        )
    }
    
    stages {
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段1:拉取代码
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Checkout') {
            steps {
                echo "========== 📥 拉取代码 =========="
                echo "分支: ${params.BRANCH}"
                
                checkout([
                    $class: 'GitSCM',
                    branches: [[name: "${params.BRANCH}"]],
                    extensions: [
                        [$class: 'CleanBeforeCheckout'],
                        [$class: 'CloneOption', depth: 1, shallow: true]
                    ],
                    userRemoteConfigs: [[
                        url: 'https://github.com/yourname/my-backend.git',  // 【改】
                        credentialsId: 'git-credentials'
                    ]]
                ])
                
                // 显示最近提交
                sh 'git log -1 --pretty=format:"%h - %s (%an, %ar)"'
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段2:Maven 编译
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Build') {
            steps {
                echo "========== 🔨 Maven 编译 =========="
                
                sh '''
                    mvn clean package -DskipTests \
                        -Dmaven.repo.local=.m2/repository \
                        -Dfile.encoding=UTF-8
                '''
                
                // 归档 JAR 包
                archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段3:单元测试
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Test') {
            when {
                expression { return !params.SKIP_TESTS }
            }
            steps {
                echo "========== 🧪 单元测试 =========="
                sh 'mvn test -Dmaven.repo.local=.m2/repository'
            }
            post {
                always {
                    junit allowEmptyResults: true, testResults: 'target/surefire-reports/*.xml'
                }
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段4:构建 Docker 镜像
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Build Image') {
            steps {
                echo "========== 🐳 构建镜像 =========="
                echo "镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
                
                sh """
                    docker build \
                        -t ${IMAGE_NAME}:${IMAGE_TAG} \
                        -t ${IMAGE_NAME}:latest \
                        --build-arg BUILD_DATE=\$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
                        --build-arg VERSION=${IMAGE_TAG} \
                        .
                """
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段5:推送镜像
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Push Image') {
            steps {
                echo "========== 📤 推送镜像 =========="
                
                withCredentials([usernamePassword(
                    credentialsId: 'aliyun-acr-credentials',
                    usernameVariable: 'DOCKER_USER',
                    passwordVariable: 'DOCKER_PASS'
                )]) {
                    sh """
                        echo \${DOCKER_PASS} | docker login ${REGISTRY} \
                            --username=\${DOCKER_USER} --password-stdin
                        
                        docker push ${IMAGE_NAME}:${IMAGE_TAG}
                        docker push ${IMAGE_NAME}:latest
                        
                        # 清理本地镜像
                        docker rmi ${IMAGE_NAME}:${IMAGE_TAG} || true
                        docker rmi ${IMAGE_NAME}:latest || true
                    """
                }
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段6:部署到服务器
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Deploy') {
            when {
                expression { params.ENVIRONMENT == 'prod' }
            }
            steps {
                echo "========== 🚀 部署到生产环境 =========="
                
                sshagent(['prod-server-ssh']) {
                    withCredentials([usernamePassword(
                        credentialsId: 'aliyun-acr-credentials',
                        usernameVariable: 'DOCKER_USER',
                        passwordVariable: 'DOCKER_PASS'
                    )]) {
                        sh """
                            ssh -o StrictHostKeyChecking=no root@${PROD_SERVER} << 'ENDSSH'
                                cd ${DEPLOY_PATH}
                                
                                # 登录镜像仓库
                                echo ${DOCKER_PASS} | docker login ${REGISTRY} \
                                    --username=${DOCKER_USER} --password-stdin
                                
                                # 拉取新镜像
                                docker pull ${IMAGE_NAME}:${IMAGE_TAG}
                                
                                # 停止旧容器
                                docker stop ${PROJECT_NAME} || true
                                docker rm ${PROJECT_NAME} || true
                                
                                # 启动新容器
                                docker run -d \\
                                    --name ${PROJECT_NAME} \\
                                    --restart unless-stopped \\
                                    -p 8080:8080 \\
                                    -e SPRING_PROFILES_ACTIVE=prod \\
                                    -e TZ=Asia/Shanghai \\
                                    -v ${DEPLOY_PATH}/logs:/app/logs \\
                                    ${IMAGE_NAME}:${IMAGE_TAG}
                                
                                # 健康检查
                                sleep 30
                                curl -sf http://localhost:8080/actuator/health || exit 1
                                
                                echo "✅ 部署成功!"
ENDSSH
                        """
                    }
                }
            }
        }
    }
    
    post {
        always {
            echo "========== 🧹 清理 =========="
            cleanWs()
        }
        success {
            echo "✅ 构建成功!镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
        }
        failure {
            echo "❌ 构建失败!请检查日志"
        }
    }
}

10.2 前端项目示例(Vue 3)

项目结构
复制代码
my-frontend/
├── src/
│   ├── main.js
│   ├── App.vue
│   └── views/
├── public/
│   └── index.html
├── package.json
├── vite.config.js
├── nginx.conf
├── Dockerfile
└── Jenkinsfile
package.json(关键配置)
json 复制代码
{
  "name": "my-frontend",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix",
    "test": "vitest run"
  },
  "dependencies": {
    "vue": "^3.3.11",
    "vue-router": "^4.2.5",
    "pinia": "^2.1.7",
    "axios": "^1.6.2"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.5.2",
    "vite": "^5.0.8",
    "vitest": "^1.0.4"
  }
}
nginx.conf(前端 Nginx 配置)
nginx 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 前端 Nginx 配置
# 
# 功能:
# 1. 托管 Vue/React 静态文件
# 2. SPA 路由支持(history 模式)
# 3. 反向代理后端 API
# 4. 静态资源缓存优化
# ═══════════════════════════════════════════════════════════════════════════════

server {
    listen 80;
    server_name localhost;
    
    # 网站根目录
    root /usr/share/nginx/html;
    index index.html;
    
    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied any;
    gzip_types text/plain text/css text/xml text/javascript 
               application/javascript application/json application/xml;
    gzip_comp_level 6;
    
    # 静态资源缓存(JS/CSS/图片等)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    # SPA 路由支持
    # Vue Router / React Router history 模式需要
    location / {
        try_files $uri $uri/ /index.html;
    }
    
    # 反向代理后端 API
    # 前端请求 /api/* 会转发到后端服务
    location /api/ {
        # 【改】替换为你的后端地址
        # Docker 环境:http://backend:8080/
        # K8s 环境:http://backend-service.prod.svc:8080/
        proxy_pass http://backend:8080/;
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # WebSocket 支持(如果需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    
    # 健康检查端点
    location /health {
        access_log off;
        return 200 'OK';
        add_header Content-Type text/plain;
    }
}
Dockerfile(前端)
dockerfile 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# Vue/React 前端 Dockerfile
# 
# 多阶段构建:
# 1. 构建阶段:Node.js 环境编译打包
# 2. 运行阶段:Nginx 托管静态文件
# ═══════════════════════════════════════════════════════════════════════════════

# ─────────────────────────────────────────────────────────────────────────────────
# 阶段1:构建阶段
# ─────────────────────────────────────────────────────────────────────────────────
FROM node:20-alpine AS builder

# 设置工作目录
WORKDIR /app

# 设置 npm 镜像(加速依赖下载)
RUN npm config set registry https://registry.npmmirror.com

# 先复制 package.json 和 lock 文件(利用 Docker 缓存)
COPY package*.json ./

# 安装依赖
# --frozen-lockfile:确保使用 lock 文件中的精确版本
RUN npm ci --frozen-lockfile

# 复制源代码
COPY . .

# 构建生产版本
# 【改】如果有环境变量,可以在这里传入
# ARG VITE_API_BASE_URL
# ENV VITE_API_BASE_URL=$VITE_API_BASE_URL
RUN npm run build

# ─────────────────────────────────────────────────────────────────────────────────
# 阶段2:运行阶段
# ─────────────────────────────────────────────────────────────────────────────────
FROM nginx:1.24-alpine

LABEL maintainer="your-email@example.com"
LABEL app="my-frontend"

# 删除默认配置
RUN rm -rf /etc/nginx/conf.d/default.conf

# 复制自定义 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 从构建阶段复制打包产物
# Vue: dist 目录
# React (CRA): build 目录
# React (Vite): dist 目录
COPY --from=builder /app/dist /usr/share/nginx/html

# 设置正确的权限
RUN chown -R nginx:nginx /usr/share/nginx/html \
    && chmod -R 755 /usr/share/nginx/html

EXPOSE 80

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
    CMD wget -q --spider http://localhost/health || exit 1

# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]
Jenkinsfile(前端完整 Pipeline)
groovy 复制代码
// ═══════════════════════════════════════════════════════════════════════════════
// Vue/React 前端项目 - 完整 CI/CD Pipeline
// 
// 流程:拉取代码 → 安装依赖 → Lint 检查 → 单元测试 → 构建 → 构建镜像 → 部署
// ═══════════════════════════════════════════════════════════════════════════════

pipeline {
    agent any
    
    // ┌─────────────────────────────────────────────────────────────────────────────┐
    // │ 环境变量配置                                                                 │
    // │【改】根据你的实际情况修改以下配置                                             │
    // └─────────────────────────────────────────────────────────────────────────────┘
    environment {
        // 项目信息
        PROJECT_NAME = 'my-frontend'
        
        // 镜像仓库配置
        REGISTRY = 'registry.cn-hongkong.aliyuncs.com'
        NAMESPACE = 'myproject'
        IMAGE_NAME = "${REGISTRY}/${NAMESPACE}/${PROJECT_NAME}"
        IMAGE_TAG = "${BUILD_NUMBER}"
        
        // 部署服务器配置
        PROD_SERVER = '47.96.xxx.xxx'    // 【改】生产服务器 IP
        DEPLOY_PATH = '/home/deploy'
        
        // Node.js 版本
        NODE_VERSION = '20'
    }
    
    // 使用 NodeJS 工具
    tools {
        nodejs 'Node20'  // 【改】与 Jenkins 工具配置中的名称一致
    }
    
    options {
        timeout(time: 20, unit: 'MINUTES')
        timestamps()
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }
    
    parameters {
        gitParameter(
            name: 'BRANCH',
            branchFilter: 'origin/(.*)',
            defaultValue: 'main',
            type: 'PT_BRANCH',
            description: '选择要构建的分支'
        )
        choice(
            name: 'ENVIRONMENT',
            choices: ['dev', 'test', 'prod'],
            description: '选择部署环境'
        )
        booleanParam(
            name: 'SKIP_TESTS',
            defaultValue: false,
            description: '是否跳过测试'
        )
    }
    
    stages {
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段1:拉取代码
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Checkout') {
            steps {
                echo "========== 📥 拉取代码 =========="
                
                checkout([
                    $class: 'GitSCM',
                    branches: [[name: "${params.BRANCH}"]],
                    extensions: [[$class: 'CleanBeforeCheckout']],
                    userRemoteConfigs: [[
                        url: 'https://github.com/yourname/my-frontend.git',  // 【改】
                        credentialsId: 'git-credentials'
                    ]]
                ])
                
                sh 'git log -1 --pretty=format:"%h - %s (%an, %ar)"'
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段2:安装依赖
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Install') {
            steps {
                echo "========== 📦 安装依赖 =========="
                
                // 设置 npm 镜像
                sh 'npm config set registry https://registry.npmmirror.com'
                
                // 显示版本信息
                sh 'node --version && npm --version'
                
                // 安装依赖
                // ci 比 install 更快,使用 lock 文件
                sh 'npm ci'
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段3:代码检查
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Lint') {
            steps {
                echo "========== 🔍 代码检查 =========="
                
                // ESLint 检查
                sh 'npm run lint || true'  // 暂时忽略 lint 错误
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段4:单元测试
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Test') {
            when {
                expression { return !params.SKIP_TESTS }
            }
            steps {
                echo "========== 🧪 单元测试 =========="
                
                sh 'npm run test || true'
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段5:构建生产版本
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Build') {
            steps {
                echo "========== 🔨 构建生产版本 =========="
                
                // 根据环境设置 API 地址
                script {
                    def apiUrl = ''
                    switch(params.ENVIRONMENT) {
                        case 'dev':
                            apiUrl = 'http://dev-api.example.com'
                            break
                        case 'test':
                            apiUrl = 'http://test-api.example.com'
                            break
                        case 'prod':
                            apiUrl = 'https://api.example.com'
                            break
                    }
                    // 设置环境变量(Vite 使用 VITE_ 前缀)
                    env.VITE_API_BASE_URL = apiUrl
                }
                
                sh 'npm run build'
                
                // 归档构建产物
                archiveArtifacts artifacts: 'dist/**/*', fingerprint: true
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段6:构建 Docker 镜像
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Build Image') {
            steps {
                echo "========== 🐳 构建镜像 =========="
                
                sh """
                    docker build \
                        -t ${IMAGE_NAME}:${IMAGE_TAG} \
                        -t ${IMAGE_NAME}:latest \
                        .
                """
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段7:推送镜像
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Push Image') {
            steps {
                echo "========== 📤 推送镜像 =========="
                
                withCredentials([usernamePassword(
                    credentialsId: 'aliyun-acr-credentials',
                    usernameVariable: 'DOCKER_USER',
                    passwordVariable: 'DOCKER_PASS'
                )]) {
                    sh """
                        echo \${DOCKER_PASS} | docker login ${REGISTRY} \
                            --username=\${DOCKER_USER} --password-stdin
                        
                        docker push ${IMAGE_NAME}:${IMAGE_TAG}
                        docker push ${IMAGE_NAME}:latest
                        
                        docker rmi ${IMAGE_NAME}:${IMAGE_TAG} || true
                        docker rmi ${IMAGE_NAME}:latest || true
                    """
                }
            }
        }
        
        // ═══════════════════════════════════════════════════════════════════════════
        // 阶段8:部署到服务器
        // ═══════════════════════════════════════════════════════════════════════════
        stage('Deploy') {
            when {
                expression { params.ENVIRONMENT == 'prod' }
            }
            steps {
                echo "========== 🚀 部署到生产环境 =========="
                
                sshagent(['prod-server-ssh']) {
                    withCredentials([usernamePassword(
                        credentialsId: 'aliyun-acr-credentials',
                        usernameVariable: 'DOCKER_USER',
                        passwordVariable: 'DOCKER_PASS'
                    )]) {
                        sh """
                            ssh -o StrictHostKeyChecking=no root@${PROD_SERVER} << 'ENDSSH'
                                cd ${DEPLOY_PATH}
                                
                                # 登录镜像仓库
                                echo ${DOCKER_PASS} | docker login ${REGISTRY} \
                                    --username=${DOCKER_USER} --password-stdin
                                
                                # 拉取新镜像
                                docker pull ${IMAGE_NAME}:${IMAGE_TAG}
                                
                                # 停止旧容器
                                docker stop ${PROJECT_NAME} || true
                                docker rm ${PROJECT_NAME} || true
                                
                                # 启动新容器
                                docker run -d \\
                                    --name ${PROJECT_NAME} \\
                                    --restart unless-stopped \\
                                    -p 80:80 \\
                                    ${IMAGE_NAME}:${IMAGE_TAG}
                                
                                # 健康检查
                                sleep 5
                                curl -sf http://localhost/health || exit 1
                                
                                echo "✅ 前端部署成功!"
ENDSSH
                        """
                    }
                }
            }
        }
    }
    
    post {
        always {
            cleanWs()
        }
        success {
            echo "✅ 前端构建成功!镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
        }
        failure {
            echo "❌ 前端构建失败!请检查日志"
        }
    }
}

10.3 前后端联合部署示例

docker-compose.yml(本地开发/测试环境)
yaml 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 前后端联合部署 docker-compose
# 
# 启动:docker compose up -d
# ═══════════════════════════════════════════════════════════════════════════════

version: '3.8'

services:
  # 前端服务
  frontend:
    image: registry.cn-hongkong.aliyuncs.com/myproject/my-frontend:latest
    container_name: frontend
    restart: unless-stopped
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - app-network
  
  # 后端服务
  backend:
    image: registry.cn-hongkong.aliyuncs.com/myproject/my-backend:latest
    container_name: backend
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - TZ=Asia/Shanghai
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/mydb
      - SPRING_DATASOURCE_USERNAME=root
      - SPRING_DATASOURCE_PASSWORD=password
      - SPRING_REDIS_HOST=redis
    depends_on:
      - mysql
      - redis
    networks:
      - app-network
  
  # MySQL 数据库
  mysql:
    image: mysql:8.0
    container_name: mysql
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=mydb
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - app-network
  
  # Redis 缓存
  redis:
    image: redis:7-alpine
    container_name: redis
    restart: unless-stopped
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  mysql-data:

附录:常用命令速查

bash 复制代码
# ════════════════════════════════════════════════════════════════════════════
# Docker 环境
# ════════════════════════════════════════════════════════════════════════════
docker compose up -d              # 启动 Jenkins
docker compose logs -f jenkins    # 查看日志
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword  # 获取密码

# ════════════════════════════════════════════════════════════════════════════
# Kubernetes 环境
# ════════════════════════════════════════════════════════════════════════════
kubectl get all -n jenkins                                    # 查看状态
kubectl logs -f deployment/jenkins -n jenkins                 # 查看日志
kubectl exec -n jenkins deployment/jenkins -- cat /var/jenkins_home/secrets/initialAdminPassword
kubectl port-forward svc/jenkins 8080:8080 -n jenkins        # 端口转发
kubectl rollout restart deployment/jenkins -n jenkins         # 重启

文档版本 :v1.0 | 更新日期:2024年

适用版本:Jenkins 2.426+ LTS、Docker 24+、Kubernetes 1.25+

相关推荐
未来之窗软件服务3 小时前
幽冥大陆(四十六)人工智能自动化交互系统ASR2——东方仙盟筑基期
运维·自动化·仙盟创梦ide·东方仙盟·东方仙盟sdk·东方仙盟vos智能浏览器·东方仙盟自动化
码界奇点3 小时前
基于RAG技术的自动化知识库构建系统设计与实现
运维·自动化·毕业设计·rpa·源代码管理·python3.11
2501_941982054 小时前
非官方 API 与企业微信外部群交互:数据加密与解密实现细节
自动化·rpa
YJlio4 小时前
Active Directory 工具学习笔记(10.9):AdInsight——命令行选项与自动化采集模板
笔记·学习·自动化
weixin_307779134 小时前
Jenkins Jackson 2 API插件详解:JSON处理的基础支柱
运维·开发语言·架构·json·jenkins
2501_941982055 小时前
RPA 技术在企业微信外部群的落地:环境配置与依赖管理
自动化·rpa
weixin_307779135 小时前
Jenkins jQuery3 API 插件详解:赋能插件前端开发的利器
运维·开发语言·前端·jenkins·jquery
守城小轩5 小时前
基于Chrome140的Gmail账号自动化——脚本撰写(二)
自动化·chrome devtools·浏览器自动化·指纹浏览器·浏览器开发·超级浏览器
未来之窗软件服务5 小时前
幽冥大陆(四十五)人工智能自动化交互系统ASR——东方仙盟筑基期
运维·自动化·asr·仙盟创梦ide·东方仙盟·东方仙盟sdk·东方仙盟自动化