AWS 기술 블로그

Seekable OCI 및 AWS Fargate를 사용한 컨테이너 이미지 지연 로딩으로 더 빠르게 컨테이너 시작하기

본 게시물은 AWS Container Blog에 게시된 “Under the hood: Lazy Loading Container Images with Seekable OCI and AWS Fargate” by Olly Pomeroy and Vaibhav Khunger을 한국어 번역 및 편집하였습니다.

서버리스 컴퓨팅 엔진인 AWS Fargate는 이제 Seekable OCI(SOCI)를 사용하여 인덱싱된 컨테이너 이미지의 레이지 로딩을 지원합니다. SOCI를 통해 컨테이너 이미지를 지연 로딩하면 AWS Fargate에서 Amazon Elastic Container Service(Amazon ECS) 작업을 시작하는 데 걸리는 시간이 줄어듭니다. Donnie Prakoso가 작성한 출시 게시글(원문: AWS Fargate Enables Faster Container Startup using Seekable OCI)에서는 AWS Fargate와 SOCI를 어떻게 시작해야 하는지에 대한 세부 정보를 제공하므로, 이 글을 읽기 전에 해당 포스트를 확인하는 것을 추천합니다.

이 게시글에서는 컨테이너 이미지의 내용을 수정하거나 기존 도구나 워크플로우를 변경하지 않고도 컨테이너 이미지를 인덱싱 할 수 있는 SOCI에 대해 자세히 알아봅니다. 그리고 SOCI 인덱스를 활용해 컨테이너 이미지를 레이지 로딩하는 remote containerd snapshotter인 SOCI snapshotter에 대해 설명합니다. 마지막으로, AWS Fargate에서 SOCI를 사용할 때 주의해야 할 점에 대해서도 다루겠습니다.

Seekable OCI 는 어떻게 동작하나요?

containerd에서 컨테이너의 파일 시스템을 관리하는 구성 요소를 snapshotter라고 합니다. 기본 snapshotter인 overlayfs는 컨테이너를 시작하기 전에 전체 컨테이너 이미지를 가져와(pull) 압축을 해제합니다. 지연 로딩 snapshotter(예: stargz 또는 SOCI snapshotter)를 사용하면 컨테이너가 전체 컨테이너 이미지를 다운로드하지 않고, 대신 Amazon Elastic Container Registry(Amazon ECR)과 같은 OCI 호환 레지스트리에서 파일을 지연 로딩하며 시작됩니다. 전체 컨테이너 이미지가 다운로드될 때까지 기다리지 않고 컨테이너를 시작하기 때문에, overlayfs와 비교할 때 시작 시간이 더 짧은 경우가 많습니다. 즉, overlayfs에서는 이미지를 가져오는 데 걸리는 시간과 컨테이너 이미지의 크기 간에 상관관계가 있기 때문에 지연 로딩 snapshotter를 사용하면 컨테이너 이미지 크기가 커질수록 overlayfs와 비교하여 상대적으로 속도 향상 효과가 커집니다.

SOCI snapshotter가 컨테이너 이미지를 지연 로딩하기 위해서는 먼저 컨테이너 이미지 내용에 대한 메타데이터를 가지고 있어야 합니다. 컨테이너 이미지는 여러 컨테이너 이미지 레이어로 구성되며, OCI 호환 레지스트리에 압축된 tarball로 저장됩니다. SOCI snapshotter가 컨테이너 이미지를 지연 로딩할 수 있게 하려면, 각 레이어에 어떤 파일들이 있는지, 압축된 tarball 내에서 어디에 저장되어 있는지, 그리고 애플리케이션에 필요한 파일만 어떻게 압축 해제할지 알아야 합니다. SOCI에서는 이러한 모든 메타데이터가 SOCI 인덱스에 저장됩니다.

출시 게시글에서 Donnie는 soci create 명령어가 컨테이너 이미지를 인덱싱하고 SOCI 인덱스 매니페스트를 생성하는 방법을 보여줍니다. soci push 명령어는 SOCI 인덱스 매니페스트를 OCI 호환 레지스트리에 푸시하여 SOCI snapshotter에서 사용할 수 있도록 합니다. 그럼 이 두 단계에 대해 좀 더 자세히 살펴보겠습니다.

SOCI 인덱스 매니페스트 생성하기

