在现代软件开发流程中,持续集成与持续部署(CI/CD)已成为提升交付效率与质量的核心引擎。Jenkins作为业界领先的开源自动化服务器,结合Docker容器化技术,能够构建出稳定、可移植且易于管理的CI/CD环境。本文将手把手带你完成从环境准备到Jenkins上线的全过程,涵盖Java 21升级、Docker环境搭建、容器化部署及安全配置等关键步骤,助你快速搭建一套现代化的自动化构建平台。

一、 基础环境准备:拥抱Java 21与Docker

一个稳固的地基是成功的一半。部署Jenkins前,我们需要确保运行环境是最新且稳定的。首先,我们将系统Java版本升级至Java 21,以获得更好的性能与新特性支持。同时,安装并配置Docker,为后续的容器化部署铺平道路。容器化部署的优势在于环境隔离、依赖统一和快速部署,这也是迈向更高级的容器编排技术(如Kubernetes (K8s))的第一步。

升级Java至21版本是首要任务。Jenkins本身基于Java运行,新版本Java能带来更优的垃圾回收机制和运行时性能。操作前,请先检查当前Java版本:

# 查看当前Java版本
java -version
​
# 查看所有已安装的Java版本
update-alternatives --display java

确认后,开始安装Java 21。我们推荐使用OpenJDK发行版,它开源且兼容性好。执行以下安装命令:

# 更新软件包列表
sudo apt update
​
# 安装OpenJDK 21
sudo apt install -y openjdk-21-jdk openjdk-21-jre
​
# 验证安装
java -version

安装完成后,预期会看到类似输出:

openjdk version "21.0.x" 2024-xx-xx
OpenJDK Runtime Environment (build 21.0.x+xx-Ubuntu-...)
OpenJDK 64-Bit Server VM (build 21.0.x+xx-Ubuntu-..., mixed mode, sharing)

接下来需要配置系统默认的Java版本,特别是当系统中存在多个Java版本时。使用update-alternatives命令进行管理:

# 配置默认Java版本
sudo update-alternatives --config java
​
# 会显示类似以下内容:
# Selection    Path                                         Priority   Status
# ------------------------------------------------------------
#   0            /usr/lib/jvm/java-21-openjdk-amd64/bin/java   2111      auto mode
#   1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java   1111      manual mode
# * 2            /usr/lib/jvm/java-21-openjdk-amd64/bin/java   2111      manual mode
​
# 输入序号选择Java 21(通常是最新版本的序号)
# 例如输入:0 或 2
# 同样配置javac
sudo update-alternatives --config javac

为了让系统应用和Jenkins能正确识别Java环境,必须设置JAVA_HOME环境变量。编辑profile文件:

# 查找Java 21安装路径
sudo update-alternatives --config java
# 记下Java 21的路径,例如:/usr/lib/jvm/java-21-openjdk-amd64
​
# 编辑环境配置文件
sudo nano /etc/environment

在文件末尾添加或修改环境变量定义,指向Java 21的安装路径。例如,添加如下行:

JAVA_HOME="/usr/lib/jvm/java-21-openjdk-amd64"

保存并退出编辑器(通常使用ESC键后输入:wq命令)。之后,使配置立即生效:

# 使配置生效
source /etc/environment
​
# 验证JAVA_HOME
echo $JAVA_HOME
java -version

⚠️ 重要提示:在确认新版本Java工作完全正常后,再考虑卸载旧版本,以避免不必要的兼容性问题。卸载命令如下:

# 列出所有Java相关包
dpkg -l | grep -i jdk
​
# 卸载JDK 11
sudo apt remove -y openjdk-11-jdk openjdk-11-jre
​
# 清理残留配置
sudo apt autoremove -y
sudo apt autoclean

最后,执行全面的验证,确保升级成功:

# 检查Java版本
java -version
​
# 检查javac版本
javac -version
​
# 检查JAVA_HOME
echo $JAVA_HOME
​
# 检查PATH
which java

当所有命令都显示Java 21相关信息时,恭喜你,基础环境升级成功!✅

