文章目录
记录一次前端部署的子包的过程: 之前是前端项目打包成docker容器,暴漏出一个端口,在宿主机nginx中配置域名直接反向代理到前端的ip:端口项目。
现在的需求是加个后缀,因为业务的需要,比如原来是 aa.com访问,现在希望 aa.com/xxx 方式访问。
比如我现在想加个shop,通过aa.com/shop/访问,如何配置呢?
现在先给出原来的的代码,然后给出具体修改的地方
之前的部署文件
项目目录

Dockerfile
js
FROM nginx:stable
MAINTAINER hufanglei
ADD default.conf /etc/nginx/conf.d/default.conf
COPY dist-prod/ /usr/share/nginx/html/
default.conf
js
# 隐藏nginx版本
server_tokens off;
# 在某些浏览器上禁用内容类型嗅探。
add_header X-Content-Type-Options nosniff;
# 此标头启用跨站点脚本 (XSS) 过滤器
add_header X-XSS-Protection "1; mode=block";
# X-Frame-Options 是为了防止clickJacking攻击
# DENY:不允许在 frame 中展示#
# SAMEORIGIN:允许在相同域名下frame展示
# ALLOW-FROM https://example.com/ :指定来源的 frame 中展示
# add_header X-Frame-Options SAMEORIGIN;
# 开启gzip
gzip on;
# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;
# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 5;
# 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
# 禁用IE 6 gzip
gzip_disable "MSIE [1-6]\.";
# 设置压缩所需要的缓冲区大小
gzip_buffers 32 4k;
# 设置gzip压缩针对的HTTP协议版本
gzip_http_version 1.0;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
# 带前缀方式的将 ${SERVER_NAME}替换为对应前缀名称即可,若访问直接在根目录下去掉${SERVER_NAME},去掉多余的/
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;#根据官网这规则配置
expires 5m;
}
# 若访问直接在根目录下,注释下面三行
# location = / {
# return 301 $scheme://$host/organization/mgt;
# }
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
jenkinsfile
js
def docker_image //定义全局的镜像变量
def docker_image_name
pipeline {
/*
1.配置docker仓库相关变量 系统环境变量:DOCKER_REGISTRY_ADDR [docker仓库地址]
credentials-[Username with password]类型:jenkins-docker-registry-creds[docker仓库账号/docker仓库密码]
2.配置docker客户端访问的证书 系统环境变量:NAME_SPACE
credentials-[X.509 Client Certificate]类型:jenkins-docker-client-creds[docker客户端凭证]
合计:1个docker仓库地址环境变量,3个credentials为必须配置;
`参考文档`:https://www.jenkins.io/zh/doc/book/pipeline/jenkinsfile
`编写语法参考 `:http://groovy-lang.org/semantics.html
*/
// 如果指定具体的节点执行,请 agent { label 'docker-slave' }
agent any
options {
//超时一小时
timeout(time: 1, unit: 'HOURS')
//不允许同时执行
disableConcurrentBuilds()
}
// #######################需要修改的区域 开始#################################
/**
* 一般情况下只需要修改environment与parameters区域的
*/
environment {
// 服务的域名,一般与项目名称相同
DOMAIN_NAME = 'xxxx'
// 表示限制内存大小,单位为M,只能为数字;
LIMIT_MEMORY = 2048
// docker仓库地址,一般与系统环境变量相同,若相同时手动修改
DOCKER_REGISTRY_ADDR = "${env.DOCKER_REGISTRY_ADDR}"
// docker仓库账号密码--对应系统环境变量DOCKER_REGISTRY_ADDR
DOCKER_REGISTRY = credentials('jenkins-docker-registry-creds')
// 名称空间
NAME_SPACE = 'jingke'
}
parameters {
// 项目名称
string(name: 'module', defaultValue: "xxx", description: '发布的项目')
/* 以下4项参数需要配置到jenkins工程的参数中 */
string(name: 'container_port', defaultValue: "49013", description: '容器端口')
string(name: 'docker_remotes', defaultValue: "1.14.5.15", description: '远程docker的api地址列表,以","隔开')
string(name: 'is_tls', defaultValue: "true", description: 'docker的api访问是否开启tls认证')
// 服务部署扩展的环境变量,eg
// choice(name: 'init_env', choices: ['-e APP_URL=htt://xxx '], description: '服务部署扩展的环境变量')
/* 以下配置为jenkins工程必须设置 */
// 配置Tag的git参数,参数类型 设置为 分支或标签
// 配置git地址:在流水线 -> 定义[Pipeline script from SCM] -> SCM[git] -> Repository URL[git地址]
// -> Credentials[git账号] -> 指定分支(为空时代表any)[${Tag}] --> 脚本路径[Jenkinsfile文件的工程路径]
// -> 轻量级检出[去掉√ ]
}
// ########################需要修改的区域 结束################################
stages {
stage('Run node') {
agent {
docker {
image 'node:20'
reuseNode true
}
}
steps {
sh "node -v && npm -v && npm config set registry https://registry.npmmirror.com && npm install && npm run build "
}
}
stage('Build And Push Docker Image') {
steps {
script {
// 获取标签版本或者分支的commitId
if (!params.Tag || params.Tag.contains('origin/')) {
sh "git rev-parse --short HEAD > commit-id"
tag = readFile('commit-id').replace("\n", "").replace("\r", "")
} else {
tag = "$params.Tag"
}
// 赋值镜像名称
docker_image = "${env.DOCKER_REGISTRY_ADDR}/${name_space}/${params.module}-main:$tag"
docker_image_name = "${env.DOCKER_REGISTRY_ADDR}/${name_space}/${params.module}-main"
// 编译镜像
sh "rm -rf cicd/main/dist-prod && mv dist-prod cicd/main"
sh "docker build -t $docker_image cicd/main"
}
echo "完成DOCKER镜像打包......"
sh "docker login ${DOCKER_REGISTRY_ADDR} --username=${DOCKER_REGISTRY_USR} --password=${DOCKER_REGISTRY_PSW}"
sh "docker push $docker_image"
sh "docker rmi $docker_image"
}
}
stage('Deploy to docker') {
environment {
// docker客户端证书凭证,若不需要ssl访问则注释
DOCKER_CERT_PATH = credentials('jenkins-docker-client-creds-hiband')
}
steps {
script {
container_port = 80
container_port_map = ""
docker_client_env = ""
if (params.container_port) {
container_port = "${params.container_port}"
container_port_map = " -p ${params.container_port}:80 "
}
if (params.docker_remotes) {
def docker_remote_arr = "${params.docker_remotes}".split(",")
// 部署服务处理
for (int i = 0; i < docker_remote_arr.size(); ++i) {
docker_remote = "${docker_remote_arr[i]}"
docker_client_env = "export DOCKER_TLS_VERIFY=1; export DOCKER_HOST=tcp://${docker_remote}:2376; docker_remote=${docker_remote};"
sh "$docker_client_env docker rm -f $DOMAIN_NAME"
//部署服务
sh "$docker_client_env docker run -d --name ${DOMAIN_NAME} --restart=always \
-e TZ='Asia/Shanghai' -e CONTAINER_PORT=${container_port} -m ${LIMIT_MEMORY}M \
$container_port_map -v /etc/localtime:/etc/localtime:ro \
$docker_image"
echo "清理过时的镜像"
sh "$docker_client_env docker images $docker_image_name -q --filter before=$docker_image | xargs --no-run-if-empty docker rmi "
}
}
}
}
}
}
post {
always {
echo '执行完成。'
sh 'rm -rf .dockerignore'
}
success {
echo '发布成功! please visit : https://aaa.com'
}
unstable {
echo '发布不稳定哦...'
}
failure {
echo '发布失败啦,请查明原因哦!'
}
changed {
echo '与之前信息有所不同哦...'
}
}
}
前端的vite配置
java
// https://vitejs.dev/config/
export default defineConfig(({command, mode}) => {
const env = loadEnv(mode, process.cwd());
return {
...
root: process.cwd(),
base: env.VITE_APP_BASE_URL || '/',
resolve: {
alias: {
'@': resolve('src'),
'assets': resolve('src/assets'),
},
extensions: ['.ts', '.js'],
},
...
router.js
java
...
const router = createRouter({
history: createWebHistory(),
routes,
})
...
宿主机的ngin配置
java
server {
listen 80;
listen [::]:80;
server_name xx.com;
server_tokens off;
gzip on;
gzip_static on;
gzip_buffers 4 16k;
gzip_comp_level 5;
gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
location / {
return 301 https://$host$request_uri;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
# hiband 443
server {
listen 443 ssl;
server_name xx.com;
server_tokens off;
ssl_certificate /xxx/cert.crt;
ssl_certificate_key /xxx/cert.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
# root /usr/share/nginx/html/aisprint-pro-online-main;
location / {
# try_files $uri $uri/ /index.html;
proxy_pass http://x.x.x.x:49013/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
修改后的代码
Dockerfile
js
FROM nginx:stable
MAINTAINER hufanglei
ADD default.conf /etc/nginx/conf.d/default.conf
#COPY dist-prod/ /usr/share/nginx/html/
RUN mkdir -p /usr/share/nginx/html/shop
COPY dist-prod/ /usr/share/nginx/html/shop/
jenkinsfile不用变
容器内的dockerfile
js
erver {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
# 带前缀方式的将 ${SERVER_NAME}替换为对应前缀名称即可,若访问直接在根目录下去掉${SERVER_NAME},去掉多余的/
location /hstub/ {
alias /usr/share/nginx/html/shop/;
index index.html;
try_files $uri $uri/ /shop/index.html;#根据官网这规则配置
expires 5m;
}
前端vite
js
export default defineConfig(({command, mode}) => {
const env = loadEnv(mode, process.cwd());
return {
plugins: [vue(),
...
],
root: process.cwd(),
// 关键代码
base: '/shop/',
...
router.js
java
const router = createRouter({
history: createWebHistory("shop"),
routes,
})
宿主机的ngin配置
java
erver {
listen 443 ssl;
server_name xx.com;
....
location /shop/ {
proxy_pass http://xxx:49014/shop/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
总结
Vite 前端源码
│ build
▼
dist-prod/\] ← 打包输出(base: /shop/) │ ▼ \[Docker 镜像构建\] → Docker 内 nginx │ RUN mkdir -p /usr/share/nginx/html/shop ▼ \[容器内 nginx 服务
│ proxy_pass
▼
宿主机 nginx\] → 外网访问 > 说明: > Vite 打包生成 /dist-prod(JS/CSS + index.html),资源路径自动加 /shop/ > > Dockerfile 内部创建 /shop 目录并拷贝 dist > > Docker 内 nginx 根据 /shop / 规则 serve SPA\>宿主机 nginx 根据 location /shop / 转发到容器 IP:PORT > > 浏览器访问 /shop/→ nginx → Docker nginx → 前端资源 *** ** * ** *** 大功告成!