Search
Duplicate

나만의 Airflow 클러스터 만들기 (feat. k3d)

데이터 엔지니어로 커리어를 이어가면서, 가장 많은 시간을 들였고 가장 많은 관련 코드를 작성했지만 아직까지도 많이 부족한 국룰 워크플로우 관리 도구, Airflow!
진짜 간단한 Bash 커멘드를 돌리는 것 부터, 복잡한 비즈니스 로직 의존관계를 가진 파이프라인까지 만들어보면서 항상 들었던 생각은, 아 이거 여기에만 쓰기에는 아까운데... 라는 것이었다.
(개발자한테 진짜 좋은 데 표현할 방법이 없는 Airflow)
오늘은 지극히 개인적인 목적으로 사용할 나만의 Airflow Cluster를 만들어보고 개발 환경 세팅을 하는 방법을 정리해보려고 한다!

목차

Basics

출처: https://www.astronomer.io/guides/airflow-components
간단하게 에어플로우의 구조에 대해서 설명을 하자면,
먼저 에어플로우는 크게 4가지 컴포넌트로 구성이 된다.
Webserver
Scheduler
Worker
Metastore DB
웹서버는 워크플로우의 상태 관리나 Connection, Pool, Variables 같은 메타 정보들을 GUI로 관리할 수 있게 도와준다 (실질적으로 제일 많이 들어간다). Scheduler는 스케줄링, Worker는 실제로 워크플로우를 실행하고, Metastore DB(이하 메타디비)는 워크플로우들의 히스토리, 메타 정보들을 저장한다.
이 중 가장 중요한 부분은 아무래도, 얼마나 Worker가 Scalable한가 인듯하다. 왜냐하면 Airflow의 목적 상 다양한 Workflow가 동시에 돌아가야 하고, 그를 위한 리소스가 잘 분배가 되어야한다.
때문에 프로덕션 환경에서는 많이들 Kubernetes 환경에서 운영을 한다고 한다. Kubernetes의 장점을 살려, 하드하게 리소스를 사용해야하는 워크플로우에는 사양 좋은 머신을 붙히고 (또는 AWS SageMaker를 그냥 붙혀버릴 수도 있다 참고), 아닌 것들은 평범한 머신에 Pod로 바인딩을 시킬 수도 있다.
실제로 전 회사에서 Kubernetes로 Airflow와 AWS EMR을 같이 사용하면서 하루에 수 백개가 넘는 태스크들을 효율적으로 관리할 수 있었다.
관련해서 제일 잘 설명해주신 발표. 존경합니닷 :3
이런 Airflow 인프라를 잘 설정하고 관리하는 게 생각보다 어렵기 때문에
Astronomer나 GCP Composer, AWS MWAA같은 Airflow 만을 위한 매니지드 서비스들이 생겨나기 시작한 것 같다. (내부적으로는 모두 Kubernetes 환경에서 동작한다)

Goal Setting

본격적으로 Airflow Cluster를 만들기 전에 요구 사항부터 정리를 해 보자면,
목표
독립된 환경에서 실행
Airflow의 특성 상, 다양한 환경 변수로 구성이 제어된다 (airflow.cfg에 하드코딩 되기도 하지만, CI를 통해서 Staging, Production 환경을 분리하고 중요한 데이터베이스 관련 정보를 Secrets Manager 같은 저장소에서 Pull하는 방식으로 사용중임). 때문에 다른 클러스터와 충돌 날 수도 있으니 주의해야함.
내 Airflow 클러스터를 톡 떼서 그대로 다른 머신에서 똑같이 사용할 수 있게 하는 게 목표
퍼블릭 링크 제공 (TODO)
내 블로그 방문자들이 가끔씩 들어와서 봐줬으면... (관종)
API Endpoint 제공 (TODO)
앞으로 다양한 서비스들과 괴랄한 토이프로젝트의 백엔드로 쓰일 airflow니깐 다양한 서비스에서 접근 가능하게 설정 해보고 싶다.
운영 및 개발 코스트 최소화
목표가 아닌 것
프로덕션 레벨 리소스 스케일링
나 16GB 맥북 프로다... 가난한 20대 휴학생 겸 직장인입니다
Authentication
나 혼자쓰는데 인증하고 들어가기 귀찮
Security
내 컴이 털리면 다 털리는 거다 ㅅㄱ
회사에서 개발하는데 보안 땜에 머리아픈데 사이드할 때는 좀 봐주라...

