초심자도 이해하는 컨테이너 도커 ECS

2021.09.24

안녕하세요 클래스메소드의 수재입니다.
이번에 ECS에 관한 영상을 찍게 되어 그 내용을 블로그에 미리 정리해보고자 합니다.
ECS라는 서비스가 있는 것도 알고 많이 쓰고 있다는 것도 알고 있지만 어떤 서비스인지? 왜 쓰는지? 컨테이너는 무엇인지? 등 컨테이너에 대해 잘 모르는 초심자도 이해할 수 있도록 컨테이너와 도커, ECS에 대하여 설명하고자 합니다.

시작하며

컨테이너를 실행하는 고도로 안전하고, 안정적이고, 확장 가능한 방식
Amazon Elastic Container Service(Amazon ECS)는 컨테이너화된 애플리케이션의 손쉬운 배포, 관리 및 조정에 도움이 되는 완전관리형 컨테이너 오케스트레이션 서비스입니다.- 공식 페이지 AWS ECS 소개문

컨테이너에 대하여 잘 모르는 초심자에게 "컨테이너화된 애플리케이션", "컨테이너 오케스트레이션" 이라는 단어는 바로 이해가 되지 않습니다.

이 소개문을 바탕으로 하나하나 알아봅시다.

컨테이너에 대해

컨테이너화?

컨테이너는 애플리케이션의 코드, 구성 및 종속성을 하나의 객체로 패키징하는 표준화된 방식을 제공합니다. 컨테이너는 서버에 설치된 운영 체제를 공유하며 리소스가 격리된 프로세스 형태로 실행되므로 환경에 상관없이 빠르고 안정적이며 일관된 배포를 보장합니다. - AWS 카테고리 심층 분석(컨테이너)

AWS의 설명과 같이 애플리케이션에 필요한 부분을 패키징하여 애플리케이션 별로 격리하는 방식입니다.
컨테이너 방식이 등장하기 전에는 지금도 많이 쓰고 있는 가상 머신(VM)을 기반으로 격리된 환경을 구축하였습니다.
가상 머신은 다음과 같은 환경으로 구성됩니다.


가상머신을 이용하여 다양한 애플리케이션의 배포는 가능했습니다. 하지만 다음과 같은 명확한 한계가 있었기 때문에 사용에 한계가 있었습니다.

  • 머신 수준의 분리를 위해 하드웨어 가상화가 필요하다
  • 다양한 부분의 가상화가 필요하므로 많은 리소스와 오버헤드가 수반됩니다
  • OS의 이미지도 포함하기 때문에 가상 머신 이미지의 용량이 크다
  • 서버의 일관된 운영이 힘들다(snowflake server)

이후 리눅스에서 cgroup(control groups)라는 리눅스 커널의 기능이 만들어지고 네임스페이스(namespace)와 함께 사용하게 됩니다.
이 기능으로 네임스페이스 안의 프로세스에 대해 독립적인 자원을 보장할 수 있게 되고 네임스페이스가 격리된 공간처럼 작동할 수 있게 되고 이것이 리눅스 컨테이너(Linux Container, LXC)의 기반이 됩니다.
이렇게 컨테이너 별로 격리하여 관리하는 것을 컨테이너화라고 합니다.
그리고 리눅스 컨테이너를 기반으로 오늘날 우리가 컨테이너라고 하면 가장 먼저 떠올리는 도커(docker)가 개발됩니다1.
물론 리눅스 컨테이너와 도커가 완전히 동일한 기술은 아니며 이 글에서 알아보는 컨테이너의 개념은 도커에 가깝습니다.

컨테이너는 다음과 같은 환경으로 구성됩니다.

컨테이너를 사용하는 이유

우선 컨테이너의 특징을 알아보겠습니다.

  • 하드웨어의 가상화를 하지 않고 커널만을 공유한다
  • 하드웨어 에뮬레이션이 없기 때문에 빠른 속도로 빠르게 실행된다
  • 이미지의 용량이 가상 머신에 비해 훨씬 작다
  • 컨테이너 간에 영향을 주지 않으며 도커와 같이 이미지 기반으로 컨테이너를 실행하는 경우 특정 실행 환경을 쉽게 재사용 할 수 있다
  • 실행/패치/업데이트 등 유지 관리와 관련하여 오버헤드가 감소한다
  • 서비스가 세분화 되어 있는 마이크로 서비스 아키텍쳐(MSA)의 특성에 컨테이너의 서비스 별 격리나 확장성 등을 잘 활용할 수 있다
  • 단, 처음 이미지를 정의한 OS에서만 사용 할 수 있다
    (리눅스라면 리눅스에서만 윈도우라면 윈도우에서만 가능)

