← 학습 카테고리

Learn

Airflow

151개 모듈 · 현재 90번째

Airflow 모듈 90/151 airflow-learn-90

프로덕션 배포: 인프라 구성과 무중단 라이브 업그레이드

Apache Airflow Official Documentation (in-repo snapshot) — Apache Software Foundation administration-and-deployment/production-deployment.rst (DB 백엔드 ~ Kerberos 절)

이 모듈을 다 읽으면

  • SQLite 기본 백엔드가 프로덕션에 부적합한 이유와 전환 절차를 설명할 수 있다
  • 멀티노드 클러스터에서 Dag/설정 동기화 방법과 보안 원칙을 설명할 수 있다
  • Executor별 무중단 라이브 업그레이드 절차의 차이를 비교할 수 있다

프로덕션급 Airflow를 운영하려면 기본 SQLite 백엔드를 벗어나 외부 DB로 전환하고, 멀티노드 클러스터에서 Dag/설정을 동기화하며, 컴포넌트별로 다른 무중단 업그레이드 전략을 이해해야 한다.

데이터베이스 백엔드 전환

Airflow는 기본적으로 ``SQLite`` 백엔드로 동작해 외부 DB 없이도 실행할 수 있지만, 이는 테스트 목적 전용이다. 이 기본 설정을 프로덕션에서 그대로 쓰면 여러 시나리오에서 데이터 유실로 이어질 수 있다. 프로덕션급으로 운영하려면 PostgreSQL이나 MySQL 같은 외부 DB로 백엔드를 구성해야 하며, ``[database] sql_alchemy_conn``으로 전환한다.

백엔드를 바꾼 뒤에는 Airflow가 동작에 필요한 모든 테이블을 만들어야 한다. 빈 DB를 만들고 Airflow 사용자에게 CREATE/ALTER 권한을 준 다음 ``airflow db migrate``를 실행한다. 이 명령은 이미 적용된 마이그레이션을 추적하므로 필요할 때마다 반복 실행해도 안전하다. (버전 민감) 2.7.0 이전에는 마이그레이션 적용에 ``airflow db upgrade``를 썼지만 ``airflow db migrate``로 대체되어 지원 중단되었다.

핵심 포인트

  • 기본 SQLite 백엔드는 테스트 전용이며 프로덕션에서는 데이터 유실 위험이 있다
  • sql_alchemy_conn으로 외부 DB를 지정하고 airflow db migrate로 테이블을 생성/갱신한다
  • (버전 민감) 2.7.0부터 airflow db upgrade 대신 airflow db migrate를 쓴다

멀티노드 클러스터

Airflow는 기본적으로 ``LocalExecutor``를 쓴다. 멀티노드 구성을 위해서는 태스크가 실행되어야 할 위치에 맞는 원격 executor나 다중 executor 구성을 선택해야 한다. 대표적으로 Celery executor, Kubernetes executor, Amazon Batch/ECS 같은 프로바이더 executor, Edge executor가 있다.

Executor를 구성한 뒤에는 클러스터의 모든 노드가 자신의 역할에 맞는 Dag와 설정을 갖추도록 해야 한다. Airflow는 "Dag Y의 태스크 X를 실행하라" 같은 단순한 지시만 보낼 뿐, Dag 파일이나 설정 자체를 전송하지 않기 때문이다. Dag 동기화에는 Dag 버전 관리가 가능한 Dag Bundle 메커니즘(``GitDagBundle`` 포함) 사용이 권장된다. 보안이 중요한 배포에서는 JWT 서명 키, DB 자격증명, Fernet 키 같은 민감한 설정을 모든 노드에 공유하지 말고 정말 필요한 컴포넌트에만 제한해야 한다.

핵심 포인트

  • 기본 LocalExecutor 대신 멀티노드에서는 태스크 실행 위치에 맞는 executor(Celery/Kubernetes/Batch/ECS/Edge 등)를 선택한다
  • Airflow는 실행 지시만 보낼 뿐 Dag 파일/설정 자체는 전송하지 않으므로 노드 간 동기화가 별도로 필요하다
  • Dag 동기화는 버전 관리가 되는 Dag Bundle(GitDagBundle 등) 메커니즘이 권장된다
  • JWT 서명 키, DB 자격증명, Fernet 키 등은 필요한 컴포넌트에만 제한해 배포해야 한다

