Skip to content

컨테이너 이미지 생성


AWS는 컨테이너 이미지를 생성하는 데 사용할 수 있는 일련의 오픈 소스 기본 이미지를 제공한다. 이러한 기본 이미지에는 Lambda와 함수 코드 간의 상호 작용을 관리하는 런타임 인터페이스 클라이언트가 포함되어 있다.

Node.js 예제와 Python 예제를 포함하는 예제 애플리케이션에 대해서는 AWS 블로그에서 Container image support for Lambda를 참조한다.

주제


1. 사전 조건

컨테이너 이미지를 Lambda에 배포하려면 AWS CLI와 Docker CLI가 필요하다. 또한 다음 요구 사항에 유의한다.

  • 컨테이너 이미지는 Lambda 런타임 API를 구현해야 한다. AWS 오픈 소스 런타임 인터페이스 클라이언트는 이 API를 구현한다. 런타임 인터페이스 클라이언트를 선호하는 기본 이미지에 추가하여 Lambda와 호환되도록 만들 수 있다.

  • 컨테이너 이미지는 읽기 전용 파일 시스템에서 실행할 수 있어야 한다. 함수 코드는 512MB에서 10,240MB 사이의 스토리지가 있는 쓰기 가능한 /tmp 디렉터리에 1MB 단위로 액세스할 수 있다.

  • 기본 Lambda 사용자는 함수 코드를 실행하는 데 필요한 모든 파일을 읽을 수 있어야 한다. Lambda는 권한이 최소 권한인 기본 Linux 사용자를 정의하여 보안 모범 사례를 따른다. 애플리케이션 코드가 다른 Linux 사용자의 실행이 제한된 파일에 의존하지 않는지 확인한다.

  • Lambda는 Linux 기반 컨테이너 이미지만 지원한다.

  • Lambda는 다중 아키텍처 기본 이미지를 제공한다. 하지만 함수에 대해 빌드하는 이미지는 아키텍처 중 하나만 대상으로 해야 한다. Lambda는 다중 아키텍처 컨테이너 이미지를 사용하는 함수를 지원하지 않는다.


2. 이미지 유형

AWS에서 제공한 기본 이미지나 Alpine, Debian과 같은 대체 기본 이미지를 사용할 수 있다. Lambda는 다음 이미지 매니페스트 형식 중 하나에 부합하는 모든 이미지를 지원한다.

  • Docker 이미지 매니페스트 V2, 스키마 2(Docker 버전 1.10 이상에서 사용됨)

  • Open Container Initiative(OCI) 사양(v1.0.0 이상)

Lambda는 최대 10GB 크기의 이미지를 지원한다.

3. 컨테이너 도구

컨테이너 이미지를 생성하려면 다음과 같은 컨테이너 이미지 매니페스트 형식 중 하나를 지원하는 개발 도구를 사용할 수 있다.

  • Docker 이미지 매니페스트 V2, 스키마 2(Docker 버전 1.10 이상에서 사용됨)

  • OCI 사양(v1.0.0 이상)

예를 들어 Docker CLI를 사용하여 컨테이너 이미지를 빌드, 테스트 및 배포할 수 있다.

4. 컨테이너 이미지 설정

Lambda는 Dockerfile에서 다음과 같은 컨테이너 이미지 설정을 지원한다.

  • ENTRYPOINT - 애플리케이션에 대한 진입점의 절대 경로를 지정한다.

  • CMD - ENTRYPOINT를 사용하여 전달할 파라미터를 지정한다.

  • WORKDIR - 작업 디렉터리의 절대 경로를 지정한다.

  • ENV - Lambda 함수의 환경 변수를 지정한다.

Note

Lambda는 Dockerfile에서 지원되지 않는 컨테이너 이미지 설정의 값을 모두 무시한다.

Docker가 컨테이너 이미지 설정을 사용하는 방법에 대한 자세한 내용은 Docker Docs 웹 사이트의 Dockerfile 참조에서 ENTRYPOINT를 참조한다. ENTRYPOINT 및 CMD를 사용하는 방법에 대한 자세한 내용은 AWS 오픈 소스 블로그에서 Demystifying ENTRYPOINT and CMD in Docker를 참조한다.

이미지를 빌드할 때 Dockerfile에서 컨테이너 이미지 설정을 지정할 수 있다. Lambda 콘솔이나 Lambda API를 사용하여 이러한 구성을 재정의할 수도 있다. 이를 통해 동일한 컨테이너 이미지를 배포하지만 런타임 구성이 다른 여러 함수를 배포할 수 있다.