즉, "애플리케이션의 배포/관리를 간단하게 해주고 오버헤드도 적다"라는 특징이 있습니다.

도커

위에서 설명한 장점들이 있었음에도 컨테이너라는 개념은 크게 주목받지 못하였습니다.
이후 도커(docker) 2의 공개 후 컨테이너에 대한 관심이 늘어나기 시작하였습니다.
그리고 도커는

  • 짧아지는 빌드/배포 주기
  • 마이크로 서비스로 설계된 애플리케이션이 늘어나며 관리 단위의 축소가 필요
  • 클라우드 서비스의 발전

이라는 시대의 흐름과 이미지의 계층화나 유니온 파일 시스템 3 등의 특징을 바탕으로 컨테이너 기술하면 많은 사람들이 도커를 떠올릴 정도로 발전하게 됩니다.

도커의 작동 방식

도커에서는 애플리케이션을 실행하기 위한 파일들의 모음을이미지 라는 개념으로 관리합니다.
이미지에는 애플리케이션의 종속성 및 실행에 필요한 정보가 포함되어 있습니다.
이러한 이미지는 로컬 혹은 도커 허브 등과 같은 원격 저장소에 태그를 붙여 커밋합니다.
이 태그로 이미지의 버전을 구분합니다.
그리고 커밋한 이미지를 사용하여 컨테이너를 생성합니다.생성한 컨테이너에는 포트 포워딩으로 접근할 수 있습니다.

이미지의 커밋부터 컨테이너의 생성은 다음과 같은 순서가 됩니다.

  • 커밋할 이미지(컨테이너의 환경) 구성
  • 작성한 이미지를 저장소에 커밋
  • 커밋한 이미지로 컨테이너를 생성

즉, 이미지 생성, 이미지 저장, 컨테이너 생성의 순서로 작동합니다.

이 중 이미지를 구성하기 위해서 다양한 패키지의 다운로드나 환경 설정 등이 필요합니다.
하지만 하나하나 직접 작업하는 것은 너무 비효율적입니다.
이를 해결하기 위해 커밋하는 이미지의 내용(환경 구축의 내용)을 dockerfile이라는 파일에 작성할 수 있습니다.
기초적인 명령어를 포함한 dockerfile의 간단한 예시는 다음과 같습니다.

FROM ubuntu:20.04 \

RUN apt-get update && apt-get install apache2 -y \
WORKDIR /var/www/html \
RUN ["/bin/bash", "-c", "echo >> test.html"] \
EXPOSE 80 \

ENV APACHE_RUN_USER www-data \
ENV APACHE_RUN_GROUP www-data \
ENV APACHE_LOG_DIR /var/log/apache2 \

CMD apachectl -DFOREGROUND

이처럼 dockerfile를 이용하는 것은 환경 구축, 이미지 커밋, git 등과 같은 개발 도구를 통해 빌드 및 배포를 자동화 할 수 있는 장점이 있습니다.

컨테이너의 생성과 배포

도커가 어떻게 작동하는지를 간단하게 알아보았습니다.
하지만 어떠한 서비스를 구성하기 위해서는 여러 개의 애플리케이션이나 데이터베이스 등이 결합하어 완성됩니다.
위의 방식만으로는 긴 명령어가 필요해지고 컨테이너를 생성하는 순서도 신경을 써야 하는 등 너무나도 불편합니다.
도커에서는 이를 위해 도커 컴포즈(docker compose)라는 도구를 제공하고 있습니다.

도커 컴포즈를 이용하면 긴 명령어를 하나의 yaml 파일로 정의하기 때문에 환경을 파악하기 쉬워집니다.
또한 컨테이너의 실행 순서나 의존성 등과 같은 부분도 해결할 수 있습니다.
내용의 예시는 다음과 같습니다.

version: "3.9"  # optional since v1.27.0
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
      - logvolume01:/var/log
    links:
      - redis
  redis:
    image: redis
volumes:
  logvolume01: {}

