生产环境VueJS应用更新需删除docker卷导致停机问题咨询
问题根因
- 命名卷
frontend_dist的特性导致旧代码残留:Docker命名卷首次挂载到容器路径时,会自动将容器内该路径的现有内容复制到卷中。但后续重建容器时,只要卷未被删除,就会直接复用卷内的旧数据,不会用新构建容器里的最新dist文件覆盖,这是必须手动删除卷才能更新的核心原因。 - 移除挂载后nginx报错的原因:当前Vue项目的Dockerfile只有构建阶段,执行完
npm run build生成dist后容器就直接退出,没有常驻进程。之前的架构依赖frontend_dist卷把前端构建产物共享给nginx服务,移除挂载后nginx的/app/dist路径为空,没有静态文件可以访问,自然返回403禁止错误。
无停机更新解决方案
方案一:合并静态文件到Nginx镜像(最推荐,彻底移除共享卷依赖)
该方案直接把Vue构建产物打包进Nginx镜像,完全废弃frontend_dist共享卷,从根源解决卷内容不更新的问题。
步骤1:调整前端Dockerfile
在mkstat_frontend目录下修改Dockerfile.prod为完整的多阶段构建,最终输出包含静态文件的Nginx镜像:
# 构建阶段:原有逻辑不变,生成dist产物 FROM node:lts-alpine as build WORKDIR /app ENV PATH /app/node_modules/.bin:$PATH COPY package.json /app/package.json RUN npm install --silent RUN npm install @vue/cli@4.5.13 -g COPY . /app RUN npm run build # 运行阶段:把构建产物放到Nginx镜像的对应路径 FROM nginx:alpine # 注意:如果你的Nginx配置里静态文件根目录是/app/dist,就复制到/app/dist,不用走默认的/usr/share/nginx/html COPY --from=build /app/dist /app/dist
步骤2:修改docker-compose.yml配置
- 移除原来独立的
frontend服务块 - 修改
nginx服务配置,删掉原有的镜像声明和frontend_dist卷挂载,改为从前端Dockerfile构建:
services: nginx: # 删掉原有的image: nginx:alpine配置,替换为以下build配置 build: context: ./mkstat_frontend dockerfile: Dockerfile.prod restart: unless-stopped command: '/bin/sh -c ''while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"''' container_name: nginx ports: - "80:80" - "443:443" volumes: - ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf - ./docker/certbot/conf:/etc/letsencrypt - ./docker/certbot/www:/var/www/certbot - static:/var/html/static - media:/var/html/media # 删掉原有的frontend_dist挂载行 depends_on: - backend # 删掉原有的frontend依赖 # 其他服务配置保持不变 volumes: pgdata: static: media: # 删掉原有的frontend_dist卷声明 redis:
步骤3:低感知更新(单节点适用)
后续执行以下命令即可完成更新,容器切换间隔仅数百毫秒,用户基本无感知:
docker-compose up --build --force-recreate --no-deps -d nginx
如果需要完全零停机,可以在Nginx服务下增加滚动更新配置,配合Docker Swarm模式使用:
services: nginx: # 其他配置不变 deploy: replicas: 2 update_config: order: start-first failure_action: rollback delay: 10s
方案二:保留现有架构,自动更新卷内容
如果不想调整现有服务拆分逻辑,可以通过修改启动命令实现无需手动删卷的无停机更新。
步骤1:修改frontend服务配置
调整docker-compose.yml中的frontend服务,修改挂载路径和启动命令,强制每次构建后覆盖卷内容:
frontend: container_name: frontend build: context: ./mkstat_frontend dockerfile: Dockerfile.prod # 新增启动命令,构建完把dist复制到挂载卷后直接退出 command: sh -c "rm -rf /dist-volume/* && cp -r /app/dist/* /dist-volume/ && exit 0" volumes: # 挂载到独立路径,避免卷自动覆盖容器内构建好的dist目录 - frontend_dist:/dist-volume depends_on: - backend
步骤2:执行无停机更新命令
# 构建前端镜像并更新卷内的静态文件 docker-compose up --build --no-deps -d frontend # 平滑重载Nginx配置,完全不中断现有请求 docker-compose exec -T nginx nginx -s reload
内容的提问来源于stack exchange,提问作者karambaq
相关产品推荐
相关产品推荐

