인프런 커뮤니티 질문&답변

yuki님의 프로필 이미지

작성한 질문수

AWS 배포 완벽가이드 (feat. Lightsail, Docker, ECS)

ECR private repository 이미지로 AWS ECS service 생성하기

안녕하세요 ECS를 활용한 ETL 작업 관련해서 질문 드립니다

해결된 질문

작성

·

421

1

현재 강사님의 강의를 듣고 크롤러와 ETL 배치 파이프라인을 ECS로 배포해서 사용해보려고 합니다

한가지 궁금한 점이 있어 문의드립니다

해당 크롤러와 배치 잡은 모두 api가 아닌 스크립트로 이루어져 있습니다.
이 경우, 클러스터 내 서비스는 생성할 필요 없이, 태스크로만 필요할 때마다 생성하면 되나요?
아님 서비스도 사용하면 좋을까요?

답변 3

3

김시훈님의 프로필 이미지
김시훈
지식공유자

좋은 질문입니다

 

서버처럼 계속 돌아가는게 아니기 때문에 task만 생성해도 될것으로 보입니다. 주기적으로 정해진 시간에 해당 테스크들이 생성되서 돌아가야할 것으로 보이는데요. 작업이 끝나면 테스크는 자동으로 사라질거고요.

테스크 생성 트리거가 필요합니다. 물론 직접 수동으로 생성할 수 있지만 주기적으로 자동생성을 하기 위해서는 외부 서비스가 필요해요. AWS에서는 CloudWatch 혹은 EventBridge라는걸 이용할 수 있고요. 강의에서 배운 Github Action으로도 가능합니다! 강의에서는 깃헙에 새로운 코드가 push/merge 됬을 때 저희가 생성한 github action workflow를 발동하도록 했었지요. 트리고를 schedule 로 수정해서 쓸 수 있습니다.

공식 깃헙 공식문서에 나와 있는 트리거 방식중 하나입니다:
https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule

우선 주기적으로 돌릴 코드들을 컨테이너화시켜서 AWS ECR에 이미지를 올려주세요! 만약 이 부분을 자주 수정할거 같으면 AWS ECR업로드까지 하나의 workflow로 만들어서 자동화시키면 됩니다. (merge/push trigger -> build/test-> image ECR upload)
그리고 원래였으면 이후에 새로운 버전의 테스크를 만들고 ECS 서비스에 업데이트해서 배포를했었는데요. 이 부분은 여기서 생략!

대신에 새로운 workflow를 만듭니다. 여기서는 트리거가 제가 위에 소개했던 schedule을 사용합니다! 이 workflow가 주기적인 테스크 배포 역할을 하게 됩니다. 여기서는 테스크를 만들어서 배포하는 부분을 진행합니다! 좀 다른점은 서비스를 생성하지 않고 task definition으로 바로 task 생성! 그래야 작업이 다 마무리되면 테스크가 중단 되고 더 이상 리소스가 낭비되지 않을테니깐요.

그리고 좀 복잡할 수 있지만 이 두번째 workflow를 좀 더 개선할 수 있는데요. task가 일시적인 장애로 죽을 수도 있단 말이죠. 하지만 서비스가 없기 때문에 다시 생성되지 않아요. 이 경우 음 서비스를 사용할 수도 있겠지만 workflow에 실패시 retry를 적용하는 방법도 있습니다.

 

근데 앞으로 만약 더 복잡한 여러개의 ETL 파이프라인을 관리해야한다면 Airflow 같은 특화된 workflow management 도구를 사용하는 방법도 있습니다. Airflow는 깃헙 액션처럼 전반적인 관리를 해주는거고 실제로 돌아가는 pipeline은 ECS로 할 수 있습니다! 근데 일단은 github action으로 최대한 해보는게 어떨까 싶습니다! 도구는 나중에 언제든지 바꿀 수 있고 선택의 폭이 끝이 없을거거든요 ㅎㅎ

 

설명 해보니 이 부분도 강의에 있으면 좋겠다라는 생각이 드네요 ㅎㅎ 나중에 이 부분 보강하는걸 검토해볼게요!

1

yuki님의 프로필 이미지
yuki
질문자

친절한 답변에 너무 감사합니다 ㅎㅎ
저는 에어플로우를 사용하는 개발자라서 말씀해주신 방법대로
위의 ECS 태스크를 이용해 ETL 잡을 처리하도록 했습니다


한가지 더 궁금한 점이 있습니다.
현재 대용량의 데이터를 컨테이너 잡을 3개를 이용해서 처리합니다.
1. 컨테이너 내에 다운받고 압축 해체

  1. 데이터를 cpu 바운드로 전처리

  2. 데이터베이스에 저장하는 작업을 해야합니다.

ECS 태스크를 처리할 때, 처리 중인 데이터를 공유하기 위해

볼륨을 잡는 것이 필요한데 이 경우, EFS와 바인드 차이가 어떻게 될지 궁금합니다.

 

김시훈님의 프로필 이미지
김시훈
지식공유자

음 만약 "대용량"이고 ETL 각각을 컨테이너 분리가 불가피하다면 EFS보다는 바인드 볼륨을 사용하는게 어떨까 싶네요. 어짜피 ETL 파이프라인 돌아가는 동안에만 저장해두는거니 EFS의 고가용성보다는 바인드 볼륨의 좀 더 좋은 I/O 성능이 유리할듯 해요.