로깅과 설정 관리

클러스터에서 디스포저블(언제든 교체 가능한) 노드를 쓴다면 로그 저장소를 S3, GCS 같은 분산 파일 시스템이나 Stackdriver Logging, ElasticSearch, Amazon CloudWatch 같은 외부 서비스로 구성해, 노드가 죽거나 교체돼도 로그가 남아있게 해야 한다. 다만 로그는 태스크가 끝난 뒤에야 DFS에 나타나며, 실행 중인 로그는 UI에서 바로 볼 수 있다.

배포마다 달라지는 설정(메타데이터 DB, 비밀번호 등)은 ``AIRFLOW__{SECTION}__{KEY}`` 형식의 환경변수로 주는 것이 권장된다. 일부 설정(예: Backend connection URI)은 ``sql_alchemy_conn_cmd``처럼 bash 명령의 결과로 파생시킬 수도 있다.

핵심 포인트

  • 디스포저블 노드 환경에서는 로그를 DFS나 외부 로깅 서비스로 보내야 노드 교체 후에도 로그가 남는다
  • 로그는 태스크 완료 후에만 DFS에 나타나고, 실행 중에는 UI에서만 실시간으로 보인다
  • 배포별로 달라지는 설정은 AIRFLOW__{SECTION}__{KEY} 환경변수로 관리하는 것이 권장된다

스케줄러 업타임, 컨테이너 이미지, Helm 차트

사용자들이 스케줄러가 흔적 없이 멈추는 문제를 종종 보고해왔다. 이를 완화하려면 스케줄러의 하트비트가 일정 시간 없을 때 감지하는 헬스체크를 반드시 구성해야 한다.

Airflow는 컨테이너화된 환경에서 항상 동일하게 동작하도록 공식 Docker(OCI) 이미지를 제공하며, 쿠버네티스 배포를 위한 공식 Helm 차트도 이 공식 이미지를 기반으로 유지보수·배포된다.

핵심 포인트

  • 스케줄러가 흔적 없이 멈추는 문제에 대비해 하트비트 기반 헬스체크 구성이 필수적이다
  • 공식 Docker 이미지와 이를 기반으로 한 공식 Helm 차트가 제공된다

무중단 라이브 업그레이드

Airflow는 설계상 분산 시스템이며, 기본 배포는 보통 완전 재시작이 필요하지만 분산 배포에서는 다운타임 없이 업그레이드하는 것이 가능하다. 이런 라이브 업그레이드는 메타데이터 DB 스키마 변경이 없을 때 가능하므로, 패치 레벨(버그픽스) 업그레이드나 릴리스 노트·마이그레이션 참조를 검토해 스키마 변경이 없는 인접 마이너 버전 업그레이드에서 시도하는 것이 좋다. DB를 먼저 업그레이드하고 마이너 버전 사이를 라이브로 넘어가는 것도 스키마 변경이 크지 않다면 가능은 하지만 권장되지 않으며, 스테이징에서 충분히 테스트해야 한다.

``Webserver``, ``Triggerer``는 별도 환경에서 여러 인스턴스로 돌린다면 하나씩 롤링 재시작하면 다운타임 없이 업그레이드할 수 있고, 보통 업그레이드 절차의 첫 단계로 수행한다. ``Dag processor``는 (별도로 배포된 구성에서) 수평 확장 대상이 아니어서 여러 개가 있어도 폴더당 보통 하나만 활성 상태이므로, 그냥 멈추고 새 걸 시작하면 된다 — 크리티컬한 컴포넌트가 아니므로 짧은 다운타임은 괜찮다.

