개발/IaC

[Terraform] Lambda 최초 배포 시 컨테이너 이미지 처리

Jaeyeon Baek 2023. 11. 13. 23:13

테라폼을 통해 람다를 배포해봅니다

 

Lambda(람다) 배포 방식에는 네 가지가 존재합니다. (1) 소스코드를 에디터에서 직접 개발 (2) ZIP 압축 파일을 업로드해서 배포 (3) S3 경로에 압축파일을 두고 배포 (4) 컨테이너 이미지를 통해 배포가 있습니다. 이번 글에서는 컨테이너 이미지를 통해 배포하는 방법을 알아볼 텐데요. 특이한 조건이 하나 붙일 겁니다. 테라폼 코드를 통해 Lambda와 ECR을 최초 배포할 때 컨테이너 이미지를 어떻게 처리해야 하는가입니다. 정확하게는 AWS 인프라를 테라폼으로 초기 구축하는 상황인 겁니다. 

이런 상황에서 무엇이 문제가 되는지 살펴보려면 생성해야 하는 리소스를 알아야 합니다. 먼저 ECR(Elastic Container Registry)를 생성해줘야 합니다. 소스코드는 대충 아래와 같은 모양입니다.

resource "aws_ecr_repository" "this" {
  name                 = var.repo_name
  image_tag_mutability = "MUTABLE"
  tags                 = var.tags
  force_delete         = false
  ...
}

 

그리고 여기서 생성된 ECR 이미지 경로를 Lambda 리소스를 생성할 때 사용해줘야 합니다. 7번째 라인에 image_uri 쪽을 봐주시면 됩니다.

resource "aws_lambda_function" "this" {
  function_name = var.function_name
  package_type  = var.package_type
  role          = var.role_arn
  handler       = var.handler
  runtime       = var.runtime
  image_uri     = format("%s:latest", aws_ecr_repository.this.repo_url) # <---
  memory_size   = var.memory_size
  timeout       = var.timeout
  tags          = var.tags
  ...
}

 

자, 이 순서대로 리소스가 배포되면 문제가 있습니다. aws_lambda_functions 리소스에 image_uri에는 유효한 이미지 경로가 있어야 하는데요. ECR이 방금 생성된 마당에 유효한 이미지가 없기 때문에 Lambda 리소스 생성에서 실패할 겁니다. 

╷
│ Error: creating Lambda Function (test-lambda-function): operation error Lambda: CreateFunction, https response error StatusCode: 400, RequestID: 6f992b28-8f5a-4812-8c7f-4482fe16e663, InvalidParameterValueException: Source image xxxxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/test-lambda-function:latest does not exist. Provide a valid source image.
│ 
│   with module.foo_lambda.aws_lambda_function.this,
│   on ../modules/aws_lambda/aws_lambda_function.tf line 1, in resource "aws_lambda_function" "this":
│    1: resource "aws_lambda_function" "this" {
│ 
╵

 

커뮤니티에서는 이런 상황 때문에 ECR 생성과 Lambda 생성을 분리하라고 합니다. 즉, (1) ECR을 생성하는 테라폼을 먼저 배포하고, (2) GitHub Actions 등에서 컨테이너 이미지를 생성해서 ECR에 넣어주는 작업을 하고 난 후에 (3) Lambda 리소스를 배포하라는 거죠. 뭔가 상당히 찝찝하고 귀찮은 프로세스임에 틀림없어 보입니다. 

이런 상황을 타개하는 방법은 의외로 간단합니다. 유효한 image_uri를 넣어주면 되는 거죠. Lambda가 정상적으로 배포될 수 있도록이요. 일단 테라폼 코드를 통해 정상적으로 초기 배포하는 게 목적이니까요. Lambda가 테라폼에 의해 정상적으로 배포되고 나면 CI/CD를 통해 정상적인 컨테이너 이미지를 배포해 주면 됩니다. 자, 그러면 어떻게 유효한 image_uri를 만들어줄 수 있을까요? AWS에서 제공해 주는 hello-world 컨테이너 이미지를 넣어주는 겁니다. 적당한 초기 이미지가 이미 있다면 그걸 사용해 주셔도 무방합니다. 아래 코드를 봐주세요.

data "aws_ecr_authorization_token" "token" {}

resource "null_resource" "local-image" {
  provisioner "local-exec" {
    command = <<-EOT
      docker pull amazon/aws-lambda-python:latest
      docker tag amazon/aws-lambda-python:latest ${aws_ecr_repository.this.repository_url}:latest
      aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin xxxxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com
      docker push ${aws_ecr_repository.this.repository_url}:latest
    EOT
  }
  depends_on = [
    data.aws_ecr_authorization_token.token,
    aws_ecr_repository.this,
  ]
}

 

(1) 사용할 컨테이너 이미지를 도커 레지스트리에서 받아오고 (2) ECR에서 사용할 규칙에 맞게 태깅해 줍니다 (3) ECR에 로그인하고 (4) 태깅된 이미지를 push 해주면 끝. 이렇게 소스코드를 작성해 주면 ECR이 생성된 후에 aws-lambda-python(약 550MB) 이미지가 push 될 겁니다. 그러고 나서 Lambda 리소스가 생성되면서 이 이미지를 사용하게 되는 거죠. 만약 550MB라는 용량이 부담스러우면 도커에서 제공해 주는 공식 hello-world( hello-world:latest, 약 13KB ) 이미지를 사용해 주셔도 무방합니다. 대신 이때는 Lambda 호출 테스트는 하실 수 없는 점을 참고해 주시면 됩니다. handler가 인식되지 않기 때문입니다.

 

# 마무리

이번 글에서는 null_resource를 통해 docker 이미지를 임시로 ECR에 push 해줌으로써 Lambda를 컨테이너 버전으로 초기 배포하는 방법을 살펴봤습니다. 초기 설정이 아니라면 사실 필요 없는 설정이고 알 필요도 없는 내용이기도 합니다. 흔히 마주치는 상황은 아니라는 거죠. 대부분 뭐가 됐든 ECR에 이미지가(Lambda에 배포하려는 이미지 말고) 이미 올라가 있는 계정에서 신규 Lambda를 생성하려고 할 테니까 존재하는 ECR 경로를 임시로 지정해 줘도 됩니다. 하지만 계정에 아무것도 없는 상태에서는 이런 방법이 꼭 필요할 겁니다.

끝으로 CI/CD가 붙고 나면 null_resource를 테라폼 코드에서 삭제해 주면 깔끔해집니다. AWS 환경을 초기부터 테라폼 코드로 잡으려는 분들께 도움이 되시길 바랍니다. :)