soci create를 실행하면, 내부적으로 각 컨테이너 이미지 계층마다 zTOC(SOCI 메타데이터의 일부)이 생성됩니다. 이 zTOC는 두 부분으로 나뉩니다.

  • Table of Contents (TOC) – 이 테이블에는 해당 계층의 모든 파일과 그 파일이 tarball에서 어디에서 찾을 수 있는지에 대한 오프셋 정보를 포함하고 있습니다.
  • zInfo – SOCI에서 압축된 tarball은 논리적인 청크(chunk)인 스팬(span)으로 나누어집니다. 스팬의 목록은 zInfo라는 테이블에 저장됩니다. 각 스팬은 레지스트리로부터의 범위 지정 GET 요청을 통해 독립적으로 검색되고, 이후에는 zInfo에 저장된 데이터를 사용하여 압축을 풀 수 있습니다. 스팬을 사용하면, SOCI snapshotter는 백그라운드 프로세스가 전체 tarball을 검색하기 전에 레지스트리에서 필요한 파일만 다운로드할 수 있습니다.

색인된 각 컨테이너 이미지에 대해, soci cli는 컨테이너 이미지에 대한 모든 zTOC와 관련된 컨테이너 이미지에 대한 참조가 포함된 SOCI 인덱스 매니페스트를 생성합니다. SOCI 인덱스 매니페스트는 soci index info 명령으로 로컬에서 확인할 수 있습니다.

SOCI 인덱스 매니페스트에서 주목할 만한 두 가지 부분은 다음과 같습니다.

  • layers – SOCI 인덱스에서는 컨테이너 이미지 계층의 목록 대신 해당 컨테이너 이미지에 대응하는 모든 zTOC의 목록이 계층이 됩니다. 주석에는 zTOC가 어떤 컨테이너 이미지 레이어에 해당하는지도 표시됩니다.
  • subject – 컨테이너 이미지 매니페스트의 다이제스트, 미디어 타입, 크기를 지정하여 이 SOCI 인덱스가 어떤 컨테이너 이미지를 참조하는지를 식별합니다. subject 필드를 읽고 SOCI 인덱스가 참조하는 이미지를 파악하는 것은 클라이언트(이 경우에는 SOCI snapshotter)에서 해야 합니다.

아래 다이어그램은 SOCI 인덱스 매니페스트와 컨테이너 이미지 매니페스트 간의 관계를 보여줍니다.

SOCI 인덱스 매니페스트 푸시하기

soci push는 SOCI 인덱스 매니페스트와 모든 zTOCs(각 컨테이너 이미지 레이어당 하나)를 OCI 호환 레지스트리로 푸시합니다. SOCI 인덱스 매니페스트와 함께 두 번째 매니페스트인 OCI 이미지 인덱스가 레지스트리로 푸시됩니다. 만약 OCI 이미지 인덱스가 이미 레지스트리에 존재하는 경우에는 업데이트됩니다. OCI 이미지 인덱스 매니페스트는 sha-<digest-of-container-image>의 태그를 가지며, 컨테이너 이미지와 관련된 모든 SOCI 인덱스의 목록을 포함합니다.

OCI 이미지 인덱스는 컨테이너 이미지에 대한 클라이언트 관리 참조를 허용하며, 레지스트리가 OCI 1.0 배포 사양만 지원하는 경우에 사용할 수 있습니다. OCI 1.1 이미지배포 사양이 릴리스되면, soci cli는 리퍼러(referrers) API를 지원하는 레지스트리에 대해 이 두 번째 아티팩트 푸시를 중단합니다.

SOCI 인덱스와 함께 컨테이너 실행하기

