前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版

docker-compose/微信云托管/serverless之部署Nestjs项目

首页2022-06-17 22:40:24Front-End
部署NestDocker

同一个 Nestjs 服务,我先后用三种方式部署过。最早是买台云服务器自己装 docker,用 docker-compose 把 MySQL、Redis 和 Node 服务编排在一起;后来做小程序后端,改成微信云托管,推代码就自动走流水线;再后来有个访问量很低的接口服务,直接扔到腾讯云 serverless 上,不跑就不花钱。

这三条路的取舍点完全不一样。自建服务器最灵活但要自己管运维,云托管省心但绑死微信生态,serverless 便宜但有代码包体积和冷启动的硬约束。

这篇把三种方式从头到尾各走一遍,中间穿插当时卡住我的地方。看完你应该能判断自己的项目该走哪条,以及每条路上会踩到什么。

在本篇文章中,我们将从浅入深,和大家一起学习以下知识:

  • CentOS 上装 docker 和 docker-compose 的完整命令,以及镜像源为什么必须配
  • 用一份 docker-compose.yml 同时拉起 MySQL、Redis 和 Nest 服务
  • depends_on 为什么保证不了「数据库就绪再启动服务」,restart 才是兜底
  • Nestjs 项目的 Dockerfile 该怎么写,时区那几行为什么不能省
  • 微信云托管的流水线部署流程,以及容器内改代码为什么无效
  • 腾讯云 serverless 部署 Nest 的两种方式,模板和自定义
  • scf_bootstrap 是什么,为什么要 chmod 777
  • 云函数代码包 500M 上限怎么处理

# 一、云服务器上用 docker-compose 部署

先说最传统的那条路。买台云服务器,自己装 docker,用 compose 把几个服务编排起来。这条路的好处是所有东西都在你手上,想装什么装什么;代价是从装 docker 开始的每一步都得自己来。

# 装 docker 环境

第一步装依赖工具包。yum-utils 提供了 yum-config-manager 命令,后面加镜像源要用;device-mapper-persistent-data 和 lvm2 是 docker 存储驱动需要的。

yum install yum-utils device-mapper-persistent-data lvm2 -y
@前端进阶之旅: 代码已经复制到剪贴板

yum 安装 docker 依赖工具包的输出

看到一堆 Installed 或者 already installed 就算过了。这一步基本不会出问题,真出问题一般是 yum 源本身有问题,先 yum makecache 一下。

接着换软件源。docker 官方源在国内拉取很慢,换成阿里的镜像。

yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
@前端进阶之旅: 代码已经复制到剪贴板

添加阿里云 docker-ce 软件源

命令执行完会在 /etc/yum.repos.d/ 下多一个 docker-ce.repo 文件。这里配的是软件源,管的是 docker 这个程序本身的下载速度,跟后面配的镜像加速是两回事,别搞混了。

然后装 docker 本体。

yum install docker-ce docker-ce-cli containerd.io -y
@前端进阶之旅: 代码已经复制到剪贴板

这三个包分别是 docker 守护进程、命令行客户端和容器运行时。装完还没跑起来,要手动启动。

systemctl start docker

# 设为开机启动
systemctl enable docker
@前端进阶之旅: 代码已经复制到剪贴板

systemctl enable 那行别省。服务器重启之后 docker 不自动起来,你的服务就全没了,这种事发生在半夜运维重启机器的时候特别难受。

# 配镜像加速

这一步管的是拉镜像的速度。

vi /etc/docker/daemon.json
@前端进阶之旅: 代码已经复制到剪贴板
{
  "registry-mirrors": ["https://register.docker-cn.com/"]
}
@前端进阶之旅: 代码已经复制到剪贴板

后续拉取镜像直接从 https://hub.docker.com 网站拉取速度更快

重启docker

systemctl restart docker
@前端进阶之旅: 代码已经复制到剪贴板

这里有个坑要注意。register.docker-cn.com 这个官方中国区镜像早就停了,现在填它是无效的,docker pull 该慢还是慢,而且不会报错,让人以为配好了。现在能用的加速地址变动比较频繁,我的做法是去阿里云容器镜像服务控制台,它会给你一个专属的加速地址,填那个最稳。配完之后用 docker info 看一眼,输出里的 Registry Mirrors 那一段能确认有没有生效。

# 先拉个 MySQL 试试

环境装完先验证一下,别等到编排整套服务的时候才发现 docker 有问题。

docker pull daocloud.io/library/mysql:8.0.20
@前端进阶之旅: 代码已经复制到剪贴板

docker pull 拉取 mysql 8.0.20 镜像

一层一层的 Pull complete 就是 docker 的分层镜像在下载。这里用的是 daocloud 的镜像仓库地址,好处是不用配加速也能拉,坏处是它不一定同步了最新的 tag。

运行mysql镜像

docker run -d -p 3307:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456(设置登录密码) be0dbf01a0f3(镜像ID)
@前端进阶之旅: 代码已经复制到剪贴板

docker run 启动 mysql 容器

