Lambda에서 SSM 매개 변수 저장 값 캐시

20995 단어 lambdatypescriptawscdk

간단한 소개


본고의 영감은 blog post의 글에서 비롯되었다. 저자는 AWS SSM Parameter Store의 값을 어떻게 캐시하는지 보여주었다.
Lambda 함수를 여러 번 호출하는 동안 동일한 값을 반복적으로 사용하고 SSM 매개변수에 저장된 API 호출 비용을 절감하기 위해 이 방법을 사용하는 것이 좋습니다.
다음은 AWS CDK을 사용한 예시입니다. 그 중에서 우리는 SSM 파라미터를 정의했고 aws-sdk을 사용하여 파라미터를 가져와 주어진 시간에 캐시를 해서 설정할 수 있습니다.
직접 투입하려는 사용자를 위한 저장소입니다.)

ryands17 / lambda ssm 캐시


캐시 SSM 매개 변수는 CDK를 통해 Lambda에 값을 저장합니다.


먼저 Lambda에서 가져올 매개변수를 정의합니다.
// lib/lambda-ssm-stack.ts
import * as ssm from '@aws-cdk/aws-ssm'

new ssm.StringParameter(this, 'dev-key1', {
  parameterName: '/dev/key1',
  stringValue: 'value1',
})
이것은 StringParameter을 만드는 코드 세그먼트입니다. 암호화되지 않은 값으로 파라미터 경로 /dev/key1과 함께 저장됩니다.
프로젝트에서는 동일한 경로 아래의 모든 값을 쉽게 얻을 수 있도록 경로 기반 형식(예: ${projectName}/${environment}/${keyName})으로 키를 저장하는 것이 좋습니다.예를 들어 서로 다른 환경에서 myProject/dev/DB_HOSTmyProject/prod/DB_HOST이다.
다음으로 Lambda 함수를 정의합니다.
// lib/lambda-ssm-stack.ts
import { join } from 'path'
import * as ln from '@aws-cdk/aws-lambda-nodejs'

const lambdaDir = join(__dirname, '..', 'lambda-fns')

