
- Airflow 운영상의 어려움
- Docker
- 간단한 Hello World 프로그램
- Docker에서 Ubuntu 실행하기
- Docker로 MySQL 실행하기
관리해야 하는 DAG의 수가 많아질수록 데이터 품질이나 데이터 리니지 이슈 이외에도 라이브러리 충돌, Worker의 부족, Worker 서버들의 관리와 활용 이슈와 같은 다양한 문제가 발생할 수 있다.
여러 DAG를 사용하게 되면서 각 DAG에 따라 실행에 필요한 라이브러리/모듈이 달라지기 시작한다. 이렇다 보니 라이브러리/모듈의 충돌 이슈가 발생할 수 있다. 이로 인해 DAG 혹은 Task 별로 별도의 독립공간을 만들어주는 것이 필요한데 이 때 사용할만한 것이 바로 Docker이다.
DAG가 많아지면서 필요한 리소스도 많아지게 된다. 특히 Airflow Worker의 부족 현상을 겪게 되는데, 이 때 우리는 다음 두가지 방법으로 서버의 용량을 늘려주어야 한다.

보통 이런 Scale Up과 Scale Out 작업은 클라우드 서비스를 사용한다. K8s와 같은 컨테이너 기술을 사용해서 필요한대로 서버를 요청하게 구성할 수 있다. 이는 비단 Airflow만이 아니라 여러대의 서버가 필요한 환경, 서버가 탄력적으로 돌아가야 하는 모든 상황에서 사용할 수 있다.

Airflow 전용 하드웨어를 지정했지만 서버들이 항상 바쁘지 않은 경우에는 여러가지 이슈를 만들어낼 수 있다.
이 역시 K8s와 같은 컨테이너 기술의 도입으로 해결이 가능하다.
- 태스크나 DAG 코드를
Docker Image로 만들어서Docker Container형태로 실행
- 라이브러리 / 모듈 충돌 방지
- 개발 환경과 프로덕션 환경을 동일하게 유지
- Airflow Worker를 K8s에서 필요한 대로 동적으로 할당하여 사용
- 전용 서버를 Airflow에 할당하지 않고
Container Orchestration서비스를 통해 할당해서 사용하고 리턴
Airflow에서 이를 해결하는 방법은 3가지가 있다.
KubernetesPodOperator를 사용
DockerOperator를 사용
Airflow Executor로 아래를 사용KubernetesExecutorCeleryKubernetesExecutorLocalKuberneesExecutor
Sequential Executor : 디폴트로 설치되며 Sqlite와 같은 싱글스레드 DB에서만 사용가능Local Executor : task들을 Airflow 마스터 노드안에서 실행Celery Executor : 다수의 Worker 노드가 있는 경우 사용되며 Celery 큐를 사용해 task들을 worker 노드로 분산하여 실행Kubernetes Executor : K8s 클러스터를 사용하여 task들을 독립된 환경에서 사용
Docker를 사용하는 이유는 내가 만든 프로그램이 다른 컴퓨터에서도 돌아갈 수 있게 하기 위해서 이다. 안 돌아가는 이유는 여러가지가 있을 수 있겠지만 다음과 같은 이유일 수 있다.
- 설치 과정에서 중요한 파일이 빠짐
- 사용하는 라이브러리 등의 버전이 안 맞음 (가장 골치 아픈 문제)
- 환경 설정이 안 맞는 것이 존재
따라서 Docker의 목표는 자신의 컴퓨터 환경을 그대로 패키징해서 다른이에게 줌으로써 같은 환경을 제공하여 소프트웨어를 일관되게 빌드하고, 실행하고, 배포하는 것이다.



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

(docker run ...)

Docker Hub이란 Docker가 제공해주는 Docker Registry 서비스로 Docker Image를 공유하고 찾기 위한 서비스이다.
다음을 포함한 여러가지 기능들을 제공한다
- Teams & Organizations
- Public & Private Repo 제공
- Official Images
- Github와 연동을 통한 Automated Build 제공
Docker Hub링크 : https://hub.docker.com/

node.js로 만든 간단한 프로그램을 단계별로 이미지 빌드부터 최종적으로 다른 서버에서 실행까지 전체 과정을 다뤄보자
만들려는 프로그램은 Node.js로 구성된 초간단 웹 서비스로, app.js 파일이 전부인 서비스이다. 이를 실행하려면 node 런타임 환경이 필요하고 보통 이를 실행하려면 node app.js명령어를 사용한다.
만약 Docker 없이 프로그램을 실행한다면 먼저 OS를 선택하고, Node를 설치한 다음, 코드를 복사하고 프로그램을 실행해야할 것이다. 이 내용을 Dockerfile로 기술하면 Docker Image 생성이 가능하고 이를 한번에 처리할 수 있을 것이다.
// app.js 내용
console.log("Hello Docker!");
Dockerfile은 Docker에게 소프트웨어 설치 명령을 기술하는 파일이다.

