一、整体架构设计
1.多容器协作模式
Docker
部署 Vue
(前端)和 Node.js
(后端)的 Web 服务,通常采用 多容器协作模式:
前端容器:基于
Nginx
镜像托管Vue
构建产物(如dist
目录)。后端容器:基于
Node.js
镜像运行API
服务,处理数据库MySQL
交互和业务逻辑。数据库容器:如
MySQL
或Redis
,通过数据卷持久化存储数据。Jenkins 容器:自动化构建与部署流水线控制中心。
Nginx 容器:反向代理前端请求,支持多域名配置。
网络与通信
- 使用
Docker
自定义网络(如my-network
)确保容器间通过服务名互通。 Nginx
通过proxy_pass
将API
请求转发至后端容器(如http://backend:3000
)。
2.整体架构
+----------+----------+
+---------------------+
| Nginx | # 反向代理/静态资源/多站点
+----------+----------+
|
+----------v----------+ +------------------+
| Vue Frontend | | Node.js Backend|
+----------+----------+ +--------+---------+
| |
+----------v------------------------v---------+
| Docker Network |
+----------+------------------+--------------+
| |
+----------v----------+ +-----v--------------+
| MySQL Container | | Redis Container |
+---------------------+ +--------------------+
3.分步部署指南
project/
├── frontend/ # Vue项目
│ ├── Dockerfile
│ ├── jenkinsfile
│ └── Vue项目文件
├── backend/ # Node.js项目
│ ├── Dockerfile
│ ├── jenkinsfile
│ └── Node.js项目文件
├── nginx/
│ ├── conf.d/
│ │ ├── site1.conf # 站点配置
│ │ └── site2.conf
│ └── nginx.conf
├── docker-compose.yml
└── jenkins/
└── jenkinsfile # 主部署脚本
二、分步部署指南
1. 前端 Vue 项目容器化
步骤 1:编写 Dockerfile
在 Vue 项目根目录创建 Dockerfile
,采用 多阶段构建 优化镜像体积:
# 第一阶段:构建项目
FROM node:latest AS build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install --registry=https://registry.npmmirror.com
COPY . .
RUN npm run build
# 第二阶段:生产环境 部署到 Nginx
# nginx:latest 是基于 Debian 或 Ubuntu 的完整 Nginx 镜像,包含了所有 Nginx 的功能和模块。
FROM nginx:latest
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
关键点:
- 使用
node:latest
安装依赖并构建,减少镜像层大小。 - 使用
.dockerignore
忽略node_modules
和.env
敏感文件。 - 通过
nginx.conf
配置反向代理(如后端 API 地址)。
步骤 2:构建并运行前端容器
docker build -t vue-app . # 使用 Dockerfile 从当前目录构建一个名为 vue-app 的 Docker 镜像
docker run -d -p 80:80 --name vue-container vue-app #运行一个基于 vue-app 镜像的容器,将其命名为 vue-container,并且将容器的 80 端口映射到主机的 80 端口。
2. 后端 Node.js 项目容器化
步骤 1:编写 Dockerfile
在 Node.js 项目根目录创建 Dockerfile
:
FROM node:latest
WORKDIR /app
COPY package*.json ./
RUN npm install --production --registry=https://registry.npmmirror.com
COPY . .
ENV MYSQL_HOST=mysql REDIS_HOST=redis
EXPOSE 3000
CMD ["npm", "start"]
关键点:
- 使用
npm install --production
仅安装生产依赖。 - 通过环境变量(如
.env
)配置数据库连接信息。 - 通过环境变量注入
MySQL
和Redis
连接信息。 - 在
backend
容器内使用ping mysql
和telnet redis 6379
验证连通性。
步骤 2:构建并运行后端容器
docker build -t node-api . # 使用 Dockerfile 从当前目录构建一个名为 node-api 的 Docker 镜像
docker run -d -p 3000:3000 --name api-container node-api #运行一个基于 node-api 镜像的容器,将其命名为 api-container,并且将容器的 3000 端口映射到主机的 3000 端口。
3. 数据库容器与数据持久化
使用 MySQL 容器:
docker run -d \
--name mysql-container \
--env-file .env \ # 加载 .env 文件中的所有变量
-v mysql-data:/var/lib/mysql \
# -e MYSQL_ROOT_PASSWORD=your_password \
# -e MYSQL_DATABASE=your_db \
-p 3306:3306 \
--network my-network \
mysql:latest
关键点:
-v mysql-data:/var/lib/mysql
通过数据卷持久化数据库。- 在
Node.js
代码中通过process.env.MYSQL_HOST
读取环境变量。 - 通过数据卷
mysql-data
持久化数据,避免容器重启后数据丢失。
4. Nginx 多站点配置
示例 nginx/conf.d/site1.conf
server {
listen 80;
server_name example.com;
# 前端
location / {
proxy_pass http://frontend;
proxy_set_header Host $host;
}
# 后端API
location /api/ {
proxy_pass http://backend:3000;
proxy_set_header Host $host;
}
}
关键点:
每个域名对应独立的
server
块,支持 SSL 证书挂载(需 Certbot 自动化)。前端静态文件路径与容器内目录映射一致。
docker-compose.yml 片段
services:
nginx:
image: nginx:latest
volumes:
- ./nginx/site1.conf:/etc/nginx/conf.d/site1.conf
- ./nginx/site2.conf:/etc/nginx/conf.d/site2.conf
ports:
- "80:80"
- "443:443"
networks:
- my-network
5.Redis 容器
docker run -d \
--name redis \
-v redis-data:/data \
-v ./redis.conf:/usr/local/etc/redis/redis.conf \
--network my-network \
redis redis-server /usr/local/etc/redis/redis.conf
关键点:
- 挂载自定义配置文件
redis.conf
,设置密码和内存限制(如requirepass your_redis_pass
和maxmemory 512mb
)。
6. Jenkins 自动化部署
Jenkins 容器启动
docker run -d \
--name jenkins \
-p 8080:8080 -p 50000:50000 \
-v jenkins-data:/var/jenkins_home \
--network my-network \
jenkins/jenkins:lts
关键点:
- 挂载
jenkins-data
卷保存配置,安装插件(Git、Publish Over SSH、Pipeline)。
Pipeline 脚本示例(jenkins/jenkinsfile
)
pipeline {
agent any
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/your-repo.git'
}
}
stage('Build Frontend') {
steps {
dir('frontend') {
sh 'docker build -t vue-app .'
}
}
}
stage('Build Backend') {
steps {
dir('backend') {
sh 'docker build -t node-api .'
}
}
}
stage('Deploy') {
steps {
sh 'docker-compose down && docker-compose up -d'
}
}
}
post {
success {
slackSend(color: '#00FF00', message: 'Deployment succeeded')
}
failure {
slackSend(color: '#FF0000', message: 'Deployment failed')
}
}
}
关键点:
- 通过
docker-compose.yml
统一管理服务启动顺序和依赖。
三、整合服务Docker Compose
编排
在项目根目录创建 docker-compose.yml
,统一管理多服务:
# version: "3.8" # Docker Compose V2+ 版本移除了对 version 字段的支持,继续保留该字段会导致警告(但不会影响运行)。
name: vue_project # 定义项目名称
services:
# 前端服务
frontend:
build:
context: ./vue-app
dockerfile: Dockerfile
container_name: vue-container
restart: always
ports:
- "8080:80"
depends_on:
- backend
networks:
- app-network
# Node.js后端服务
backend:
build:
context: ./node-api
# args:
# # 构建时传参
# NPM_REGISTRY: "https://registry.npmmirror.com"
dockerfile: Dockerfile
container_name: api-container
restart: always
env_file: .env # 直接指向文件
# command: npm run dev # 开发模式启用热重载
environment:
# npm 镜像源
- NPM_CONFIG_REGISTRY="https://registry.npmmirror.com"
- NODE_ENV=production
- DB_HOST=mysql
- DB_USER=root
- DB_PASSWORD=${MYSQL_ROOT_PASSWORD} #your_mysql_root_password
- DB_NAME=${MYSQL_DATABASE} #your_database_name
- REDIS_HOST=redis
- REDIS_PORT=6379
ports:
- "3000:3000"
volumes:
# 持久化 npm 缓存(加速后续构建)
- ./npm_cache:/root/.npm
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app-network
#Nginx反向代理
nginx:
image: nginx:latest
container_name: nginx-proxy
restart: always
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
ports:
- "80:80"
- "443:443"
depends_on:
- frontend
- backend
networks:
- app-network
#MySQL数据库
mysql:
image: mysql:latest
container_name: mysql-container
restart: always
env_file: .env # 直接指向文件
environment:
# 🌟 基础配置(必须项) 🌟
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} #your_password 设置 root 用户的密码
MYSQL_DATABASE: ${MYSQL_DATABASE} #your_database 创建的数据库名称(可选)
# 🔒 高级安全配置(新增部分) 🔒
MYSQL_ROOT_HOST: "%" # '%' 允许 root 用户从任意 IP 访问,生产环境强烈建议关闭;'localhost' 仅允许本机访问
# MYSQL_USER_HOST: "%" # 允许普通用户从任意 IP 访问,生产环境强烈建议关闭
# MYSQL_SSL_MODE: "REQUIRED" # 强制SSL连接
# MYSQL_SSL_CA: "/etc/ssl/certs/ca-certificates.crt" # SSL证书路径
# 🔐 其他配置(可选) 🔐
TZ: "Asia/Shanghai" # 设置容器时区为上海时间
volumes:
- mysql_data:/var/lib/mysql
# - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql # 自定义初始化脚本目录
ports:
- "3306:3306"
# 明确启动命令
command: ["mysqld", "--character-set-server=utf8mb4"]
networks:
- app-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 10s
retries: 10
logging: # Docker 的日志配置
driver: "json-file" # 使用文件日志
options:
max-size: "200m"
max-file: "10"
#Redis缓存
redis:
image: redis:latest
container_name: redis-cache
restart: always
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- app-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 10s
retries: 10
#Jenkins自动化部署
jenkins:
image: jenkins/jenkins:lts
container_name: jenkins-cli
restart: unless-stopped
user: root
ports:
- "8081:8080"
- "50000:50000"
volumes:
- jenkins_data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- ./:/var/jenkins_workspace
networks:
- app-network
# kuma 网络监听
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: always
volumes:
- ./uptime-kuma:/var/lib/kuma/data
ports:
- 30001:30001
networks:
- app-network
#数据卷定义
volumes:
mysql_data:
redis_data:
jenkins_data:
kuma_data:
#网络定义
networks:
app-network:
driver: bridge
# .env 文件
MYSQL_ROOT_PASSWORD=my-secret-pw
MYSQL_DATABASE=appdb
MYSQL_USER=appuser
MYSQL_PASSWORD=apppw
# 环境变量
ENVIRONMENT=dev
关键点:
- 通过
depends_on
控制服务启动顺序。 - 使用共享网络确保容器间通过服务名通信(如
backend
访问mysql
)。
总结
通过 Docker Compose
编排,我们可以将多个容器组合成一个应用,实现服务的统一管理和部署。同时,通过 docker-compose.yml
配置文件,我们可以定义服务的依赖关系、网络配置和数据卷挂载,简化了容器的启动和管理过程。
1.部署流程说明:
- Jenkins 配置流水线任务,监听代码仓库变更
- 触发构建时自动执行:
- 前端:npm install && npm run build
- 后端:npm install && 运行测试
- 通过 Docker 命令重新构建镜像并重启容器
- 使用 Webhook 通知部署状态
2.使用前需要:
- 替换所有密码(your_mysql_root_password)
- 配置 Nginx 的域名和 SSL 证书
- 根据项目需求调整端口和路径
- 配置 Jenkins 流水线脚本
- 添加.env 文件管理敏感信息(推荐)
3.建议的安全增强措施:
- 为 MySQL 创建专用用户代替 root
- 使用 Docker secrets 管理敏感信息
- 添加适当的容器资源限制
- 配置 Redis 密码保护
- 启用 Nginx 的 HTTPS 配置
- 设置防火墙规则限制外部访问
四、 初始化及启动
# 创建网络
docker network create app-network
# 启动所有服务
docker-compose up -d --build
# 查看日志
docker-compose logs -f
针对项目中的容器名(根据 docker-compose.yml
定义)
容器名 | 服务用途 | 推荐进入命令 |
---|---|---|
mysql-container |
MySQL 数据库 | docker exec -it mysql-container mysql -u root -p |
api-container |
Node.js 后端 | docker exec -it api-container sh |
vue-container |
Vue 前端 | docker exec -it vue-container sh |
redis-cache |
Redis 缓存 | docker exec -it redis-cache redis-cli |
nginx-proxy |
Nginx 反向代理 | docker exec -it nginx-proxy nginx -t |
五、关键注意事项及优化建议
1.注意事项
- 环境变量管理:
- 使用
.env
文件管理敏感信息 - 在 Docker Compose 中使用
env_file
配置
- 数据持久化:
volumes:
- ./mysql/data:/var/lib/mysql
- ./redis/data:/data
- 集群扩展:
docker-compose scale backend=3
- 健康检查:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
2.优化与扩展
镜像加速:在
Dockerfile
中配置国内镜像源(如npmmirror.com
)提升构建速度。负载均衡:通过
pm2
启动Node.js
服务,支持多进程和自动重启。安全与性能:
- 使用
.dockerignore
忽略node_modules
和敏感文件。 - 通过
nginx.conf
配置HTTPS
和Gzip
压缩。 - HTTPS 配置:在
Nginx
配置中添加SSL
证书,使用Let's Encrypt
自动更新SSL
证书。 - Redis 优化:启用
AOF
持久化,设置内存淘汰策略(如maxmemory-policy allkeys-lru
)。 - MySQL 备份:通过
Cron
定时任务导出数据库至宿主机。
- 自动化流程整合
- 配置 GitLab Webhook:代码提交后触发
Jenkins Pipeline
。 - 钉钉通知插件:部署结果实时推送至团队群。
- 横向扩展
- 负载均衡:
Nginx
配置upstream
实现后端多容器负载。 - Redis 集群:使用
Docker Swarm
或Kubernetes
扩展Redis
节点。
六、常见问题排查
环境变量未生效:确认 Dockerfile 或
docker-compose.yml
中变量传递正确。容器网络不通:
- 检查
docker-compose.yml
中的服务名和端口映射。 - 检查
Docker
网络配置,确保depends_on
和自定义网络正确
- 检查
依赖安装失败:确认
package.json
中依赖版本与Node.js
镜像版本兼容。数据库连接超时:确保
MySQL
容器已启动且环境变量正确。Nginx 403 错误:检查静态文件目录权限(如
chown -R www-data:www-data /var/www
)。无权限进入容器:添加
--user root
参数容器未运行:先执行
docker start [容器名]
命令不存在:改用镜像内置的命令(如 Redis 用
redis-cli
)
超时报错
安装 docker 镜像时,抛出Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
解决方法:
sudo vi /etc/resolv.conf
#删掉默认的nameserver地址在后面增加
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 114.114.114.114
#从新加载
systemctl restart systemd-resolved.service
七、常用运维命令
# 进入正在运行的容器
docker exec -it [容器名或ID] [执行的命令]
# 进入容器默认 shell(适用于大多数镜像)
docker exec -it mysql-container sh # Alpine 系镜像用 sh
docker exec -it api-container bash # Debian/Ubuntu 系镜像用 bash
# 直接运行特定命令(不进入交互模式)
# 在 MySQL 容器中执行查询
docker exec -it mysql-container mysql -u root -p -e "SHOW DATABASES;"
# 查看 Nginx 容器配置
docker exec -it nginx-proxy cat /etc/nginx/nginx.conf
# 检查容器是否能访问其他服务
docker exec -it api-container ping redis
# 进入正在运行的 MySQL 容器 第一个mysql是容器的名字
docker exec -it mysql mysql -u root -p
# 执行数据库备份
docker exec -i mysql sh -c 'mysqldump -u root -prootpass appdb' > backup.sql
# 进入Redis CLI
docker exec -it redis redis-cli
# 运行 Docker Compose
docker-compose up -d
# 查看容器状态
docker-compose ps
# 停止所有容器
docker-compose stop
# 启动所有容器
docker-compose start
# 查看容器日志
docker-compose logs -f --tail=100
# 停止旧服务(如果已运行)
docker-compose down
# 查看compose是否成功执行
docker compose ls
# 查看卷是否创建
docker volume ls
# 查看网络是否创建
docker network ls
# 重新启动(建议指定项目名,避免目录名不合法)
docker-compose -p my_project up -d
# 查看运行状态
docker-compose -p my_project ps
# 查看 MySQL 日志
docker-compose -p my_project logs mysql
# 查看 Redis 日志
docker-compose -p my_project logs redis