NestJs TypeORM 配置使用 AWS Parameter Store
Posted
技术标签:
【中文标题】NestJs TypeORM 配置使用 AWS Parameter Store【英文标题】:NestJs TypeORM configuration using AWS Parameter Store 【发布时间】:2019-09-18 13:30:10 【问题描述】:NestJS 新手,遇到了一个问题。对于我们的部署,我们需要从 AWS Parameter Store (Systems Manager) 获取我们的配置,包括数据库连接字符串。我有一个 ConfigModule 和 ConfigService,它根据参数存储路径检索我的环境的所有参数存储条目:
这是我的配置服务:
import * as dotenv from 'dotenv';
import * as fs from 'fs';
import * as AWS from 'aws-sdk';
export class ConfigService
private readonly envConfig: [key: string]: string ;
private awsParamStoreEntries: [key: string]: string [];
constructor(awsParamStorePath: string, filePath: string)
this.envConfig = dotenv.parse(fs.readFileSync(filePath));
this.loadAwsParameterStoreEntries(awsParamStorePath).then((data) =>
this.awsParamStoreEntries = data;
);
loadAwsParameterStoreEntries(pathPrefix: string)
const credentials = new AWS.SharedIniFileCredentials( profile: 'grasshopper-parameter' );
AWS.config.credentials = credentials;
const ssm = new AWS.SSM( region: 'us-west-2' );
var params: [key: string]: string [] = [];
return getParams(
Path: '/app/v3/development/',
Recursive: true,
WithDecryption: true,
MaxResults: 10,
).then(() =>
return params;
);
function getParams(options)
return new Promise((resolve, reject) =>
ssm.getParametersByPath(options, processParams(options, (err, data) =>
if (err)
return reject(err);
resolve(data);
));
);
function processParams(options, cb)
return function (err, data)
if (err)
return cb(err)
;
data.Parameters.forEach(element =>
let key = element.Name.split('/').join(':')
params.push( key: key, value: element.Value );
);
if (data.NextToken)
const nextOptions = Object.assign(, options);
nextOptions.NextToken = data.NextToken;
return ssm.getParametersByPath(nextOptions, processParams(options, cb));
return cb(null);
;
get(key: string): string
return this.envConfig[key];
getParamStoreValue(key: string): string
return this.awsParamStoreEntries.find(element => element.key === key)['value'];
getDatabase(): string
return this.awsParamStoreEntries.find(element => element.key === 'ConnectionStrings:CoreDb')['value'];
这是主应用模块声明块:
@Module(
imports: [ConfigModule, TypeOrmModule.forRootAsync(
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => (
url: configService.getDatabase()
),
inject: [ConfigService]
),
CoreModule, AuthModule],
controllers: [AppController],
providers: [AppService],
)
如您所见,我告诉 TypeORM 调用 ConfigService 中的 getDatabase() 方法但问题是加载参数存储条目大约需要 3-4 秒,因此“发生 undefined” 错误是因为当 TypeORM 尝试加载连接字符串时“this.awsParamStoreEntries”仍未定义。
已在网上搜索以查看是否已完成此操作,但找不到以这种方式使用 NestJS / TypeORM / AWS Parameter Store 的任何内容。 *** 上也有一个现有的(未回答的)问题。
谢谢!
【问题讨论】:
【参考方案1】:我们可以使用异步提供程序。
使用 AWS SSM 参数存储参数和 NestJS 配置服务的工作项目示例:
创建异步提供者:
import * as AWS from 'aws-sdk';
import Parameter from 'aws-sdk/clients/ssm';
export const ssmProvider =
provide: 'AWS_SSM',
useFactory: async (): Promise<Parameter[]> =>
const ssmClient = new AWS.SSM(
endpoint: 'endpoint',
region: 'us-west-2',
);
const result = await ssmClient
.getParametersByPath(
Path: '/ssm/path',
Recursive: true,
)
.promise();
return result?.Parameters;
,
;
然后我们可以使用这个提供者来注入值。
例如在配置服务中注入 AWS SSM 参数:
export class ConfigModule
static register(options: ConfigModuleOptions): DynamicModule
return
global: true,
module: ConfigModule,
providers: [
ssmProvider,
provide: CONFIG_OPTIONS,
useValue: options,
,
ConfigService,
],
exports: [ConfigService],
;
在配置服务构造函数中:
constructor(
@Inject(CONFIG_OPTIONS) options: ConfigOptions,
@Inject('AWS_SSM') awsParameters: Parameter[],
)
编辑:提供在应用程序启动时加载 aws 参数存储参数的服务的 NPM 包:
param-store-service
【讨论】:
你有这个代码的完整示例吗? @Metallikanz 我已经编辑了我的答案。看看 NPM 包。您可以按原样使用它,也可以查看 GitHub 代码库。【参考方案2】:你能做这样的事情吗?
import TypeOrmOptionsFactory, TypeOrmModuleOptions from '@nestjs/typeorm';
import ConfigService from './config.service';
import Injectable from '@nestjs/common';
@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory
constructor(private readonly configService: ConfigService)
async createTypeOrmOptions(): Promise<TypeOrmModuleOptions>
this.configService.awsParamStoreEntries = await this.configService.loadAwsParameterStoreEntries(this.configService.awsParamStorePath);
return
url: this.configService.getDatabase(),
;
@Module(
imports: [
ConfigModule,
TypeOrmModule.forRootAsync(
imports: [ConfigModule],
useClass: TypeOrmConfigService,
),
CoreModule,
AuthModule
],
controllers: [AppController],
providers: [AppService],
)
import * as dotenv from 'dotenv';
import * as fs from 'fs';
import * as AWS from 'aws-sdk';
import Injectable from '@nestjs/common';
@Injectable()
export class ConfigService
private readonly envConfig: [key: string]: string ;
awsParamStoreEntries: [key: string]: string [];
private readonly awsParamStorePath: string;
constructor(awsParamStorePath: string, filePath: string)
this.envConfig = dotenv.parse(fs.readFileSync(filePath));
this.awsParamStorePath = awsParamStorePath;
loadAwsParameterStoreEntries(pathPrefix: string) ...
https://docs.nestjs.com/techniques/database
【讨论】:
以上是关于NestJs TypeORM 配置使用 AWS Parameter Store的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Nestjs 中使用 .env 文件设置 Typeorm 的配置