인덱싱된 컨테이너 이미지가 있는 컨테이너가 시작하기 전에, SOCI snapshotter는 SOCI 인덱스 매니페스트와 모든 zTOC를 컨테이너 호스트에 다운로드합니다. 또한 각 컨테이너 이미지 레이어에 대해 FUSE 파일 시스템을 생성합니다. 추가로, 컨테이너가 시작한 후에 snapshotter는 전체 컨테이너 이미지를 로컬 스토리지로 이동시키는 백그라운드 프로세스를 시작합니다. 워크로드가 아직 로컬에 존재하지 않는 파일에 접근하려고 하면, snapshotter는 다음과 같은 작업을 수행합니다.

  1. SOCI snapshotter는 먼저 파일이 포함된 레이어를 찾기 위해 조회를 수행합니다.
  2. snapshotter는 TOC에서 파일의 레이어 tarball 내 위치를 검색합니다.
  3. snapshotter는 오프셋과 zInfo 테이블을 사용하여 해당 파일 데이터를 포함하는 스팬(즉, 압축된 tarball의 논리적 청크) 집합을 찾습니다.
  4. 마지막으로, 필요한 스팬만을 다운로드하고 압축을 풀어 파일 데이터를 반환합니다. 한 번 스팬이 다운로드되면, SOCI는 로컬 캐싱을 사용하여 각 스팬을 한 번만 다운로드하고 압축을 푸는 것을 보장합니다.

SOCI 인덱스 이미지 생성 자동화

SOCI 프로젝트의 주요 목표 중 하나는 고객들이 기존 워크플로우와 도구를 변경하지 않고도 지연 로딩을 가능하게 하는 것입니다. SOCI로 컨테이너 이미지를 색인해도 컨테이너 이미지 데이터는 수정되지 않기 때문에 기존 서명 및 다이제스트 검증 프로세스에 존재하는 신뢰 체인이 그대로 유지됩니다. 또한 SOCI 프로젝트는 고객들이 SOCI 인덱스 생성을 자동화하기를 원할 것이라는 점도 알고 있었습니다. 따라서 SOCI를 이용한 AWS Fargate에서 컨테이너 이미지의 지연 로딩 기능 출시와 함께, AWS 인프라 자동화의 일환으로 SOCI 인덱스 빌더 프로젝트를 함께 출시했습니다.


SOCI 인덱스 빌더는 컨테이너 이미지가 Amazon ECR에 푸시될 때 SOCI 인덱스 생성을 자동화하는 블루프린트를 제공합니다. 이 프로젝트의 소스 코드는 오픈 소스이며 GitHub에서 이용 가능합니다. 블루프린트는 AWS CloudFormation 템플릿으로, Amazon EventBridge Rule과 두 개의 AWS Lambda Function으로 구성되어 있습니다. Amazon ECR Repository에 성공적으로 컨테이너 이미지가 푸시되면, Amazon EventBridge 규칙이 AWS Lambda 함수를 트리거합니다. 첫 번째 함수는 컨테이너 이미지를 검증하고, 두 번째 함수는 SOCI 인덱스를 생성하고 이를 컨테이너 이미지와 함께 ECR에 푸시합니다. 이는 SOCI 인덱스를 완전히 자동으로 생성하는 방법을 제공합니다.

이 프로젝트를 시작하고 여러분 계정에 배포하려면 여기에서 호스팅되는 설명서를 참조하세요.

추가 도구들

SOCI 인덱스 빌더와 함께, 우리는 또한 기존 워크플로우에 어떻게 SOCI 인덱스 생성이 통합될 수 있는지를 보여주기 위해 SOCI snapshotter on AWS Fargate toolbox repository를 만들었습니다. 샘플 저장소 안에는 두 가지 도구가 있습니다.

  • A containerized index builder – 개발 워크플로우의 일부로 Docker 엔진을 활용하는 고객(예: Docker Desktop을 실행하는 고객)은 그들의 컨테이너 이미지가 soci cli으로 검색되지 않는다는 것을 알게 됩니다. 이는 Docker 엔진이 기본적으로 컨테이너 이미지를 Docker 엔진 이미지 스토어에 저장하고, containerd 이미지 스토어에는 저장하지 않기 때문입니다. Moby 프로젝트에서는 Docker 엔진 이미지 스토어를 containerd로 이동하는 작업이 진행 중이지만, 글을 쓰는 현재 시점에서 containerd 이미지 스토어가 기본값은 아닙니다. 고객이 Docker 엔진을 활용할 때 SOCI 인덱스를 생성하는 데 도움이 되도록 이 컨테이너화된 이미지 빌더를 사용하여 SOCI 인덱스를 생성할 수 있습니다. 이 도구는 컨테이너 내부에서 containerd를 실행하는 방식으로 작동하며(마치 Docker in Docker처럼), 원격 레지스트리에서 컨테이너 이미지를 가져오고, 컨테이너 이미지를 인덱싱한 다음, 인덱스를 OCI 호환 레지스트리에 다시 푸시합니다.
  • AWS Code Pipeline Demo – 고객들은 빈번하게 연속적인 통합 및 연속적인 배포 파이프라인의 일부로 프로덕션용 컨테이너 이미지를 빌드합니다. 툴박스 저장소에는 AWS CodePipeline을 위한 블루프린트가 있어, CI/CD 파이프라인의 일부로 컨테이너 이미지를 어떻게 빌드하고 인덱스할 수 있는지 보여줍니다. 이 예제는 SOCI를 기존의 CI/CD 파이프라인에 통합하는 방법에 대한 영감을 제공하고자 합니다.

