背景:以前没使用 docker 时,要搭建一个 jenkins 环境,还是蛮麻烦的,需要下载 java 的 jdk,并且还要在
/etc/profile
中配置环境变量,将 java 文件位置写进 jenkins 配置内。 并且在安装过程中,难免要处理报错或异常,玩着玩着,就把服务器搞得乱七八糟....
本文主要记录一下,通过写好配置docker-compose.yml
,执行 sh 脚本、自动创建 jenkins 和 nginx 相关容器。
1. 最终目标 🎯
实现下列体验:
- 首次执行
init.sh
:自动创建目录、生成 Nginx 配置、初始化 Jenkins、拉起容器。 - 在 Jenkins 创建一个构建任务(或 Pipeline):
- 拉取前端仓库代码。
npm ci && npm run build
。- 将
dist/
复制到共享目录/app/shared-dist
。
- 浏览器访问:
- Jenkins 管理界面:
http://<HOST>:8080
- 已发布前端:
http://<HOST>
(默认 80 端口)
- Jenkins 管理界面:
- 再次构建 → Nginx 直接读取最新静态资源(无需重启)。
2. 架构设计概览
scss
┌──────────────────────────────────────────┐
│ Host (Host) │
│ /app │
│ ├── jenkins_home (Jenkins data/plugins)│
│ ├── shared-dist (built static assets) │
│ └── nginx │
│ └── default.conf (Nginx vhost) │
│ │
│ Docker Bridge Network: ci_net │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Jenkins │ │ Nginx │ │
│ │ :8080 /50000 │ │ :80 │ │
│ │ build → dist │ │ read-only │ │
│ └──────────────┘ └──────────────┘ │
└──────────────────────────────────────────┘
- 解耦:Jenkins 专注构建,Nginx 专注静态文件分发。
- 持久化:删除容器不丢 Jenkins 数据与构建产物。
- 原子部署:构建后直接同步文件。
3. 目录设计
目录 | 用途 | 注意事项 |
---|---|---|
/app/jenkins_home |
Jenkins 工作目录(插件、配置、Job、用户、密钥等) | 勿轻易清空,可做定期备份 |
/app/shared-dist |
最新前端构建产物 | Nginx 以只读方式挂载 |
/app/nginx/default.conf |
Nginx 相关配置 | 可扩展 HTTPS、缓存策略 |
提示:上面3个目录会在 sh 脚本执行时创建。
docker 创建启动容器时,会做目录挂载;其中jenkins_home
目录初始为空,但是 jenkins 启动脚本首次初始化时,会自动写入相关文件,不必担心宿主机覆盖容器内配置。
4. docker-compose.yml 配置
yaml
version: "3.9" # 使用 Compose 3.9 语法版本,通用且新
services: # 定义要运行的服务集合
jenkins: # Jenkins 服务:负责前端构建
image: jenkins/jenkins:lts-jdk17
container_name: wj-jenkins # 固定容器名,方便 docker logs / ps 查询
restart: unless-stopped # 除非手动停止,否则异常退出会自动拉起
ports:
- "8080:8080" # 宿主 8080 → Jenkins Web 界面
- "50000:50000" # Jenkins inbound agent 端口(保留,可能未来用)
environment:
TZ: Asia/Shanghai # 时区,影响日志时间显示
volumes:
- /app/jenkins_home:/var/jenkins_home # 绝对路径:持久化 Jenkins 主目录;删除该目录相当于重装,第一次执行脚本,jenkins_home 空目录会自动初始化
- /app/shared-dist:/var/jenkins_home/deploy/frontend_dist # 构建产物共享目录;Jenkins 将 dist/* 复制到这里
networks:
- ci_net # 加入自定义网络,使与 Nginx 容器互通(未来扩展方便)
nginx: # Nginx 服务:仅提供静态文件访问
image: nginx:1.28.0
container_name: wj-nginx # 固定容器名
restart: unless-stopped # 异常自动重启,保证前端站点存活
depends_on:
- jenkins # 启动顺序提示:先启动 Jenkins(不是硬依赖,只是声明)
ports:
- "80:80" # 宿主 80 → Nginx 80;浏览器 http://localhost 访问
volumes:
- /app/shared-dist:/usr/share/nginx/html:ro # 将 Jenkins 产物目录挂载为 Nginx 静态根,只读防误改
- /app/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro # 将 Jenkins 产物目录挂载为 Nginx 静态根,只读防误改
networks:
- ci_net # 同网络:未来可加反向代理、健康检查等
networks: # 自定义网络声明
ci_net:
driver: bridge # 使用默认桥接模式(本地开发足够)
# 注意:
# 1. 所有宿主机目录使用绝对路径 /app/... ,需要你在宿主机先创建并赋予权限。
# 2. shared-dist 与 jenkins_home 目录不可与其他无关服务混用,避免污染。
关键说明:
jenkins:lts-jdk17
、nginx:1.28.0
是在docker hub
上挑选的 2 个镜像版本。- 上面比较关键的是
/app/shared-dist
分别和 jenkins 和 nginx 做了目录挂载 ,其中nginx
使用:ro
只读挂载,避免误写。 jenkins
服务把/app/shared-dist
挂载进它的工作目录中,便于复制产物。- 自定义网络
ci_net
:可忽略,为后续拓展更灵活。
5. init.sh 一键初始化脚本
bash
#!/usr/bin/env bash
set -e
echo "[+] 创建目录"
sudo mkdir -p /app/jenkins_home /app/shared-dist /app/nginx
echo "[+] 写 Nginx default.conf (若不存在)"
if [ ! -f /app/nginx/default.conf ]; then
sudo tee /app/nginx/default.conf >/dev/null <<'EOF'
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / { try_files $uri $uri/ /index.html; }
}
EOF
else
echo " 已存在,跳过。"
fi
echo "[+] 写占位 index.html (若不存在)"
[ -f /app/shared-dist/index.html ] || echo "<h1>Waiting for build</h1>" | sudo tee /app/shared-dist/index.html >/dev/null
echo "[+] 设置 Jenkins 可写权限"
sudo chown -R 1000:1000 /app/jenkins_home /app/shared-dist || true
echo "[+] 启动 docker compose"
if docker compose version >/dev/null 2>&1; then
docker compose up -d
else
docker-compose up -d
fi
echo "[✓] 完成:Jenkins -> http://<host>:8080 Nginx -> http://<host>:80"
echo "查看初始密码: docker logs wj-jenkins | grep -i 'initialAdminPassword'"
设计:
- 创建挂载需要的目录。
- 当目录为空时,生成默认配置
default.conf
和index.html
,避免403/404. - 自动权限修复:Jenkins 在容器内默认 UID=1000,必须让宿主目录属主匹配。
- 兼容新版
docker compose
与旧版docker-compose
。
6. 快速启动步骤
bash
# 1. 准备环境:安装 Docker / Docker Compose
# 2. 上传 docker-compose.yml、init.sh 两个文件到同一目录
chmod +x init.sh
# 3. 执行初始化
./init.sh
# 4. 查看 Jenkins 初始管理员密码
docker logs wj-jenkins | grep -i 'initialAdminPassword'
# 5. 浏览器访问
# Jenkins: http://服务器IP:8080
# 前端站点: http://服务器IP
经过上面的配置后,打开 8080 端口就可以看到下面页面,执行命令获取初始密码,粘贴进去就可以了。

