← 학습 카테고리

Learn

Airflow

151개 모듈 · 현재 35번째

Airflow 모듈 35/151 airflow-learn-35

Multi-Team 실행기 설정과 트리거러 스코핑

Apache Airflow Official Documentation (in-repo snapshot) — Apache Software Foundation core-concepts/multi-team.rst - Team-based Executor Configuration, Dag Bundle to Team Association, How Scheduling Works, Team-scoped Triggerer (L345-665)

이 모듈을 다 읽으면

  • 팀별 실행기 구성 문법과 규칙을 정확히 읽고 검증할 수 있다
  • 팀 실행기 설정 값의 해석 순서(resolution order)를 설명할 수 있다
  • 팀 스코프 Triggerer가 어떤 트리거를 처리하는지, --queues와 어떻게 결합되는지 설명할 수 있다

Multi-Team 모드의 강력한 기능 중 하나는 팀마다 서로 다른 실행기 또는 같은 실행기의 다른 설정을 쓸 수 있다는 것이다. 이 모듈은 팀별 실행기 구성 문법과 규칙, 실행기 별칭, 팀별 설정값 해석 순서, Dag Bundle-Team 연결에 따른 스케줄링 동작, 그리고 3.3.0에 추가된 팀 스코프 Triggerer를 다룬다.

팀별 실행기 구성 문법과 규칙

팀별 실행기는 `executor = GlobalExecutor;team1=Team1Executor;team2=Team2Executor` 형식으로 구성한다. 예: `executor = LocalExecutor;team_a=CeleryExecutor;team_b=KubernetesExecutor`에서 LocalExecutor는 전역 기본 실행기이고, team_a의 태스크는 CeleryExecutor나 LocalExecutor를, team_b의 태스크는 KubernetesExecutor나 LocalExecutor를 쓸 수 있으며, 팀이 없는(글로벌) 태스크는 LocalExecutor를 쓴다.

지켜야 할 규칙은 다섯 가지다. 첫째, 전역 실행기가 반드시 맨 앞에 와야 한다 — 팀 접두사가 없는 실행기가 최소 하나 있어야 하고, 어떤 팀 전용 실행기보다도 앞서야 한다. 둘째, 구성에 등장하는 모든 팀 이름은 Airflow가 시작하기 전에 DB에 존재해야 한다. 셋째, 실행기 클래스가 멀티팀을 지원해야 한다 — 즉 supports_multi_team = True 속성을 가져야 한다. 넷째, 같은 팀이 중복 등장할 수 없다. 다섯째, 한 팀 안에서 같은 실행기를 중복 설정할 수 없다.

핵심 포인트

  • 전역 실행기는 팀 접두사 없이 반드시 목록 맨 앞에 와야 한다
  • 실행기 클래스가 supports_multi_team=True가 아니면 팀 스코프로 쓸 수 없다
  • 같은 팀 안에서 동일 실행기를 중복 지정하는 것과, 팀 이름을 중복 지정하는 것 모두 잘못된 설정이다

실행기 별칭으로 전역/팀 인스턴스 구분하기

같은 실행기 타입이 전역과 팀 레벨 모두에서 쓰일 때(예: LocalExecutor가 전역에도, 어떤 팀에도 쓰일 때), 태스크가 어느 인스턴스를 대상으로 할지 구분할 방법이 필요하다. `Alias:ExecutorName` 문법으로 별칭을 지정한다.

[core]
executor = global_celery_exec:CeleryExecutor;team1=team_celery_exec:CeleryExecutor

이 구성에서 전역 CeleryExecutor는 별칭 global_celery_exec로, team1의 CeleryExecutor는 별칭 team_celery_exec로 접근할 수 있다. team1의 태스크가 executor="team_celery_exec", executor="CeleryExecutor", 또는 전체 모듈 경로 중 무엇을 지정하든 팀 실행기에서 실행되고, executor="global_celery_exec"를 지정하면 전역 실행기에서 실행된다. 실행기를 아예 지정하지 않은 태스크는 그 팀의 암묵적 기본 실행기(팀 실행기)로 실행된다. 별칭은 모든 코어 실행기(LocalExecutor, CeleryExecutor, KubernetesExecutor 등)와 커스텀 모듈 경로 모두에서 쓸 수 있다.

핵심 포인트

  • 별칭 없이 팀과 전역에서 같은 실행기 클래스를 쓰면 어느 인스턴스를 가리키는지 모호해진다 — Alias:ExecutorName 문법으로 구분한다
  • 팀 안에서는 클래스명이나 전체 모듈 경로를 지정해도 별칭 없이 지정하면 팀 인스턴스로 해석된다
  • 실행기를 아예 지정하지 않은 태스크는 그 팀의 암묵적 기본 실행기로 실행된다

팀별 실행기 설정값 해석 순서

팀 실행기가 설정값(예: [celery] broker_url)을 읽을 때, 다음 순서로 소스를 확인해 처음 발견된 값을 쓴다: 1) 팀별 환경 변수 `AIRFLOW__{TEAM}___{SECTION}__{KEY}`(AIRFLOW__ 접두사의 일부로 팀 앞에 더블 언더스코어, 팀과 섹션 사이는 트리플 언더스코어, 섹션과 키 사이는 더블 언더스코어이며 팀 이름은 대문자로 쓴다), 2) 팀별 config 파일 섹션 `[team_name=section]`, 3) 기본값(빌트인 기본값 또는 fallback 값).

다음 소스들은 팀 실행기에서는 아직 지원되지 않아 건너뛴다: 명령 실행({key}_cmd), 시크릿 백엔드({key}_secret).