Warning

Dockerfile에서 또는 재정의로 ENTRYPOINT 또는 CMD를 지정할 때 절대 경로를 입력해야 한다. 또한 심볼릭 링크를 컨테이너의 진입점으로 사용하면 안 된다.

5. AWS 기본 이미지에서 이미지 생성

새 Lambda 함수에 대한 컨테이너 이미지를 빌드하기 위해 Lambda용 AWS 기본 이미지로 시작할 수 있다. Lambda는 두 가지 유형의 기본 이미지를 제공한다.

  • 다중 아키텍처 기본 이미지

    기본 이미지 태그(예: python:3.9 또는 java:11) 중 하나를 지정하여 이 유형의 이미지를 선택한다.

  • 아키텍처별 기본 이미지

    아키텍처 접미사가 있는 이미지 태그를 지정한다. 예를 들어 3.9-arm64를 지정하여 Python 3.9의 arm64 기본 이미지를 선택한다.

다른 컨테이너 레지스트리의 대체 기본 이미지를 사용할 수도 있다. Lambda는 Lambda와 호환될 수 있도록 대체 기본 이미지에 추가하는 오픈 소스 런타임 인터페이스 클라이언트를 제공한다.

Note

AWS는 Lambda용 AWS 기본 이미지를 주기적으로 업데이트한다. Dockerfile의 FROM 속성에 이미지 이름이 포함되어 있으면 Docker 클라이언트는 Amazon ECR 리포지토리에서 최신 버전의 이미지를 가져온다. 업데이트된 기본 이미지를 사용하려면 컨테이너 이미지를 다시 빌드하고 함수 코드를 업데이트해야 한다.

Lambda용 AWS 기본 이미지에서 이미지를 생성하려면

  1. 로컬 컴퓨터에서 새 함수에 대한 프로젝트 디렉터리를 생성한다.

  2. 프로젝트 디렉터리에 app이라는 디렉터리를 생성한 다음 함수 핸들러 코드를 app 디렉터리에 추가한다.

  3. 텍스트 편집기를 사용하여 새 Dockerfile을 생성한다.

    AWS 기본 이미지는 다음과 같은 환경 변수를 제공한다.

    • LAMBDA_TASK_ROOT=/var/task

    • LAMBDA_RUNTIME_DIR=/var/runtime

    함수 처리기와 함께 ${LAMBDA_TASK_ROOT} 디렉터리 아래에 종속성을 설치하여 Lambda 런타임에서 함수를 호출할 때 해당 종속성을 찾을 수 있도록 한다.

    다음 예제에서는 Node.js, Python, Ruby에 대한 예제 Docker 파일이다.

    FROM public.ecr.aws/lambda/nodejs:14
    
    # Assumes your function is named "app.js", and there is a package.json file in the app directory
    
    COPY app.js package.json  ${LAMBDA_TASK_ROOT}
    
    # Install NPM dependencies for function
    
    RUN npm install
    
    # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
    
    CMD [ "app.handler" ]  
    
    FROM public.ecr.aws/lambda/python:3.8
    
    # Install the function's dependencies using file requirements.txt
    # from your project folder.
    
    COPY requirements.txt  .
    RUN  pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"
    
    # Copy function code
    COPY app.py ${LAMBDA_TASK_ROOT}
    
    # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
    CMD [ "app.handler" ] 
    
    FROM public.ecr.aws/lambda/ruby:2.7
    
    # Copy function code
    COPY app.rb ${LAMBDA_TASK_ROOT}
    
    # Copy dependency management file
    COPY Gemfile ${LAMBDA_TASK_ROOT}
    
    # Install dependencies under LAMBDA_TASK_ROOT
    ENV GEM_HOME=${LAMBDA_TASK_ROOT}
    RUN bundle install
    
    # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
    CMD [ "app.LambdaFunction::Handler.process" ]
    
  4. docker build 명령을 사용하여 Docker 이미지를 빌드한다. 이미지의 이름을 입력한다. 다음 예제에서는 이미지의 이름을 hello-world로 지정한다.

    docker build -t hello-world .
    
  5. docker run 명령을 사용하여 Docker 이미지를 시작한다. 이 예에서는 hello-world를 이미지 이름으로 입력한다.

    docker run -p 9000:8080 hello-world
    
  6. (선택 사항) 런타임 인터페이스 에뮬레이터를 사용하여 로컬에서 애플리케이션을 테스트한다. 새 터미널 창에서 curl 명령을 사용하여 다음 엔드포인트에 이벤트를 게시한다.

    curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
    

    이 명령은 컨테이너 이미지에서 실행되는 함수를 호출하고 응답을 반환한다.