7. Jenkins 首次配置建议
登录后:
- 选择:安装推荐插件/选择插件安装。推荐自己选择插件按照,默认会勾选一些,自己只需要安装一个
NodeJS Plugin
就可以了。 - 创建管理员账号。
- 创建一个全局凭据,这个凭据是为了拉取 github/gitlab 代码的,使用下面命令,在
/app
目录下创建一个密钥对。
bash
mkdir -p /app/jenkins_keys && ssh-keygen -t ed25519 -C "jenkins-ci" -f /app/jenkins_keys/id_ed25519 -N ''
- 复制出来公钥
id_ed25519.pub
加到代码库的 SSH 里;复制id_ed25519
私钥,去 jenkins 里创建一个全局凭据。

8. 创建 jenkins job
可以使用 Freestyle Job
或者 Pipeline
的,以前者为例。
注意,由于加了 ssh,所以git仓库就不要使用 https:
这种了,否则拉取时可能出错。

环境这里,首先需要去 tool
里面找到之前安装的 NodeJS 插件,选择一个版本,创建完这里就可以选了。

Shell 脚本配置
- 执行命令
- 复制到指定目录
sh
#!/bin/bash
set -e
echo "[1] 显示 Node 版本"
node -v
npm -v
echo "[2] 安装依赖(使用 package-lock 有的话优先 npm ci)"
if [ -f package-lock.json ]; then
npm ci
else
npm install
fi
echo "[3] 构建"
npm run build
echo "[4] 发布到共享目录"
TARGET_DIR="$JENKINS_HOME/deploy/frontend_dist"
mkdir -p "$TARGET_DIR"
# 清空旧内容
rm -rf "${TARGET_DIR:?}/"*
# 复制新产物(假设 dist 为输出目录)
cp -r dist/* "$TARGET_DIR"/
echo "[5] 完成。Nginx 将立即提供新的静态文件。"
访问 http://<HOST>
即看到最新页面,无需重启 Nginx。
9. Nginx 配置拓展
当前 default.conf
:
nginx
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# SPA 前端:路径不匹配时回退 index.html
location / { try_files $uri $uri/ /index.html; }
}
可扩展:
-
添加 gzip:
nginxgzip on; gzip_types text/css application/javascript application/json image/svg+xml;
-
添加缓存策略:
nginxlocation ~* \.(js|css|png|jpg|jpeg|svg|ico)$ { add_header Cache-Control "public,max-age=31536000,immutable"; }
10.常见问题:
- 第一次拉代码,会有这个提示,按照提示,去对应位置选择
Accept first connection
就可以了!

-
如果有需要,可以和进一步自动化:
Git Webhook + 自动触发
,实现CICD
闭环 。 (下面未经验证,个人觉得自动触发在生产环境不太适用)- Jenkins → 新建 Pipeline → 构建触发器勾选
GitHub hook trigger for GITScm polling
。 - 在 Git 平台(GitHub/GitLab)配置 Webhook 指向:
http://<HOST>:8080/github-webhook/
- Push 即自动触发构建 → 发布。
- Jenkins → 新建 Pipeline → 构建触发器勾选
完结~撒花 💐
至此,就完成了 docker + jenkins + nginx 的自动化配置,学废了吗?
本文主要是 CD 相关,如果需要 GitLab CI 相关配置,可看另一篇关于 gitlab-runner 文章。