Kubernetes Cluster 만들기

주의: 쿠린이가 쓴 글입니다... 틀린 게 있다면 댓글로 남겨주세요
처음에는 GKE나 EKS 같은 매니지드 서비스를 생각했다.
GCP 크레딧이 남아서 GKE로 운영을 할 까 생각을 했지만, 생각보다 크레딧이 빨리 닳았다. GKE 보다는 GCE(인스턴스 비용)가 더 많이 나갔다 (노드 2개 기준 한 달에 8-9만원 정도). 일단은 로컬에서 클러스터를 만들어서 켜고 끄고 하다가, 필요하면 GKE로 다시 돌아가야지

로컬 Kubernetes Cluster 만들기

쿠버네티스를 로컬에서 실행하는 방법에는 Minikube, Kind, Microk8s 등이 있지만, 최근 시도를 해보고 있는 k3s로 구성을 해본다. k3s를 쉽게 사용하게 해주는 wrapper, k3d를 사용한다.
k3s는 Rancher에서 나온 작고 귀여운 Kubernetes Distribution이다. IoT나 Edge Computing 쪽에서 쓰이는 목적이라는데, 그냥 로컬 환경에 하기도 편하다. 개인적으로 Kind나 Minikube 보다 Pod 뜨는거나 Scale In-Out이 훨씬 매끄럽고 빨랐다.
출처: https://k3s.io/

IDE

쿠버네티스 IDE는 Lens... 두 번 쓰세요... 세 번 쓰세요
평소 쓰던 Lens를 그대로 쓴다.
원래 정말 찐은 CLI로 모든 것들을 제어하지만, 나는 쭈구리라 IDE쓸거다
왼쪽에 아이콘 클릭해서 터미널을 열면, KubeConfig 스위칭도 자동으로 해주고, Service Expose해주는 것도 그냥 클릭 한 번으로 해결한다. 클릭 한번에 Node Exporter랑 Prometheus 설치해주는 것도 실화냐
When you go Lens, you never come back...

Cluster Installation

codye로 뽑은 코드가 너무 예뻐서 중복이어도 넣어본다
brew install k3d
Bash
k3d 설치는 간단하다
k3d cluster create <클러스터 이름> -p "<호스트머신 포트>:80@loadbalancer" \ --agents 3 --servers 3 \ --k3s-server-arg '--no-deploy=traefik' \ --volume "$(pwd)/helm-ingress-nginx.yaml:/var/lib/rancher/k3s/server/manifests/helm-ingress-nginx.yaml"
Bash
k3s는 기본 Ingress Controller를 Traefik을 사용한다. -p 옵션 뒤에 설정 값은 traefik이 기본적으로 바라보는 80포트와 호스트 머신의 포트를 바인딩 시켜준다. 나는 38080 포트를 내 k3d 클러스터의 노드의 80 포트와 바인딩을 시켜주고, Agent를 3개로 맞춰줬다 (딱히 이유는 없음. 그냥 스파크 클러스터 만들 때 부터 습관임)
Traefik보다는 나는 Nginx Ingress Controller가 더 익숙해서 오버라이딩을 했다.
apiVersion: helm.cattle.io/v1 kind: HelmChart metadata: name: ingress-controller-nginx namespace: kube-system spec: repo: https://kubernetes.github.io/ingress-nginx chart: ingress-nginx version: 3.7.1 targetNamespace: kube-system # valuesContent: |- # controller: # service: # type: NodePort # nodePorts: # http: 32080 # https: 32443 # tcp: # 8080: 32808
YAML
valuesContent 필드에서 ingress-nginx 차트의 values 필드를 주입할 수 있다.
다른 방법으로는 Node Port를 사용해서 로컬 호스트랑 바인딩 하는 방법이 있다. (이건 나중에 제대로 셋업하고 업데이트하겠다)
자세한 건 아래 링크에서

