Docker 安装 Jenkins
大约 8 分钟约 2337 字
Docker 安装 Jenkins
简介
Jenkins 是最流行的开源持续集成/持续交付(CI/CD)工具之一,广泛用于自动化构建、测试和部署流程。它拥有丰富的插件生态,可以与 Git、Maven、Docker、Kubernetes 等工具无缝集成,帮助团队实现 DevOps 自动化流水线。
使用 Docker 部署 Jenkins 有两个显著优势:一是部署快速,几分钟即可搭建完整的 Jenkins 环境;二是与 Docker 生态天然融合,可以在 Jenkins 中直接调用 Docker 命令来构建和发布容器化应用。
本文将详细介绍使用 Docker 部署 Jenkins 的完整流程,包括环境准备、镜像拉取、容器配置、Docker-in-Docker 方案、Pipeline 脚本编写、插件管理以及生产环境的最佳实践。
环境准备
系统要求
| 项目 | 最低要求 | 推荐配置 |
|---|---|---|
| 操作系统 | CentOS 7+ / Ubuntu 18.04+ | CentOS 7.9 |
| 内存 | 2GB | 4GB+ |
| 磁盘 | 20GB | 50GB+ |
| Docker | 19.03+ | 最新稳定版 |
| JDK | 11+(LTS 镜像已包含) | 17 |
端口规划
| 端口 | 说明 |
|---|---|
| 8080 | Jenkins Web 界面(容器内) |
| 50000 | Jenkins Agent 通信端口(容器内) |
第一步:配置 Docker 镜像加速
在中国大陆地区,由于网络原因,直接从 Docker Hub 拉取镜像可能非常缓慢。建议配置镜像加速器:
# 使用 DaoCloud 镜像加速(示例,可根据实际情况选择其他加速器)
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io
# 或者手动配置 /etc/docker/daemon.json
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
EOF
# 重启 Docker 服务
systemctl daemon-reload
systemctl restart docker
# 验证配置
docker info | grep -A 5 "Registry Mirrors"第二步:拉取 Jenkins 镜像
# 拉取 Jenkins LTS(长期支持版)镜像
docker pull jenkins/jenkins:lts
# 查看可用的 Jenkins 版本
docker pull jenkins/jenkins:2.401.3-lts
# 查看已拉取的镜像
docker images | grep jenkins镜像选择
jenkins/jenkins:lts:LTS 长期支持版本,推荐生产环境使用jenkins/jenkins:latest:最新版本,包含最新功能但可能不够稳定- 生产环境务必固定版本标签
第三步:配置本地存储目录
# 创建 Jenkins 数据目录
mkdir -p /apps/devops/jenkins
# 设置目录权限
# Jenkins 容器内的 Jenkins 用户 UID 通常为 1000
chown -R 1000:1000 /apps/devops/jenkins
chmod -R 755 /apps/devops/jenkins
# 查看目录信息
ls -ld /apps/devops/jenkins第四步:启动 Jenkins 容器
基础启动方式
# 如果之前有同名容器,先停止并删除
docker stop jenkins 2>/dev/null
docker rm jenkins 2>/dev/null
# 配置 Docker 权限(让 Jenkins 容器可以执行 Docker 命令)
sudo usermod -a -G docker root
sudo chmod 666 /var/run/docker.sock
# 启动 Jenkins 容器
docker run -itd \
-p 9003:8080 \
-p 9004:50000 \
--restart always \
-v /apps/devops/jenkins:/var/jenkins_home \
--name jenkins \
--volume /var/run/docker.sock:/var/run/docker.sock \
-v $(which docker):/usr/bin/docker \
jenkins/jenkins:lts参数详解
| 参数 | 说明 |
|---|---|
-itd | 交互式 + 终端 + 后台运行 |
-p 9003:8080 | 将容器 8080 端口映射到宿主机 9003 端口 |
-p 9004:50000 | 将容器 50000 端口映射到宿主机 9004 端口 |
--restart always | Docker 服务重启后自动启动 |
-v /apps/devops/jenkins:/var/jenkins_home | 持久化 Jenkins 数据目录 |
--volume /var/run/docker.sock:/var/run/docker.sock | 挂载 Docker Socket,允许容器内执行 Docker 命令 |
-v $(which docker):/usr/bin/docker | 挂载 Docker 二进制文件到容器内 |
Docker-in-Docker 安全风险
挂载 /var/run/docker.sock 赋予了 Jenkins 容器对宿主机 Docker 的完全控制权,这在安全敏感的环境中需要谨慎使用。替代方案包括使用 Docker-in-Docker (dind) 或 Sysbox 运行时。
使用 Docker Compose 部署
# docker-compose-jenkins.yml
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts
container_name: jenkins
restart: always
privileged: true
user: root
ports:
- "9003:8080"
- "9004:50000"
volumes:
- /apps/devops/jenkins:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
environment:
- TZ=Asia/Shanghai
- JAVA_OPTS=-Xmx2g -Xms1g
networks:
- devops-net
networks:
devops-net:
driver: bridge第五步:初始化 Jenkins
获取管理员密码
# 方法1:从容器日志中获取初始密码
docker logs jenkins | grep -A 5 "Please use the following password"
# 方法2:从数据目录中获取
cat /apps/devops/jenkins/secrets/initialAdminPassword
# 方法3:进入容器获取
docker exec -it jenkins cat /var/jenkins_home/secrets/initialAdminPassword访问 Web 界面
在浏览器中打开以下地址:
http://<服务器IP>:9003输入初始密码后,按照向导完成以下步骤:
- 安装插件:选择「安装推荐的插件」或自定义选择
- 创建管理员:设置管理员用户名和密码
- 配置实例:确认 Jenkins URL
推荐安装的插件
| 插件名称 | 说明 |
|---|---|
| Git | Git 版本控制集成 |
| Pipeline | 流水线支持 |
| Docker Pipeline | Docker 流水线集成 |
| Configuration as Code | Jenkins 配置即代码 |
| Chinese Localization | 中文界面支持 |
| Blue Ocean | 现代化流水线可视化界面 |
| Maven Integration | Maven 项目构建支持 |
| SSH Agent | SSH 密钥管理 |
| Credentials Binding | 凭证绑定 |
Docker 构建实践
构建并运行 ASP.NET Core 项目
# 构建 Docker 镜像
docker build -f src/aspnetcoredemo/Dockerfile -t aspnetcoredemo .
# 使用 Git Hash 作为镜像标签
GITHASH=$(git rev-parse --short HEAD)
docker build -f src/aspnetcoredemo/Dockerfile -t aspnetcoredemo:${GITHASH} .
docker tag aspnetcoredemo:${GITHASH} aspnetcoredemo:latest
# 运行容器
docker run -it -d -p 7000:80 --name aspnetcoredemo aspnetcoredemo:latest自动化构建脚本
#!/bin/bash
# /opt/scripts/build.sh
# ASP.NET Core 项目自动构建脚本
set -euo pipefail
# 获取短版本号
GITHASH=$(git rev-parse --short HEAD)
IMAGE_NAME="aspnetcoredemo"
PORT="7000"
echo "========================================"
echo "Building ${IMAGE_NAME}:${GITHASH}..."
echo "========================================"
# 停止并删除旧容器
docker stop ${IMAGE_NAME} 2>/dev/null || true
docker rm ${IMAGE_NAME} 2>/dev/null || true
# 构建 Docker 镜像
echo "Building Docker Image..."
docker build -f src/aspnetcoredemo/Dockerfile -t ${IMAGE_NAME}:${GITHASH} .
docker tag ${IMAGE_NAME}:${GITHASH} ${IMAGE_NAME}:latest
# 启动新容器
echo "Launching Container..."
docker run -it -d \
-p ${PORT}:80 \
--name ${IMAGE_NAME} \
--restart=always \
${IMAGE_NAME}:latest
# 清理悬空镜像
docker image prune -f
echo "========================================"
echo "Deploy completed: ${IMAGE_NAME}:${GITHASH}"
echo "Access: http://localhost:${PORT}"
echo "========================================"Jenkinsfile 示例
pipeline {
agent any
environment {
REGISTRY = 'registry.example.com'
IMAGE_NAME = 'myapp'
IMAGE_TAG = "${env.BUILD_NUMBER}"
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'docker build -t ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} .'
sh 'docker tag ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} ${REGISTRY}/${IMAGE_NAME}:latest'
}
}
stage('Test') {
steps {
sh 'docker run --rm ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} dotnet test'
}
}
stage('Push') {
steps {
withCredentials([usernamePassword(
credentialsId: 'registry-credentials',
usernameVariable: 'REGISTRY_USER',
passwordVariable: 'REGISTRY_PASS'
)]) {
sh 'docker login ${REGISTRY} -u ${REGISTRY_USER} -p ${REGISTRY_PASS}'
sh 'docker push ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}'
sh 'docker push ${REGISTRY}/${IMAGE_NAME}:latest'
}
}
}
stage('Deploy') {
steps {
sh 'docker stop ${IMAGE_NAME} 2>/dev/null || true'
sh 'docker rm ${IMAGE_NAME} 2>/dev/null || true'
sh 'docker run -d -p 8080:80 --name ${IMAGE_NAME} --restart=always ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}'
}
}
}
post {
always {
cleanWs()
sh 'docker image prune -f'
}
failure {
mail to: 'dev@example.com',
subject: "Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Build ${env.BUILD_URL} failed."
}
}
}常见问题排查
容器启动失败
# 查看容器日志
docker logs jenkins
# 查看最近 50 行日志
docker logs --tail 50 jenkins
# 常见原因1:目录权限问题
ls -ld /apps/devops/jenkins
# 解决:chown -R 1000:1000 /apps/devops/jenkins
# 常见原因2:端口被占用
ss -tlnp | grep 9003
ss -tlnp | grep 9004
# 常见原因3:Docker Socket 权限
ls -la /var/run/docker.sock
# 解决:chmod 666 /var/run/docker.sockDocker 命令在 Pipeline 中无法执行
# 检查容器内 Docker 是否可用
docker exec -it jenkins docker version
# 检查 Docker Socket 是否挂载
docker inspect jenkins | grep -A 5 "Binds"
# 如果仍然无法使用,可能需要在 Jenkins 中安装 Docker Pipeline 插件Jenkins 插件安装失败
问题:插件下载速度慢或安装失败
解决方案:
1. 配置 Jenkins 镜像源(修改 /var/jenkins_home/hudson.model.UpdateCenter.xml)
2. 在 Manage Jenkins -> Advanced 中更换 Update Site URL
3. 手动下载 .hpi 文件上传安装安全加固建议
- 修改默认端口:不使用默认的 8080 端口
- 启用 HTTPS:配置 SSL 证书,使用 HTTPS 访问
- 角色权限控制:安装 Role-based Authorization Strategy 插件
- 凭证管理:使用 Credentials 插件管理敏感信息,不要硬编码
- 定期备份:备份
/var/jenkins_home目录 - 更新插件:定期更新 Jenkins 和插件到最新版本
- 审计日志:启用 Jenkins 审计日志功能
Jenkins 高级配置
Jenkins 备份与恢复
# 备份 Jenkins 主目录
tar czf jenkins_backup_$(date +%Y%m%d).tar.gz /apps/devops/jenkins/
# 仅备份关键配置(不包含构建历史和 workspace)
tar czf jenkins_config_backup.tar.gz \
/apps/devops/jenkins/jobs/ \
/apps/devops/jenkins/plugins/ \
/apps/devops/jenkins/users/ \
/apps/devops/jenkins/secrets/ \
/apps/devops/jenkins/credentials.xml \
/apps/devops/jenkins/config.xml \
/apps/devops/jenkins/hudson.tasks.Maven.xml \
/apps/devops/jenkins/tools.xml
# 恢复(停止 Jenkins 后解压)
docker stop jenkins
tar xzf jenkins_backup_20260414.tar.gz -C /
docker start jenkins多分支 Pipeline
// Jenkinsfile(放在代码仓库根目录)
pipeline {
agent any
tools {
maven 'Maven-3.9'
jdk 'JDK-17'
}
parameters {
choice(name: 'ENV', choices: ['dev', 'staging', 'prod'], description: '部署环境')
string(name: 'BRANCH', defaultValue: 'main', description: '分支名')
}
stages {
stage('Checkout') {
steps {
git branch: "${params.BRANCH}", url: 'https://github.com/myorg/myapp.git'
}
}
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}
stage('Docker Build & Push') {
steps {
script {
def image = "harbor.example.com/myapp:${env.BUILD_NUMBER}"
sh """
docker build -t ${image} .
docker push ${image}
"""
}
}
}
stage('Deploy') {
steps {
script {
def image = "harbor.example.com/myapp:${env.BUILD_NUMBER}"
sh """
kubectl set image deployment/myapp myapp=${image} -n ${params.ENV}
kubectl rollout status deployment/myapp -n ${params.ENV}
"""
}
}
}
}
post {
success {
echo 'Pipeline 执行成功!'
}
failure {
mail to: 'dev@example.com',
subject: "Pipeline Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Pipeline ${env.BUILD_URL} failed."
}
always {
cleanWs()
}
}
}Jenkins 参数化构建
pipeline {
agent any
parameters {
string(name: 'VERSION', defaultValue: '1.0.0', description: '版本号')
booleanParam(name: 'DEPLOY', defaultValue: true, description: '是否部署')
choice(name: 'ENV', choices: ['dev', 'staging', 'prod'], description: '环境')
text(name: 'CHANGELOG', defaultValue: '', description: '变更说明')
password(name: 'DEPLOY_KEY', defaultValue: '', description: '部署密钥')
}
stages {
stage('Info') {
steps {
echo "版本: ${params.VERSION}"
echo "环境: ${params.ENV}"
echo "部署: ${params.DEPLOY}"
}
}
}
}Jenkins Agent 节点配置
# 通过 SSH 方式添加 Agent 节点
# 1. 在 Jenkins 管理界面中:Manage Jenkins -> Nodes -> New Node
# 2. 配置 SSH 连接信息
# 在 Agent 节点上准备环境
yum install -y java-17-openjdk docker git maven
# 在 Pipeline 中指定运行节点
pipeline {
agent { label 'build-agent' }
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
}
}Jenkins 凭证管理
// 在 Pipeline 中使用凭证
pipeline {
agent any
stages {
stage('Deploy') {
steps {
withCredentials([
usernamePassword(credentialsId: 'harbor-creds',
usernameVariable: 'HARBOR_USER',
passwordVariable: 'HARBOR_PASS'),
string(credentialsId: 'kube-config', variable: 'KUBE_CONFIG')
]) {
sh """
echo "${HARBOR_USER}"
docker login harbor.example.com -u ${HARBOR_USER} -p ${HARBOR_PASS}
"""
}
}
}
}
}Jenkins 性能优化
# 1. 增加 Jenkins JVM 内存
docker run -d \
--name jenkins \
-e JAVA_OPTS="-Xms2g -Xmx2g -XX:MaxPermSize=512m" \
-v /apps/devops/jenkins:/var/jenkins_home \
jenkins/jenkins:lts
# 2. 减少构建历史保留天数
# Manage Jenkins -> Configure System
# 丢弃旧构建:保留 15 天,最多保留 30 个构建
# 3. 定期清理 workspace
# 在 Pipeline 的 post 块中添加 cleanWs()
# 4. 禁用不需要的插件
# Manage Jenkins -> Plugin Manager -> Installed
# 5. 配置 Jenkins 镜像源加速
# Manage Jenkins -> Advanced -> Update Site
# https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json