이렇게 하나의 서버(호스트)에서 여러 개의 컨테이너를 배포하는 방법을 알게 되었습니다. 하지만 더 많은 컨테이너가 필요하게 된다면 서버를 추가(서버 클러스터링)해야 할 필요가 있습니다.
그럼 서버 간의 컨테이너의 관리는 어떻게 해야할까요?
이를 위해 다양한 서버들의 컨테이너를 관리하는 컨테이너 오케스트레이션이라는 개념이 필요하게 되었고 이러한 기능을 하는 것을 컨테이너 오케스트레이션 툴 이라고 합니다.
현재 많이 사용되고 있는 것은 쿠버네티스(kubernates), 도커 스웜(Docker Swarm), 아파치 메소스(Apache Mesos), AWS ECS 등이 있습니다.

이러한 오케스트레이션 툴은 보통 다음과 같은 기능들을 제공하고 있습니다.

  • 서버의 특성이나 자원, 배포 상태를 파악하여 컨테이너를 할당하는 스케쥴링
  • 서버에서 도커를 통해 지정된 컨테이너를 안전하게 실행
  • 업그레이드, 롤백 등 서비스의 배포에 관한 대응
  • 오류 등의 대응
  • 새로운 서버나 컨테이너가 추가되었을 때 발견하는 서비스 디스커버리(service discovery), 서버 간 네트워킹 등의 클러스터 리소스 생성

이와 같이 단순히 배포하는 것으로 끝이 아닌 서비스 디스커버리, 배포 방식, 로드밸런싱, 로깅 및 모니터링, 고가용성 등 많은 부분을 고려해야 합니다.

Amazon ECS

서두의 "컨테이너화된 애플리케이션", "컨테이너 오케스트레이션"에 대한 설명이 끝났으니 마지막으로 ECS를 알아보겠습니다.

ECS란?

위에서 설명하였듯이 ECS(Elastic Container Service)는 AWS에서 제공하는 컨테이너 오케스트레이션 서비스입니다.
ECS를 사용하여 Amazon EC2 인스턴스의 관리형 클러스터 혹은 AWS Fargate를 통한 서버리스 환경에서 애플리케이션을 손쉽게 실행할 수 있습니다.
ECS를 사용함으로써 다음과 같은 이점을 얻을 수 있습니다.

  • 다양한 AWS의 서비스 연계
    AWS에서 제공하고 있는 다양한 서비스들과 옵션들을 연계하여 더욱 효율적으로 컨테이너를 관리할 수 있습니다.
  • 제어 플레인 또는 노드 관리 불필요
    AWS Fargate를 통해 서버리스 환경을 이용할 수 있으며 제어 플레인 또는 노드를 관리, 인스턴스 패치 및 조정이 불필요하므로 운영에 소요되는 시간이 줄어듭니다.
  • 컴퓨팅 비용 절감
    클라우드 서비스라서 물리적 서버에 대한 요금을 절약할 수 있습니다. 또한 ECS는 프로비저닝 및 자동 조정을 자율적으로 처리하므로 컴퓨팅 비용을 최대 50%까지 절감할 수 있습니다.
  • 보안 및 규제 요구 사항 충족
    ECS는 AWS 관리 및 거버넌스 솔루션과 기본적으로 통합됩니다. 따라서 전 세계 거의 모든 규제 기관의 보안 및 규정 준수 표준을 충족할 수 있습니다.

AWS에서 제공하는 서비스이기 때문에 제대로 활용하기 위해서는 AWS의 다른 서비스에 대한 어느 정도의 지식을 요구합니다.

관련 서비스

출처 : AWS ECS 공식 페이지

작동 방식을 설명하기 전 관련 서비스를 간략하게 살펴보겠습니다.

  • AWS ECR(Elastic Container Registry)
    • 컨테이너 이미지 저장소 입니다.
  • AWS Fargate
    • 종량제 서버리스 컴퓨팅 엔진입니다. ECS와 EKS 둘 다 호환 가능합니다.
  • AWS ELB(Elastic Load Balancer)
    • 로드밸런서 입니다. ALB와 함께 사용하여 동적 포트를 지정할 수 있습니다.
  • AWS VPC
    • ECS의 사용에 필요한 네트워크 리소스를 제공하는 서비스입니다.
  • AWS IAM
    • 클러스터나 서비스 등 다양한 작업의 권한을 설정하는 서비스입니다.
  • AWS CloudWatch
    • 컨테이너의 각 지표와 로그 등을 확인할 수 있습니다. 컨테이너형 애플리케이션 및 마이크로 서비스에 대한 모니터링, 트러블 슈팅 및 알람을 위한 서비스인 Container Insight도 제공하고 있습니다.