const handler = new ln.NodejsFunction(this, 'fetchParams', {
  runtime: lambda.Runtime.NODEJS_12_X,
  memorySize: 512,
  handler: 'handler',
  entry: join(lambdaDir, 'src', 'index.ts'),
  depsLockFilePath: join(lambdaDir, 'yarn.lock'),
  nodeModules: ['ms'],
  sourceMap: true,
})
위 코드 세그먼트에서 노드를 사용하여 Lambda 함수를 만들었습니다.js 12가 실행될 때 512MB의 메모리를 분배하고 특정한 값을 가지고 있습니다.이것 좀 봅시다.
  • entry 옵션은 파일을 수락합니다. 우리는 상기 정의된 파라미터를 얻기 위해 코드를 정의할 것입니다.이 예에서, 이것은 index.ts이라는 목록의 lambda-fns 파일로, 우리는 그것을 더욱 연구할 것이다.
  • handler 옵션은 index.ts 파일에서 내보낸 함수 이름으로, Lambda는 이 함수를 사용합니다.
  • depsLockFilePath, nodeModulessourceMap 옵션은 노드를 바인딩하는 데 사용됩니다.배치하기 전에 js 함수를 사용합니다.이것은 aws-lambda-nodejs 패키지를 사용하여 완성된 것입니다. 이 패키지는 node_modules을 통해 Lambda에서 실행할 수 있도록 저희 TypeScript 코드를 자바스크립트로 전송합니다.
  • 우리는 이미 함수의 생성을 완성했다.스택을 배포하는 데 필요한 마지막 코드를 살펴보겠습니다.
    // lib/lambda-ssm-stack.ts
    handler.addToRolePolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ['ssm:GetParametersByPath'],
        resources: [`arn:aws:ssm:${this.region}:*:parameter/dev*`],
      })
    )
    
    마지막 코드 세그먼트를 사용하면 Lambda 함수는 매개변수 저장소에서 생성된 매개변수를 가져올 수 있으며 매개변수가 아닌 /dev에서 시작하는 매개변수에 액세스할 수 있습니다.이것은 우리가 특히 다른 항목에 대해 필요하지 않은 비밀 값을 얻지 못할 것을 보장한다.
    이제 lambda-fns 폴더의 Lambda 함수를 살펴보겠습니다.
    // lambda-fns/index.ts
    import { Context } from 'aws-lambda'
    import { config, loadParameters } from './config'
    
    export const handler = async (event: any, context: Context) => {
      await loadParameters()
      return {
        value: config.values['/dev/key1'],
        success: true,
      }
    }
    
    이것은 우리의 handler 함수입니다. 이것은 loadParameters 함수를 호출하여 매개 변수를 가져오고 값을 되돌려줍니다.
    매개 변수와 캐시를 가져오는 주 코드를 포함하는 config.ts을 살펴보겠습니다.
    변수 정의부터 시작하겠습니다.
    // lambda-fns/config.ts
    
    import { SSM } from 'aws-sdk'
    import ms from 'ms'
    
    type Config = {
      values: Record<string, string | undefined>
      expiryDate?: Date
    }
    
    const ssm = new SSM()
    export let config: Config = { values: {} }
    
    여기에서 우리는 SSM의 실례를 초기화했다. 우리는 이 실례를 사용하여 파라미터를 얻고 config 변수를 사용하여 파라미터를 저장할 것이다.우리는 또한 여러 개의 값을 얻어 여기에 저장할 수 있다.config 변수의 유형을 주의하십시오.이것은 두 개의 키가 있습니다. values은 우리의 파라미터를 저장하고, expiryDate은 우리의 캐시를 효력을 상실시키고 모든 파라미터를 다시 가져옵니다.
    만료 시간은 설정할 수 있습니다. 다음에 loadParameters 함수에서 어떻게 사용하는지 보십시오.
    // lambda-fns/config.ts
    export const loadParameters = async ({
      expiryTime: cacheDuration = '1h',
    }: {
      expiryTime?: string
    } = {}) => {
      if (!config.expiryDate) {
        config.expiryDate = new Date(Date.now() + ms(cacheDuration))
      }
      if (isConfigNotEmpty() && !hasCacheExpired()) return
    
      console.log('[Cost]: API called')
      config.values = {}
      const { Parameters = [] } = await ssm
        .getParametersByPath({
          Path: '/dev',
        })
        .promise()
    
      for (let param of Parameters) {
        if (param.Name) config.values[param.Name] = param.Value
      }
    }
    
    const hasCacheExpired = () =>
      config.expiryDate && new Date() > config.expiryDate
    
    const isConfigNotEmpty = () => Object.keys(config.values).length
    
    Lambda의 마지막이자 가장 중요한 함수인 loadParameters 함수는 expiryTime이라는 값을 받아들인다. 이 값은 기본적으로 1시간으로 설정되어 덮어쓸 수 있다.나는 ms 라이브러리를 사용하여 인류가 읽을 수 있는 시간대를 설정했는데, 이 시간대는 자동으로 밀리초로 전환된다.
    우리는 우선 유효기간이 존재하는지 검사한다.없으면 현재 시간 + 만료 시간으로 설정합니다.
    그리고 우리는 이 장면이 있다.
    if (isConfigNotEmpty() && !hasCacheExpired()) return
    
    다음 내용은 구성에 값이 있고 캐시가 만료되지 않은 경우 값이 이미 있고 API를 호출하여 매개변수를 가져오지 않으려면 함수를 종료합니다.
    이러한 함수는 조건을 읽을 수 있도록 다음과 같이 정의되어 있을 뿐입니다.
    const hasCacheExpired = () =>
      config.expiryDate && new Date() > config.expiryDate
    
    const isConfigNotEmpty = () => Object.keys(config.values).length
    
    다음 세션은 매개 변수의 전체 가져오기와 설정입니다. 상기 조건을 검사했기 때문에 캐시가 만료되었거나 설정에 아무런 값이 없다는 것을 알 수 있습니다.
    console.log('[Cost]: API called')
    config.values = {}
    const { Parameters = [] } = await ssm
      .getParametersByPath({
        Path: '/dev',
      })
      .promise()
    
    for (let param of Parameters) {
      if (param.Name) config.values[param.Name] = param.Value
    }
    
    본고에서 우리는 파라미터를 가져오고 있는지 알아보기 위해 로그를 추가했을 뿐입니다. values을 빈 대상({})으로 설정합니다.그리고 우리는 getParametersByPath 방법을 호출하여 자원 파일에 생성된 경로 dev을 전달합니다.마지막으로, 우리는 이 매개 변수를 순환해서 설정의 values 속성에 추가합니다.
    우리 망했어!이 스택을 배치하려면 yarn cdk deploy 또는 npm run cdk deploy을 실행하십시오.
    참고: 이러한 사전 요구 사항은 aws-cli을 설치하고 액세스 키 및 키 구성 프로파일을 사용하는 것입니다(이 경우 default 프로파일을 구성했습니다).
    이제 콘솔에서 테스트 이벤트를 만들어서 이 lambda를 실행합니다.

    Test 를 클릭하면 첫 번째 실행 시 다음과 같은 로그가 표시됩니다.

    우리가 저장한 파라미터의 결과를 성공적으로 얻었습니다. 로그를 검사하면 API가 호출되는 것을 볼 수 있습니다. 값이 존재하지 않기 때문입니다. 이것은 첫 번째 호출이기 때문에 호출된 파라미터 저장은 값을 얻기 위해서입니다.
    테스트 이벤트를 다시 실행하고 결과를 봅시다.

    이 값을 받았지만 호출된 로그 API가 존재하지 않습니다. 이것은 캐시에서 얻은 값임을 의미합니다.)
    람바다가 후속 호출에서 execution environment을 재사용했기 때문에 이 값은 여전히 존재한다.이것은 최고 Lambda 버전으로 외부에서 설정할 수 없습니다.Lambda는 깨끗한 상태에서 시작할 수 있습니다. loadParameters 함수에서 설명한 바와 같이 값을 다시 얻기 위해 조건을 추가해야 합니다.
    이것이 바로 Lambda 함수에서 SSM 매개변수 저장소에 캐시된 값입니다.yarn cdk destroy을 사용하여 이 스택을 완성한 후 삭제하는 것을 잊지 마십시오.
    읽어주셔서 감사합니다!만약 당신이 좋아한다면, 반드시 이 글을 좋아하고 공유해야 한다:)

    좋은 웹페이지 즐겨찾기