AWS Fargate에서 컨테이너 이미지의 지연 로딩

AWS Fargate에서 컨테이너 이미지의 지연 로딩은 새로운 Amazon ECS 태스크의 시작 시간을 줄이는 것으로 나타났습니다. 그러나 모든 태스크 부하와 컨테이너 이미지에서 이점을 보는 것은 아닙니다. 내부 테스트 중에는 대형(> 250 MB) 컨테이너 이미지가 SOCI를 사용했을 때 가장 큰 이점을 보는 것으로 나타났습니다. 반대로 워크로드가 파일시스템 메타데이터에 자주 접근하거나, 애플리케이션 시작 후 빠르게 모든 이미지 데이터에 접근해야 하는 경우, SOCI의 이점은 감소했습니다. 현재 우리는 SOCI를 활용할 수 있는 워크로드의 수를 늘리면서 성능을 개선하기 위해 반복하고 있습니다. 이 섹션에서는 AWS Fargate에서 컨테이너 이미지의 지연 로딩에 대한 몇 가지 구체적인 사항에 대해 자세히 알아보겠습니다.

Amazon ECS 태스크 내의 모든 컨테이너 이미지는 SOCI 인덱스 매니페스트 필요

AWS Fargate에서의 SOCI snapshotter는 Linux 플랫폼 버전 1.4에 배포된 모든 Amazon ECS 태스크에 대해 활성화됩니다. 태스크 정의 내에서 SOCI를 활성화하거나 비활성화하기 위한 플래그를 설정할 필요가 없습니다. 대신, Fargate는 태스크 정의 내에 정의된 각 컨테이너 이미지에 대해 OCI 호환 레지스트리에 SOCI 인덱스 메니패스트가 존재하는지 확인합니다. 만약 인덱스가 발견되면, AWS Fargate는 컨테이너 이미지를 지연 로딩합니다. 어떤 컨테이너 이미지라도 SOCI 인덱스가 없다면, AWS Fargate는 컨테이너를 시작하기 전에 컨테이너 이미지를 완전히 pull 하도록 기본 설정됩니다.

다시 강조하자면, 작성 시점에 태스크에 하나의 컨테이너만 있으면, 하나의 컨테이너 이미지에 대해 SOCI 인덱스를 생성합니다. 태스크에 워크로드 컨테이너와 로깅 사이드카 컨테이너가 있는 경우, 워크로드 컨테이너 이미지와 로깅 사이드카 컨테이너 이미지 모두에 대해 SOCI 인덱스를 생성합니다.

컨테이너 이미지가 지연 로딩되었는지 확인하는 방법

Amazon ECS 태스크에는 태스크 메타데이터 엔드포인트가 있습니다. 이 태스크 메타데이터 엔드포인트는 컨테이너 사양, 사용 메트릭, 그리고 이제 컨테이너를 시작하는 데 사용된 containerd snapshotter 등에 대한 유용한 정보를 포함하고 있습니다. 이 엔드포인트는 실행 중인 태스크가 지연 로딩되었는지 여부를 확인하는 데 사용할 수 있습니다.

$ curl -s $ECS_CONTAINER_METADATA_URI_V4 | jq -r '.Snapshotter'
soci

$ curl -s $ECS_CONTAINER_METADATA_URI_V4/task | jq -r '.Containers | .[0].Snapshotter'
soci

고객이 이 엔드포인트를 사용하도록 애플리케이션을 수정하는 것을 방지하기 위해, 이 엔드포인트를 조회하고 정보를 AWS CloudWatch Logs에 넣는 예제 init 컨테이너를 SOCI snapshotter on AWS Fargate toolbox repository에서 찾을 수 있습니다.

