You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS ECS服务环境变量未定义问题排查求助

问题:NestJS部署到AWS ECS后环境变量读取失败

本地通过Docker或docker-compose运行NestJS应用时,能正常读取JWT_SECRET、MONGODB_URI等环境变量,但部署到AWS ECS服务后,日志显示这些变量为undefined。

相关配置文件

Dockerfile

FROM --platform=linux/amd64 alpine:latest 

WORKDIR /usr/app

RUN apk add --no-cache nodejs npm

COPY . .

RUN npm install

RUN npm run build

# Start the server using the production build
CMD [ "node", "dist/main.js" ]

docker-compose.yaml

services:
  iu-app:
    restart: always
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 3000:3000
    environment:
      - NODE_ENV=production
      - PORT=3000
      - MONGODB_URI=<db uris are same as env.>
      - JWT_SECRET=JWT_SECRET=verysecretkey
      - JWT_EXPIRES=7d
    command: npm run start:prod

app.module.ts

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import { UsersModule } from './users/users.module';
import { TeachersModule } from './teachers/teachers.module';
import { AuthModule } from './auth/auth.module';
import { MailerModule } from './mailer/mailer.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: '.env',
    }),
    JwtModule.register({
      secret: process.env.JWT_SECRET,
      signOptions: { expiresIn: '7d' },
      global: true,
    }),
    MongooseModule.forRoot(process.env.MONGODB_URI),
    UsersModule,
    TeachersModule,
    AuthModule,
    MailerModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
console.log('process.env.JWT_SECRET', process.env.JWT_SECRET);
console.log('process.env.MONGODB_URI', process.env.MONGODB_URI);

GitHub Actions部署脚本

---
name: Build and Push Node.js Docker image to AWS ECR
on:
  push:
    branches: [master]
jobs:
  build-and-push:
    name: Build and Push to ECR
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: eu-west-1

      - name: Login to AWS ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: ui-app-be
          IMAGE_TAG: latest
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

      - name: Download task definition
        run: |
          aws ecs describe-task-definition --task-definition iu-app-task --query taskDefinition > task-definition.json

      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: iu-app-container
          image: ${{ steps.build-image.outputs.image }}

      - name: Deploy Amazon ECS task definition
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: iu-app-servicev2
          cluster: iu-app-cluster
          wait-for-service-stability: true

排查与解决方案

1. ECS任务定义未配置环境变量

本地docker-compose通过environment字段直接注入环境变量,但ECS不会自动继承这些配置。你的GitHub Actions脚本仅替换了镜像地址,未在ECS任务定义中添加所需环境变量。

解决:

  • 登录AWS控制台,进入ECS服务,找到目标任务定义(iu-app-task),编辑容器配置(iu-app-container),手动添加NODE_ENV、PORT、MONGODB_URI、JWT_SECRET、JWT_EXPIRES等环境变量。
  • 敏感变量(如JWT_SECRET、MONGODB_URI)建议用AWS Secrets Manager或Parameter Store管理,在任务定义中通过secrets字段引用,避免明文暴露。

2. ConfigModule强制读取本地.env文件

当前ConfigModule.forRoot指定了envFilePath: '.env',但ECS容器中不存在该文件,且生产环境应优先读取系统环境变量而非本地文件。

修改app.module.ts中的ConfigModule配置:

ConfigModule.forRoot({
  isGlobal: true,
  // 仅开发环境加载本地.env,生产环境忽略
  envFilePath: process.env.NODE_ENV === 'development' ? '.env' : undefined,
  ignoreEnvFile: process.env.NODE_ENV === 'production',
}),

3. 同步注册模块导致环境变量未加载

JwtModule.register和MongooseModule.forRoot是同步执行的,可能在ConfigModule完成环境变量加载前就已运行,导致读取到undefined。

改为异步注册:

JwtModule异步配置

JwtModule.registerAsync({
  global: true,
  useFactory: () => ({
    secret: process.env.JWT_SECRET,
    signOptions: { expiresIn: process.env.JWT_EXPIRES || '7d' },
  }),
}),

MongooseModule异步配置

MongooseModule.forRootAsync({
  useFactory: () => ({
    uri: process.env.MONGODB_URI,
  }),
}),

4. 验证容器启动命令一致性

Dockerfile中CMD为node dist/main.js,但docker-compose使用npm run start:prod。需确认ECS任务定义中的容器启动命令与本地一致,避免因启动命令差异导致环境变量加载逻辑异常。

5. 验证环境变量注入状态

  • 部署完成后,在AWS控制台查看ECS任务详情,检查容器环境变量是否正确配置。
  • 在main.ts中添加全局日志,打印所有环境变量,确认是否被正确注入:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  console.log('All environment variables:', process.env);
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.PORT || 3000);
}
bootstrap();

内容的提问来源于stack exchange,提问作者antisuri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:05:05