在 Ubuntu 上使用 Docker 部署与调用 Jenkins
一 方案总览
- 在 Ubuntu 上运行 Jenkins 通常有两种做法:直接在宿主机安装 Jenkins,或采用 Docker 运行 Jenkins。若希望 Jenkins 在容器内也能执行 docker 命令(构建/推送镜像、运行容器),需将宿主机的 Docker 守护进程套接字与(可选)docker 二进制挂载到容器内,并处理好权限与安全性。
- 常见需求包括:在 Pipeline 中使用“Docker 代理镜像”运行构建、在容器内直接调用宿主机的 Docker 引擎、以及将镜像推送到仓库或远程主机部署。
二 方式一 Docker 运行 Jenkins 并挂载 Docker 引擎
- 准备持久化目录与权限(Jenkins 容器内默认用户 UID/GID 为 1000:1000):
- sudo mkdir -p /opt/jenkins_home
- sudo chown -R 1000:1000 /opt/jenkins_home
- 启动容器(挂载 Docker 套接字,按需挂载 docker 二进制;示例采用 jenkins/jenkins:lts-jdk17 镜像):
- docker run -d
–name jenkins
–restart unless-stopped
-p 8080:8080
-p 50000:50000
-v /opt/jenkins_home:/var/jenkins_home
-v /var/run/docker.sock:/var/run/docker.sock
-v /usr/bin/docker:/usr/bin/docker
jenkins/jenkins:lts-jdk17
- 获取初始管理员密码并访问:
- docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
- 浏览器访问:http://<服务器IP>:8080,完成插件安装与账号初始化。
三 方式二 Docker Compose 编排(更易维护)
- 创建 /opt/docker-compose.yaml:
- version: ‘3.8’
services:
jenkins:
image: jenkins/jenkins:lts-jdk17
container_name: jenkins
restart: always
user: root
ports:
- “8080:8080”
- “50000:50000”
volumes:
- /opt/jenkins_home:/var/jenkins_home
- /usr/bin/docker:/usr/bin/docker
- /var/run/docker.sock:/var/run/docker.sock
- /etc/localtime:/etc/localtime:ro
networks:
- jenkins-net
networks:
jenkins-net:
driver: bridge
- 启动与验证:
- docker-compose -f /opt/docker-compose.yaml up -d
- docker ps 应能看到 jenkins 容器处于 Up 状态
- 初始密码:docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword。
四 在 Jenkins 内使用 Docker 的关键配置
- 安装插件:进入 Manage Jenkins → Manage Plugins,安装 Docker Pipeline、Pipeline、Git、SSH Pipeline Steps(如需远程部署)等常用插件。
- 连接 Docker 引擎(容器内调用宿主机 Docker):
- 进入 Manage Jenkins → Configure System,在 Docker 配置处添加 Docker Host URL:unix:///var/run/docker.sock,保存并测试连接。
- 权限与安全提示:
- 挂载 /var/run/docker.sock 会让容器内拥有较高权限,务必限制可登录 Jenkins 的人员与凭据。
- 不建议以 root 运行 Jenkins 生产实例;若采用 root,请确保最小权限与审计;也可考虑使用 rootless Docker 或仅授予 jenkins 用户加入 docker 组的权限(需谨慎评估)。
五 示例 Jenkinsfile 与常见问题
- 示例一 Docker 代理镜像(在容器内按需拉取镜像,无需挂载 Docker 套接字)
- pipeline {
agent { docker ‘python:3.8’ }
stages {
stage(‘Build’) { steps { sh ‘echo “Building in Docker!”’ } }
stage(‘Test’) { steps { sh ‘echo “Testing in Docker!”’ } }
}
}
- 示例二 在容器内调用宿主机 Docker(需挂载 docker.sock 与 docker 二进制)
- pipeline {
agent any
environment {
DOCKER_IMAGE = “your-dockerhub-username/your-app:${BUILD_NUMBER}”
REMOTE_SERVER = “user@your-server-ip”
REMOTE_DIR = “/path/to/deploy”
}
stages {
stage(‘Checkout’) {
steps { git branch: ‘main’, url: ‘https://github.com/your/repo.git’ }
}
stage(‘Build Image’) {
steps {
script { dockerImage = docker.build(env.DOCKER_IMAGE) }
}
}
stage(‘Push Image’) {
steps {
script {
docker.withRegistry(‘https://registry.hub.docker.com’, ‘dockerhub-credential-id’) {
dockerImage.push()
}
}
}
}
stage(‘Deploy’) {
steps {
sshagent([‘ssh-credential-id’]) {
sh “”"
ssh ${REMOTE_SERVER} “docker pull ${DOCKER_IMAGE}”
ssh ${REMOTE_SERVER} “docker stop your-container || true”
ssh ${REMOTE_SERVER} “docker run -d --name your-container -p 8080:8080 ${DOCKER_IMAGE}”
“”"
}
}
}
}
}
- 常见问题速查
- 无法访问 http://IP:8080:检查云安全组/本机防火墙是否放行 8080;UFW 示例:sudo ufw allow 8080 && sudo ufw reload。
- 目录权限错误:确保 /opt/jenkins_home 属主为 1000:1000,否则容器启动或写入会失败。
- 容器内执行 docker 报权限不足:确认已挂载 /var/run/docker.sock 与(可选)/usr/bin/docker,并理解由此带来的安全边界变化。