背景
新项目使用 nestjs + nginx + vue3 进行全栈开发,使用docker进行部署,记录下遇到的问题及解决方案。 docker 新手,欢迎大佬指正。
部署方案
使用 docker-compose 管理,部署 nestjs 后端服务和 nginx 服务器,使用 github actions 部署前端项目。
问题
ssl 证书申请
ssl 免费证书申请可以通过 Let's Encrypt 申请。 Let's Encrypt 提供了 cebert 工具,可以一行命令搞定。 同时可以使用 docker cebert 镜像部署。
// 生成证书
sudo certbot certonly --standalone -d yourdomain.com -d www.yourdomain.com
// docker 配置
certbot:
image: certbot/certbot
container_name: certbot
restart: always
volumes:
- /etc/letsencrypt/:/etc/letsencrypt
networks:
- cms-network
// 容器启动时配置证书自动更新
entrypoint: /bin/sh -c 'trap exit TERM; while :; do sleep 12h & wait $${!}; certbot renew --webroot --webroot-path=/etc/letsencrypt --quiet --post-hook "nginx -s reload"; done;'
-
certonly表示只生成证书,而不配置 Web 服务器。 -
--standalone表示使用内置的临时服务器进行验证。 -
-d用于指定要为其生成证书的域名。
注意
standalone模式需要占用 80 端口,执行命令前需注意端口占用情况。- 证书每90天需要更新
docker 容器时区
由于大部分 Docker 镜像都是基于 Alpine,Ubuntu,Debian,CentOS 等基础镜像制作而成。
基本上都采用 UTC 时间,默认时区为零时区。
所以在使用 docker 时需要检查时区。
ps:我就是在支付时订单总是超时发现的。
docker run -e TZ=Asia/Shanghai ...
environment:
- TZ=Asia/Shanghai # 设置为上海时区
volumes:
# 挂载宿主机时区
- /etc/localtime:/etc/localtime:ro
docker 网络通信
由于使用 docker-compose 进行管理,所以在配置 docker-compose.yml 文件时,需要配置网络,我使用的是桥接网络,用于各 docker 容器间进行通信。
# 定义桥接网络,用于各服务之间的通知
networks:
cms-network:
driver: bridge
静态资源服务
对于 nestjs 启动的静态资源服务,需要将数据挂载到服务器,以免重新部署时丢失。
volumes:
- /root/uploads:/app/uploads
docker-compose.yml
services:
nginx:
image: nginx:latest
container_name: nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- /etc/letsencrypt/:/etc/letsencrypt
- ./nginx/html:/usr/share/nginx/html
depends_on:
- certbot
networks:
- cms-network
certbot:
image: certbot/certbot
container_name: certbot
restart: always
volumes:
- /etc/letsencrypt/:/etc/letsencrypt
networks:
- cms-network
entrypoint: /bin/sh -c 'trap exit TERM; while :; do sleep 12h & wait $${!}; certbot renew --webroot --webroot-path=/etc/letsencrypt --quiet --post-hook "nginx -s reload"; done;'
# 构建Nodejs服务
node:
# 构建Node.js服务的Docker镜像
build:
# 设置构建上下文为当前的目录
context: ./net-shop-back-end
# 使用当前目录的Dockerfile进行构建
dockerfile: Dockerfile
environment:
- TZ=Asia/Shanghai # 设置为上海时区
# 加载环境变量文件 .env
env_file:
- ./net-shop-back-end/.env.docker
volumes:
- /root/uploads:/app/uploads
#设置服务的依赖,确保在启动Node服务前先启动依赖的服务
depends_on:
- mysql
- redis
networks:
- cms-network
mysql:
# 使用官方的MYSQL8.0镜像
image: mysql:8.0
#挂载数据卷来持久化数据库
volumes:
- mysql-data:/var/lib/mysql
# 挂载本地的init.sql文件 到容器内,用于数据初始化
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
#设置必要的环境变量,包括mysql的root密码和默认的数据库的名称
environment:
MYSQL_ROOT_PASSWORD: netshop20241111mysql
MYSQL_DATABASE: net_shop
networks:
- cms-network
redis:
image: redis:6.2
volumes:
- redis-data:/data
networks:
- cms-network
# 在宿主机内创建三个数据卷,用于持久化数据
volumes:
mysql-data:
redis-data:
# 定义桥接网络,用于各服务之间的通知
networks:
cms-network:
driver: bridge