Dockerfile 사용 가능 기타 키워드
ARG : Docker Image를 만들 때 사용되는 변수 지정. 최종 이미지에는 안 들어감ENV : 컨테이너가 실행될 때 사용되는 환경변수. 최종 이미지에 저장됨USER : 컨테이너를 실행할 때 사용할 유저 IDEXPOSE : 서비스 사용 포트번호RUN : 빌드 시 실행되어야하는 명령들이 저장됨 (docker build)RUN apt-get update && apt-get install -y curlENTRYPOINT : Container가 시작할 때 실행되어야 하는 명령어를 지정하는데 사용 (docker run)CMD 명령어와 굉장히 흡사하지만 ENTRYPOINT의 우선순위가 더 높다는 차이가 있다CMD, ENTRYPOINT 둘다 한 Dockerfile에서 여러번 실행되면 각각 마지막 것만 사용됨CMD 사용을 권장
CMD와 ENTRYPOINT 둘을 한 Dockerfile에서 같이 지정 가능하다. 같이 사용하는 경우 ENTRYPOINT가 기본 명령이 되고 CMD가 인자를 제공하는 방식으로 작동한다. ENTRYPOINT는 --entrypoint 옵션을 통해서만 덮어쓰기가 가능하다.

작성된 Dockerfile 예시를 보면서 더 이해해보자.

이 내용을 바탕으로 Dockefile을 만들어보자. 적당한 디렉토리에 app.js파일과 Dockerfile 두개를 작성하자







https://hub.docker.com/ 에서 회원가입을 한 뒤 repository를 만들어보자. 자신의 Account 계정명과 Repository Name을 기억해두자. 현재 예시에서는 hjjwa1234/hello-world-docker


그 후, 터미널로 이동하여 다음 명령을 실행한다.
docker image ls
docker tag hello-world-docker:latest hjjwa1234/hello-world-docker:latest
docker login --username = hjjwa1234
docker push hjjwa1234/hello-world-docker
docker tag hello-world-docker:latest hjjwa1234/hello-world-docker:latest : 현재 이미지의 별칭을 우리가 만든 repository의 이름으로 변경
이 hjjwa1234/hello-world-docker repository에 우리가 push할 수 있는 권한이 있다는 것을 알리기 위해 docker login --username = hjjwa1234명령어를 실행한 뒤 비밀번호를 입력해주자
push 명령을 실행한 뒤 docker hub 웹페이지에서 우리가 만든 이미지 파일이 잘 올라갔는지 확인해보자



우리가 방금 올린 Image파일을 다른 리눅스 서버에서 다운받아 실행해보자. 이 실습에서는 Docker를 사용하는 사람들에게 4시간동안 서버를 하나 무료로 제공해주는 서비스를 이용해서 테스트를 진행한다. (https://labs.play-with-docker.com/)

docker 계정을 연동해서 접속한 뒤 Alt + Enter(MAC : Option + Enter)로 터미널 윈도우를 최대화 하고 아래 명령을 실행해보자
docker version
docker pull hjjwa1234/hello-world-docker
docker image ls
docker run hjjwa1234/hello-world-docker
만일 로컬에 다운로드 받은 이미지가 없다면 docker hub에서 pull을 알아서 수행하게 된다
--platform 옵션 사용이 필요하다WARNING: The requested image's platform
(linux/arm64/v8) does not match the detected host
platform (linux/amd64/v3) and no specific platform was
requested exec /usr/local/bin/docker-entrypoint.sh: exec
format error


이번엔 각자 Docker 위에서 Linux OS중 하나인 Ubuntu를 Docker 컨테이너로 실행해보자.
docker run ubuntu 명령어를 실행하면 현재 Local 환경에서 ubuntu라는 도커 이미지가 없기 때문에 Docker Hub에서 자동으로 ubuntu를 pull하게 된다. (ubuntu는 docker hub에서 official image가 있기 때문)



설치한 뒤 nano를 실행해보면 컨테이너 안의 Linux(Ubuntu) 서버에서 잘 실행되는 걸 확인할 수 있다.


터미널을 실행한 뒤 먼저 MySQL docker image를 다운로드 하자 (docker pull mysql/mysql-server:8.0)

다운로드 받은 이미지로 Docker Container를 실행, --name 옵션을 이용해서 읽기 쉬운 이름으로 설정해보자 (docker run --name=mysql_container mysql/mysql-server:8.0)
docker exec 명령어를 사용해서 컨테이너를 실행할 수도 있지만 docker run과는 차이점이 있다.docker exec : 이미 실행이 된 컨테이너에 어떠한 명령들을 보내는 작업 (-it 옵션으로 Interactive하게 실행)docker run : 새로운 컨테이너를 실행

다음으론 새로운 터미널을 열어서 MySQL root 계정의 패스워드를 찾자 (docker logs mysql_container 2>&1 | grep GENERATED) 여기서 찾은 PASSWORD는 MySQL에에 접속할 때 필요하기 때문에 복사해두자.

마지막으로 MySQL shell 실행하기 (docker exec -it mysql_container mysql -uroot -p)

docker를 중단하고 싶다면 docker stop ['컨테이너 ID' or '컨테이너 이름'] 명령어를 사용해주자
