简介
Jenkins 通常以未初始化的控制器状态启动。首位管理员需要使用初始密码解锁控制器,创建永久管理员账号,并确认 Jenkins 已准备就绪。
在本实验中,你将安全地练习这一首次运行的工作流程。由于虚拟机中的主 Jenkins 服务已用于其他实验,你将会在 18080 端口启动第二个临时 Jenkins 控制器。你只需初始化该临时控制器,验证结果,然后将其移除即可。
启动一个隔离的全新 Jenkins 控制器
在此步骤中,你将启动一个新的 Jenkins 控制器,而不会更改主 Jenkins 服务。Jenkins 控制器将其配置存储在 /var/jenkins_home 下,因此本实验使用了一个名为 jenkins-init-lab-home 的独立 Docker 数据卷。
下方的 docker run 命令会在后台启动临时控制器。-d 选项表示后台运行模式,--name 为容器指定一个稳定的名称,-p 18080:8080 将 Jenkins 发布到宿主机的 18080 端口,-v 则挂载隔离的 Jenkins 主目录数据卷。
docker run -d \
--name jenkins-init-lab \
-p 18080:8080 \
-v jenkins-init-lab-home:/var/jenkins_home \
jenkins/jenkins:latest
Docker 会输出新的容器 ID。每次生成的 ID 都不相同,因此任何长十六进制值都是正常的。
接下来,等待 Jenkins 开始响应 HTTP 请求。下方的循环会不断向本地控制器请求 /login 路径,直到它返回 HTTP 状态码。200 响应表示登录页面已可用。
until [ "$(curl -s -o /dev/null -w '%{http_code}' http://localhost:18080/login)" = "200" ]; do
echo "Waiting for the temporary Jenkins controller..."
sleep 5
done
你应该会看到几次等待提示,随后命令提示符会返回。确认容器和端口映射:
docker ps --filter name=jenkins-init-lab --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
输出应包含容器名称和 18080 端口:
NAMES STATUS PORTS
jenkins-init-lab Up ... 0.0.0.0:18080->8080/tcp, ...
获取初始管理员密码
在此步骤中,你将获取 Jenkins 为首位管理员创建的一次性密码。Jenkins 将此密码存储在控制器主目录下的 /var/jenkins_home/secrets/initialAdminPassword 文件中。
使用 docker exec 在临时 Jenkins 容器内运行 cat 命令,并将密码保存到你的项目目录中:
docker exec jenkins-init-lab cat /var/jenkins_home/secrets/initialAdminPassword > /home/labex/project/jenkins-init-password.txt
该命令使用 > 重定向将输出写入文件。这样可以在后续步骤中使用该密码,而无需依赖 shell 变量。
仅显示前几个字符,以便在不暴露完整值的情况下确认文件不为空:
cut -c1-8 /home/labex/project/jenkins-init-password.txt
你应该能看到密码的前八个字符,类似于:
1a2b3c4d
创建永久管理员账号
在此步骤中,你将使用初始密码创建一个名为 lab-admin 的正式 Jenkins 管理员账号。初始密码仅用于设置阶段。控制器初始化完成后,团队通常使用正式的管理员账号进行操作。
Jenkins 使用 crumb 令牌来保护表单提交。Crumb 与请求它的浏览器或 HTTP 会话绑定,因此下方的命令还会将 Jenkins 的 Cookie 保存到 Cookie 存储文件中。
INIT_PASSWORD=$(tr -d '\r\n' < /home/labex/project/jenkins-init-password.txt)
COOKIE_JAR=/home/labex/project/jenkins-init-cookies.txt
curl -fsS -c "${COOKIE_JAR}" -u "admin:${INIT_PASSWORD}" \
http://localhost:18080/crumbIssuer/api/json \
> /home/labex/project/jenkins-init-crumb.json
下一条命令向 Jenkins 发送一段简短的 Groovy 脚本。该脚本会创建一个私有安全域,添加 lab-admin 用户,授予已登录用户完全控制权限,并将设置向导标记为已完成。
CRUMB_FIELD=$(sed -n 's/.*"crumbRequestField":"\([^"]*\)".*/\1/p' /home/labex/project/jenkins-init-crumb.json)
CRUMB_VALUE=$(sed -n 's/.*"crumb":"\([^"]*\)".*/\1/p' /home/labex/project/jenkins-init-crumb.json)
cat > /home/labex/project/initialize-controller.groovy <<'GROOVY'
import jenkins.model.Jenkins
import jenkins.install.InstallState
import hudson.security.HudsonPrivateSecurityRealm
import hudson.security.FullControlOnceLoggedInAuthorizationStrategy
def jenkins = Jenkins.get()
def realm = new HudsonPrivateSecurityRealm(false)
realm.createAccount('lab-admin', 'LabEx-Admin-123')
jenkins.setSecurityRealm(realm)
def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
strategy.setAllowAnonymousRead(false)
jenkins.setAuthorizationStrategy(strategy)
jenkins.setInstallState(InstallState.INITIAL_SETUP_COMPLETED)
jenkins.save()
println('created lab-admin and completed setup')
GROOVY
curl -fsS -b "${COOKIE_JAR}" -u "admin:${INIT_PASSWORD}" \
-H "${CRUMB_FIELD}: ${CRUMB_VALUE}" \
--data-urlencode "script@/home/labex/project/initialize-controller.groovy" \
http://localhost:18080/scriptText \
> /home/labex/project/jenkins-init-result.txt
读取结果文件:
cat /home/labex/project/jenkins-init-result.txt
预期的输出信息为:
created lab-admin and completed setup
确认初始化后的控制器仪表盘
在此步骤中,你将确认临时控制器不再仅仅是一个解锁界面。一个健康且已初始化的控制器应该能够验证 lab-admin 用户并返回 Jenkins 主页面。
使用带有 -u 参数的 curl 进行身份验证。-o 选项将 HTML 写入文件,-w '%{http_code}' 仅打印 HTTP 状态码。
curl -s -u 'lab-admin:LabEx-Admin-123' \
-o /home/labex/project/jenkins-init-dashboard.html \
-w '%{http_code}\n' \
http://localhost:18080/
状态码应为:
200
现在,在保存的仪表盘页面中搜索 Jenkins 的标识文本:
grep -o -E 'Dashboard|Welcome to Jenkins|Jenkins' /home/labex/project/jenkins-init-dashboard.html | head
你应该至少看到一行匹配内容。虽然具体的 HTML 结构可能会随 Jenkins 版本变化,但它应该能识别出该页面为 Jenkins。
停止并移除临时控制器
在此步骤中,你将清理临时控制器。清理工作非常重要,因为主 Jenkins 服务是其他 Jenkins 实验所使用的,而临时控制器仅用于练习首次运行初始化。
首先停止并移除临时容器:
docker rm -f jenkins-init-lab
然后移除其隔离的 Jenkins 主目录数据卷:
docker volume rm jenkins-init-lab-home
最后,验证临时控制器已被移除:
docker ps -a --filter name=jenkins-init-lab --format '{{.Names}}'
该命令不应输出任何内容。结果为空意味着该名称的容器已不存在。
总结
你启动了一个隔离的 Jenkins 控制器,获取了其一次性初始管理员密码,创建了永久管理员账号,确认了初始化后的仪表盘可访问,并清理了临时控制器。这就是一个可用的 Jenkins 控制器背后核心的首次运行初始化工作流程。