Production 배포
Production 배포 (Production Deployment)
이 페이지는 DAG를 production 환경에 배포하기 전에 준비해야 할 Airflow 설정을 다뤄요. 기본 SQLite 백엔드를 PostgreSQL·MySQL 같은 외부 데이터베이스로 바꾸고, 멀티 노드 클러스터에서는 적절한 Executor를 선택하며, 분산 파일시스템으로 로깅을 구성하는 방법 등을 설명해요. 또한 스케줄러 상태 확인, 컨테이너 이미지·Helm 차트 배포, 무중단 실시간 업그레이드, Kerberos 인증, Google Cloud 보안 접근까지 다뤄요.
출처: 문서
본문
이제 DAG를 production에 배포할 때가 됐어요. 그러려면 먼저 Airflow 자체가 production 준비가 되어 있는지 확인해야 해요. 어떤 주의사항을 취해야 하는지 살펴볼게요.
데이터베이스 백엔드
Airflow는 기본적으로 SQLite 백엔드를 제공해요. 이는 외부 데이터베이스 없이 Airflow를 실행할 수 있게 해줘요. 하지만 그런 설정은 테스트 목적으로만 사용되어야 해요. 기본 설정을 production에서 실행하면 여러 시나리오에서 데이터 손실이 발생할 수 있어요. production급 Airflow를 실행하려면 백엔드를 PostgreSQL이나 MySQL 같은 외부 데이터베이스로 구성했는지 확인해야 해요.
다음 설정으로 백엔드를 변경할 수 있어요:
[database]
sql_alchemy_conn = my_conn_string
백엔드를 변경한 후에는 Airflow가 운영에 필요한 모든 테이블을 생성해야 해요. 빈 DB를 만들고 Airflow 사용자에게 그것을 CREATE/ALTER할 권한을 줘요. 그런 다음 다음을 실행하면 돼요:
airflow db migrate
migrate는 이미 적용된 마이그레이션을 추적하므로, 필요할 때마다 안전하게 실행할 수 있어요.
Warning
Airflow 2.7.0 이전에는 마이그레이션 적용에
airflow db upgrade가 사용됐지만,airflow db migrate를 위해 deprecated됐어요.
멀티 노드 클러스터
Airflow는 기본적으로 LocalExecutor를 사용해요. 멀티 노드 설정에서는 Task가 실행되어야 할 곳과 일치하는 원격 executor나 멀티 executor 구성을 선택해요. 일반적인 선택으로는 Celery executor, Kubernetes executor, Batch·ECS 같은 Amazon provider executor, Edge executor가 있어요. 현재 목록과 트레이드오프는 executor 비교를 참고해요.
executor를 구성한 후에는 클러스터의 모든 노드가 그 역할에 맞는 DAG와 설정을 포함하도록 해야 해요. Airflow는 "Task X of Dag Y를 실행하라" 같은 단순한 지시만 보내고, Dag 파일이나 설정은 보내지 않아요. DAG 동기화를 위해 우리는 DAG 버전 관리를 활용할 수 있는 Dag Bundle 매커니즘(GitDagBundle 포함)을 권장해요. 보안에 민감한 배포에서는 민감한 설정(JWT 서명 키, 데이터베이스 자격 증명, Fernet 키)을 모든 노드에 모든 설정을 공유하지 말고 필요한 컴포넌트에만 제한해요 — 지침은 Airflow Security Model을 참고해요.
로깅
클러스터에서 일회용(disposable) 노드를 사용한다면 로그 저장소를 S3·GCS 같은 분산 파일시스템(DFS)이나 Stackdriver Logging, Elasticsearch, Amazon CloudWatch 같은 외부 서비스로 구성해요. 이렇게 하면 노드가 다운되거나 교체된 후에도 로그를 사용할 수 있어요. 설정은 Logging for Tasks를 참고해요.
Note
로그는 Task가 끝난 후에야 DFS에 나타나요. Task가 실행되는 동안에는 UI 자체에서 로그를 볼 수 있어요.
설정
Airflow에는 기본 airflow.cfg 설정 파일이 함께 제공돼요. 배포마다 바뀌는 설정(예: 메타데이터 DB, 비밀번호)에는 환경 변수를 사용해야 해요. AIRFLOW__{SECTION}__{KEY} 형식을 사용해 이렇게 할 수 있어요:
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=my_conn_id
AIRFLOW__API__BASE_URL=http://host:port
Airflow Backend 연결 URI 같은 일부 설정은 bash 명령에서도 파생할 수 있어요:
sql_alchemy_conn_cmd = bash_command_to_run
스케줄러 가동 시간
Airflow 사용자는 가끔 scheduler가 흔적도 없이 멈추는 경우를 보고해요. 예를 들어 다음 이슈들에서요:
이런 문제를 완화하려면 scheduler가 오랫동안 하트비트하지 않았을 때 감지할 health check를 설정했는지 확인해요.
Production 컨테이너 이미지
컨테이너화된 환경에서 사용할 Apache Airflow용 Docker 이미지(OCI)를 제공해요. 어디에 배포되든 소프트웨어가 항상 동일하게 실행되도록 보장하려면 이 이미지를 사용하는 것을 고려해 보세요.
Kubernetes용 Helm 차트
Helm은 Kubernetes 클러스터에 소프트웨어를 배포하는 간단한 매커니즘을 제공해요. 배포를 정의·설치·업그레이드하는 데 도움을 주는 공식 Helm 차트를 관리하고 있어요. Helm 차트는 커뮤니티가 관리하고 배포하는 우리의 공식 Docker 이미지와 Dockerfile을 사용해요.
Airflow 실시간 업그레이드하기
Airflow는 설계상 분산 시스템이며, 기본 Airflow 배포는 업그레이드에 보통 전체 Airflow 재시작이 필요하지만, 분산 배포에서 Airflow를 실행하면 다운타임 없이 업그레이드할 수 있어요.
이런 실시간 업그레이드는 Airflow 메타데이터 데이터베이스 스키마에 변화가 없을 때 가능해요. 따라서 같은 minor Airflow 버전의 patch-level(bugfix) 버전으로 업그레이드하거나, 인접한 minor 버전(feature) 간 업그레이드 시 release notes와 데이터베이스 마이그레이션 참조를 검토해 그 사이에 데이터베이스 스키마 변화가 없는지 확인한 뒤 수행하는 것을 목표로 해야 해요.
데이터베이스 마이그레이션이 크지 않은 경우에는, MINOR 버전 사이에서 Airflow 데이터베이스를 먼저 업그레이드해 실시간 마이그레이션이 가능할 수도 있어요. 하지만 이는 권장되지 않으며, 데이터베이스 스키마에 적용될 수정 사항을 신중히 검토하고 업그레이드 위험을 평가해 전적으로 자체 위험으로만 해야 해요. Airflow 데이터베이스 ERD 스키마에 대한 깊은 지식과 데이터베이스 마이그레이션 참조 검토가 필요해요. 항상 staging 환경에서 그런 업그레이드를 철저히 테스트해야 해요. 보통 이런 실시간 업그레이드 준비와 관련된 비용이 Airflow의 짧은 다운타임 비용보다 높으므로, 우리는 이런 실시간 업그레이드를 적극적으로 권장하지 않아요.
production에서 수행하기 전에 staging 환경에서 이 실시간 업그레이드 절차를 테스트해 놀라움과 부작용을 피해야 해요.
Webserver, Triggerer 컴포넌트를 실시간 업그레이드할 때, 그것들을 별도 환경에서 실행하고 각각이 인스턴스를 두 개 이상 갖고 있다면 다운타임 없이 하나씩 롤링 재시작할 수 있어요. 이는 보통 업그레이드 절차의 첫 단계로 수행해야 해요.
별도의 Dag processor를 가진 배포를 실행 중이라면, 별도 Dag 처리 배포에서 Dag processor는 수평 확장되지 않아요 — 더 많이 있어도 특정 폴더당 보통 한 번에 하나의 Dag processor가 실행되므로, 그냥 멈추고 새 것으로 시작하면 돼요. 하지만 Dag processor는 핵심 컴포넌트가 아니므로, 짧은 다운타임이 발생해도 괜찮아요.
scheduler와 worker를 업그레이드할 때는 사용 중인 executor의 실시간 업그레이드 기능을 사용할 수 있어요:
- Local executor의 경우 Task가 scheduler의 서브프로세스로 실행되므로, Task를 죽이지 않고 Scheduler를 업그레이드할 수 없어요. 모든 DAG를 일시 중지하고 실행 중인 Task가 완료되길 기다리거나, 그냥 scheduler를 멈추고 실행 중인 모든 Task를 죽이면 돼요 — 그러면 업그레이드 완료 후 그 Task를 수동으로 clear·재시작해야 해요(또는 중지된 Task에
retry가 설정되어 있으므로 그것에 의존). - Celery executor의 경우, 먼저 worker를 오프라인 모드로 전환하고(보통 worker에 단일
TERM신호를 보냄) worker가 실행 중인 모든 Task를 끝낼 때까지 기다린 다음 코드를 업그레이드해야 해요(예: worker가 실행되는 이미지를 교체하고 worker를 재시작).flower모니터링 도구로 worker를 모니터링하고 실행 중인 Task 수가 0으로 내려가는 것을 볼 수 있어요. worker가 업그레이드되면 자동으로 온라인 모드가 되어 새 Task를 선택하기 시작해요. 그런 다음Scheduler를 롤링 재시작 모드로 업그레이드할 수 있어요. - Kubernetes executor의 경우 scheduler, triggerer, webserver를 롤링 재시작 모드로 업그레이드할 수 있고, worker에 대해서는 일반적으로 걱정할 필요가 없어요. worker는 Kubernetes 클러스터가 관리하고, 업그레이드·재시작되면
Schedulers가 자동으로 채택하니까요.
대부분의 롤링 재시작 업그레이드 시나리오는 Apache Airflow용 Helm Chart에 구현되어 있어서, 특히 patch-level 업그레이드 시 다운타임 없이 Airflow 배포를 업그레이드하는 데 사용할 수 있어요.
Kerberos 인증 worker
Apache Airflow에는 KDC(Key Distribution Center)로 작업을 인증하는 내장 매커니즘이 있어요. Airflow에는 토큰 새로고침기(refresher) 역할을 하는 별도 명령 airflow kerberos가 있어요. 이 명령은 사전 구성된 Kerberos Keytab을 사용해 KDC에서 유효한 토큰을 얻고, 현재 토큰 만료 창 안에서 정기적으로 유효한 토큰을 새로고침해요.
각 새로고침 요청은 구성된 principal을 사용하며, 지정된 principal에 유효한 keytab만 인증 토큰을 검색할 수 있어요.
이 경우 적절한 보안 매커니즘을 구현하는 모범 사례는 worker 워크로드가 Keytab에 접근할 수 없고, 주기적으로 새로고침되는 임시 인증 토큰에만 접근할 수 있게 하는 것이에요. Docker 환경에서는 airflow kerberos 명령과 worker 명령을 별도 컨테이너로 실행해 이를 달성할 수 있어요 — airflow kerberos 토큰만 Keytab 파일(가급적 secret 리소스로 구성)에 접근하도록 말이죠. 두 컨테이너는 임시 토큰을 airflow kerberos가 쓰고 worker가 읽는 볼륨을 공유해야 해요.
Kubernetes 환경에서는 sidecar 개념으로 이를 구현할 수 있어요. Kerberos 토큰 새로고침기와 worker가 같은 Pod의 일부인 거죠. Kerberos sidecar만 Keytab secret에 접근하고, 같은 Pod의 두 컨테이너는 sidecar 컨테이너가 쓰고 worker 컨테이너가 읽는 볼륨을 공유해요.
이 개념은 Apache Airflow용 Helm Chart에 구현되어 있어요.
Google Cloud에서의 보안 서버·서비스 접근
이 섹션은 Airflow 환경이 Google Cloud에 배포되거나 Google 서비스에 연결하거나 Google API에 연결할 때 서버와 서비스에 안전하게 접근하는 기법과 해결책을 설명해요.
IAM과 서비스 계정
주요 보안 매커니즘으로 내부 네트워크 분리나 방화벽에 의존해서는 안 돼요. 조직 데이터를 보호하려면 하는 모든 요청에 발신자 정체성(sender identity)이 포함되어야 해요. Google Cloud의 경우 정체성은 IAM과 Service account가 제공해요. 각 Compute Engine 인스턴스에는 연결된 서비스 계정 정체성이 있어요. 이는 워크로드가 Google API나 서드파티 서비스에 호출할 때 자신의 정체성을 증명하는 데 사용할 수 있는 암호화 자격 증명을 제공해요. 각 인스턴스는 수명이 짧은(short-lived) 자격 증명에만 접근할 수 있어요. Google 관리 서비스 계정 키를 사용한다면 개인 키는 항상 escrow에 보관되며 직접 접근할 수 없어요.
Kubernetes Engine을 사용한다면 Workload Identity를 사용해 개별 pod에 정체성을 할당할 수 있어요.
Airflow의 서비스 계정에 대한 자세한 내용은 Google Cloud Connection을 참고해요.
서비스 계정 가장(impersonate)하기
다른 서비스 계정에 접근해야 한다면 다른 서비스 계정을 가장(impersonate)하여 기본 정체성의 토큰을 다른 서비스 계정으로 교환할 수 있어요. 따라서 계정 키는 여전히 Google이 관리하며 워크로드가 읽을 수 없어요.
서비스 계정 키를 생성해 메타데이터 데이터베이스나 secrets backend에 저장하는 것은 권장하지 않아요. backend secret을 사용하더라도 서비스 계정 키는 워크로드가 사용할 수 있게 돼요.
Compute Engine 인스턴스 접근
Compute Engine 인스턴스에 SSH 연결을 설정하려면 그 인스턴스의 네트워크 주소와 접근 자격 증명이 있어야 해요. 이 작업을 단순화하려면 SSHHook 대신 ComputeEngineHook을 사용할 수 있어요.
ComputeEngineHook은 Google OS Login 서비스로 인증을 지원해요. 이는 Linux 접근을 제대로 관리하는 매우 견고한 방법이에요. 수명이 짧은 ssh 키를 메타데이터 서비스에 저장하고, 접근·sudo 권한 확인을 위한 PAM 모듈을 제공하며, 메타데이터 서비스로 nsswitch 사용자 조회도 제공하니까요.
또한 인프라가 성장하면서 생기는 발견(discovery) 문제도 해결해요. 네트워크 주소 대신 인스턴스 이름을 사용할 수 있어요.
Amazon Web Service 접근
Web Identity Federation 덕분에 Google Cloud Platform 정체성을 Amazon Web Service 정체성으로 교환할 수 있는데, 이는 효과적으로 Amazon Web Service 플랫폼에 접근한다는 뜻이에요. 자세한 내용은 Web Identity Federation을 사용한 Google Cloud to AWS 인증을 참고해요.