중요한 점은, 팀별 설정이 전역 환경 변수나 전역 config 파일 설정으로 폴백하지 않는다는 것이다. 예를 들어 전역 CeleryExecutor와 팀 CeleryExecutor가 함께 있을 때, 전역 CeleryExecutor가 celery.worker_concurrency를 기본값 16에서 32로 올리도록 오버라이드했다고 해도, 팀 CeleryExecutor는 명시적으로 오버라이드하지 않는 한 이 32를 물려받지 않고 계속 기본값 16을 쓴다.

환경 변수 예시:

export AIRFLOW__TEAM_A___CELERY__BROKER_URL="redis://team-a-redis:6379/0"
export AIRFLOW__TEAM_B___CELERY__BROKER_URL="redis://team-b-redis:6379/0"

config 파일 예시:

[celery]
broker_url = redis://default-redis:6379/0

[team_a=celery]
broker_url = redis://team-a-redis:6379/0

핵심 포인트

  • 팀 실행기 설정 조회 순서는 팀별 환경변수 → 팀별 config 섹션([team=section]) → 기본값 순이다
  • {key}_cmd(명령 실행)와 {key}_secret(시크릿 백엔드) 조회는 아직 팀 실행기에서 지원되지 않아 건너뛴다
  • 팀 실행기 설정은 전역 설정을 폴백으로 상속하지 않는다 — 전역에서 값을 올려도 팀은 명시적으로 오버라이드하지 않으면 기본값을 쓴다

Dag Bundle-Team 연결과 스케줄링 동작

Dag 번들은 dag_bundle_config_list(dag_processor 설정) 안에서 각 번들 항목에 team_name을 지정해 팀과 연결된다. team_name이 없는 번들은 글로벌로 취급된다.

Multi-Team이 켜지면 스케줄러는 각 태스크의 실행기를 결정하기 위해 추가 로직을 수행한다: 1) 태스크-팀 해석 — 스케줄러는 Task → Dag(dag_id 경유) → Dag Bundle(bundle_name 경유) → Team(dag_bundle_team 연관 테이블 경유) 관계 체인을 따라 각 태스크의 팀을 해석한다. 2) 실행기 선택 — 팀이 결정되면, 팀 전용 실행기가 구성되어 있으면 그 실행기를 쓰고, 아니면 전역 기본 실행기로 폴백한다.

Multi-Team Airflow는 팀을 위한 안전한 경계를 갖춘 논리적 격리(logical isolation)를 제공할 뿐, 완전한 격리를 제공하지는 않는다. 모든 팀이 같은 메타데이터 DB와 공통 Airflow 인프라를 공유한다. 절대적으로 엄격한 보안 요구사항이 있다면 별도의 Airflow 배포를 고려해야 한다.

핵심 포인트

  • 번들에 team_name을 지정하지 않으면 그 번들의 Dag들은 글로벌(팀 없음)로 취급된다
  • 스케줄러는 Task→Dag→Dag Bundle→Team 순으로 팀을 해석한 뒤, 팀 전용 실행기가 있으면 그것을, 없으면 전역 기본 실행기를 쓴다
  • Multi-Team은 논리적 격리이지 완전한 테넌트 분리가 아니다 — 엄격한 보안이 필요하면 별도 배포를 고려해야 한다

Team-scoped Triggerer

3.3.0부터 Multi-Team 모드에서는 --team-name CLI 인자로 Triggerer를 특정 팀에 스코프할 수 있다. 팀 스코프 Triggerer는 그 팀의 Dag에 속한 디퍼된 태스크(트리거)만 처리하므로, 팀마다 독립적인 용량과 장애 도메인을 가진 격리된 Triggerer 인스턴스를 운영할 수 있다.

`airflow triggerer --team-name team_a`처럼 시작하며, `airflow triggerer`(인자 없음)는 글로벌 Triggerer로 팀 소속이 없는 Dag의 트리거만 처리한다. 시작 시 core.multi_team이 켜져 있는지, 지정한 팀이 DB에 존재하는지 검증한다.

동작 방식: 팀 스코프 Triggerer(--team-name team_x)는 원본 Dag가 team_x에 매핑된 번들에 속하는 트리거만 가져간다. 글로벌 Triggerer(--team-name 없음)는 팀 배정이 없는 번들에 속한 트리거만 가져간다. Multi-Team이 꺼져 있으면 --team-name은 거부되며 필터링 없이 모든 Triggerer가 모든 트리거를 처리한다(기존 동작).

--queues와의 상호작용: 팀 필터링과 큐 필터링은 서로 독립적(orthogonal)이며 AND 조건으로 결합된다. 예를 들어 `--team-name team_a --queues q1,q2`로 시작한 Triggerer는 team_a에 속하면서 동시에 큐 q1 또는 q2에서 디퍼된 트리거만 처리한다. 모든 팀에(그리고 --queues를 쓴다면 모든 큐 조합에도) 최소 하나의 Triggerer가 반드시 떠 있어야 한다 — 그렇지 않으면 해당 팀의 트리거는 Triggerer가 뜰 때까지 처리되지 않고 대기한다. --team-name과 --queues를 함께 쓰면 이 요구사항이 모든 팀×큐 조합으로 확장된다.

핵심 포인트

  • --team-name 없는 트리거러는 팀 없는(글로벌) Dag의 트리거만 처리하고, --team-name team_a는 team_a 소속 트리거만 처리한다
  • --team-name과 --queues는 AND로 결합된다 — 둘 다 지정하면 두 조건을 모두 만족하는 트리거만 처리한다
  • 모든 팀(그리고 --queues 사용 시 모든 팀×큐 조합)에 최소 하나의 트리거러가 떠 있어야 하며, 없으면 해당 트리거는 처리되지 않고 대기한다