Serverless
Fastify 无法直接运行在无服务器平台上,需要做一点修改。本文为如何在知名的无服务器平台上运行 Fastify 应用提供指导。
我应该在无服务器平台上使用 Fastify 吗?
取决于你自己!FaaS 通常使用精简专注的函数,但你依然可以运行完整的 web 应用。但请牢记,应用越繁重,初始化越漫长。在无服务器环境中运行 Fastify,最好的方式便是使用例如 Google Cloud Run、AWS Fargate 以及 Azure Container Instances 之类的平台,它们能同时处理多个请求,因此能充分利用 Fastify 的特性。
开发便利是通过 Fastify 构建无服务器应用的优势之一。在本地环境,Fastify 应用无需任何额外工具即可运作,而相同的代码加上一些额外内容便能在无服务器平台上运行。
以下是使用 Fastify 在 AWS Lambda 和 Amazon API Gateway 架构上构建无服务器 web 应用/服务的示例。
注:使用 仅是一种可行方案。
app.js
你可以简单地把初始化代码包裹于可选的 选项里。
当执行 lambda 函数时,我们不需要监听特定的端口,因此,在这个例子里我们只要导出 函数即可。 在 lambda.js
里,我们会用到它。
lambda.js
const awsLambdaFastify = require('aws-lambda-fastify')
const init = require('./app');
const proxy = awsLambdaFastify(init())
// 或
// const proxy = awsLambdaFastify(init(), { binaryMimeTypes: ['application/octet-stream'] })
exports.handler = proxy;
// 或
// exports.handler = (event, context, callback) => proxy(event, context, callback);
// 或
// exports.handler = (event, context) => proxy(event, context);
// 或
// exports.handler = async (event, context) => proxy(event, context);
我们只需要引入 aws-lambda-fastify (请确保安装了该依赖 npm i --save aws-lambda-fastify
) 以及我们写的 ,并使用 app
作为唯一参数调用导出的 awsLambdaFastify
函数。 以上步骤返回的 proxy
函数拥有正确的签名,可作为 lambda 的处理函数。 如此,所有的请求事件 (API Gateway 的请求) 都会被代理到 aws-lambda-fastify 的 proxy
函数。
示例
你可以在这里找到使用 的可部署的例子。
- 你没法操作 stream,因为 API Gateway 还不支持它。
- API Gateway 的超时时间为 29 秒,请务必在此时限内回复。
与 AWS Lambda 和 Google Cloud Functions 不同,Google Cloud Run 是一个无服务器容器环境。它的首要目的是提供一个能运行任意容器的底层抽象 (infrastucture-abstracted) 的环境。因此,你能将 Fastify 部署在 Google Cloud Run 上,而且相比正常的写法,只需要改动极少的代码。
参照以下步骤部署 Google Cloud Run。如果你对 gcloud 还不熟悉,请看其。
调整 Fastify 服务器
为了让 Fastify 能正确地在容器里监听请求,请确保设置了正确的端口与地址:
function build() {
const fastify = Fastify({ trustProxy: true })
return fastify
}
async function start() {
// Google Cloud Run 会设置这一环境变量,
const IS_GOOGLE_CLOUD_RUN = process.env.K_SERVICE !== undefined
// 监听 Cloud Run 提供的端口
const port = process.env.PORT || 3000
// 监听 Cloud Run 中所有的 IPV4 地址
const address = IS_GOOGLE_CLOUD_RUN ? "0.0.0.0" : undefined
try {
const server = build()
const address = await server.listen(port, address)
console.log(`Listening on ${address}`)
} catch (err) {
process.exit(1)
}
}
module.exports = build
if (require.main === module) {
start()
}
添加 Dockerfile
你可以添加任意合法的 Dockerfile
,用于打包运行 Node 程序。在 gcloud 官方文档中,你能找到一份基本的 Dockerfile
。
# 使用官方 Node.js 10 镜像。
# https://hub.docker.com/_/node
FROM node:10
# 创建并切换到应用目录。
WORKDIR /usr/src/app
# 拷贝应用依赖清单至容器镜像。
# 使用通配符来确保 package.json 和 package-lock.json 均被复制。
# 独立地拷贝这些文件,能防止代码改变时重复执行 npm install。
COPY package*.json ./
# 安装生产环境依赖。
RUN npm install --only=production
# 复制本地代码到容器镜像。
COPY . .
# 启动容器时运行服务。
CMD [ "npm", "start" ]
添加 .dockerignore
添加一份如下的 .dockerignore
,可以将仅用于构建的文件排除在容器之外 (能减小容器大小,加快构建速度):
gcloud builds submit --tag gcr.io/PROJECT-ID/APP-NAME
部署镜像
镜像构建之后,使用如下命令部署它:
gcloud beta run deploy --image gcr.io/PROJECT-ID/APP-NAME --platform managed
如此,便能从 Google 云平台提供的链接访问你的应用了。
首先,完成与 AWS Lambda 有关的准备工作。
新建 functions
文件夹,在其中创建 server.js
(应用的入口文件)。
functions/server.js
export { handler } from '../lambda.js'; // 记得将路径修改为你的应用中对应的 `lambda.js` 的路径
netlify.toml
别忘记添加这个文件,否则会有不少问题
const dotenv = require('dotenv-safe');
const webpack = require('webpack');
const env = process.env.NODE_ENV || 'production';
if (dev) {
dotenv.config({ allowEmptyValues: true });
}
module.exports = {
mode: env,
devtool: dev ? 'eval-source-map' : 'none',
externals: [nodeExternals()],
devServer: {
proxy: {
'/.netlify': {
target: 'http://localhost:9000',
pathRewrite: { '^/.netlify/functions': '' }
}
}
},
module: {
rules: []
},
plugins: [
new webpack.DefinePlugin({
'process.env.APP_ROOT_PATH': JSON.stringify('/'),
'process.env.NETLIFY_ENV': true,
'process.env.CONTEXT': env
})
]
};
Scripts
在 package.json
的 scripts 里加上这一命令
"scripts": {
...
"build:functions": "netlify-lambda build functions --config ./webpack.config.netlify.js"
...
}
这样就完成了。
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/api/serverless.js"
}
]
}
之后,写一个 api/serverless.js
文件: