一、示例环境版本
- Docker : v24.0.7
# 查看 docker 版本命令
docker -v
- Docker Compose : v2.23.3
# 查看 docker-compose 版本命令
docker-compose -v
- Git : v2.39.2
# 查看 git 版本命令
git -v
- Nginx : v1.29.8
# 查看 nginx 版本命令
# 首先进入 nginx 容器内
docker exec -it nginx_dev bin/bash
# 然后再查看版本信息
nginx -v
- Jenkins : v2.541.3
# 查看 Jenkins 版本命令
# 首先进入 Jenkins 容器内
docker exec -it jenkins bin/bash
# 然后再查看版本信息
java -jar /usr/share/jenkins/jenkins.war --version
二、环境准备
安装 Docker
在 MacOS 安装 Docker 相对简单,只需在 Docker 官网 下载 Docker Destop,安装就好了。
启动 Docker
直接打开 Docker Destop 应用程序或在终端输入以下命令:
open -a Docker
安装 Docker Compose
因为使用的是 Docker Desktop,所以 Docker Compose已经包含在内了。
安装 Git
首先,确保你已经安装了 Homebrew,如果没有,你可以访问 Homebrew官网 并按照指示进行安装。
或者你可以使用别的方式安装 git。
brew install git
安装 Nginx 和 Jenkins
使用 docker 拉取nginx、jenkins 镜像
docker pull nginx
docker pull jenkins/jenkins:lts
拉取完后查看镜像
docker images
创建目录结构
创建 docker 的相关目录,方便维护 最终的目录结构如下:
+ docker
+ compose
- docker-compose.yml // docker-compose配置
+ html // 各环境代码目录(实际项目可能不在同一目录)
+ dev // dev环境代码目录
+ release // release 环境代码目录
+ sit // sit环境目录
+ pro // pro环境代码目录
+ jenkins_home // jenkins 工程目录
+ nginx // nginx 工程目录
+ conf
= nginx.conf // nginx配置
nginx.conf
# nginx.conf 例:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
gzip on;
# dev环境
server {
# 监听的端口
listen 8001;
server_name localhost;
# 设置日志
# access_log logs/dev.access.log main;
# 定位到index.html
location / {
# linux下HTML文件夹,就是你的前端项目文件夹
root /usr/share/nginx/html/dev/dist;
# 输入网址(server_name:port)后,默认的访问页面
index index.html;
try_files $uri $uri/ /index.html;
}
}
#sit环境
server {
# 监听的端口
listen 8002;
server_name localhost;
# 设置日志
# access_log logs/sit.access.log main;
# 定位到index.html
location / {
#容器内路径(宿主机html目录通过volume映射到/usr/share/nginx/html)
root /usr/share/nginx/html/sit/dist;
#输入网址(server_name:port)后,默认的访问页面
index index.html;
try_files $uri $uri/ /index.html;
}
}
# include /etc/nginx/conf.d/*.conf;
}
docker-compose.yml
version: '3'
networks:
frontend:
external: true
services: # 容器
docker_jenkins:
user: root # root权限
restart: always # 重启方式
image: jenkins/jenkins:lts # 使用的镜像
container_name: jenkins # 容器名称
environment:
- TZ=Asia/Shanghai
- "JENKINS_OPTS=--prefix=/jenkins_home" ## 自定义 jenkins 访问前缀(上下文context)
ports: # 对外暴露的端口定义
- 8080:8080
- 50000:50000
volumes: # 卷挂载路径
- 上面创建的docker/jenkins_home的绝对路径:/var/jenkins_home # 挂载到容器内的jenkins_home目录
- 上面创建的docker/compose的绝对路径:/usr/local/bin/docker-compose
docker_nginx_dev: # nginx-dev环境
restart: always
image: nginx
container_name: nginx_dev
ports:
- 8001:8001
volumes:
- 上面创建的nginx.conf的绝对路径:/etc/nginx/nginx.conf
- 上面创建的docker/html的绝对路径:/usr/share/nginx/html
- 上面创建的docker/nginx/logs的绝对路径:/var/log/nginx
docker_nginx_sit: # nginx-sit环境
restart: always
image: nginx
container_name: nginx_sit
ports:
- 8002:8002
volumes:
- 上面创建的docker/nginx/conf/nginx.conf的绝对路径:/etc/nginx/nginx.conf
- 上面创建的docker/html的绝对路径:/usr/share/nginx/html
- 上面创建的docker/nginx/log的绝对路径:/var/log/nginx
配置说明
docker_jenkins 是一个定义的服务名称。
user: root 指定了 Jenkins 容器使用 root 权限。
restart: always 表示容器总是在退出时重启。
image: jenkins/jenkins:lts 指定了 Jenkins 镜像及其版本。
container_name: jenkins 是容器的名称。
ports 定义了容器内外端口的映射。
volumes 定义了主机文件系统路径与容器内路径的挂载关系。
image: nginx指定了 Nginx 镜像。
container_name: nginx_dev 是容器的名称。
三、启动环境
1. 启动 docker
open -a Docker
# 或者直接打开Docker Destop应用程序
2. 启动 Jenkins、nginx
docker-compose up -d
3. 查看运行状态
要在 compose 文件夹下运行该命令(也就是要在 docker-compose.yml 文件目录下运行)
docker-compose ps -a
四、验证服务
1. 验证 Nginx
在 /docker/html/dev/dist 目录下新建 index.html,文件内容如下:
或者把你的前端打包好的项目把 dist 目录替换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Welcome to Nginx!</h1>
</body>
</html>
浏览器打开,输入 服务器地址:8001 看到下面的页面说明 nginx 配置没问题,同样的操作可以测试8002端口。
2. 验证 Jenkins
浏览器输入 服务器地址:8080/jenkins_home,看到下面的页面,会提示要输入密码,密码位于docker/jenkins_home/secrets/initialAdminPassword,
cat /docker/jenkins_home/secrets/initialAdminPassword
登录后,选择安装推荐的插件。
然后等待安装。
要是插件一直安装失败,最后经多番查找,是 jenkens 会对 update-center.json 做签名校验安全检查,需要我们先关闭掉才行。可以尝试以下方法:
- 关闭对 update-center.json 的安全检查,并禁用下载签名检查:
# 在 docker-compose.yml 中修改 jenkins 配置
environment:
...其他配置
- "JAVA_OPTS=-Dhudson.model.DownloadService.noSignatureCheck=true" # 添加这行配置
安装完成! 创建管理员用户:
保存并完成,继续下一步:
开始使用Jenkins!
到达Jenkins主页面,我的地址是:http://localhost:8080/jenkins_home/
五、Jenkins 自动化部署配置
1. 设置中文
提示:由于我在一开始安装插件的时候已经自动安装,已经是中文版本。
jenkins 版本不一样,显示的页面可能不一样,如果跟我的界面不一样可以自行查找设置中文的教程,实际上大差不差。
第一步:点击右上角设置图标
第二步:点击插件管理
第三步:点击Available plugins,搜索框输入local,选择 Localization: Chinese (Simplified),点击安装。我已经安装所以搜索不到(请参考提示)。
安装完成后,重启 Jenkins 或者在浏览器输入
服务器地址:8080/jenkins_home/restart。
2. 安装 Publish Over SSH 和 NodeJS 插件
同样的步骤安装插件,这里不再具体操作。
(1)Publish Over SSH 配置远程服务器
Publish Over SSH 用来连接远程服务器,接下来去设置连接远程服务器验证方式,本案例采用密码验证。
找到Publish Over SSH,点击新增。
在新增后出来的面板中输入信息,之后点击高级。
输入密码、服务器端口,并点击Test Configuration Success进行测试,显示successs则成功,之后先点击应用,再保存。
(2)NodeJS 配置
【系统管理】---->【全局工具配置】---->【NodeJS 安装】
点击新增 Node JS。
配置安装 NodeJS 的基本信息,自定义别名、选择安装版本,最后,先点击应用再保存。
3. 添加凭据
添加凭据,也就是 GitHub 或者其他远程仓库的账号密码,方便之后使用。
【系统管理】---> 【凭证管理】
点击全局凭证,再点击添加凭证,选择 Username with password。
填写用户名、密码、描述
4. 创建 Job
输入项目名称:测试项目,选择
构建一个自由风格的软件项目,点击确定。
接下来需要配置项目的一些信息
配置完成后,先点击应用后保存,然后返回首页,打开项目,点击立即构建
可以看到构建过程中并没有出现error,并最终显示success,此时基础构建基本完成(我把我仓库地址打马赛克了)
5. GitHub webHooks 配置
在git push代码之后,可以自动触发 Jenkins 自动拉取 GitHub 上的代码进行构建。打开GitHub中的项目,在Setting中选择Webhooks.
payload URL 为:http://ip:8080/jenkins_home/github-webhook/,之后点击Add webHook就可以了。
然后需要在 Jenkins 为该项目配置一个选项。构建触发器模块中的GitHub hook trigger for GITScm polling,先点击应用后保存。
6. 构建环境
在 Jenkins 中将 Node.js 和 npm 的 bin 文件夹添加到 PATH 中,否则可能就会报错。
7. Build Steps
因为提交服务器代码是没有node_moudle,所以我们需要执行脚本去安装依赖。
源码管理可以看到Build Steps模块,选择Execute NodeJS script。
选择node版本,这个node版本是在上面我们已经配置过的,如果需要其他版本可通过上面操作新增NodeJs即可。
配置完成之后,建议 立即构建 项目。
如果这一步构建失败遇到跟我类似的错误,可以按照我下面的方式进行修复。
在compose文件夹下创建 Dockerfile:
FROM jenkins/jenkins:lts
USER root
RUN apt-get update && apt-get install -y libatomic1 || \
(curl -L -o /tmp/libatomic1.deb "https://mirrors.aliyun.com/debian/pool/main/g/gcc-14/libatomic1_14.2.0-19_arm64.deb" && \
dpkg-deb -x /tmp/libatomic1.deb /tmp/libatomic_extract && \
cp /tmp/libatomic_extract/usr/lib/aarch64-linux-gnu/libatomic.so.1.2.0 /usr/lib/aarch64-linux-gnu/ && \
cd /usr/lib/aarch64-linux-gnu && ln -sf libatomic.so.1.2.0 libatomic.so.1 && \
ldconfig && rm -rf /tmp/libatomic1.deb /tmp/libatomic_extract)
USER jenkins
然后修改docker-compose.yml文件:
...
services:
docker_jenkins:
build: . # 添加这一行:使用自定义 Dockerfile 构建
...
...
然后 Jenkins 重新构建就成功了!
8. Shell 命令
选择增加构建步骤,在下拉框选中执行 shell
输入下面指令:
#!/bin/bash
node -v
npm -v
echo $PATH
之后去构建,可以看到我们打印的版本信息都打印出了
接下来我们脚本中执行安装
node_module以及打包命令。
#!/bin/bash
node -v
npm -v
npm install
# npm i esbuild-linux-64@0.13.4 -D
echo "依赖安装成功"
npm run build
echo "打包成功"
echo $PATH
然后先点击应用后保存,去立即构建。 如果构建出现这个错误(Error: The package "@esbuild/linux-x64" could not be found, and is needed by esbuild.),就取消npm i esbuild-linux-64@0.13.4 -D注释。
【注意】:我把前端项目和docker配置放在了同一个仓库地址了,可以参考一下我的目录结构:
+ client -前端项目
+ docker -配置
+ compose
+ html
+ jenkins_home
+ nginx
- .gitignore
- README.md
所以我需要修改jenkins的构建步骤shell:
#!/bin/bash
set -e
cd client
node -v
npm -v
test -f package.json || {
echo "错误:client 目录下不存在 package.json"
exit 1
}
npm ci
echo "依赖安装成功"
npm run build
test -d dist || {
echo "错误:构建完成,但没有生成 dist 目录"
exit 1
}
echo "打包成功"
echo "构建产物:"
find dist -maxdepth 2 -type f -print
echo "PATH=$PATH"
9. 自动部署到对应环境项目目录
上面打包到了jenkins中的workspace中 docker/jenkins_home/workspace/测试项目/client/dist,但是我们设置的项目环境路径跟这个不同,比如开发环境项目目录是 /docker/html/dev/dist,所以需要打包后,把dist文件内容推送到 /docker/html/dev/dist/ 目录下。修改一下上面的脚本,改为下面:
#!/bin/bash
node -v
npm -v
npm install
# npm i esbuild-linux-64@0.13.4 -D
echo "依赖安装成功"
npm run build
echo "打包成功"
rm -rf dist.tar #每次构建删除已存在的dist压缩包
tar -zcvf dist.tar ./dist #将dist文件压缩成dist.tar
echo $PATH
【注意】:我把前端项目和docker配置放在了同一个仓库地址了,所以上面的脚本,改为下面的:
#!/bin/bash
set -e
cd client
node -v
npm -v
test -f package.json || {
echo "错误:client 目录下不存在 package.json"
exit 1
}
npm ci
echo "依赖安装成功"
npm run build
test -d dist || {
echo "错误:构建完成,但没有生成 dist 目录"
exit 1
}
echo "打包成功"
echo "构建产物:"
find dist -maxdepth 2 -type f -print
# ========== 新增:部署到开发环境 ==========
DEPLOY_DIR="/html/dev/dist"
echo "开始部署到 ${DEPLOY_DIR}"
# 确保目标目录存在
mkdir -p "${DEPLOY_DIR}"
# 清空旧产物(保留目录本身,避免残留已删除文件)
rm -rf "${DEPLOY_DIR:?}"/*
# 复制新构建产物(dist/ 内容 → 目标目录)
cp -r dist/. "${DEPLOY_DIR}/"
echo "部署完成,目标目录内容:"
ls -la "${DEPLOY_DIR}"
【注意】由于我Jenkins 和 Nginx 是同一台机器上的两个 Docker 容器,通过 volume 共享文件就能完成部署,所以下面的步骤我不需要!
然后点击增加构建步骤,选择 Send files or execute commands over SSH,这个命令允许你在构建过程中通过SSH连接到远程服务器执行命令或发送文件。
然后填写源文件、目标路径、执行脚本
cd /docker/html/dev
rm -rf dist/
tar zxvf dist.tar
rm dist.tar
打包流程是:删除之前打包的 tar 压缩文件 dist,把本次打包的 dist 文件压缩,然后以压缩后的 dist.tar 为源文件,连接远程服务器,放到 docker/html/dev 目录下。然后删除 dist 目录,解压刚刚远道而来的 dist.tar 文件,之后删除压缩包。
- Source files: 准备发送的文件,该文件是相对于这个项目的 workspace 目录。例如要发送 /docker/jenkins_home/workspace/gitlab_web/dist.tar 到目标目录,则设置 Source files 为 dist.tar
- Remove prefix: 目标目录,本案例要复制到 dev 环境下的 dist 文件,/docker/html/dev
- Exec Command: 最后执行的命令,可在这里进行解压,删除,复制等操作
最后再次执行 立即构建。打开 你的服务器地址:8001(我的是 http://localhost:8001/ ),然后就可以看到刚刚部署的项目啦。
六、踩坑记录
任务里虽然勾选了 GitHub Push 触发器,但 Jenkins 地址是 localhost,GitHub 服务器无法访问我电脑上的回调地址,所以任务配置里我把触发器改成 Poll SCM:
# 含义:每 5 分钟检查一次 GitHub,有新提交就自动构建
H/5 * * * *
或者你可以把本地 Jenkins 暴露成一个公网地址,给 GitHub webhook 用。用 ngrok:
# 安装
brew install ngrok
# 暴露 Jenkins 端口(假设 8080)
ngrok http 8080
执行后会给你一个公网地址,比如 https://xxxx.ngrok-free.app 。然后在 GitHub 仓库:
Settings → Webhooks → Add webhook- Payload URL:
https://xxxx.ngrok-free.app/github-webhook/ - Content type:
application/json - 勾选
Just the push event
七、最后
恭喜你,已经学会 Docker + Jenkins + Nginx 前端自动化部署 啦~