记录一下利用docker分别部署前后端服务到阿里云,记录一下坑点
项目整体技术栈
整体实现了网站的登录注册/权限校验/基本crud功能,其中
前端: react+axios+zustand
后端: nestjs+typeorm+mysql
在阿里云服务器上用docker部署
前端
主要是dockerfile的配置,以及nginx的配置,这里贴一下
# 第一阶段:构建应用
FROM node:18-alpine as builder
# 创建工作目录
WORKDIR /app
# 复制package.json和yarn.lock文件
COPY package.json yarn.lock ./
# 安装yarn
# RUN npm install -g yarn
# 安装项目依赖
RUN yarn install
# 复制项目文件
COPY . .
# 构建项目
RUN yarn build
# 第二阶段:构建Nginx镜像
FROM nginx:alpine
# 复制构建的文件到nginx html目录
COPY --from=builder /app/dist /usr/share/nginx/html
# 复制nginx配置文件 !!需要替换默认的default.conf文件!!
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 暴露端口 暴露内部容器端口
EXPOSE 80
# 启动nginx
CMD ["nginx", "-g", "daemon off;"]
server {
listen 80;
listen [::]:80;
server_name localhost;
root /usr/share/nginx/html;
# Handle root location
location / {
try_files $uri $uri/ /index.html; # history 路由需要此配置
index index.html index.htm;
}
# Handle API proxying
location /api-x/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://8.140.248.120:3000/api-x/;
# wsl下可以直接访问host.docker.internal获取到主机Ip
# proxy_pass http://host.docker.internal:3000/api-x/;
}
# Error pages
error_page 404 /404.html;
location = /404.html {}
error_page 500 502 503 504 /50x.html;
location = /50x.html {}
}
有几个坑点:
api转发请求的时候在nginx中不能用loaclhost: 宿主机和容器的网络是独立的,所以Localhost不能直接用,在wsl或者mac下可以用host.docker.internal
,但是在ubuntu里无法使用,所以我目前直接写死的api后端服务所在ip
nginx配置需要替换default.conf文件: 在docker中拉取nginx镜像的文件目录/etc/nginx/conf.d/
下有一个默认的default.conf配置,所以需要将自定义的配置覆盖掉这个文件,哟啊不然会nginx报错(因为应用到了默认的server配置)
后端
后端采用了nestjs+typeorm,数据库采用的mysql,后端dockerfile部署相对比较顺利,这里也贴一下
# 第一阶段:构建应用
FROM node:18-alpine as builder
# 设置工作目录
WORKDIR /home/nestService
# 复制package.json和yarn.lock文件
COPY package.json yarn.lock ./
# 安装项目依赖
RUN yarn install
# 复制项目文件
COPY . .
# 构建项目
RUN yarn build
# 安装PM2
RUN yarn global add pm2
# 暴露端口
EXPOSE 3000
# 设置启动命令
CMD ["pm2-runtime", "start", "dist/main.js"]
然后就是根据不同的环境连不同的数据库什么的,这里也贴一下
ConfigModule.forRoot({
isGlobal: true,
envFilePath:
process.env.NODE_ENV === 'production'
? path.join(process.cwd(), './env/.prod.env')
: path.join(process.cwd(), './env/.dev.env'),
}),
// 接入mysql数据库
/**
* https://juejin.cn/post/7032079740982788132#heading-12
* 环境配置: https://juejin.cn/post/7316202589603807259
*/
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
const config = {
type: 'mysql' as const, // 数据库类型
entities: [], // 数据表实体
host: configService.get('DB_HOST'), // 主机,默认为localhost
port: configService.get<number>('DB_PORT', 3306), // 端口号
username: configService.get('DB_USER', 'root'), // 用户名
password: configService.get('DB_PASSWORD'), // 密码
database: configService.get('DB_DATABASE'), //数据库名
timezone: '+08:00', //服务器上配置的时区
synchronize: true, //根据实体自动创建数据库表, 生产环境建议关闭
//如果为true,将自动加载实体 forFeature()方法注册的每个实体都将自动添加到配置对象的实体数组中
autoLoadEntities: true,
};
return config;
},
}),
部署
docker 构建镜像后部署就比较简单了
直接docker run 命令就行了,在控制台运行docker ps
,可以看到前端和后端两个容器,说明前后端服务已经跑起来了。
todolist
- 前端监控数据入库: 目前前端接入了自己写的监控sdk并完成了上报,后端还没有将监控数据写入数据库
最后,有什么问题欢迎各位大佬指教交流~