二、 搭建容器化基石:安装与配置Docker

完成Java升级后,我们进入容器化部署的核心环节——安装Docker。Docker将应用程序及其所有依赖打包在一个轻量级、可移植的容器中,是实现环境一致性的利器。首先,清理可能存在的旧版本Docker,避免冲突:

sudo apt remove docker docker-engine docker.io containerd runc

接着,更新系统包索引并安装必要的依赖工具:

# 更新软件包索引
sudo apt update
​
# 安装必要的依赖包
sudo apt install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release \
    software-properties-common

为了从官方源安全地安装Docker,需要添加Docker的GPG密钥和软件仓库:

# 创建密钥目录
sudo mkdir -p /etc/apt/keyrings
​
# 下载并添加Docker GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
​
# 设置密钥权限
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu jammy stable" | sudo tee /etc/apt/sources.list.d/docker.list

现在,可以安装Docker Engine(社区版)及其命令行工具:

# 更新软件包索引
sudo apt update
​
# 安装Docker及相关组件
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

安装完成后,启动Docker服务并设置为开机自启,确保服务持久运行:

# 启动Docker服务
sudo systemctl start docker
​
# 设置开机自启动
sudo systemctl enable docker
​
# 检查Docker状态
sudo systemctl status docker

关键步骤:为了避免每次使用docker命令都需要sudo权限,需要将当前用户加入docker用户组:

# 创建docker用户组(通常已存在)
sudo groupadd docker 2>/dev/null || true
​
# 将当前用户添加到docker组
sudo usermod -aG docker $USER
​
# 刷新用户组权限(二选一)
# exit 后重新连接服务器

执行此命令后,需要退出当前终端并重新登录,用户组变更才会生效。

最后,运行一个测试容器来验证Docker安装是否成功:

# 检查Docker版本
docker --version
​
# 运行测试容器
docker run hello-world

如果一切正常,你将看到来自Docker Hub的欢迎信息:

Hello from Docker!
This message shows that your installation appears to be working correctly.

如果遇到网络超时或连接Docker Hub失败的错误(这在某些地区很常见),通常是因为网络问题。一个高效的解决方案是配置国内镜像加速器,例如阿里云镜像加速服务,能极大提升镜像拉取速度[AFFILIATE_SLOT_1]。配置方法如下:

# 直接运行命令:
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://地址.mirror.aliyuncs.com",//替换成你的镜像加速的地址
    "https://docker.1panel.live",
    "https://docker.rainbond.cc"
  ]
}
EOF
​
# 重启Docker
sudo systemctl daemon-reload
sudo systemctl restart docker
​
# 验证
docker info | grep -A 10 "Registry Mirrors"
# 测试拉取镜像
docker run hello-world
# 如果成功,应该看到:
# Hello from Docker!
# This message shows that your installation appears to be working correctly.

此外,我们还需要Docker Compose工具,它用于定义和运行多容器Docker应用程序。新版本的Docker Desktop通常已包含Compose插件,可以通过以下命令验证:

# 检查Docker Compose版本
docker compose version

如果显示版本号(例如v2.24.5),则说明已安装。若未安装,可使用以下命令手动安装:

# 下载Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
​
# 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose
​
# 创建软链接
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
​
# 验证安装
docker-compose --version

三、 核心部署:使用Docker Compose运行Jenkins

环境就绪后,我们开始部署Jenkins。采用Docker Compose方式部署,能够通过一个YAML文件定义所有服务、网络和卷,实现一键式部署和配置即代码,管理起来非常清晰。

首先,为Jenkins创建一个专属的项目目录,并规划好用于持久化数据的子目录:

# 创建Jenkins项目目录(可以在你自己想放的目录下,我的在/root/mynane/main下面创建的)
mkdir -p jenkins-docker
cd jenkins-docker
​
# 创建数据持久化目录(一定要在jenkins-docker目录下运行哦)
mkdir -p jenkins_home
​
# 查看当前目录结构
pwd  # 应该显示:/root/你的用户名/jenkins-docker

