《从零到一:Docker部署全栈项目实操指南(附避坑清单)》
目录导读
- 全栈容器化的核心价值:为何你的项目必须用Docker?
- 前后端分离的镜像构建实战:从Dockerfile到多阶段构建
- Nginx反向代理 + 数据库容器化编排
- docker-compose一键部署:网络、环境变量与数据持久化
- 生产环境踩坑记录:权限、跨域、日志与性能调优
- 问答环节:关于Docker部署的5个高频问题
全栈容器化的核心价值
传统部署方式中,前端(React/Vue)、后端(Node.js/Java/Python)、数据库(MySQL/MongoDB)运行时环境若不一致,极易出现“在我电脑上能跑”的尴尬,Docker通过容器化将应用及依赖打包为标准镜像,确保开发、测试、生产环境一致。
实操收益:
- 环境隔离:每个微服务独立容器,互不干扰
- 快速伸缩:基于Kubernetes可水平扩展容器实例
- 版本控制:每个镜像对应特定代码Commit
前后端分离的镜像构建实战
前端镜像:Nginx多阶段构建
# 构建阶段 FROM node:18-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build # 运行阶段 FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
技巧:使用
.dockerignore排除node_modules、.env等文件,减小镜像体积。
后端镜像:轻量级运行
FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 3000 CMD ["node", "app.js"]
避坑:若后端依赖sharp等C++库,需安装build-base、python3等编译工具,建议使用node:18-slim基础镜像代替alpine以减少兼容问题。
Nginx反向代理 + 数据库容器化编排
Docker-compose.yml 核心配置:
version: '3.8'
services:
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
networks:
- app-net
backend:
build: ./backend
environment:
- DB_HOST=mariadb
- DB_USER=root
- DB_PASSWORD=secret
ports:
- "3000:3000"
depends_on:
- mariadb
networks:
- app-net
mariadb:
image: mariadb:10.11
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: myapp
volumes:
- db-data:/var/lib/mysql
networks:
- app-net
volumes:
db-data:
networks:
app-net:
关键点:
- 网络隔离:所有服务共享
app-net,通过服务名(如backend)互相访问,无需IP绑定 - 数据持久化:数据库挂载命名卷
db-data,防止容器重启丢失数据 - 端口暴露:仅前端暴露80端口,后端和数据库不对外暴露更安全
docker-compose一键部署
# 在项目根目录执行 docker-compose up -d --build
生产环境优化建议:
- 环境变量外置:使用
.env文件,在compose中通过${VARIABLE}引用 - 健康检查:为后端添加
healthcheck,确保服务就绪后再启动Nginx - 日志切割:配置
logging驱动限制日志文件大小,避免磁盘爆满
生产环境踩坑记录
① 权限与用户映射
容器默认以root运行,挂载宿主机目录时可能产生文件所有权问题。
解决:在Dockerfile中创建特定用户(如node),并赋予挂载目录读写权限。
② 跨域请求失败
前后端不同容器端口时,浏览器可能拦截跨域请求。
解决:Nginx统一转发,配置如下:
location /api/ {
proxy_pass http://backend:3000/;
add_header Access-Control-Allow-Origin *;
}
③ 容器时区不一致
默认UTC时区导致日志时间偏差。
解决:在docker-compose中添加环境变量TZ=Asia/Shanghai,或挂载宿主机时区文件。
④ 性能调优
- 减少镜像层:合并
RUN指令,使用apt-get update && apt-get install -y - 使用Alpine镜像:体积缩小60%,但注意部分依赖需额外编译工具
问答环节:关于Docker部署的5个高频问题
Q1:Docker容器中的数据库如何备份?
A:使用docker exec导出SQL文件:docker exec mariadb-container mysqldump -u root -p myapp > backup.sql,或挂载卷定时备份backup目录。
Q2:如何更新部署?
A:只需修改代码后重新docker-compose up -d --build,Docker会自动使用新镜像重建更改的服务。
Q3:容器日志占用磁盘太多怎么办?
A:在docker-compose.yml中添加:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Q4:是否必须使用docker-compose?
A:小型项目可用;但多服务场景强烈推荐Compose(或K8s),让部署步骤从10步缩至1条命令。
Q5:前端静态资源如何更新而不重建镜像?
A:使用volumes挂载宿主机静态文件目录,但生产环境应走CDN + 持续部署流水线。