[프로그래머스] 데브코스 데이터엔지니어링 TIL Day 46

주재민·2023년 12월 18일
0
post-thumbnail

📖 학습주제

개발환경 구축을 위한 Docker와 K8S 실습 (1)


Airflow 운영상의 어려움

데이터 품질이나 데이터 리니지 이슈 이외에도 다양한 이슈들이 발생

라이브러리 충돌

  • 라이브러리/모듈의 충돌 이슈가 발생하기 시작함
  • DAG에 따라 실행에 필요한 라이브러리/모듈이 달라지기 시작
    - 예) Python 버전
  • 이로 인해 DAG 혹은 Task별로 별도의 독립공간을 만들어주는 것이 필요
    - Docker to the rescue
    - Dag 혹은 Task 코드를 Docker Image로 만들고 이를 독립된 공간(Docker Container)안에서 실행

Worker의 부족

  • Scale Up
  • Scale Out
    - 클라우드 서비스 사용
  • K8s와 같은 컨테이너 기술 사용 : 필요한대로 서버 요청

낮은 Server Utilization 이슈

  • Airflow 전용 하드웨어를 지정했는데 서버들이 항상 바쁘지 않다면?
  • 서비스별로 전용 서버를 할당하는 것은 여러가지로 이슈를 만들어냄
    - 서비스별로 Capacity 관리를 해야함
    - 각 서비스에 속한 서버들은 보면 utilization이 낮은 이슈 발생
  • 이 역시 K8s와 같은 컨테이너 기술의 도입으로 해결 가능

해결책

  • 태스크나 DAG 코드를 Docker Image로 만들어서 Docker Container 형태로 실행
    - 라이브러리/모듈 충돌을 방지
    - 개발 환경과 프로덕션 환경을 동일하게 유지
  • Airflow Worker를 K8s에서 필요한 대로 동적으로 할당하여 사용
    - 전용 서버를 Airflow에 할당하지 않고 Container Orchestration 서비스를 통해 할당해서 사용하고 리턴
  • Airflow에서 이를 해결하는 방법은 3가지
    - Airflow Operator로 KubernetesPodOperator를 사용 : 특정 태스크를 Docker Image로 만들어 K8s에서 실행
    - Airflow Operator로 DockerOperator를 사용 : 특정 태스크를 Docker Image로 만들어 Docker Container 위 에서 실행
    - Airflow Executor로 아래를 사용
       KubernetesExecutor : 모든 DAG 코드가 Docker Image로 빌드되어 K8s에서 실행
       CeleryKubernetesExecutor : CeleryExecutor와 KubernetesExecutor를 동시에 사용하는 방법을 제공
       LocalKubernetesExecutor : LocalExecutor와 KubernetesExecutor를 동시에 사용하는 방법을 제공

Airflow Executor

  • Task들을 관리하고 실행하는 역할을 수행
  • 다양한 수의 Executor 타입이 존재
    - Sequential Executor: 디폴트로 설치되며 Sqlite와 같은 싱글스레드 DB에서만 사용가능
    - Local Executor: task들을 Airflow 마스터 노드안에서 실행
    - Celery Executor: 다수의 Worker 노드가 있는 경우 사용되며 Celery 큐를 사용해 task들을 worker 노드로 분산하여 실행
    - Kubernetes Executor는 K8s 클러스터를 사용하여 task들을 독립된 환경에서 사용
    - Local Kubernetes Executor와 Celery Kubernetes Executor도 존재

Docker 소개

내가 만든 프로그램이 다른 컴퓨터에서 안 돌아간다면?
-> 설치 과정에서 중요한 파일이 빠짐
-> 사용하는 라이브러리 등의 버전이 안 맞음
-> 환경 설정이 안 맞는 것이 존재

내 컴퓨터 환경을 그대로 패키징해서 다른 이에게 줄 수
있다면?

  • Docker Image: 이렇게 독립적으로 완전하게 만들어진 패키지
  • Docker Container: 이 Docker Image를 독립된 환경에서 실행한 것