设置正确的目录权限至关重要,这能保证Jenkins容器有足够的权限读写宿主机上的数据卷:

# Jenkins容器内使用UID 1000运行
# 需要给jenkins_home目录正确的权限
sudo chown -R 1000:1000 jenkins_home
​
# 验证权限
ls -la jenkins_home

接下来,在项目根目录创建核心配置文件docker-compose.yml:

# 使用nano编辑器创建配置文件
vim docker-compose.yml

将以下配置内容粘贴到该文件中。我们选择官方提供的jenkins/jenkins:lts-jdk21镜像,它基于最新的Jenkins长期支持(LTS)版本并运行在Java 21上,兼顾了稳定性和性能。如果你因项目兼容性需要Java 17环境,只需将镜像标签改为jenkins/jenkins:lts-jdk17即可。

version: '3.8'
​
services:
  jenkins:
    image: jenkins/jenkins:lts-jdk21
    container_name: jenkins
    restart: unless-stopped
    privileged: true
    user: root
    ports:
      - "8080:8080"      # Jenkins Web界面
      - "50000:50000"    # Jenkins代理通信端口
    volumes:
      # 持久化Jenkins数据
      - ./jenkins_home:/var/jenkins_home
      # 允许Jenkins使用主机的Docker
      - /var/run/docker.sock:/var/run/docker.sock
      # 挂载Docker二进制文件(可选,用于在Jenkins中执行docker命令)
      - /usr/bin/docker:/usr/bin/docker
    environment:
      - JAVA_OPTS=-Duser.timezone=Asia/Shanghai -Dhudson.model.DirectoryBrowserSupport.CSP=
      - JENKINS_OPTS=--prefix=/jenkins
    networks:
      - jenkins-network
​
networks:
  jenkins-network:
    driver: bridge
重要说明:

配置文件定义了服务端口映射、数据卷挂载(确保Jenkins配置和插件持久化)以及容器重启策略。保存文件后,使用一条命令即可启动整个Jenkins服务栈:

# 启动容器(后台运行)
docker compose up -d
​
# 查看容器状态
docker compose ps
​
# 查看容器日志
docker compose logs -f jenkins

命令执行后,控制台会输出容器启动日志。你应当看到类似下面的信息,表明容器正在启动:

[+] Running 2/2
 ✔ Network jenkins-docker_jenkins-network  Created
 ✔ Container jenkins                       Started

启动过程可能需要1-2分钟。你可以使用以下命令实时查看启动日志,监控初始化进度:

#解决方法:是网络原因,修改一下镜像就行
sudo tee /etc/docker/daemon.json <<'EOF'
{
  "registry-mirrors": [
    "https://x1doswo1.mirror.aliyuncs.com",
    "https://docker.1panel.live",
    "https://docker.rainbond.cc",
    "https://docker.m.daocloud.io",
    "https://docker.mirrors.ustc.edu.cn",
    "https://docker.nju.edu.cn",
    "https://mirror.baidubce.com"
  ]
}
EOF

当日志中出现类似“Jenkins is fully up and running”的信息时,说明服务已就绪。此时可以按Ctrl+C退出日志跟踪。

Jenkins首次启动时,会生成一个随机的初始管理员密码,并存储在容器内。我们需要获取这个密码以完成后续的解锁操作:

解决方法:sed -i '/^version:/d' docker-compose.yml

耐心等待Jenkins完全启动(通常需要1-2分钟初始化插件和配置),然后获取初始密码:

# 实时查看启动日志
docker compose logs -f jenkins
​
# 看到以下信息说明启动成功:
# Jenkins is fully up and running

复制终端显示的密码字符串(例如:3f4a6b8c1d2e5f7a9b0c1d2e3f4a5b6c7),稍后使用。

四、 安全与访问:配置防火墙与初始化Jenkins

在通过网络访问Jenkins之前,必须配置服务器的安全策略,这是保护你的CI/CD平台不被未授权访问的关键步骤。

1. 配置服务器防火墙
如果你使用的是Ubuntu系统,默认的防火墙工具是UFW。我们需要开放Jenkins的Web服务端口(默认为8080):

