使用 Docker 部署 Jenkins 并实现自动化部署 —— 从零到一的 CI/CD 实践指南

🐳 使用 Docker 部署 Jenkins 并实现自动化部署 ------ 从零到一的 CI/CD 实践指南

从容器化部署到 Git 触发自动化构建镜像,一篇带你把 Jenkins CI/CD 流水线跑起来(附流程图)


📌 文章导览

持续集成与持续部署(CI/CD)已成为现代软件开发不可或缺的环节,而 Jenkins 作为全球最流行的开源自动化服务器,被广泛应用于各类自动化任务中。结合 Docker 的轻量化和可移植性,我们可以快速搭建一个高效、灵活且易于扩展的自动化部署环境。

本文涵盖:

✅ Docker 环境准备与镜像选择

✅ Jenkins 容器部署(单容器 + 权限配置)

✅ 初始化与插件安装

核心重点 :让 Jenkins 容器内调用 Docker(两种方案对比)

✅ 凭证管理(Git + 容器仓库)

✅ Jenkins Pipeline 声明式流水线编写(构建 → 推送 → 部署)

✅ 完整流程图 + 架构图(Mermaid 格式)

✅ 生产环境优化建议与常见问题排查

🧱 一、前置条件

项目 要求
操作系统 Linux(Ubuntu 20.04+ / CentOS 7+ / Debian)
Docker 版本 ≥ 20.10(含 docker compose
硬件配置 建议 2 核 4G 以上(Jenkins 运行需一定资源)
代码仓库 GitHub / GitLab / Gitee(任意 Git 仓库即可)
Docker Registry Docker Hub / 私有 Harbor / 阿里云容器镜像服务

⚠️ 本文基于 Docker 官方 LTS 镜像 jenkins/jenkins:lts,此版本兼容性最佳,适合生产部署。

🗺 二、端到端自动化部署流程总览

开发者提交代码到 Git 仓库
Git Webhook 触发 Jenkins
Jenkins 拉取最新代码
Pipeline:代码编译构建
Pipeline:Docker 镜像打包
Pipeline:登录容器镜像仓库
Push 镜像到仓库
部署到目标服务器/环境
完成自动化部署

🔄 核心闭环:代码提交 → Webhook 触发 → Jenkins 构建 → 镜像推送 → 自动部署,全程无需人工干预。

🐳 三、Docker 环境下部署 Jenkins

3.1 拉取 Jenkins 官方镜像

我们选择 Jenkins 长期支持(LTS)版本,它不仅稳定,而且是目前生产环境的主力选择:

bash 复制代码
docker pull jenkins/jenkins:lts

若拉取较慢,可配置国内镜像加速源或使用阿里云加速器。

3.2 创建数据持久化目录

bash 复制代码
mkdir -p /data/jenkins_home
chown -R 1000:1000 /data/jenkins_home

💡 设置权限为 1000:1000 是因为 Jenkins 容器内的默认运行用户 jenkins 的 UID 正是 1000,确保容器能够正常读写该目录,避免使用 777(生产环境权限应最小化)。

3.3 启动 Jenkins 容器(基础版)

bash 复制代码
docker run -d \
  --name jenkins \
  --restart always \
  -p 8080:8080 \
  -p 50000:50000 \
  -v /data/jenkins_home:/var/jenkins_home \
  -e TZ="Asia/Shanghai" \
  jenkins/jenkins:lts

关键参数说明

参数 作用
-p 8080:8080 Web 管理界面访问端口
-p 50000:50000 Jenkins Master-Slave 通信端口
-v Jenkins 数据持久化
-e TZ="Asia/Shanghai" 设置容器时区
--restart always 保障容器异常退出后自动拉起

此时一个基础的 Jenkins 容器已经运行起来。但是请注意:这个容器内无法执行 Docker 命令 ------流水线中的 docker build 等指令会直接报错。接下来我们要解决这个核心问题。

🔑 四、核心配置:让 Jenkins 能调用 Docker

✅ 这是本教程的核心重点。Jenkins 要构建 Docker 镜像,就必须具备 Docker 能力。

4.1 两种技术路线对比

对比维度 方案 A:挂载 Docker Socket 方案 B:Docker-in-Docker (DinD)
原理 Jenkins 容器直接调用宿主机 Docker 在 Jenkins 旁启动一个独立的 Docker 守护进程容器
容器大小 轻量 稍重
隔离性 较低(同宿主共享 Docker 引擎) 高(独立的 Docker 进程)
适用阶段 测试/预发布环境 生产环境(隔离要求高时)
安全风险 容器获得宿主机 root-like 权限 --privileged 运行但存在独立隔离
官方示例 较为常见 官方推荐 DinD 保持环境纯净

4.2 方案 A:挂载 Socket(推荐入门)

bash 复制代码
docker run -d \
  --name jenkins \
  --restart always \
  -p 8080:8080 \
  -p 50000:50000 \
  -v /data/jenkins_home:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /usr/bin/docker:/usr/bin/docker \
  -e TZ="Asia/Shanghai" \
  jenkins/jenkins:lts

核心选项

  • -v /var/run/docker.sock:/var/run/docker.sock:让 Jenkins 容器与宿主机 共享 Docker 守护进程
  • -v /usr/bin/docker:/usr/bin/docker:让容器内的 docker CLI 可执行
  • 在容器内验证是否成功:docker exec jenkins docker ps

⚠️ 安全提示:该方案相当于将宿主机的 Docker 完全"借"给 Jenkins 容器,务必确保 Jenkins 流水线中不能执行恶意命令。

4.3 方案 B:Docker-in-Docker(DinD,更隔离)

适用场景:K8s 环境、高安全性 CI/CD 集群、多租户场景

步骤一:创建专用 Docker 网络
bash 复制代码
docker network create jenkins
步骤二:启动 DinD 守护进程容器
bash 复制代码
docker run --name jenkins-docker \
  --rm --detach \
  --privileged \
  --network jenkins \
  --network-alias docker \
  -e DOCKER_TLS_CERTDIR=/certs \
  -v jenkins-docker-certs:/certs/client \
  -p 2376:2376 \
  docker:dind \
  --storage-driver overlay2
步骤三:启动 Jenkins 并连接到 DinD
bash 复制代码
docker run --name jenkins-blueocean \
  --restart=on-failure \
  --detach \
  --network jenkins \
  -e DOCKER_HOST=tcp://docker:2376 \
  -e DOCKER_CERT_PATH=/certs/client \
  -e DOCKER_TLS_VERIFY=1 \
  -p 8080:8080 \
  -v jenkins-data:/var/jenkins_home \
  -v jenkins-docker-certs:/certs/client:ro \
  jenkins/jenkins:lts

关键解释

  • --network-alias docker:为 DinD 容器设置了固定的网络别名,Jenkins 可通过 tcp://docker:2376 与之通信
  • DOCKER_TLS_VERIFY=1:启用 TLS 加密验证
  • :ro:只读挂载证书,进一步增强安全性

🌐 五、Jenkins 初始化与插件配置

5.1 获取初始解锁密码

bash 复制代码
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

执行后会打印一长串字符串,复制备用。

5.2 Web 初始化流程

  1. 浏览器访问 http://<服务器IP>:8080
  2. 粘贴解锁密码进入安装向导
  3. 选择 "安装推荐插件"(后续可按需增删)
  4. 创建管理员用户并完成基础设置

5.3 必装插件清单

安装完成之后,建议手动补充以下插件(路径:Dashboard → Manage Jenkins → Plugins → Available plugins):

插件名称 用途
Git Plugin 从 Git 仓库拉取代码
Pipeline Jenkins 核心流水线支持
Blue Ocean(可选) 可视化流水线界面,提升排错效率
Docker Pipeline 提供 Jenkinsfile 中的 docker.build(), docker.withRegistry() 语法
Credentials Binding 安全管理凭证信息(避免在脚本中硬编码)
GitHub Integration / Gitee 实现 Git 触发 Webhook

💡 安装 Docker Pipeline 后,在流水线中即可调用丰富的 Docker 操作语法。

🔐 六、凭证管理(核心安全配置)

6.1 凭证类型与使用场景

凭证类型 典型使用场景
Username with password 登录 Docker Hub / 私有镜像仓库
SSH Username with private key Jenkins 免密拉取 Git 仓库(推荐 GitHub 部署密钥)
Secret text API Token(如 GitHub Personal Access Token)
Certificate PKCS#12 证书文件

在 Jenkins 中配置凭证的位置:Dashboard → 系统管理 → 凭证 → 系统 → 全局凭据 → 添加凭据

6.2 添加 Git 拉取凭证(SSH 方式)

💡 这是确保 Jenkins 能拉取私有仓库代码的必备操作。

在 Jenkins 服务器上生成 SSH 密钥对
bash 复制代码
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

生成的文件:

  • ~/.ssh/id_rsa ------ 私钥(内容粘贴到 Jenkins)
  • ~/.ssh/id_rsa.pub ------ 公钥(添加到 GitHub/GitLab 账户的 SSH Keys)
将公钥添加到代码仓库
  • GitHub:Settings → SSH and GPG keys → New SSH key
  • GitLab:Preferences → SSH Keys
在 Jenkins 中添加私钥

添加凭证时选择 SSH Username with private key

  • Username :填写代码仓库账户(如 git 或 GitHub 用户名)
  • Private KeyEnter directly → 粘贴 id_rsa 私钥的完整内容 (包含 -----BEGIN OPENSSH PRIVATE KEY----- 头尾)
  • 输入可选的 Passphrase(若生成密钥时设置了密码短语)

6.3 添加容器镜像仓库凭证

选择 Username with password 类型:

注册表类型 Username Password 凭证 ID 示例
Docker Hub Docker Hub 用户名 Docker Hub 密码/Access Token dockerhub-creds
阿里云容器镜像 阿里云账号名 镜像仓库访问密码 aliyun-acr-creds

📌 关键提示 :为凭证填写一个有意义的 ID (如 dockerhub-credentialsgit-ssh-key),因为在 Jenkinsfile 中要引用这个 ID,而不是直接硬编码用户名密码。

Pipeline 中的凭证引用示例
groovy 复制代码
withCredentials([usernamePassword(
    credentialsId: 'dockerhub-credentials', 
    usernameVariable: 'DOCKER_USER', 
    passwordVariable: 'DOCKER_PASS'
)]) {
    sh 'echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin'
}

📄 七、Jenkinsfile 自动化部署流水线

7.1 流程图速览

检出代码
Maven/NPM 构建
Build Docker 镜像
Login Registry
Push 镜像
部署镜像

docker run 或 remote deploy
通知/清理

7.2 完整声明式 Pipeline 模板

在代码仓库的根目录下创建一个 Jenkinsfile(以 Spring Boot Java 应用为例,实际可灵活适配):

groovy 复制代码
pipeline {
    agent any
    
    environment {
        // ==================== 请根据实际修改此处 ====================
        DOCKER_REGISTRY = 'your-registry.cn-hangzhou.cr.aliyuncs.com'  // 镜像仓库地址
        IMAGE_NAME      = 'your-namespace/your-app'                    // 镜像名称
        // ==========================================================
    }
    
    stages {
        // Stage 1: 从 Git 仓库拉取最新代码
        stage('Checkout') {
            steps {
                checkout scm
                script {
                    // 生成唯一的镜像标签: 构建号-提交哈希前7位(保证可追溯)
                    SHORT_COMMIT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
                    TAG = "${env.BUILD_NUMBER}-${SHORT_COMMIT}"
                    echo "镜像标签: ${TAG}"
                }
            }
        }
        
        // Stage 2: 【构建】根据项目类型调整
        stage('Build') {
            steps {
                // Java/Maven 项目示例
                sh 'mvn clean package -DskipTests'
                // Node.js 示例: sh 'npm install && npm run build'
            }
        }
        
        // Stage 3: 【打包】基于项目 Dockerfile 构建镜像(利用宿主机 Docker)
        stage('Build Docker Image') {
            steps {
                script {
                    // 方案 A(挂载 socket)语法:
                    docker.build("${DOCKER_REGISTRY}/${IMAGE_NAME}:${TAG}")
                    
                    // 方案 B(DinD)语法:
                    // docker.withServer('tcp://docker:2376', 'docker-certs') {
                    //     docker.build("${DOCKER_REGISTRY}/${IMAGE_NAME}:${TAG}")
                    // }
                }
            }
        }
        
        // Stage 4: 【推送】登录私有镜像仓库并推送镜像
        stage('Push to Registry') {
            steps {
                script {
                    // 使用之前配置的 Docker Hub / 私有仓库凭证
                    docker.withRegistry("https://${DOCKER_REGISTRY}", 'dockerhub-credentials') {
                        docker.image("${DOCKER_REGISTRY}/${IMAGE_NAME}:${TAG}").push()
                        // 可选: 为 latest 标签也推送一次
                        docker.image("${DOCKER_REGISTRY}/${IMAGE_NAME}:${TAG}").push('latest')
                    }
                }
                echo "✅ 镜像推送完成: ${DOCKER_REGISTRY}/${IMAGE_NAME}:${TAG}"
            }
        }
        
        // Stage 5: 【部署】在目标服务器上拉取并运行新版本容器
        stage('Deploy to Server') {
            steps {
                script {
                    // 方式一: 如果部署在本地宿主机(直接 docker run 更新)
                    sh """
                        docker pull ${DOCKER_REGISTRY}/${IMAGE_NAME}:${TAG}
                        docker stop my-app || true
                        docker rm my-app || true
                        docker run -d --name my-app -p 80:8080 ${DOCKER_REGISTRY}/${IMAGE_NAME}:${TAG}
                    """
                    
                    // 方式二: 如果部署在远程服务器(通过 SSH 执行命令)
                    // 需要安装 SSH Pipeline Steps 插件并配置远程主机凭证
                    // sshagent(['remote-server-ssh-key']) {
                    //     sh "scp ... && ssh user@remote-server 'docker pull ... && docker run ...'"
                    // }
                }
            }
        }
    }
    
    post {
        // 每个阶段结束后自动清理工作空间残留
        always {
            cleanWs()
        }
        success {
            echo "🎉 流水线执行成功!镜像已推送并部署。"
        }
        failure {
            echo "❌ 流水线执行失败,请检查日志。"
        }
    }
}

7.3 关键代码解读

代码块 作用
checkout scm 自动拉取触发此次构建的 Git 仓库对应分支的最新代码
SHORT_COMMIT + BUILD_NUMBER 组合镜像标签,保证唯一性且易于回溯提交记录
docker.build(...) Docker Pipeline 插件提供的原生镜像构建命令,底层调用 docker build
docker.withRegistry 安全登录镜像仓库并推送,全程无需暴露明文密码
post -> always/cleanWs Jenkins Pipeline 的"最终执行块",保证每次构建完毕清理残留文件,避免磁盘占满

🚀 八、多分支流水线配置(推荐生产环境)

8.1 多分支流水线的价值

多分支 Pipeline 是 Jenkins 提供的一种高级功能,它可以自动扫描 Git 仓库中所有分支,并为每个分支独立创建和触发对应的流水线。这意味着:

  • 开发分支(develop)自动构建并部署到测试环境
  • 主干分支(main / master)自动构建并部署到预发环境
  • 发布分支(release/*)自动构建并部署到生产环境
  • 无需为每个分支单独配置 Jenkins Job

8.2 配置步骤

  1. 在 Jenkins 首页点击 新建任务
  2. 输入项目名称,选择 Multibranch Pipeline(多分支流水线)
  3. Branch Sources 中添加 Git 仓库 URL 并选择之前配置的 SSH 凭证
  4. Build Configuration 中指定 Jenkinsfile 的路径(默认为仓库根目录的 Jenkinsfile
  5. 点击 保存,Jenkins 将自动扫描全部分支并启动构建

Git 仓库
独立构建
独立构建
独立构建
main 分支
develop 分支
feature/xxx 分支
Jenkins 多分支扫描
main 流水线 → 生产部署
develop 流水线 → 测试环境部署
feature 分支 → 快速验证

🏗 九、整体架构图(UML 部署图)

渲染错误: Mermaid 渲染失败: Lexical error on line 8. Unrecognized text. ...e
配置 + 插件 + 构建历史] end -----------------------^

📐 此图展示了 Jenkins Master 与宿主机 Docker Engine、代码仓库、镜像仓库、以及部署目标之间的关联关系。

🔧 十、常见问题排查与优化建议

10.1 容器内无法执行 docker 命令

现象 :构建阶段报 docker: command not foundCannot connect to the Docker daemon

解决方案

  1. 确认启动容器时已挂载 /var/run/docker.sock/usr/bin/docker
  2. 进入容器验证:docker exec jenkins docker ps
  3. 检查宿主机 Docker 是否正常运行:systemctl status docker

10.2 Webhook Git 推送不触发构建

现象:代码已 push 到仓库,但 Jenkins 未自动触发构建。

解决方案

  1. 确认 Jenkins 能够被外网/Git仓库访问(检查安全组或防火墙是否放行 8080 端口)
  2. GitHub 仓库的 Settings → Webhooks 中添加 Payload URL:
    http://<jenkins-公网IP>:8080/github-webhook/
  3. GitLab 的 Webhook URL 为:http://<jenkins-公网IP>:8080/project/<项目名>
  4. Jenkins 全局安全配置中勾选 "GitHub 自动触发" 相关选项

10.3 Docker socket 权限不足

现象Got permission denied while trying to connect to the Docker daemon socket

解决方案

bash 复制代码
# 查看 /var/run/docker.sock 的属主
ls -l /var/run/docker.sock
# 将 Jenkins 容器用户加入 docker 组
sudo usermod -aG docker $USER
newgrp docker
# 或修改 socket 权限(不推荐生产环境)
sudo chmod 666 /var/run/docker.sock

10.4 Jenkins 频繁崩溃或内存不足

现象 :容器 502 无法访问,日志显示 OutOfMemoryError

解决方案

  • 启动容器时增加资源限制:--memory="4g" --memory-swap="4g"
  • docker run 参数中加入 --shm-size=256m
  • 定期清理构建历史:系统管理 → 构建记录管理器 → 配置规则

10.5 生产环境安全强化清单

类别 推荐实践
网络隔离 Jenkins 置于专用 Docker 网络,不与其他服务混用
HTTPS 前置 Nginx/Traefik 反向代理并启用 Let's Encrypt 自动签发证书
权限最小化 避免容器以 root 运行:--user 1000:1000
凭证轮换 镜像仓库 Token 每 90 天轮换一次,Git SSH Key 与个人用户严格区分
数据备份 每日凌晨自动备份 /data/jenkins_hometar -zcvf jenkins_backup_$(date +%Y%m%d).tar.gz /data/jenkins_home
日志轮转 配置 Jenkins 系统日志保留 30 天,避免磁盘写满

📝 十一、总结

本文系统地介绍了使用 Docker 部署 Jenkins 并实现自动化部署的完整路径:

章节 核心收获
三、部署 Jenkins 掌握 docker rundocker-compose 两种容器化部署方式
四、Docker 集成 理解 挂载 socketDocker-in-Docker 两种方案的原理与适用场景,并根据安全要求做出正确选择
六、凭证管理 学会安全存储 Git 和镜像仓库的登录凭据,避免密钥泄露
七、Jenkinsfile 能够独立编写声明式 Pipeline,完成从代码拉取到镜像推送再到部署的自动化闭环
八、多分支 掌握多分支流水线的配置,让不同分支的 CI/CD 策略独立运行

完成本教程后,你可以将这套 CI/CD 流水线快速集成到团队的 Spring Boot、Node.js、Python 等项目之中,实现"一次提交,自动构建,一键部署"的 DevOps 全流程。

📎 十二、快速命令参考集

bash 复制代码
# 1. 启动 Jenkins(挂载 socket 方案)
docker run -d --name jenkins --restart always \
  -p 8080:8080 -p 50000:50000 \
  -v /data/jenkins_home:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e TZ=Asia/Shanghai \
  jenkins/jenkins:lts

# 2. 获取解锁密码
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

# 3. 进入容器调试
docker exec -it jenkins bash

# 4. 查看实时日志
docker logs -f jenkins

# 5. 重启 Jenkins
docker restart jenkins

# 6. 停止并删除容器(保留数据在 /data/jenkins_home)
docker stop jenkins && docker rm jenkins

# 7. 升级 Jenkins(先保留数据目录,再用新镜像启动)
docker pull jenkins/jenkins:lts
docker stop jenkins && docker rm jenkins
docker run ... # 使用相同的挂载目录重新启动

相关推荐
深念Y8 小时前
Python + PyAutoGUI 实现一键清理:从 OpenCV 图像识别到“按键精灵“的自动化之路
python·opencv·自动化·codex·claudecode·skills·ccswitch
就叫飞六吧8 小时前
docker快速启动sqlserver实例并自动测试shell脚本
docker·容器·sqlserver
你的秋裤穿反了8 小时前
SCL 第一个程序
自动化
醉颜凉8 小时前
Elasticsearch高阶聚合实战:Pipeline Aggregation 用法详解与典型场景全攻略
大数据·elasticsearch·jenkins
qq_4523962316 小时前
第十五篇:《UI自动化中的稳定性优化:解决flaky tests的七种武器》
运维·ui·自动化
云飞云共享云桌面18 小时前
东莞智能装备工厂数字化实践—研发部门10名SolidWorks设计共享一台云主机流畅设计
服务器·自动化·汽车·负载均衡·制造
皮皮冰燃19 小时前
docker-18-WSL中安装docker并部署flask服务
docker·容器·flask
少年白char19 小时前
整理上万首音乐后的完整工作流:下载、刮削、播放与避坑指南
docker·nas·musictag·音乐刮削·音乐标签
福大大架构师每日一题20 小时前
openclaw v2026.4.24 发布:Google Meet 深度集成、DeepSeek V4 上线、浏览器自动化与插件架构全面升级
运维·架构·自动化·openclaw