이 외에도 쿠버네티스를 위한 EKS, 커밋/빌드/배포와 관련된 AWS Code 시리즈 등 다양한 서비스와 연계가 가능합니다.

ECS의 작동 방식

ECS의 구성 요소는 크게 5가지 입니다.

  • Task Definition(작업 정의)
  • Task(작업)
  • Continer Instacne(컨테이너 인스턴스)
  • Service(서비스)
  • Cluster(클러스터)

이를 그림으로 나타내면 다음과 같습니다.

  1. Task ECS의 최소 단위는 task입니다.
    그리고 1개 이상의 컨테이너가 task에 구성됩니다.

  2. Task Definition task의 구성 요소는 task definition에 json 형식으로 작성되어있습니다.
    작성된 내용을 참고로 task가 구성됩니다.
    task definition에서 작업 및 컨테이너가 참고할 이미지, 사용할 리소스 양, 시작 유형, 로깅 구성 등 다양한 매개변수를 정의할 수 있습니다.

  3. Service task definition을 참고하여 task를 실행합니다. 또한 원하는 수의 task를 유지 관리하는 스케쥴러 역할을 합니다.
    선택적으로 로드 밸런서 뒤에서 실행하여 로드 밸런싱과 오토 스케일링 기능을 할 수 있습니다.

  4. Container Instance ECS 컨테이너 에이전트를 실행하고 cluster에 등록된 EC2 인스턴스입니다.
    리눅스, 윈도우 OS를 지원하며 온프레미스 VM 등의 다른 OS도 지원합니다.
    Fargate 시작 유형을 사용하는 task는 서버리스로 배포되므로 container instance는 적용되지 않습니다.

  5. Cluster container instance(Fargate라면 task)의 논리적 그룹입니다.

따라서 다음과 같은 순서로 작업을 하게 됩니다.

  1. 컨테이너의 이미지를 저장소(ECR)에 커밋
  2. task definition에서 사용할 이미지 및 시작 유형, 리소스 정의
  3. cluster 생성
  4. service가 task definition을 참고하여 task 생성
  5. elb에 들어온 요청에 따라 오토 스케일링 및 로드 밸런싱

이 외에

ECR/ECS와 AWS code 시리즈와 함께 활용하여 코드의 커밋부터 배포까지 자동화를 하거나
ECS task를 위한 다양한 옵션(AWS Wavelength, AWS Outposts)등과 함께 사용하면 더욱 효율적이고 능동적인 컨테이너 생태계를 구축할 수 있습니다.

마무리

이번 발표를 위해 컨테이너부터 ECS까지 정리하며 저도 다시 개념을 잡을 수 있었습니다.
이 외에도 devio 2021 decade에 다양한 세션들이 준비되어 있으니 봐주셨으면 합니다.

긴 글 읽어주셔서 감사합니다.
내용 피드백 및 오탈자 제보는 must01940지메일로 보내주시면 감사합니다.

참고 자료


  1. 현재의 도커는 리눅스 컨테이너와의 종속관계를 벗어나 containerd와 runc를 기반으로 동작합니다.
    이제 이 둘은 "시스템 컨테이너(리눅스 컨테이너)인가? 애플리케이션 컨테이너(도커)인가?"로 구분됩니다. 
  2. 오픈소스 커뮤니티 프로젝트, 오픈소스 프로젝트의 툴, 프로젝트의 주요 지지자인 회사, 이전에 회사에서 지원했던 툴 모두 "Docker"입니다.
    이 글에서 설명하는 "도커"는 컨테이너를 실행하고 관리하는 애플리케이션 컨테이너 런타임입니다. 
  3. 이미지에는 애플리케이션의 실행에 필요한 여러 파일이 계층화되어 있고 이를 레이어라고 합니다.
    여러 레이어를 하나의 파일 시스템처럼 관리하는 것을 유니온 파일 시스템이라고 합니다.
    하나의 파일 시스템에 여러 개의 파일 시스템을 마운트하게 되면 중복되는 파일이 생깁니다.
    유니온 파일 시스템은 이런 파일을 마지막에 작성되는 파일으로 덮어쓰는 방식을 통해 관리합니다.