6. 대체 기본 이미지에서 이미지 생성

사전 조건

  • AWS CLI

  • Docker Desktop

  • 함수 코드

대체 기본 이미지를 사용하여 이미지를 생성하려면

  1. 기본 이미지를 선택한다. Lambda는 Alpine, Debian, Ubuntu 등 모든 리눅스 배포판을 지원한다.

  2. 로컬 컴퓨터에서 새 함수에 대한 프로젝트 디렉터리를 생성한다.

  3. 프로젝트 디렉터리에 app이라는 디렉터리를 생성한 다음 함수 핸들러 코드를 app 디렉터리에 추가한다.

  4. 텍스트 편집기를 사용하여 다음과 같은 구성으로 새 Dockerfile을 생성한다.

    • FROM 속성을 기본 이미지의 URI로 설정한다.

    • 런타임 인터페이스 클라이언트를 설치하기 위한 명령을 추가한다.

    • ENTRYPOINT 속성을 설정하여 런타임 인터페이스 클라이언트를 호출한다.

    • CMD 인수를 설정하여 Lambda 함수 핸들러를 지정한다.

    다음 예제에서는 Python용 Dockerfile을 보여준다.

    # Define function directory
    
    ARG FUNCTION_DIR="/function"
    
    FROM python:buster as build-image
    
    # Install aws-lambda-cpp build dependencies
    
    RUN apt-get update && \
      apt-get install -y \
      g++ \
      make \
      cmake \
      unzip \
      libcurl4-openssl-dev
    
    # Include global arg in this stage of the build
    
    ARG FUNCTION_DIR
    
    # Create function directory
    
    RUN mkdir -p ${FUNCTION_DIR}
    
    # Copy function code
    
    COPY app/* ${FUNCTION_DIR}
    
    # Install the runtime interface client
    
    RUN pip install \
            --target ${FUNCTION_DIR} \
            awslambdaric
    
    # Multi-stage build: grab a fresh copy of the base image
    
    FROM python:buster
    
    # Include global arg in this stage of the build
    
    ARG FUNCTION_DIR
    
    # Set working directory to function root directory
    
    WORKDIR ${FUNCTION_DIR}
    
    # Copy in the build image dependencies
    
    COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
    
    ENTRYPOINT [ "/usr/local/bin/python", "-m", "awslambdaric" ]
    CMD [ "app.handler" ]
    
  5. docker build 명령을 사용하여 Docker 이미지를 빌드한다. 이미지의 이름을 입력한다. 다음 예제에서는 이미지의 이름을 hello-world로 지정한다.

    docker build -t hello-world .
    
  6. (선택 사항) 런타임 인터페이스 에뮬레이터를 사용하여 로컬에서 애플리케이션을 테스트한다.

7. Amazon ECR 리포지토리에 이미지 업로드

다음 명령에서 123456789012를 AWS 계정 ID로 바꾸고 리전 값을 Amazon ECR 리포지토리를 생성할 리전으로 설정한다.

Note

Amazon ECR에서 이미지 태그를 다른 이미지에 다시 할당하면 Lambda가 이미지 버전을 업데이트하지 않는다.

  1. Docker CLI를 Amazon ECR 레지스트리에 인증한다.

    aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
    
  2. create-repository 명령을 사용하여 Amazon ECR에 리포지토리를 생성한다.

    aws ecr create-repository --repository-name hello-world --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
    
  3. 리포지토리 이름과 일치하도록 이미지에 태그를 지정하고 docker push 명령을 사용하여 Amazon ECR에 이미지를 배포한다.

    docker tag  hello-world:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
    docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
    

이제 컨테이너 이미지가 Amazon ECR 컨테이너 레지스트리에 상주하므로 Lambda 함수를 만들고 실행할 수 있다.

8. AWS SAM 도구 키트를 사용하여 이미지 생성

AWS Serverless Application Model(AWS SAM) 도구 키트를 사용하여 컨테이너 이미지로 정의된 함수를 생성하고 배포할 수 있다. 새 프로젝트의 경우 AWS SAM CLI init 명령을 사용하여 선호하는 런타임에 프로젝트의 스캐폴딩을 설정할 수 있다.

AWS SAM 템플릿에서 Runtime 유형을 Image로 설정하고 기본 이미지의 URI를 제공한다.

자세한 내용은 AWS Serverless Application Model 개발자 안내서의 애플리케이션 빌드를 참조한다.


References