컨테이너 이미지 사이즈

컨테이너 이미지의 크기가 커짐에 따라 이미지를 완전히 다운로드하는 데 걸리는 시간은 증가합니다(큰 사이즈의 컨테이너 이미지가 AWS Fargate의 시작 시간에 비례하여 영향을 미치는 이유입니다). 우리의 내부 테스트에서 SOCI는 대형(>250 MB) 컨테이너 이미지와 함께 사용될 때 작업 시작 시간을 줄이는 데 가장 큰 영향을 미쳤습니다.

작은 컨테이너 이미지의 경우, SOCI의 영향은 적고, 심지어는 AWS Fargate 작업을 시작하는 데 걸리는 시간을 늦출 수도 있습니다. 이는 SOCI 아티팩트를 다운로드하고 FUSE 파일 시스템을 설정하는 데 오버헤드가 발생하기 때문입니다. 테스트에서는 컨테이너 이미지가 압축하여 250MB 이상일 때 SOCI가 눈에 띄는 영향을 미치기 시작한다는 것을 발견했습니다. 컨테이너 이미지가 250MB 미만인 경우, 초기의 지연 로딩 오버헤드는 전통적인 방법을 사용하여 전체 컨테이너 이미지를 pull 하는 데 걸리는 시간보다 더 클 수 있습니다.

컨테이너 이미지 레이어 사이즈

soci create를 사용하여 SOCI 인덱스를 생성할 때, 클라이언트가 zTOC를 생성할 컨테이너 이미지 계층의 최소 크기를 제어하는 매개변수가 있습니다. 기본적으로 이는 10MB으로, --min-layer-size 플래그로 조정합니다. 클라이언트가 작은 계층을 감지하면 SOCI 인덱스 생성 시 해당 계층에 대한 zTOC 생성을 건너뛰며, 이 계층은 런타임에 지연 로딩되지 않습니다. 내부적으로 테스팅를 한 결과 작은 계층 전체를 시작 시간에 단순히 다운로드하는 것은 지연 로딩보다 더 성능이 좋다는 것이 나타났습니다. 작은 컨테이너 이미지에서, 컨테이너 이미지의 모든 계층이 10MB 이하라면 SOCI 인덱스는 생성되지 않습니다.

사이드카 컨테이너에 대한 SOCI 인덱스를 생성할 때 위 내용을 기억하는 것이 중요합니다. 로깅 또는 모니터링 컨테이너 이미지의 모든 컨테이너 이미지 계층은 10MB 이하일 수 있습니다. 따라서, 이런 이미지들에 대한 SOCI 인덱스를 생성하려면 이 매개변수를 조정해야 할 수 있습니다.

결론

이 게시물에서는 Seekable OCI와 SOCI snapshotter에 대해 자세히 살펴보았습니다. SOCI 인덱스가 컨테이너 이미지의 내용을 어떻게 목록화하는지, AWS와 기존 CI/CD 파이프라인에서 어떻게 자동화될 수 있는지 살펴보았습니다. 마지막으로, AWS Fargate에서 SOCI를 사용할 때 주의해야 할 몇 가지 사항을 살펴보았습니다.

SOCI snapshotter는 Google의 CRFS 프로젝트에서 처음 논의되었던(이후에는 stargz snapshotter에서 논의) 컨테이너 이미지의 지연 로딩에 대한 기초 작업을 기반으로 합니다. 이번 주에 AWS Fargate에서 출시됨에 따라, 앞으로 고객들은 AWS Fargate의 Amazon ECS 태스크에서 컨테이너 이미지를 지연 로딩할 수 있습니다. 앞으로 다른 컨테이너 오케스트레이터에서도 SOCI를 더 쉽게 실행할 수 있도록 할 예정입니다. 여러분께서는 soci-snapshotter project on GitHub 프로젝트에서 계속 진행되는 개발을 주시하고 참여해보시길 권장드립니다.

Jungseob Shin

Jungseob Shin

신정섭 Solutions Architect는 다양한 분야의 Backend 서버 개발 경험을 바탕으로 Startup 고객이 비즈니스 목표를 달성하도록 AWS 서비스의 효율적인 사용을 위한 아키텍처 설계 가이드와 기술을 지원하는 역할을 수행하고 있습니다. 컨테이너와 서버리스 기술에 관심이 많습니다.