개발이군고구마

[멱살잡고 DevOps] 1. Docker Compose와 ECS (컨테이너의 분산 배포) 본문

Cloud Deploy

[멱살잡고 DevOps] 1. Docker Compose와 ECS (컨테이너의 분산 배포)

김구황 2025. 7. 14. 08:44
728x90

1. 현 상황 

EC2 1개의 인스턴스를 사용 

-> Docker compose 스크립트 파일을 작성함 

-> Github Action을 실행시키는 도커 컴포즈 이미지 빌드 후 푸시

-> EC2 인스턴스 작동 스크립트 작성 

 

언제  ECS가 필요한거지? 

 

2. 왜 문제가 되는가 

[도커 컴포즈의 문제] 

  • 단일 호스트 중심
    • Compose는 기본적으로 한 호스트(EC2 인스턴스) 안에서 여러 컨테이너를 띄우는 도구. 여러 EC2에 걸쳐 분산 배포하려면 직접 스크립트(GitHub Actions → SSH → docker-compose up -d)를 짜야함.
# .github/workflows/deploy-matrix.yml
name: Deploy to Multiple EC2

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        host:
          - ${{ secrets.EC2_HOST_1 }}
          - ${{ secrets.EC2_HOST_2 }}
          - ${{ secrets.EC2_HOST_3 }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Start SSH agent
        uses: webfactory/ssh-agent@v0.5.4
        with:
          ssh-private-key: ${{ secrets.EC2_SSH_KEY }}

      - name: Copy docker-compose.yml to ${{ matrix.host }}
        run: |
          scp -o StrictHostKeyChecking=no \
            docker-compose.yml \
            ec2-user@${{ matrix.host }}:/home/ec2-user/app/

      - name: Deploy containers on ${{ matrix.host }}
        run: |
          ssh -o StrictHostKeyChecking=no ec2-user@${{ matrix.host }} << 'EOF'
            cd /home/ec2-user/app
            docker-compose pull
            docker-compose up -d
          EOF

EC2를 직접 지정해서 배포를 해야함 

  • 자동화·높은 가용성 부족
    • 인스턴스 장애 시 복구(다른 호스트로 컨테이너 재스케줄링), 헬스체크 기반 롤링 업데이트, 오토스케일링, 로드밸런싱(다단계 ALB/ELB 통합) 등을 직접 관리.
  • 운영 오버헤드
    • CI/CD에서 SSH 키 관리, 인벤토리 관리(몇 대에 배포할지), 배포 순서, 장애 대응 등 모든 운영 로직을 직접 구현.

 

 

3. 개념

자동으로 다중 EC2에 배포될 수 있는 방법은 없을까?

EC2 (서버) 의 용량이나 상태에 따라 적정하게 분배하는 것을 자동으로 해볼 수는 없을까? 

"ECS 클러스터" 

ECS 서비스에서 몇 개의 Task를 관리할 것인지 결정한다. 보통 Task 한개당 1개의 컨테이너

 

 

💠 개념 정리 

1. ECS는 몇 개의 EC2를 실행시키는 거지? 
  • 컨테이너 인스턴스 = EC2
  • ECS 태스크(Task) = Docker 컨테이너 묶음

몇 대의 EC2를 쓰느냐는 내가 클러스터에 등록해 놓은 EC2 용량과 CPU 메모리에 달려있음 

 

1) 내가 등록한 인스턴스 수

  • 예: Auto Scaling Group으로 최소 2대, 최대 5대 EC2를 클러스터에 등록

2) 태스크의 리소스 요구량

  • Task Definition에 cpu: 512, memory: 1024를 지정하면
  • 각 EC2 인스턴스(예: t3.medium)의 총 CPU·메모리 쿼타(예: 2 vCPU, 4 GiB) 중 남은 용량에 맞춰 스케줄링

 

2. 클러스터의 실제 흐름은 어떻게 되지? 
  • 클러스터 구성
    • EC2 런치 타입 선택 시, AMI에 ECS 에이전트 설치된 EC2를 Auto Scaling Group으로 기동
    • 각 EC2는 ecs-agent를 통해 “나는 이만큼의 CPU·메모리 갖고 있어요”를 ECS에 알림
  • 태스크 등록 & 서비스 실행
    • register-task-definition으로 Task Definition 등록
    • create-service로 서비스 실행 → “Task 3개” 요청
  • 스케줄링 & 실행
    • ECS 스케줄러가 클러스터 내 등록된 EC2 인스턴스의 남은 리소스 확인
    • 조건에 맞춰 Task를 EC2 위에 분배
    • EC2 수, 남은 용량, Placement 전략 따라 할당 개수가 결정

 

3. Fargate 런치 타입 🔅 

ㄴ 이 방벙을 주로 이용 (EC2 설정하지 않아도 됨)

서버리스 방식으로, AWS가 백그라운드에서 컨테이너를 실행 (EC2 인스턴스 개념 없음)

 

 

4. ALB 를 중간에 두는 경우, ALB의 로드 밸런싱 대상은 무엇일까? 

 

  • ECS 클러스터(cluster) 는 단순히 태스크를 구동하는 논리적 단위
  • 실제 로드밸런싱 대상은 “클러스터” 자체가 아니라, 해당 클러스터에 속해 있고 Target Group에 등록된 각 태스크(컨테이너)

로드밸런싱 동작 요약

  1. 클라이언트 → my-alb-xxx.elb.amazonaws.com
  2. ALB → 지정된 Listener (예: HTTP 80, HTTPS 443)
  3. Listener 룰에 따라 → Target Group으로 전달
  4. Target Group → 등록된 ECS 태스크(또는 EC2 인스턴스의 특정 포트)로 분산

 

5. Cluster가 논리적 단위라는데? 

 

클러스터 자체가 물리적 서버나 네트워크 엔드포인트를 직접 갖고 있는 실체가 아니라는 뜻

  • 네임스페이스(namespace) 역할
    • 클러스터는 AWS 리소스(태스크, 서비스, 용량 제공자 등)를 묶어 관리하기 위한 그룹 이름입니다.
    • 예를 들어 prod-cluster, staging-cluster처럼 환경별로 나눠 두고, 그 안에서 서비스와 태스크를 운영할 수 있습니다.
  • 물리 인프라와의 분리
    • 클러스터에 태스크를 띄울 때, 실제로는
      • EC2 인스턴스(셀프 매니지드 또는 ECS 매니지드) 또는
      • Fargate
        위 둘 중 하나를 통해 컨테이너가 실행됩니다.
    • 클러스터 자체가 서버를 갖고 있는 게 아니라, ‘이 클러스터에 이만큼의 EC2 용량을 연결할 수도 있고, Fargate를 쓸 수도 있다’는 논리적 경계만 제공.
  • 스케줄링과 관리의 경계
    • 클러스터를 기준으로 태스크가 어디에 배치되는지(AZ, 인스턴스 종류 등) 정해집니다.
    • 클러스터 단위로 IAM 권한, 로그 그룹, 모니터링 대상을 설정할 수 있어 관리·운영의 범위를 구분하기 편합니다.

 

 

✅ 간단히 이해하기

  • 클러스터 = ‘아파트 단지 이름’
    • “그 아파트(클러스터)에 몇 동(EC2 인스턴스/Fargate)이 있고, 각 동에 몇 가구(태스크)가 사는지”를 관리하는 개념
  • 태스크 = ‘개별 가구(세대)’
    • 실제로 사람이 살고(트래픽을 처리) 주소를 갖고 있음
  • ALB → 태스크
    • 배달원(ALB)이 아파트 단지가 아니라, 각 가구(태스크)의 초인종을 누름