命令里那两个括号是注释说明,实际敲的时候要去掉。-p 3307:3306 是宿主机 3307 映射到容器 3306,这里故意错开是因为服务器上可能已经装了 MySQL 占着 3306。-e MYSQL_ROOT_PASSWORD 是 MySQL 官方镜像约定的环境变量,不传这个容器起不来。

跑完 docker ps 能看到容器在 Up 状态就对了。如果是 Exited,用 docker logs mysql 看原因,八成是密码环境变量没传或者端口被占。

进入mysql容器内部

进入 mysql 容器执行 mysql 命令行

进容器用 docker exec -it mysql bash,然后 mysql -uroot -p 输密码。能进到 mysql> 提示符就说明整条链路都通了。

至此mysql镜像搭建成功,下面我们使用docker-compose来管理docker容器,不在单独一个个安装MySQL、redis、nginx

# 装 docker-compose

一个个 docker run 的问题在于,参数记不住、顺序要靠人保证、容器之间怎么互相访问还得单独配网络。compose 把这些都写进一个 yml 文件里。

# 使用国内源安装
curl -L https://get.daocloud.io/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
@前端进阶之旅: 代码已经复制到剪贴板

uname -s 和 uname -m 会被展开成系统名和架构,比如 Linux 和 x86_64,拼出来正好是对应平台的二进制文件名。

设置docker-compose执行权限

chmod +x /usr/local/bin/docker-compose
@前端进阶之旅: 代码已经复制到剪贴板

下下来的是个二进制文件,默认没有执行权限,不加这一步敲命令会报 Permission denied。

创建软链

sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
@前端进阶之旅: 代码已经复制到剪贴板

有些系统的 PATH 里没有 /usr/local/bin,软链到 /usr/bin 保证哪个用户都能直接敲。

测试是否安装成功:

$ docker-compose --version

docker-compose version 1.22.0, build f46880fe
@前端进阶之旅: 代码已经复制到剪贴板

能打出版本号就装好了。这里补一句时效性的话,docker-compose 独立二进制这个形态属于 v1,后来 docker 把它做成了插件,命令变成 docker compose(中间是空格)。新装的机器上两种都可能有,行为基本一致但配置文件的兼容性有细微差别。这篇里的写法是 v1 的。

# 编排文件怎么写

这份 yml 是整节的核心,一次拉起三个服务。

version: '3.0'

services:
  # docker容器启动的redis默认是没有redis.conf的配置文件,所以用docker启动redis之前,需要先去官网下载redis.conf的配置文件
  redis: # 服务名称
    container_name: redis # 容器名称
    image: daocloud.io/library/redis:6.0.3-alpine3.11 # 使用官方镜像
    # 配置redis.conf方式启动
    command: redis-server /usr/local/etc/redis/redis.conf --requirepass 123456 --appendonly yes # 设置redis登录密码 123456、--appendonly yes:这个命令是用于开启redis数据持久化
    # 无需配置文件方式启动
    # command: redis-server --requirepass 123456 --appendonly yes # 设置redis登录密码 123456
    ports:
      - 6380:6379 # 本机端口:容器端口
    restart: on-failure # 自动重启
    volumes:
      - ./deploy/redis/db:/data # 把持久化数据挂载到宿主机
      - ./deploy/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf # 把redis的配置文件挂载到宿主机
      - ./deploy/redis/logs:/logs # 用来存放日志
    environment:
      - TZ=Asia/Shanghai # 解决容器 时区的问题
    networks:
      - my-server
@前端进阶之旅: 代码已经复制到剪贴板

Redis 这一段有两个地方值得单独说。

volumes 里的三条挂载,第一条是数据目录。容器被删除时里面的文件会一起消失,Redis 开了 appendonly 做持久化,如果不把 /data 挂出来,重新部署一次数据就没了。这是最容易踩的坑,本地测的时候感觉不到,因为你不会频繁删容器。

第二条挂的是配置文件。Redis 官方镜像里确实不带 redis.conf,command 里指定了配置文件路径的话,宿主机上对应位置必须真有这个文件,否则容器启动就报错退出。嫌麻烦的话用注释掉的那种写法,不要配置文件,直接命令行传参数。

TZ=Asia/Shanghai 这个环境变量解决的是容器内时区。不配的话容器是 UTC 时间,Redis 的 key 过期时间、日志时间戳全都跟你想的差 8 小时。

接着是 MySQL 那段。

fe
  • 一、云服务器上用 docker-compose 部署
    • 装 docker 环境
    • 配镜像加速
    • 先拉个 MySQL 试试
    • 装 docker-compose
    • 编排文件怎么写
    • Nestjs 的 Dockerfile
    • 改代码适配容器环境
    • 开放端口和启动
  • 二、微信云托管部署
    • 复用已有的 Redis 和 MySQL
    • 改代码
    • 新建服务
    • 调试接口
  • 三、腾讯云 serverless 部署
    • 模板部署
    • 自定义部署自己的 Nest 项目
    • 代码包 500M 超限怎么办
  • 总结
  • 参考

← Serverless 部署前后端项目实践,腾讯云 SCF 全流程笔记Egg 项目部署实战 docker-compose 微信云托管 serverless 三种方案 →