# 方式1:从日志中查看
docker compose logs jenkins | grep -A 5 "initialAdminPassword"
​
# 方式2:从容器内查看
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
​
# 方式3:从持久化目录查看
cat jenkins_home/secrets/initialAdminPassword

2. 配置云服务商安全组
如果你的服务器运行在阿里云、腾讯云等云平台上,还需要在云控制台配置安全组规则。以阿里云ECS为例,你需要添加一条入方向规则:

端口范围授权对象说明
22/220.0.0.0/0SSH
8080/80800.0.0.0/0Jenkins Web
50000/500000.0.0.0/0Jenkins Agent

⚠️ 安全警告:规则中的源地址0.0.0.0/0表示允许所有IP访问。在生产环境中,强烈建议将其改为你公司或团队的特定IP地址段,以最小化安全风险。

完成安全配置后,就可以在浏览器中访问并初始化Jenkins了。

步骤1:访问Jenkins
在浏览器地址栏输入你的服务器IP地址和端口号:

# 检查防火墙状态
sudo ufw status
​
# 如果防火墙未启用,先启用
sudo ufw enable
​
# 允许SSH(防止被锁在外面!)
sudo ufw allow 22/tcp
​
# 允许Jenkins Web端口
sudo ufw allow 8080/tcp
​
# 允许Jenkins代理端口(如果需要)
sudo ufw allow 50000/tcp
​
# 重新加载防火墙
sudo ufw reload
​
# 查看规则
sudo ufw status numbered

例如:http://192.168.1.100:8080。

步骤2:解锁Jenkins
首次访问会看到一个“解锁Jenkins”的页面。将之前从容器日志中复制的初始管理员密码粘贴到输入框中,点击“Continue”。

步骤3:安装插件
接下来,Jenkins会建议安装插件。对于新手,选择“Install suggested plugins”(安装推荐插件)是最快捷的方式。安装过程可能需要5-10分钟,取决于你的网络速度。除了推荐插件,对于现代化的CI/CD流水线,我强烈建议后续在插件管理中安装以下扩展:

  • Git plugin / GitHub Integration:源代码管理核心。
  • Pipeline / Docker Pipeline:定义流水线即代码,是容器化部署自动化的核心。
  • Blue Ocean:提供可视化、更直观的流水线编辑和监控界面。
  • Kubernetes Plugin:如果你计划将来将构建任务或Jenkins本身部署到Kubernetes (K8s)集群,这个插件必不可少[AFFILIATE_SLOT_2]。

步骤4:创建管理员用户
插件安装完成后,系统会提示你创建第一个管理员用户。请务必使用一个强密码,并填写有效的邮箱地址。

步骤5:配置实例URL
Jenkins URL通常会自动填充,确认无误后保存即可。

步骤6:开始使用
点击“Start using Jenkins”,你将正式进入Jenkins的仪表盘。至此,一个基于Docker容器化部署的Jenkins CI/CD平台已经成功搭建完成!

五、 总结与进阶展望

通过本文的步骤,我们完成了一套基于Java 21和Docker的现代化Jenkins CI/CD平台的部署。我们不仅升级了基础运行环境,还利用Docker Compose实现了Jenkins的容器化部署,确保了环境的一致性和可重复性。同时,我们兼顾了安全配置,为平台的稳定运行打下了基础。

这套方案只是一个起点。接下来,你可以探索更多进阶主题,例如:

  • 使用Jenkins Pipeline编写复杂的构建、测试、部署流水线。
  • 将构建代理(Agent)也容器化,实现动态伸缩的构建资源池。
  • 将整套Jenkins系统(Master和Agents)迁移到Kubernetes上进行编排和管理,实现更高可用性和弹性伸缩。
  • 集成SonarQube进行代码质量分析,集成Nexus作为私有制品仓库。

容器化和自动化是云原生时代的基石。掌握Jenkins与Docker的结合,将为你的团队迈向高效的DevOps实践和更复杂的容器编排世界铺平道路。现在,开始创建你的第一个自动化任务吧!