Airflow Deployment

Helm Chart를 이용해서 배포하는 게 국룰이다.
원래는 stable 차트를 이용했지만 최근에 airflow-helm이라는 chart repository를 하나 판 듯.
values.yaml을 수정해서 배포하거나, helm cli를 활용해서 --set 옵션을 활용해서 yaml을 몽키패칭해서 사용할 수 있다. 나는 다양한 Kubernetes Cluster에 배포를 할거라 환경 별로 yaml을 만들어두는 게 더 편해서 전자를 선택했다.

내 도메인 과 연결하기(TBD)

Namecheap에서 산 내 도메인과 k3s를 연결하려고 삽질을 많이 해봤지만 아직 잘 모르겠다. k3s의 마스터 노드external IP와 도메인을 바인딩 시켜줘야하는 데, 생각보다 시간이 많이 들었고 굳이 지금 airflow를 expose할 필요가 있을 까 해서 일단은 패스... 방법 아시는 분은 댓글로 남겨주세용
참고한 문서

대안들

에어플로우 너무 오버엔지니어링이고, 러닝커브도 있으니 아래 대안들도 한번 고려해 볼 수 있다.
1.
Github Action
깃헙에서 (제한적으로) 무료로 제공하는 워크플로우. 내부적으로 Docker를 사용해서 워크플로우를 실행할 수 있다. 다양한 Integration들을 Market Place에서 찾아볼 수 있는 게 장점. 하지만 Free Plan에서는 월간 2000분의 시간 quota가 있음. 하다보면 이게 생각보다 적다는 걸 알게된다.
워크플로우의 시간이 길어지면 생각보다 요금 폭탄 맞을 수 있으니 주의... (경험해봄)
재밌게 봤던 프로젝트들 공유
2.
IFTTT
이것도 부분적 무료 툴. programmatically 제어가 가능한지는 잘 모르겠지만, 유명한 서비스들 (e.g., gsuite, slack, instagram 등) 끼리의 연동이 자유로움. 현재에는 3개의 Applet (프로젝트 단위)까지만 무료로 나와있는데 정말 단순한 것 할 때 활용하기 좋을 듯. 예전에는 Webhook 받아서 연결하기도 편했는 데 요즘에는 안써서 잘 모르겠다.
3.
ios Shortcuts
ios 단축키에서도 다양한 Workflow 표현이 가능하다.
전 회사에서 출근할 때 Slack으로 메시지를 남기는 문화가 있었는데, 위치 기반으로
회사 근처 도착 → ios 단축키 실행 → Slack Webhook으로 HTTP 요청 → 출근 찍기
이런 식으로 구성을 해봤는 데 생각보다 너무 잘 되서 놀랐음;
좀 더 상상력을 발휘해 보면 더 재미있는 Workflow들 표현해볼 수 있을 듯. 이건 나중에 다른 글에서 써 봐야지

Docker Compose 환경 세팅하기

퍼블릭하게 쓰는 걸 고려하지 않고, 혼자 하기 제일 쉬운 방법은 그냥 Docker-compose로 말아서 쓰는 거다.
TBD

Summary

나만의 Airflow 클러스터를 만들어 봤다. 이제 내 로컬 머신에서 다양한 DAG를 만들어보고, 배포도 빠르게 할 수 있고, 간단하게 내 도메인과 연결해서 재미있는 것들을 많이 해볼 수 있게 되었다. 다음번에는 기상천외한 DAG로 글 써봐야지 ㅃㅇ