스케줄러와 워커 업그레이드는 쓰고 있는 executor의 라이브 업그레이드 능력에 달려 있다. LocalExecutor는 태스크가 스케줄러의 서브프로세스로 돌기 때문에 태스크를 죽이지 않고는 스케줄러를 업그레이드할 수 없다 — 모든 Dag를 일시정지하고 실행 중인 태스크가 끝나길 기다리거나, 그냥 스케줄러를 멈추고 태스크를 모두 죽인 뒤 업그레이드 후 수동으로 클리어·재시작해야 한다(또는 중단된 태스크에 retry가 설정되어 있음에 의존). CeleryExecutor는 먼저 워커를 오프라인 모드로 두고(보통 TERM 시그널 한 번), 실행 중인 태스크가 모두 끝나길 기다린 뒤(flower로 모니터링 가능) 이미지를 교체하고 워커를 재시작한다 — 재시작된 워커는 자동으로 온라인 모드가 되어 새 태스크를 받기 시작하며, 이후 스케줄러를 롤링 재시작하면 된다. KubernetesExecutor는 스케줄러/트리거러/웹서버를 롤링 재시작 모드로 업그레이드할 수 있고, 워커는 쿠버네티스가 관리하므로 스케줄러가 재시작·업그레이드된 뒤 자동으로 다시 채택(adopt)되기 때문에 크게 신경 쓸 필요가 없다.

대부분의 롤링 재시작 업그레이드 시나리오는 Helm 차트에 이미 구현되어 있어, 특히 패치 레벨 업그레이드에서는 Helm 차트를 활용하면 다운타임 없이 업그레이드할 수 있다.

핵심 포인트

  • 라이브 업그레이드는 메타데이터 DB 스키마 변경이 없는 패치/인접 마이너 버전 업그레이드에서만 안전하게 시도할 수 있다
  • Webserver/Triggerer는 다중 인스턴스라면 하나씩 롤링 재시작하면 되고, 보통 첫 단계로 수행한다
  • Dag processor는 수평 확장 대상이 아니라 폴더당 하나만 활성 상태이므로 그냥 멈추고 새로 시작해도 된다
  • LocalExecutor는 태스크를 죽이지 않고 스케줄러를 업그레이드할 수 없고, CeleryExecutor는 워커를 오프라인 전환 후 롤링 교체하며, KubernetesExecutor는 워커가 자동 재채택되어 가장 유연하다
  • Helm 차트가 대부분의 롤링 재시작 시나리오를 이미 구현하고 있다

Kerberos 인증 워커

Airflow는 KDC(Key Distribution Center)와 연동해 인증하는 내장 메커니즘을 갖고 있다. ``airflow kerberos``라는 별도 명령이 토큰 갱신기 역할을 하며, 사전 구성된 Kerberos Keytab으로 KDC에서 유효한 토큰을 얻고, 만료 전에 주기적으로 갱신한다. 갱신 요청마다 구성된 프린시펄을 사용하며, 지정된 프린시펄에 유효한 Keytab만 해당 인증 토큰을 가져올 수 있다.

보안 모범 사례는 워커 워크로드가 Keytab에는 접근하지 못하고 주기적으로 갱신되는 임시 인증 토큰에만 접근하게 하는 것이다. Docker 환경에서는 ``airflow kerberos`` 명령과 워커 명령을 별도 컨테이너로 분리해, Keytab(비밀 리소스로 구성하는 것이 바람직)에는 kerberos 컨테이너만 접근하게 하고, 두 컨테이너가 볼륨을 공유해 kerberos 컨테이너가 임시 토큰을 쓰고 워커가 읽게 한다.

쿠버네티스 환경에서는 사이드카 개념으로 구현할 수 있다 — Kerberos 토큰 갱신기와 워커가 같은 파드의 일부가 되고, Kerberos 사이드카만 Keytab 시크릿에 접근하며 두 컨테이너는 볼륨을 공유해 사이드카가 쓰고 워커 컨테이너가 읽는다. 이 개념은 공식 Airflow Helm 차트에 구현되어 있다.

핵심 포인트

  • airflow kerberos 명령이 Keytab으로 KDC에서 토큰을 얻고 만료 전 주기적으로 갱신하는 역할을 한다
  • 워커 워크로드는 Keytab이 아니라 갱신된 임시 토큰에만 접근해야 한다는 것이 보안 모범 사례다
  • 쿠버네티스에서는 Kerberos 사이드카 패턴(사이드카만 Keytab 접근, 볼륨 공유로 워커에 토큰 전달)으로 구현되며 공식 Helm 차트에 반영되어 있다