Airflow를 사용 중인 개발자라면 한번쯤은 Executor와 Operator에 대해 들어보셨을 겁니다. 하지만 둘의 정의를 어림짐작하고 사용하는 경우도 꽤나 많을 텐데요. 저 또한 그 둘의 관계를 잘 모르는 상태로 단지 사용만 하고 있었는데요. 이번 포스팅으로 Executor와 Operator의 관계, 특히 프로덕션 환경에서 많이들 사용하는 KubernetesExecutor와 KubernetesPodOperator의 관계에 대해 알아보려고 합니다.
Executor와 Operator에 대해
KubernetesExecutor와 KubernetesPodOperator에 대해 알아보기 전에 먼저 그냥 Executor와 Operator에 대해 알아보도록 하겠습니다. 사실 이 둘을 알면 결과적으로는 KubernetesExecutor와 KubernetesPodOperator 알게 되니까 말이죠.
Executor와 Operator는 둘다 Airflow의 task를 다룬다는 공통점이 있습니다. 이런 공통점 하에 둘의 차이점을 살펴보면 둘의 역할을 아주 간결하고 쉽게 설명할 수 있죠.
•
Executor: Airflow가 어떻게 Task를 실행할지 결정
•
Operator: Airflow가 무슨 Task를 실행할지 결정
각각 조금 더 자세히 알아보도록 하겠습니다.
먼저 executor입니다. executor는 말 그대로 Airflow task를 실행하는 주체입니다. executor에는 다양한 종류가 있습니다. SequentialExecutor, LocalExecutor, CeleryExecutor, KubernetesExecutor 등 다양한 종류가 있는데요.
각각의 이름에서 알 수 있다시피 모두 task를 실행하는 방법이 다릅니다. 예를 들면 가장 기본적인 executor인 SequentialExecutor는 task를 순차적으로만 실행시킬 수 있죠. 나머지 executor에 대해서는 나중에 시간이 된다면 다뤄보도록 하고 오늘 알아볼 것은 KubernetesExecutor입니다.
이름에서 알 수 있다시피 KubernetesExecutor는 쿠버네티스를 이용하여 task를 실행합니다. 가장 큰 특징은 아래 3가지로 정리할 수 있습니다.
1.
분산 처리
a.
쿠버네티스를 사용하기 때문에 여러 개의 task를 한 번에 실행할 수 있습니다.
2.
독립된 환경
a.
각 task는 독립된 컨테이너에서 실행됩니다. 이는 서로 다른 task가 동일한 환경에서 실행되지 않음을 의미합니다.
3.
리소스 절감
a.
task를 실제로 수행하는 역할을 하는 것이 worker인데 KubernetesExecutor는 이러한 worker를 task 실행시 파드 형태로 띄우고 실행이 완료되면 삭제하기 때문에 리소스 관리 측면에서 유리합니다.
다음은 Operator입니다. operator는 무엇을 할지 결정하는 역할을 합니다. 마찬가지로 operator도 다양한 종류가 있는데요. 가장 유명한 게 BashOperator와 PythonOperator입니다. 지금 다룰 건 KubernetesPodOperator인데요. 먼저 이를 이야기 하기 전에 오해할 수 있는 부분을 먼저 짚고 가야합니다.
KubernetesPodOperator와 KubernetesExecutor는 서로 종속된 관계가 아닙니다! 둘은 무슨 task를 실행할지와 어떻게 실행할지의 차이를 가지고 있기 때문인데요. 둘의 공통점이라고 한다면 전제 조건으로 Airflow가 무조건 Kubernetes 위에 설치되어 있어야 한다는 것 뿐이죠.
즉, Airflow on K8S 이기만 한다면 KubernetesPodOperator는 Airflow의 Executor가 LocalExecutor인지 CeleryExecutor인지는 상관이 없다는 이야기입니다. 어떤 것이 더 효율적인지는 각자의 상황에 따라 달라질 것 이구요.
다시 돌아와서 KubernetesPodOperator의 가장 큰 특징은 task를 독립된 이미지로 실행할 수 있다는 것입니다. 이렇게 되면 task별로 필요한 라이브러리나 환경을 개발자가 직접 정의할 수 있어 훨씬 독립적인 환경을 만들 수 있죠.
위의 그림과 같이 만약 KubernetesExecutor와 KubernetesPodOperator를 같이 사용한다면 executor가 동적으로 파드 형태로 워커를 실행하고, 워커가 개발자가 직접 정의한 이미지를 불러와서 task를 실행하게 됩니다.