Docker의 목표

  • 소프트웨어를 일관되게 빌드하고 실행하고 배포

Virtual Machines vs. Docker Containers

Virtual Machine

  • 하드웨어를 추상화하여 한 컴퓨터 위에 가상 컴퓨터를 올리는 것(AWS의 EC2 등)

장점

  • 소프트웨어를 실행하기 위한 독립적이고 분리된 공간을 제공
  • 다수의 소프트웨어를 각 VM단에서 독립적으로 실행가능

단점

  • 각 VM은 자신만의 OS를 필요로 함 (가상 하드웨어위에서 돌기 때문)
    - 유료 OS라면 라이센스 비용 필요
    - 그러다보니 시작하는데 오래 걸림
  • 자원을 많이 사용함 (VM들끼리 자원을 나눠써야함)

Docker Container

  • 소프트웨어를 실행하기 위한 독립적이고 분리된 공간
  • 자체 파일 시스템을 갖고 있음 (Volume이라고 부름)

장점

  • 소프트웨어를 실행하기 위한 독립적이고 분리된 공간을 제공 : 다수의 소프트웨어를 각 컨테이너단에서 독립적으로 실행가능
  • 자원 소비가 적음 (lightweight) : 몇 십개에서 몇 백개의 container를 실행 가능
  • 호스트 OS를 사용 (별도 비용 없음) : 따라서 빠르게 실행됨

단점

  • 많은 수의 Docker Container를 관리하는 것은 쉽지 않음
  • Host OS를 사용하기에 Cross-platform compatibility를 항상 지원하지 않음
  • GUI 소프트웨어 개발에 적합치 않음

Virtual Machines와 (Docker) Containers 비교

Docker 프로그램 개발 프로세스

하이레벨 Docker 사용 프로세스

  • 먼저 대상 소프트웨어를 선택
    - 다수의 컴포넌트로 구성되는 소프트웨어라면 각각이 Docker Image로 만들어져야할 수도
    있음
  • 이를 Docker Image로 빌드하자: Dockerization이라고 부름
    - Dockerfile이란 텍스트 파일로 세부 정보를 기술
       해당 소프트웨어를 이미지로 바꾸기 위한 Docker에게 주는 명령들을 포함
    - Docker Image: 하나의 Docker Container안에서 실행됨!
       Dockerfile을 기준으로 만들어지며 소프트웨어를 실행하기위해 필요한 모든 것을 포함

Docker Image의 구성 요소

  • 기본 OS (리눅스라면 우분투, 데비안 등등)와 같은 소프트웨어의 실행환경
  • 소프트웨어 자체 (코드)
  • 소프트웨어가 필요로 하는 라이브러리
  • 파일 시스템 스냅샷: 이는 스택화된 형태로 구현됨 (뒤에서 더 설명)
  • 환경 설정 변수: 빌드할 때 변수와 실행 때 변수 두 가지가 존재
  • 메타 데이터: 이미지 자체에 대한 정보 (버전, 작성자, 설명 등등)

위 정보와 설치 관련 실행 순서등이 Dockerfile에 기술됨
Docker Image는 다수의 파일로 구성됨 (“docker image ls”)

Docker Image의 실행

  • Container를 통해 Docker Image안의 소프트웨어를 실행
    - Container는 자체 파일 시스템을 가진 특수한 프로세스로 이미지의 파일 시스템이 로딩됨
  • Image를 Container 안에서 실행
    - docker run : 주어진 Image를 Container에 처음 실행
    • docker execute : 이미 실행된 Docker에 명령

Docker Image의 등록

  • Docker Registry는 Docker Image들의 보관소
    - On-prem registry와 Cloud registry가 존재
    - docker hub이 가장 유명
  • 여기에 등록을 하면 회사내 혹은 퍼블릭하게 이미지를 공유 가능

Docker Hub

