云计算与部署容器与 Kubernetes
容器与 Kubernetes
Bun 服务的可复现镜像、探针、信号、密钥和扩缩容基线
最后更新于
生产镜像
优先使用 Bun 官方镜像,并固定经过验证的标签或 digest。下面按开发依赖、测试、生产依赖分层,最终镜像只复制运行所需内容:
FROM oven/bun:1 AS base
WORKDIR /app
FROM base AS install
COPY package.json bun.lock ./
RUN bun ci
FROM base AS verify
COPY --from=install /app/node_modules ./node_modules
COPY . .
RUN bun run typecheck && bun test && bun run build
FROM base AS production-deps
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile --production --ignore-scripts
FROM base AS release
ENV NODE_ENV=production
COPY --from=production-deps /app/node_modules ./node_modules
COPY --from=verify /app/dist ./dist
COPY package.json ./
USER bun
EXPOSE 3000
CMD ["bun", "run", "--no-env-file", "dist/index.js"]如果生产依赖确实需要安装脚本,不要静默删除 --ignore-scripts:先用 bun pm untrusted 定位依赖,审查后通过 trustedDependencies 做最小放行。
这个 Dockerfile 是单包且 dist 仍需要生产依赖的基线。Monorepo 安装阶段还必须复制相关 Workspace manifest;完全 bundle 的产物可以不复制 node_modules,但 external、动态文件和原生依赖必须先检查。完整工程门禁见 生产工程基线。
服务契约
const port = Number(Bun.env.PORT ?? 3000);
const server = Bun.serve({
port,
idleTimeout: 30,
maxRequestBodySize: 2 * 1024 * 1024,
routes: {
'/live': () => new Response('ok'),
'/ready': async () => {
const ready = await dependenciesAreReady();
return new Response(ready ? 'ok' : 'not ready', { status: ready ? 200 : 503 });
},
},
fetch: handleRequest,
});
async function shutdown(signal: string) {
console.info('shutdown_started', { signal });
await server.stop();
await closeDependencies();
}
process.once('SIGTERM', () => void shutdown('SIGTERM'));
process.once('SIGINT', () => void shutdown('SIGINT'));dependenciesAreReady() 与 closeDependencies() 是项目边界函数,不是 Bun 内置 API。把数据库、队列和外部服务放进去,但给探针设置短超时,避免健康检查自己拖垮服务。
三类探针
| 探针 | 回答的问题 | 失败后的动作 |
|---|---|---|
| startup | 进程是否已经完成首次启动? | 启动期间暂不运行其他探针 |
| readiness | 现在能否接收新流量? | 从负载均衡摘除,不应直接重启 |
| liveness | 进程是否卡死且需要重启? | 重启容器 |
不要让 liveness 依赖偶发抖动的外部 API。Kubernetes 官方特别提醒,错误的存活探针会制造级联故障。
云原生检查表
- 端口:读取
PORT;Cloud Run 默认把请求发到配置的容器端口。 - 状态:会话、任务状态和上传对象放外部存储;容器文件系统可随时消失。
- 日志:输出结构化 stdout/stderr,包含请求 ID;禁止记录提示词中的密钥和完整用户数据。
- 资源:设置 CPU/内存 request 与 limit;用压测决定并发,不从本机结果猜测。
- 数据库迁移:作为单独 Job 或发布步骤执行,不让每个副本同时迁移。
- 密钥:使用平台 secret 引用。注入为环境变量的密钥通常不会自动刷新,轮换后要重新部署或实现动态读取。
官方参考:Bun Docker guide、Kubernetes probes、Kubernetes Secrets、Cloud Run configuration。