# 部署方式：PM2 / Docker / Serverless

URL: https://caijiao.org/fastify/deploy/methods
Source: docs/fastify/deploy/methods.md
Description: 本节将介绍如何使用 PM2、Docker 和 Serverless 来部署 Fastify API 项目，帮助你选择适合的部署方式。

在本节中，我们将介绍如何使用三种流行的方式来部署你的 [Fastify](/fastify/) API 项目：PM2、Docker 和 Serverless。这些方式各有优缺点，适合不同的应用场景。

## 1. 使用 PM2 部署

PM2 是一个进程管理器，可以帮助你启动、监控和管理 Node.js 应用程序。它非常适合在生产环境中运行应用。

### 安装 PM2

首先，安装 PM2：

```bash
npm install pm2 -g
```

### 启动 Fastify 项目

在项目根目录下，运行以下命令使用 PM2 启动你的应用：

```bash
pm2 start app.ts --name fastify-api --watch
```

- `--name fastify-api` 为你的进程指定一个名字，方便管理。
- `--watch` 会启用文件监控，当文件发生变化时自动重启应用。

### 管理 PM2 应用

你可以使用以下命令来管理你的应用：

- 查看应用状态：

  ```bash
  pm2 status
  ```

- 查看应用日志：

  ```bash
  pm2 logs fastify-api
  ```

- 停止应用：

  ```bash
  pm2 stop fastify-api
  ```

- 重启应用：

  ```bash
  pm2 restart fastify-api
  ```

- 将应用设置为开机自动启动：

  ```bash
  pm2 startup
  pm2 save
  ```

### 持久化进程

为了确保服务器重启后应用也能自动启动，可以使用以下命令保存当前的进程列表：

```bash
pm2 save
```

## 2. 使用 Docker 部署

Docker 是一种容器化技术，可以让你将应用及其依赖打包到一个容器中，便于在任何地方运行。

### 创建 Dockerfile

在项目根目录下创建一个名为 `Dockerfile` 的文件，内容如下：

```Dockerfile
# 使用官方 Node.js 镜像
FROM node:16

# 设置工作目录
WORKDIR /usr/src/app

# 复制 package.json 和 package-lock.json 并安装依赖
COPY package*.json ./
RUN npm install

# 复制项目文件
COPY . .

# 暴露应用端口
EXPOSE 3000

# 启动应用
CMD ["node", "app.js"]
```

### 构建 Docker 镜像

在项目根目录下，运行以下命令构建 Docker 镜像：

```bash
docker build -t fastify-api .
```

### 运行 Docker 容器

构建完成后，你可以使用以下命令运行 Docker 容器：

```bash
docker run -p 3000:3000 fastify-api
```

这将会将容器的 3000 端口映射到主机的 3000 端口。

### 使用 Docker Compose（可选）

如果你有多个服务需要一起运行，可以使用 Docker Compose 来管理多个容器。创建一个 `docker-compose.yml` 文件，内容如下：

```yaml
version: '3'
services:
  fastify-api:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
```

然后运行以下命令启动所有服务：

```bash
docker-compose up
```

## 3. 使用 Serverless 部署

Serverless 是一种不需要管理服务器的部署方式，可以帮助你将应用作为无状态函数运行。常见的 Serverless 平台有 AWS Lambda、Google Cloud Functions 和 Azure Functions。

### 安装 Serverless 框架

首先，安装 Serverless 框架：

```bash
npm install -g serverless
```

### 配置 Serverless 项目

在项目根目录下运行以下命令初始化一个新的 Serverless 项目：

```bash
serverless create --template aws-nodejs --path fastify-api
cd fastify-api
```

将生成的 `serverless.yml` 文件内容修改为：

```yaml
service: fastify-api

provider:
  name: aws
  runtime: nodejs16.x

functions:
  app:
    handler: app.handler
    events:
      - http:
          path: users
          method: get
      - http:
          path: users/{id}
          method: get
      - http:
          path: users
          method: post
```

### 创建 Lambda 处理函数

修改 `handler.js` 文件，设置 Fastify 作为 Lambda 函数的处理程序。

```javascript
const fastify = require('fastify')();

fastify.get('/users', async (request, reply) => {
  return [
    { id: 1, name: 'John Doe' },
    { id: 2, name: 'Jane Smith' }
  ];
});

fastify.get('/users/:id', async (request, reply) => {
  const userId = request.params.id;
  if (userId === '1') {
    return { id: 1, name: 'John Doe' };
  } else if (userId === '2') {
    return { id: 2, name: 'Jane Smith' };
  } else {
    return reply.status(404).send({ error: 'User not found' });
  }
});

fastify.post('/users', async (request, reply) => {
  const { name } = request.body;
  if (!name) {
    return reply.status(400).send({ error: 'Name is required' });
  }
  const newUser = { id: Date.now(), name };
  return reply.status(201).send(newUser);
});

module.exports.handler = async (event, context) => {
  const handler = await fastify;
  return handler(event, context);
};
```

### 部署到 AWS Lambda

使用以下命令将应用部署到 AWS Lambda：

```bash
serverless deploy
```

部署完成后，你将得到一个 API Gateway URL，使用这个 URL 你可以访问你的 API。

## 4. 总结

在本节中，我们介绍了如何使用三种不同的方式来部署 Fastify API 项目：

- **PM2**：适用于传统的虚拟机或物理服务器，能方便地管理 Node.js 应用。
- **Docker**：适合在容器化环境中运行，确保跨平台的一致性，便于迁移和扩展。
- **Serverless**：适合无服务器架构，通过云服务提供弹性伸缩，不需要管理服务器。

你可以根据项目需求和架构选择最适合的部署方式。
