Docker化Nest.js应用无法读取.env文件变量问题排查
问题:Docker化Nest.js应用无法读取.env环境变量
我有一个已Docker化的Nest.js应用,包含server、PostgreSQL数据库和pgAdmin4三个服务,原本运行正常,但后来发现项目根目录下的.env文件中的变量无法被读取:调用ConfigService的configService.get()方法始终返回undefined,直接使用process.env.VARIABLE也得到同样结果,在配置JWT策略认证时发现了这个问题。项目通过docker-compose up启动,代码来自一个未Docker化的项目。
相关代码及配置文件
main.ts
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { ValidationPipe } from '@nestjs/common'; import { TransformInterceptor } from './transform.interceptor'; import { ConfigService } from '@nestjs/config'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors(); const configService = app.get(ConfigService); app.enableCors(); app.useGlobalPipes(new ValidationPipe()); app.useGlobalInterceptors(new TransformInterceptor()); const port = configService.get('PORT'); const secret = configService.get('JWT_SECRET'); // const port = process.env.PORT; // const secret = process.env.JWT_SECRET; console.log('port', port, 'secret', secret); await app.listen(port || 4250); } bootstrap();
app.module.ts
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { UsersModule } from './users/users.module'; import { TaskModule } from './task/task.module'; import { ConfigModule, ConfigService } from '@nestjs/config'; // import { ConfigService } from '@nestjs/config/dist'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, envFilePath: `.env`, }), // TypeOrmModule.forRoot({ // type: 'postgres', // host: 'db', // port: 5432, // username: 'postgres', // password: 'postgres', // database: 'postgres', // autoLoadEntities: true, // synchronize: true, // }), TypeOrmModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: async (configService: ConfigService) => { const isProduction = configService.get('STAGE') === 'prod'; return { ssl: isProduction, extra: { ssl: isProduction ? { rejectUnauthorized: false } : null, }, type: 'postgres', autoLoadEntities: true, synchronize: true, // host: configService.get('DB_HOST'), // port: configService.get('DB_PORT'), // username: configService.get('DB_USERNAME'), // password: configService.get('DB_PASSWORD'), // database: configService.get('DB_DATABASE'), host: 'db', port: 5432, username: 'postgres', password: 'postgres', database: 'postgres', }; }, }), UsersModule, TaskModule, ], }) export class AppModule {}
Dockerfile
FROM node:18-alpine AS base WORKDIR /app COPY package*.json ./ ## dev ## FROM base AS dev RUN npm i --frozen-lockfile COPY . . CMD ["npm", "run", "start:dev"] ## prod ## FROM base AS prod RUN npm ci --frozen-lockfile COPY . . RUN npm run build CMD ["npm", "run", "start:prod"]
docker-compose.yml
version: '3.9' services: app: build: context: . dockerfile: Dockerfile target: dev ports: - 4250:4250 volumes: - ./src:/app/src depends_on: - db db: image: postgres restart: always ports: - 5432:5432 environment: POSTGRES_PASSWORD: postgres dbadmin: image: dpage/pgadmin4 restart: always ports: - 5050:80 environment: PGADMIN_DEFAULT_EMAIL: admin@admin.com PGADMIN_DEFAULT_PASSWORD: pgadmin4
.env
JWT_SECRET=SUPERsecret123PAssWORd PORT=4250 DB_HOST=db DB_PORT=5432 DB_USERNAME=postgres DB_PASSWORD=postgres DB_DATABASE=postgres
请问我遗漏了什么配置?是否应该弃用.env文件,转而在docker-compose.yml中定义所有变量?
解决方案
1. 核心问题:.env文件未被挂载到容器内
你的docker-compose.yml中只挂载了./src目录到容器的/app/src,但根目录下的.env文件并没有被挂载进去,也没有通过其他方式传递给容器。容器内的应用无法访问宿主机上的.env文件,自然读取不到变量。
2. 修复方式(二选一即可)
方式一:挂载.env文件到容器
修改docker-compose.yml中的app服务配置,添加.env文件的挂载:
services: app: build: context: . dockerfile: Dockerfile target: dev ports: - 4250:4250 volumes: - ./src:/app/src - ./.env:/app/.env # 新增这一行,挂载.env文件 depends_on: - db
方式二:在docker-compose.yml中定义环境变量
如果不想使用.env文件,可以直接在docker-compose.yml的app服务里通过environment字段定义变量,或者通过env_file字段引入整个.env文件:
services: app: build: context: . dockerfile: Dockerfile target: dev ports: - 4250:4250 volumes: - ./src:/app/src environment: - JWT_SECRET=SUPERsecret123PAssWORd - PORT=4250 - DB_HOST=db - DB_PORT=5432 - DB_USERNAME=postgres - DB_PASSWORD=postgres - DB_DATABASE=postgres # 或者用env_file直接引入整个.env文件: # env_file: # - ./.env depends_on: - db
3. 额外注意事项
- 如果使用挂载.env的方式,确保宿主机上的.env文件路径正确,容器内的路径要和
ConfigModule.forRoot中envFilePath配置的一致(你这里是.env,对应容器内/app/.env,挂载路径匹配)。 - 开发环境下,挂载.env文件更方便修改后实时生效;生产环境建议使用
docker-compose.yml的environment字段或者Docker secrets来管理敏感变量,避免.env文件泄露。
内容的提问来源于stack exchange,提问作者Paul Gutsal
相关产品推荐
相关产品推荐