https://hub.docker.com/

  • Docker가 제공해주는 서비스로 Docker Image를 공유하고 찾기 위한 서비스
  • Teams & Organizations
  • Public과 Private Repo 제공
  • Official Images
  • Github과 연동을 통한 Automated Build 제공

Docker 실행

Dockerfile의 생성

  • Docker에게 소프트웨어 설치 명령을 기술
  • 먼저 베이스 이미지를 기술 (FROM)
  • 다음으로 코드 복사
  • 마지막으로 코드 실행

Dockerfile 사용 가능 기타 키워드

  • ARG : Docker Image를 만들 때 사용되는 변수 지정. 최종 이미지에는 안 들어감
  • ENV : 컨테이너가 실행될 때 사용되는 환경변수. 최종 이미지에 저장됨
  • USER : 컨테이너를 실행할 때 사용할 유저 ID
  • EXPOSE : 서비스 사용 포트번호
  • RUN
    - 빌드시 실행되어야하는 명령들이 지정됨 (docker build)
    - RUN apt-get update && apt-get install -y curl

CMD vs ENTRYPOINT

  • Container가 시작할 때 실행되어야 하는 명령어를 지정하는데 사용 (docker run)
    - 굉장히 흡사한 기능을 제공하지만 우선 순위가 있음 (ENTRYPOINT 우선)

  • 둘다 한 DOCKERFILE에서 여러번 실행되면 각각 마지막 것만 사용됨

  • 아래의 경우 docker run 실행시 동일한 결과가 나옴

  • CMD나 ENTRYPOINT 중 하나만 지정되면 그게 container가 실행될 때 실행

  • 둘이 한 DOCKERFILE에서 같이 지정가능함
  • 둘이 같이 사용되면 ENTRYPOINT가 기본 명령이 되고 CMD가 인자를 제공
  • ENTRYPOINT는 --entrypoint 옵션을 통해서만 덮어쓰기가 가능

CMD or ENTRYPOINT?

  • 최대한 CMD만 사용 : 명령 자체를 편하게 바꿔치기 할 수 있음
  • ENTRYPOINT를 사용하면 실행시 타이핑을 덜 할 수 있음
    - 파라미터를 지정해주면 되기 때문이지만 감춰지기 때문에 오히려 혼란을 줄 수 있음

Dockerfile 더 살펴보기 : Airflow 예

FROM python:3.7-slim-buster

ENV DEBIAN_FRONTEND noninteractive

ARG AIRFLOW_USER_HOME=/usr/local/airflow    # 이미지에도 최종 저장됨
ARG AIRFLOW_VERSION=1.10.9                  # 이미지에도 최종 저장됨

COPY config/airflow.cfg ${AIRFLOW_USER_HOME}/airflow.cfg

RUN chown -R airflow: ${AIRFLOW_USER_HOME}  # 빌드할 때 실행되는 명령

EXPOSE 8080 5555 8793

USER airflow
WORKDIR ${AIRFLOW_USER_HOME}
ENTRYPOINT ["/entrypoint.sh"]
CMD ["webserver"]                         # => /entrypoint.sh webserver

Docker Image 생성

Docker Container로 실행

$ docker run hello-world-docker
Hello Docker!                      # docker run을 Dockerfile에서 CMD 명령이 실행됨

Docker tag

  • Docker Image의 버전이나 변형을 나타내는 문자열
    - 디폴트 값은 latest
    - Docker Image의 부가정보를 나타냄
  • Docker Image 이름에서 :뒤에 해당

Docker Image 이름

  • docker image ls에서 Repository에 해당
    - Docker Hub에서 다운로드받은 것이라면 어카운트ID(네임스페이스)를 포함할 수 있음
  • 포맷 : Repo이름:태그
    - e.g.) hello-world-docker:latest
  • 공식 이미지들의 경우에는 네임스페이스가 없음
    - e.g.) ubuntu:18.04

0개의 댓글