AWS 노트

로컬에서 AWS CDK Stack 빌드해서 Lambda 함수 실행시키기

Jonchann 2020. 4. 8. 22:52

CDK란 코드 인프라를 관리하기 위한 소프트웨어 개발 프레임워크이다.

예를 드는게 이해가 빠르니 먼저 DynamoDB에서 데이터를 가져와 Lambda 함수로 처리해 S3 버킷에 격납하는 상황을 상상해보자.
AWS 콘솔로 위의 태스크를 수행한다 했을 때 DynamoDB의 데이터, Lambda 함수, S3 버킷을 하나 하나 만들어야 한다.
상황이 변해 더이상 DynamoDB의 데이터를 사용하지 않는다던가 더이상 사용할 데이터가 없을 경우, Lambda 함수와 S3 버킷도 사용을 중지하거나 삭제해야 할 것이다. 그리고 각각의 서비스에 들어가 하나 하나 정성스레 중지/삭제를 해야 한다.

 

하지만 Amazon CDK(Cloud Development Kit)stack을 하나 만들어 그 안에 DynamoDB, Lambda handler, S3 버킷 인프라를 구축한다면 컴파일도(Python 제외) Github에의 commit, push도 한 방에 가능하고 만약 수정하거나 삭제하게 될 시에는 stack을 작성한 파일에서 코드를 수정하거나 삭제하기만 하면 된다.

자세한 설명은 아래 블로그를 보는게 좋다. 한 방에 이해가 간다!
코드로 인프라 관리: AWS CDK

로컬에 CDK 환경을 구축하자


먼저, 이 블로그 다른 글을 보면 알겠지만 나는 `Python3.x`유저이다.
하지만 `CDK stack`은 정적 언어인 `TypeScript`를 사용하는 것이 안전하고 좀 더 객체지향적이기 때문에 이제부터 공부해야 한다.
때문에 `CDK`환경은 `TypeScript`로 구축했다.

node.js와 npm 설치
npm을 위 링크에서 다운로드 해 설치한다.

$ npm install -g aws-cdk

하지만 설치하는데 에러가 났다(자세한 내용은 잊어버렸다).
`node_modules`의 소유자를 변경해주자.

sudo chown -R $USER /usr/local/lib/node_modules

먼저 CDK 환경을 이용해 개발할 repositoryclonebranchcheckout 한다.

$ git clone [repository_name]
$ git checkout -b [branch_name]

이미 무언가 들어있는 폴더에서는 초기화할 수 없다.
때문에 새로운 작업 폴더를 생성해야 한다.

$ mkdir NewCDKdir && cd NewCDKdir
$ cdk init --language typescript

Lambda 핸들러를 처리해야 하기 때문에 그에 필요한 라이브러리를 설치한다.

$ npm install @aws-cdk/aws-lambda @aws-cdk/core

Pythonaws-cdk.aws-lambda라는 식으로 하나 설치하면 20개 정도 AWS 서비스가 쫙 설치 되는데 TypeScript는 그렇지 않은 것 같다.

Stack을 만들자


나는 Visual Studio Code를 깔았다.
iTerms2로 개발하는건 역시 멋지긴 한데 편리하긴 에디터가 편하다. 하이라이트도 그렇고.
Installing the AWS Toolkit for Visual Studio Code를 보고 AWS Toolkit을 설치한다.

작업할 repository를 VS에서 열어 내가 만든 폴더에 간다.
binlib이라는 폴더가 있을 것이다.
bin에는 example_dir_name.ts가 있는데 그 안에는 아래와 같은 코드가 적혀 있다.

import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { ExampleDirNameStack } from '../lib/example_dir_name-stack';

const app = new cdk.App();
new ExampleDirNameStack(app, 'ExampleDirNameStack');

읽어보면 알겠지만 ExampleDirNameStack을 호출해 실행하는 역할을 하는 코드이다.

그럼 lib에는 어떤 것이 들어있을까.
그렇다. 위 코드가 실행시키는 ExampleDirNameStack 클래스가 있다.

import * as cdk from '@aws-cdk/core';

export class ExampleDirNameStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here

      }
}

scope가 뭔지 아직은 잘 모르겠지만 Python적인 사고로 코드를 읽으면 아마 __init__아닐까 싶다.(아님 말고..)

CDK에 놓을 Lambda함수를 명시하자


위의 코드에 Lambda handler의 정보를 전달해주면 된다.

제일 위에서 말했던 '안전'하다는 것은 `const`를 말한다.
typescript에는 const, let, var가 있다는데 const는 일단 정의를 한 후에는 다른 값을 대입할 수 없기 때문이다.
import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';
import { Duration } from '@aws-cdk/core' // Python에서 class를 import하는 것과 같다. 즉, cdk.Duration이 아니라 Duration이라고만 적어도 되게 된다.

export class ExampleDirNameStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here
    const func = new lambda.Function(this, 'ExampleDirName-lambda', { // ExampleDirName라고만 적으면 식별되기 힘들다 한다.
        code: lambda.Code.fromAsset('src'), // Asset으로 쓰면 계속 directory 혹은 file을 찾지 못한다는 에러가 나서 그냥 폴더만 써도 되는 fromAsset()을 사용했다. 차이는 잘 모른다..
        handler: 'lambda_handler.lambda_handler', // handler의 정보
        runtime: lambda.Runtime.PYTHON_3_7, // runtime(프로그래밍 언어) 정보
        timeout: Duration.seconds(60) // lambda가 실행되는데 timeout에서 정한 시간을 넘으면 log에 남는다.
    });
  }
}

lambda.Function의 인수로 {}를 주면 이건 구조체를 정의하는 것이라고 한다.
this..는 까먹었다. 나중에 찾아봐야겠다.
src는 handler코드가 있는 폴더 이름이다.

그나마 기쁜 정보는 Stack 안에 있는 구조체 혹은 리소스 혹은 서비스 .. 뭐라 해야할지 모르겠지만 어쨌든 이것들은 Python3.x로 코딩해도 된다는 것이다!

handler를 만들자


참고로 src폴더는 bin이나 lib과 다르게 직접 생성해야 한다.

def lambda_handler(event, context):
    return "Hello CDK"

일단 움직이는지 확인해야 하기 때문에 적당히 만들어준다.

Repository에 push 하자.


컴파일

다시 터미널에 가서

$ npm run build

를 한다.
그래야 컴파일이 된다.
Python만 써보다 컴파일을 해야 하는 언어를 사용하니 참 신기하다.

Deploy

처음으로 CDK stackdeploy하기 위해서는 bootstrap을 해야한다.

$ cdk bootstrap --profile [switched_account]

그 후 deploy한다.

$ cdk deploy [stack_name] --profile [switched_account]

deploy를 하게 되면 AWS CloudFormation이 해당 stack을 실행할 수 있게 된다.
[stack_name]을 적게 되면 특정 stack만을 deploy한다는 것이고 적지 않으면 해당 폴더에 있는 모든 stack을 한꺼번에 deploy한다는 뜻이니 이름 적는 것을 습관화 해야할 것 같다.
참고로 [stack_name]은 Stack class의 이름이 아니라 bin에 생성된 example_dir_name.tsnew ExampleDirNameStack(app, 'ExampleDirNameStack');'ExampleDirNameStack'문자열 부분이다.
보통은 이름이 다 다르다 하는데 왠지 이번에는 동일한 이름이 되어 버려 참 설명하기 애매하다.

add, commit, push

$ git add .
$ git commit -m "lambda in cdk stack"
$ git push origin [new_branch_name]

물론 AWS 콘솔에서 함수가 제대로 실행 성공하는지 확인하고 해야 한다.