Google App Engine部署NestJS成功 实例运行但无法访问服务
NestJS部署到App Engine后实例正常运行但无法访问,按出现概率从高到低对应以下问题,可逐一排查修复:
- 端口监听配置错误:App Engine运行时会通过
PORT环境变量动态分配服务监听端口,NestJS默认硬编码监听3000端口,会导致实例存活但无法接收平台转发的流量。 - 生产启动脚本错误:部署流程仅执行了
npm run build生成编译产物,但package.json的start脚本仍使用开发模式的nest start命令,GAE生产环境默认不安装devDependencies下的@nestjs/cli,会导致服务实际未正常启动监听。 - 部署包文件缺失:
.gcloudignore或.gitignore规则将dist编译产物目录排除在上传范围外,GAE侧拿到的部署包无可用的生产环境可执行文件。 - 访问地址不匹配:配置中指定服务名为
rest,该服务的访问域名格式和默认服务不同,直接访问默认服务域名无法路由到该服务。
1. 修正启动端口与监听地址
修改项目入口文件(默认路径src/main.ts),从环境变量读取平台分配的端口,同时绑定0.0.0.0地址确保平台可转发流量:
async function bootstrap() { const app = await NestFactory.create(AppModule); // 本地调试时无PORT环境变量, fallback到3000端口 const listenPort = process.env.PORT ? Number(process.env.PORT) : 3000; await app.listen(listenPort, '0.0.0.0'); } bootstrap();
禁止绑定127.0.0.1回环地址,否则平台侧的流量转发规则无法生效
2. 修正生产启动脚本
调整package.json内的脚本配置,生产启动命令直接执行编译后的JS文件,不要依赖Nest CLI:
{ "scripts": { "start:dev": "nest start --watch", "build": "nest build", "start": "node dist/main.js" } }
GAE部署生产版本时默认以生产模式安装依赖,仅会安装dependencies下的包,devDependencies内的@nestjs/cli不会被安装,使用nest start作为生产启动命令会直接报错退出。
3. 检查部署忽略规则
打开项目根目录的.gcloudignore文件,确认没有配置dist/的排除规则,至少保证以下规则不会拦截编译产物上传:
node_modules/ .git .github
gcloud app deploy执行时会同时遵循.gitignore和.gcloudignore的排除规则,只要任意一个文件中配置了忽略dist目录,部署包内就不会包含编译后的产物。
4. 调整Cloud Build配置(可选)
现有构建逻辑无需大改,可新增一步构建产物校验,提前拦截构建异常:
steps: - name: node:16.0.0 entrypoint: npm args: ["install"] - name: node:16.0.0 entrypoint: npm args: ["run", "build"] # 校验dist目录及入口文件存在 - name: node:16.0.0 entrypoint: ls args: ["-la", "dist/main.js"] - name: "gcr.io/cloud-builders/gcloud" args: ["app", "deploy", "-v", "20220628t175507"] timeout: "1600s"
5. 确认正确的访问地址
自定义服务rest的访问地址格式为:https://rest-dot-<你的GCP项目ID>.appspot.com
默认服务地址https://<你的GCP项目ID>.appspot.com只会路由到名为default的服务,无法访问到rest服务的接口。
验证方式
部署完成后进入GAE控制台对应版本的日志页面,查看实例启动日志:
- 若日志显示服务监听端口为3000,说明端口配置未修正
- 若日志出现
nest: command not found报错,说明启动脚本未修正 - 若日志出现
Cannot find module './dist/main.js'报错,说明dist目录被忽略规则拦截未上传 - 若日志打印
Nest application successfully started且监听端口与环境变量PORT一致,说明服务启动正常,检查访问地址是否正确即可。
内容的提问来源于stack exchange,提问作者puntero

