title: 部署到生产环境 - ElysiaJS head:
- meta
- property: 'og:title' content: 部署到生产环境 - ElysiaJS
- meta
- name: 'description' content: 本页面
- meta
- property: 'og:description' content: Elysia 可以通过向构造函数传递对象来进行配置。我们可以通过向构造函数传递对象来配置 Elysia 的行为。
部署到生产环境
本页面是关于如何将 Elysia 部署到生产环境的指南。
集群模式
Elysia 默认是单线程的。为了利用多核 CPU,我们可以在集群模式下运行 Elysia。
让我们创建一个 index.ts 文件,从 server.ts 导入我们的主服务器,并根据可用的 CPU 核心数派生多个工作进程。
import cluster from 'node:cluster'
import os from 'node:os'
import process from 'node:process'
if (cluster.isPrimary) {
for (let i = 0; i < os.availableParallelism(); i++)
cluster.fork()
} else {
await import('./server')
console.log(`Worker ${process.pid} started`)
}import { Elysia } from 'elysia'
new Elysia()
.get('/', () => 'Hello World!')
.listen(3000)这将确保 Elysia 在多个 CPU 核心上运行。
TIP
在 Bun 上的 Elysia 默认使用 SO_REUSEPORT,这允许多个实例监听同一个端口。这只在 Linux 上有效。
编译为二进制文件
我们建议在部署到生产环境之前运行构建命令,因为它可能会显著减少内存使用和文件大小。
我们建议使用以下命令将 Elysia 编译为单个二进制文件:
bun build \
--compile \
--minify-whitespace \
--minify-syntax \
--target bun \
--outfile server \
src/index.ts这将生成一个可移植的二进制文件 server,我们可以运行它来启动我们的服务器。
将服务器编译为二进制文件通常比开发环境显著减少 2-3 倍的内存使用。
这个命令有点长,让我们分解一下:
- --compile 将 TypeScript 编译为二进制文件
- --minify-whitespace 移除不必要的空白字符
- --minify-syntax 压缩 JavaScript 语法以减少文件大小
- --target bun 为 Bun 运行时优化二进制文件
- --outfile server 将二进制文件输出为
server - src/index.ts 我们服务器的入口文件(代码库)
要启动我们的服务器,只需运行二进制文件。
./server一旦二进制文件编译完成,你不需要在机器上安装 Bun 来运行服务器。
这很好,因为部署服务器不需要安装额外的运行时来运行,使得二进制文件具有可移植性。
目标平台
你也可以添加 --target 标志来为目标平台优化二进制文件。
bun build \
--compile \
--minify-whitespace \
--minify-syntax \
--target bun-linux-x64 \
--outfile server \
src/index.ts以下是可用目标平台的列表:
| Target | Operating System | Architecture | Modern | Baseline | Libc |
|---|---|---|---|---|---|
| bun-linux-x64 | Linux | x64 | ✅ | ✅ | glibc |
| bun-linux-arm64 | Linux | arm64 | ✅ | N/A | glibc |
| bun-windows-x64 | Windows | x64 | ✅ | ✅ | - |
| bun-windows-arm64 | Windows | arm64 | ❌ | ❌ | - |
| bun-darwin-x64 | macOS | x64 | ✅ | ✅ | - |
| bun-darwin-arm64 | macOS | arm64 | ✅ | N/A | - |
| bun-linux-x64-musl | Linux | x64 | ✅ | ✅ | musl |
| bun-linux-arm64-musl | Linux | arm64 | ✅ | N/A | musl |
为什么不使用 --minify
Bun 确实有 --minify 标志可以压缩二进制文件。
但是如果我们使用 OpenTelemetry,它会将函数名减少到单个字符。
这使得跟踪变得比应该的更困难,因为 OpenTelemetry 依赖于函数名。
但是,如果你不使用 OpenTelemetry,你可以选择使用 --minify 代替
bun build \
--compile \
--minify \
--outfile server \
src/index.ts权限
一些 Linux 发行版可能无法运行二进制文件,如果你在 Linux 上,我们建议为二进制文件启用可执行权限:
chmod +x ./server
./server未知的随机中文错误
如果你尝试将二进制文件部署到服务器但无法运行并出现随机中文字符错误。
这意味着你运行的机器不支持 AVX2。
不幸的是,Bun 需要具有 AVX2 硬件支持的机器。
据我们所知,没有解决方法。
编译为 JavaScript
如果你无法编译为二进制文件或者你正在 Windows 服务器上部署。
你可以将你的服务器打包为一个 JavaScript 文件。
bun build \
--minify-whitespace \
--minify-syntax \
--outfile ./dist/index.js \
src/index.ts这将生成一个单一的可移植 JavaScript 文件,你可以部署到你的服务器上。
NODE_ENV=production bun ./dist/index.jsDocker
在 Docker 上,我们建议始终编译为二进制文件以减少基础镜像开销。
以下是使用 Distroless 镜像和使用二进制文件的示例镜像。
FROM oven/bun AS build
WORKDIR /app
# 缓存包安装
COPY package.json package.json
COPY bun.lock bun.lock
RUN bun install
COPY ./src ./src
ENV NODE_ENV=production
RUN bun build \
--compile \
--minify-whitespace \
--minify-syntax \
--outfile server \
src/index.ts
FROM gcr.io/distroless/base
WORKDIR /app
COPY --from=build /app/server server
ENV NODE_ENV=production
CMD ["./server"]
EXPOSE 3000OpenTelemetry
如果你使用 OpenTelemetry 来部署生产服务器。
由于 OpenTelemetry 依赖猴子补丁 node_modules/<library>。为了让插桩正常工作,我们需要指定要插桩的库是外部模块,以将其排除在打包之外。
例如,如果你使用 @opentelemetry/instrumentation-pg 来插桩 pg 库。我们需要将 pg 排除在打包之外,并确保它正在导入 node_modules/pg。
为了实现这一点,我们可以将 pg 指定为外部模块,使用 --external pg
bun build --compile --external pg --outfile server src/index.ts这告诉 bun 不要将 pg 打包到最终输出文件中,而是在运行时从 node_modules 目录导入。因此在生产服务器上,你也必须保留 node_modules 目录。
建议将生产服务器中应该可用的包在 package.json 中指定为 dependencies,并使用 bun install --production 来仅安装生产依赖。
{
"dependencies": {
"pg": "^8.15.6"
},
"devDependencies": {
"@elysiajs/opentelemetry": "^1.2.0",
"@opentelemetry/instrumentation-pg": "^0.52.0",
"@types/pg": "^8.11.14",
"elysia": "^1.2.25"
}
}然后在运行构建命令后,在生产服务器上
bun install --production如果 node_modules 目录仍然包含开发依赖,你可以删除 node_modules 目录并重新安装生产依赖。
Monorepo
如果你在 Monorepo 中使用 Elysia,你可能需要包含依赖的 packages。
如果你使用 Turborepo,你可以将 Dockerfile 放在应用程序目录中,如 apps/server/Dockerfile。这也适用于其他 monorepo 管理器,如 Lerna 等。
假设我们的 monorepo 使用 Turborepo,结构如下:
- apps
- server
- Dockerfile(在此处放置 Dockerfile)
- server
- packages
- config
然后我们可以在 monorepo 根目录(而不是应用程序根目录)构建我们的 Dockerfile:
docker build -t elysia-mono .使用如下 Dockerfile:
FROM oven/bun:1 AS build
WORKDIR /app
# 缓存包
COPY package.json package.json
COPY bun.lock bun.lock
COPY /apps/server/package.json ./apps/server/package.json
COPY /packages/config/package.json ./packages/config/package.json
RUN bun install
COPY /apps/server ./apps/server
COPY /packages/config ./packages/config
ENV NODE_ENV=production
RUN bun build \
--compile \
--minify-whitespace \
--minify-syntax \
--outfile server \
src/index.ts
FROM gcr.io/distroless/base
WORKDIR /app
COPY --from=build /app/server server
ENV NODE_ENV=production
CMD ["./server"]
EXPOSE 3000Railway
Railway 是一个流行的部署平台。
Railway 为每次部署分配一个随机端口,可以通过 PORT 环境变量访问。
我们需要修改我们的 Elysia 服务器以接受 PORT 环境变量以符合 Railway 端口要求。
而不是固定端口,我们可以使用 process.env.PORT 并在开发时提供回退。
new Elysia()
.listen(3000)
.listen(process.env.PORT ?? 3000) 这应该允许 Elysia 拦截 Railway 提供的端口。
TIP
Elysia 自动将主机名分配为 0.0.0.0,这与 Railway 兼容