하지만 그 전에 한번 근본적인 설계 고민을 해보시길 권장합니다! 대용량이면 얼만큼인지 모르겠지만 수백 메가이면 (10기가 이하까지도 개인적으로 괜찮다고 생각은 합니다) 과연 볼륨이 필요할까? ETL 전체를 하나의 컨테이너로 만들 수는 없을까? 분리해야할 정도로 복잡한 ETL인가? 만약 하나의 컨테이너로 해결할 수 있고 처리해야할 데이터를 어느정도 제한 할 수 있다면 그냥 ephemeral storage로도 충분할 수 있어요. 물론 이런 상황일 수도 있어요. 코드는 간결해서 합칠 수 있으나 데이터가 워낙 많아서 장애 발생시 처음부터 재시도 하는게 너무 비쌀 수 있습니다. 근데 더 근본적으로 가서 애초에 데이터를 쪼개서 받을 수는 없을까라는 의문을 가질 수도 있습니다.

예전에 Google Bigquery로 데이터를 추출한적이 있는데요. GCP cloud storage로 추출한적이 있는데요. 1기가짜리 파일 여러개로 나눠서 추출해주더라고요. 이 때 수십기가를 처리했어야 했는데 파일 각각이 작기 때문에 하나의 컨테이너로 모두 해결 할 수 있었요.

이렇게 하면 모든게 간결해질뿐더러 확장성도 뛰어납니다. 병렬처리가 가능해지니깐요!

0

yuki님의 프로필 이미지
yuki
질문자

정말 많이 배워갑니다 ㅎㅎ 강사님
나중에 강사님께서 ECS 관련된 강의 하나 더 내시면 또 따라가야겠어요 ㅎㅎ

강의를 들으면서 도커 컴포즈 파일을 이용한 ECS 배포를 해보려고 하는데
기존의 강의처럼 웹 콘솔로 하는 것과 상이한 것 같아 어려움을 겪고 있습니다.
https://dev.to/raphaelmansuy/10-minutes-to-deploy-a-docker-compose-stack-on-aws-illustrated-with-hasura-and-postgres-3f6e

이와 같은 컴포즈 파일의 경우 어떻게 진행할 수 있는지 궁금합니다.

질문이 뭔가 추상적인 것 같아 강사님께서 참고 url을 추천해주실 수 있다면 너무 감사할 것 같습니다 (이미 너무 많은 정보와 도움을 주셔서 ㅠ)

version: "3"

services:
  chrome:
    image: .dkr.ecr.us-east-2.amazonaws.com/de_selenium_grid_chrome
    platform: linux/amd64
    build:
      context: ./chrome
      dockerfile: Dockerfile
    container_name: de_selenium_grid_chrome
    shm_size: 3gb
    depends_on:
      - selenium-hub
    environment:
      - SE_EVENT_BUS_HOST=de_selenium_grid_selenium_hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_MAX_SESSIONS=7
      - SE_NODE_MAX_INSTANCES=4
      - SE_NODE_OVERRIDE_MAX_SESSIONS=true
      - SE_NODE_SESSION_TIMEOUT=300
    deploy:
      mode: replicated
      replicas: 3
      resources:
        limits:
          cpus: '1.5'
          memory: 4000M
        reservations:
          cpus: '0.25'
          memory: 1000M
    volumes:
      - ./logs/chrome:/var/log/selenium
    networks:
      - selenium_grid

  selenium-hub:
    image: .dkr.ecr.us-east-2.amazonaws.com/de_selenium_grid_selenium_hub
    platform: linux/amd64
    build:
      context: ./selenium-hub
      dockerfile: Dockerfile
    container_name: de_selenium_grid_selenium_hub
    ports:
      - "4442:4442"
      - "4443:4443"
      - "4444:4444"
    volumes:
      - ./logs/hub:/var/log/selenium
    networks:
      - selenium_grid

  nginx:
    image: .dkr.ecr.us-east-2.amazonaws.com/de_selenium_grid_nginx
    build:
      context: ./nginx
      dockerfile: Dockerfile
    platform: linux/amd64
    container_name: de_selenium_grid_nginx
    ports:
      - "80:80"
    volumes:
      - .nginx/nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - de_selenium_grid_selenium_hub
    networks:
      - selenium_grid

networks:
    selenium_grid:
        driver: bridge

태스크 정의에 필요한 컨테이너 이름과 태스크 이름은 container_name과 동일하게 설정했습니다.


nginx conf에서

    server {
        listen 80;

        location / {
            proxy_pass http://de_selenium_grid_selenium_hub:4444;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

위와 같이 설정 후,

image
위와 같이 서비스를 단일 클러스터에 배포했는데요

또한 서비스 디스커버리를 아래와 같이 설정했습니다

첫번째가 nginx, 두번째가 de_selenium_grid_selenium_hub 입니다

imageimage

근데 nginx 서비스에서 계속 nginx conf에 적힌 de_selenium_grid_selenium_hub
를 찾질 못하네요

혹시 제가 서비스 디스커버리를 컨테이너 이름과 다르게 설정했을까요?

2023/11/19 09:29:08 [emerg] 1#1: host not found in upstream "de_selenium_grid_selenium_hub" in /etc/nginx/nginx.conf:39

김시훈님의 프로필 이미지
김시훈
지식공유자

음 docker-compose를 이용해서 배포하신걸까요? (docker-compose는 개발환경에서 사용하는것만 권장해서요)

yuki님의 프로필 이미지
yuki
질문자

답변 감사드립니다 ㅎㅎ
개발 환경에서만 도커 컴포즈를 사용하는 것을 권장하시는 군요

뭔가 kubernetes 폴더 구조를 보면 항상 도커 컴포즈가 있어서 저는 도커 컴포즈가 표준 규격 같은 건 줄 알았습니다.

항상 친절한 답변 감사드립니다

yuki님의 프로필 이미지

작성한 질문수

질문하기