Docker로 Airflow 실행하기

Docker로 Airflow 실행하기 (Running Airflow in Docker)

Docker Compose에서 CeleryExecutor로 Airflow를 빠르게 띄우는 방법을 설명하는 quick-start 문서예요. docker-compose.yaml을 가져오고, 환경을 초기화하고, 서비스를 실행하고, CLI·웹 UI·REST API로 접근하고, 커스텀 이미지를 사용하는 것까지 다뤄요.

출처: 문서

본문

이 quick-start 가이드는 Docker에서 CeleryExecutor로 Airflow를 빠르게 띄워 실행하게 해 줘요.

주의 (Caution)

이 절차는 학습과 탐구에 유용할 수 있어요. 하지만 실제 상황에 적용하기는 복잡할 수 있고, docker compose 파일은 프로덕션 시스템에 필요한 어떤 보안 보장도 제공하지 않아요. 이 절차를 수정하려면 Docker & Docker Compose에 대한 전문 지식이 필요하며, Airflow 커뮤니티가 도와주지 못할 수 있어요.

그 이유로 프로덕션에서 Airflow를 실행할 준비가 되면 Kubernetes와 Official Airflow Community Helm Chart를 사용하는 것을 권장해요.

시작하기 전에 (Before you begin)

이 절차는 Docker와 Docker Compose에 익숙하다고 가정해요. 이 도구들을 사용해 본 적이 없다면, Docker Quick Start를 잠시 살펴보고(특히 Docker Compose 섹션) 어떻게 동작하는지 익숙해지세요.

아직 하지 않았다면 다음 단계를 따라 필요한 도구를 설치하세요.

  1. 워크스테이션에 Docker Community Edition (CE)을 설치해요. OS에 따라 Airflow 컨테이너가 제대로 실행되도록 Docker가 최소 4.00GB의 메모리를 사용하도록 구성해야 할 수 있어요. 자세한 내용은 Docker for Windows 또는 Docker for Mac 문서의 Resources 섹션을 참고하세요.
  2. 워크스테이션에 Docker Compose v2.14.0 이상을 설치해요.

docker-compose의 이전 버전은 Airflow docker-compose.yaml 파일이 요구하는 모든 기능을 지원하지 않으므로, 버전이 최소 요구사항을 충족하는지 다시 확인하세요.

팁 (Tip)

macOS에서 Docker가 사용할 수 있는 기본 메모리 양은 Airflow를 실행하기에 충분하지 않은 경우가 많아요. 충분한 메모리가 할당되지 않으면 웹서버가 계속 재시작될 수 있어요. Docker Engine에 최소 4GB 메모리(이상적으로 8GB)를 할당해야 해요.

다음 명령으로 메모리가 충분한지 확인할 수 있어요:

docker run --rm "debian:bookworm-slim" bash -c 'numfmt --to iec $(echo $(($(getconf _PHYS_PAGES) * $(getconf PAGE_SIZE))))'

경고 (Warning)

일부 운영체제(Fedora, ArchLinux, RHEL, Rocky)는 최근 커널 변경을 도입해서, OS 팀이 유지보수하는 커뮤니티 Docker 구현 안에서 실행할 때 Docker Compose의 Airflow가 메모리를 100% 소비하게 돼요.

이는 일부 Airflow 의존성이 문제를 겪는 하위 호환되지 않는 containerd 구성 문제이며 여러 이슈로 추적되고 있어요:

containerd 팀의 해결책은 아직 없지만, Docker Desktop on Linux를 설치하면 이 코멘트에서 설명하듯 문제를 해결하고 Breeze를 문제 없이 실행할 수 있는 것 같아요.

docker-compose.yaml 가져오기 (Fetching docker-compose.yaml)

Docker Compose에서 Airflow를 배포하려면 docker-compose.yaml을 가져와야 해요.

curl -LfO 'https://airflow.apache.org/docs/apache-airflow/3.3.2/docker-compose.yaml'

중요 (Important)

2023년 7월부터 Compose V1은 업데이트를 받지 않았어요. 제공되는 docker-compose.yaml이 Compose V1에서 정확히 동작하지 않을 수 있으므로, 최신 버전의 Docker Compose로 업그레이드하는 것을 강력히 권장해요.

이 파일은 여러 서비스 정의를 포함해요:

  • airflow-schedulerscheduler가 모든 태스크와 Dags를 모니터링하고, 의존성이 완료되면 task instance를 트리거해요.
  • airflow-dag-processor — Dag processor가 Dag 파일을 파싱해요.
  • airflow-api-server — api server가 http://localhost:8080에서 사용 가능해요.
  • airflow-worker — 스케줄러가 준 task를 실행하는 worker.
  • airflow-triggerer — triggerer가 deferrable 태스크를 위한 이벤트 루프를 실행해요.
  • airflow-init — 초기화 서비스.
  • postgres — 데이터베이스.
  • redisThe redis — 스케줄러에서 worker로 메시지를 전달하는 broker.

선택적으로 --profile flower 옵션을 추가해 flower를 활성화할 수 있어요. 예: docker compose --profile flower up, 또는 명령줄에 명시적으로 지정해 docker compose up flower.

  • flower — 환경을 모니터링하는 The flower app. http://localhost:5555에서 사용 가능해요.

이 모든 서비스는 CeleryExecutor로 Airflow를 실행하게 해 줘요. 자세한 내용은 Architecture Overview를 참고하세요.

컨테이너의 일부 디렉토리가 마운트되어, 그 내용이 컴퓨터와 컨테이너 사이에 동기화돼요.

  • ./dags — Dag 파일을 여기에 둘 수 있어요.
  • ./logs — 태스크 실행과 스케줄러의 로그를 포함해요.
  • ./config — 커스텀 로그 파서를 추가하거나 클러스터 정책을 구성하기 위한 airflow_local_settings.py를 추가할 수 있어요.
  • ./plugins커스텀 플러그인을 여기에 둘 수 있어요.

이 파일은 최신 Airflow 이미지(apache/airflow)를 사용해요. 새 Python 라이브러리나 시스템 라이브러리를 설치해야 한다면 이미지를 빌드할 수 있어요.

환경 초기화 (Initializing Environment)

처음 Airflow를 시작하기 전에 환경을 준비해야 해요. 즉 필요한 파일, 디렉토리를 만들고 데이터베이스를 초기화해야 해요.

올바른 Airflow 사용자 설정 (Setting the right Airflow user)

Linux에서는 quick-start가 호스트 사용자 id를 알아야 하고 group id를 0으로 설정해야 해요. 그렇지 않으면 dags, logs, config, plugins에 생성된 파일이 root 사용자 소유로 만들어져요. docker-compose를 위해 다음과 같이 구성해야 해요:

mkdir -p ./dags ./logs ./plugins ./config
echo -e "AIRFLOW_UID=$(id -u)" > .env

Docker Compose 환경 변수 참고:

다른 운영체제에서는 AIRFLOW_UID가 설정되지 않았다는 경고가 나올 수 있지만, 안전하게 무시할 수 있어요. docker-compose.yaml과 같은 폴더에 이 내용으로 .env 파일을 수동으로 만들어 경고를 없앨 수도 있어요:

AIRFLOW_UID=50000

airflow.cfg 초기화 (선택) (Initialize airflow.cfg (Optional))

airflow 서비스를 시작하기 전에 airflow.cfg를 기본값으로 초기화하고 싶다면 실행해요.

docker compose run airflow-cli airflow config list

이렇게 하면 config 폴더에 기본값으로 airflow.cfg를 시드해요.

SELinux/AppArmor가 있는 시스템에서는 권한 문제가 발생할 수 있어요. 이런 경우 docker-compose.yaml 파일을 편집해 모든 volumes에 :z 접미사를 추가해요:

volumes:
  - ${AIRFLOW_PROJ_DIR:-.}/dags:/opt/airflow/dags:z
  - ${AIRFLOW_PROJ_DIR:-.}/logs:/opt/airflow/logs:z
  - ${AIRFLOW_PROJ_DIR:-.}/config:/opt/airflow/config:z
  - ${AIRFLOW_PROJ_DIR:-.}/plugins:/opt/airflow/plugins:z

이 변경 후에도 airflow.cfg 파일을 만들 때 여전히 권한 문제가 발생한다면, config/ 폴더에 매우 허용적인 설정을 적용할 수 있어요:

sudo chmod -R 777 ./config

위의 것은 임시 방편(work around) 이며 프로덕션에서 절대 사용하지 말아야 한다는 점을 참고하세요.

데이터베이스 초기화 (Initialize the database)

모든 운영체제에서 데이터베이스 마이그레이션을 실행하고 첫 사용자 계정을 만들어야 해요. 이를 위해 실행해요:

docker compose up airflow-init

초기화가 완료되면 파일, 폴더, 플러그인과 관련된 출력과 마지막으로 이런 메시지를 보게 될 거예요:

airflow-init-1 exited with code 0

생성된 계정은 로그인 airflow, 비밀번호 airflow예요.

환경 정리하기 (Cleaning-up the environment)

준비한 docker-compose 환경은 "quick-start"용이에요. 프로덕션에 사용하도록 설계되지 않았고 몇 가지 함정이 있어요 — 그 중 하나는 어떤 문제에서든 복구하는 가장 좋은 방법은 정리하고 처음부터 다시 시작하는 것이에요.

가장 좋은 방법은:

  • docker-compose.yaml 파일을 다운로드한 디렉토리에서 docker compose down --volumes --remove-orphans 명령을 실행
  • docker-compose.yaml 파일을 다운로드한 디렉토리 전체를 제거 — rm -rf '<DIRECTORY>'
  • 이 가이드를 처음부터 다시 실행 — docker-compose.yaml 파일을 다시 다운로드하면서 시작

Airflow 실행하기 (Running Airflow)

이제 모든 서비스를 시작할 수 있어요:

docker compose up

참고 (Note)

docker-compose는 옛 문법이에요. Stackoverflow를 확인하세요.

두 번째 터미널에서 컨테이너의 상태를 확인하고 어떤 컨테이너도 unhealthy 상태가 아닌지 확인할 수 있어요:

$ docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS                    PORTS                              NAMES
247ebe6cf87a   apache/airflow:3.3.2   "/usr/bin/dumb-init …"   3 minutes ago    Up 3 minutes (healthy)    8080/tcp                           compose_airflow-worker_1
ed9b09fc84b1   apache/airflow:3.3.2   "/usr/bin/dumb-init …"   3 minutes ago    Up 3 minutes (healthy)    8080/tcp                           compose_airflow-scheduler_1
7cb1fb603a98   apache/airflow:3.3.2   "/usr/bin/dumb-init …"   3 minutes ago    Up 3 minutes (healthy)    0.0.0.0:8080->8080/tcp             compose_airflow-api_server_1
74f3bbe506eb   postgres:16            "docker-entrypoint.s…"   18 minutes ago   Up 17 minutes (healthy)   5432/tcp                           compose_postgres_1
0bd6576d23cb   redis:latest           "docker-entrypoint.s…"   10 hours ago     Up 17 minutes (healthy)   0.0.0.0:6379->6379/tcp             compose_redis_1

환경 접근하기 (Accessing the environment)

Airflow를 시작한 후 3가지 방법으로 상호작용할 수 있어요:

CLI 명령 실행하기 (Running the CLI commands)

CLI 명령도 실행할 수 있지만, 정의된 airflow-* 서비스 중 하나에서 실행해야 해요. 예를 들어 airflow info를 실행하려면 다음 명령을 실행하세요:

docker compose run airflow-worker airflow info

Linux나 Mac OS를 사용한다면, 더 간단한 명령으로 명령을 실행할 수 있는 선택적 래퍼 스크립트를 다운로드해 작업을 쉽게 할 수 있어요.

curl -LfO 'https://airflow.apache.org/docs/apache-airflow/3.3.2/airflow.sh'
chmod +x airflow.sh

이제 명령을 더 쉽게 실행할 수 있어요.

./airflow.sh info

bash를 파라미터로 사용해 컨테이너에서 대화형 bash 셸에 들어가거나, python으로 python 컨테이너에 들어갈 수도 있어요.

./airflow.sh bash
./airflow.sh python

웹 인터페이스 접근하기 (Accessing the web interface)

클러스터가 시작되면 웹 인터페이스에 로그인해 Dags로 실험을 시작할 수 있어요.

웹서버는 http://localhost:8080에서 사용할 수 있어요. 기본 계정은 로그인 airflow, 비밀번호 airflow예요.

REST API에 요청 보내기 (Sending requests to the REST API)

기본 username password 인증이 현재 REST API에서 지원되므로, 일반 도구로 API에 요청을 보낼 수 있어요.

웹서버는 http://localhost:8080에서 사용할 수 있어요. 기본 계정은 로그인 airflow, 비밀번호 airflow예요.

pool 목록을 가져오는 요청을 보내는 예시 curl 명령이에요:

ENDPOINT_URL="http://localhost:8080"
JWT_TOKEN=$(curl -s -X POST ${ENDPOINT_URL}/auth/token \
                 -H "Content-Type: application/json" \
                 -d '{"username": "airflow", "password": "airflow"}' |\
            jq -r '.access_token' \
          )
curl -X GET \
    "${ENDPOINT_URL}/api/v2/pools" \
    -H "Authorization: Bearer ***"

정리 (Cleaning up)

컨테이너를 중지·삭제하고, 데이터베이스 데이터가 있는 volumes를 삭제하고, 이미지를 다운로드하려면 실행해요:

docker compose down --volumes --rmi all

커스텀 이미지 사용하기 (Using custom images)

Airflow를 로컬에서 실행할 때 일부 추가 의존성을 포함하는 확장 이미지를 사용하고 싶을 수 있어요 — 예를 들어 새 python 패키지를 추가하거나 airflow providers를 최신 버전으로 업그레이드할 수 있어요. 이는 docker-compose.yamlbuild: .를 지정하고 docker-compose.yaml 옆에 커스텀 Dockerfile을 두면 매우 쉽게 할 수 있어요. 그런 다음 docker compose build 명령으로 이미지를 빌드할 수 있어요(한 번만 하면 됨). 다른 docker compose 명령을 실행할 때 이미지를 즉석에서 재빌드하려면 docker compose 명령에 --build 플래그를 추가할 수도 있어요.

커스텀 provider, python 패키지, apt 패키지 등으로 이미지를 확장하는 방법의 예시는 Building the image에서 찾을 수 있어요.

참고 (Note)

커스텀 이미지를 만들면, 설치하려는 패키지나 Airflow가 업그레이드될 때 이미지를 다시 만들어야 하므로 자동화 수준도 유지해야 해요. 이 스크립트를 보관하는 것을 잊지 마세요. 또한 순수 Python 태스크를 실행할 때는 런타임 중 python 의존성을 동적으로 소스·설치하는 Python Virtualenv functions를 사용할 수 있다는 점도 명심하세요. Airflow 2.8.0부터 virtualenv도 캐시할 수 있어요.

특수 사례 — requirements.txt 파일로 의존성 추가하기 (Special case - adding dependencies via requirements.txt file)

커스텀 이미지의 보통 용도는 보통 requirements.txt 파일에 저장된 요구사항 세트를 추가하는 것이에요. 개발 중에는 원래 airflow 이미지를 시작할 때 동적으로 추가하고 싶을 수 있는데, 이는 여러 부작용이 있어요(예: 컨테이너 시작이 훨씬 느려짐 — 각 추가 의존성은 컨테이너 시작 시간을 더 지연시켜요). 또한 docker compose에 개발 워크플로우가 내장되어 있으므로 완전히 불필요해요. 이전 장을 따라 로컬에서 docker compose로 반복할 때 커스텀 이미지를 자동으로 빌드·사용할 수 있어요. 구체적으로 자신의 requirement 파일을 추가하고 싶을 때는 다음 단계를 해야 해요:

  1. docker-compose.yaml 파일에서 image: ... 줄을 주석 처리하고 build: . 줄의 주석을 해제해요. docker-compose 파일의 관련 부분은 다음과 비슷해야 해요(올바른 이미지 태그 사용):
#image: ${AIRFLOW_IMAGE_NAME:-apache/airflow:3.3.2}
build: .
  1. docker-compose.yaml 파일과 같은 폴더에 다음과 같은 내용으로 Dockerfile을 만들어요:
FROM apache/airflow:3.3.2
ADD requirements.txt .
RUN pip install apache-airflow==${AIRFLOW_VERSION} -r requirements.txt

원본 이미지에서 나온 것과 같은 버전의 apache-airflow를 설치하는 것이 가장 좋은 관행이에요. 이렇게 하면 다른 requirements를 설치하는 동안 pip가 apache airflow를 다운그레이드하거나 업그레이드하려 하지 않도록 보장할 수 있어요. 이는 사용 중인 apache-airflow 버전과 충돌하는 의존성을 추가하려고 할 때 발생할 수 있는 문제예요.

  1. requirements.txt 파일을 같은 디렉토리에 두어요.
  2. docker compose build를 실행해 이미지를 빌드하거나, docker compose up 또는 docker compose run 명령에 --build 플래그를 추가해 필요할 때 이미지를 자동으로 빌드하세요.

특수 사례 — 커스텀 구성 파일 추가하기 (Special case - Adding a custom config file)

커스텀 구성 파일이 있고 Airflow 인스턴스에서 사용하고 싶다면 다음 단계를 수행해야 해요:

  1. 로컬 config 폴더의 자동 생성된 airflow.cfg 파일을 커스텀 구성 파일로 교체해요.
  2. 구성 파일 이름이 airflow.cfg가 아니라면 AIRFLOW_CONFIG: '/opt/airflow/config/airflow.cfg'에서 파일 이름을 조정해요.

네트워킹 (Networking)

일반적으로 로컬에서 Airflow를 사용하려면 Dags가 호스트에서 실행 중인 서버에 연결하려 할 수 있어요. 이를 위해 docker-compose.yaml에 추가 구성이 필요해요. 예를 들어 Linux에서는 services: airflow-worker 섹션에 extra_hosts: - "host.docker.internal:host-gateway"를 추가하고, localhost 대신 host.docker.internal을 사용해야 해요. 이 구성은 플랫폼마다 다르다. 자세한 내용은 Docker 문서의 WindowsMac을 참고하세요.

PyCharm으로 docker 컨테이너 안에서 Airflow 디버깅하기 (Debug Airflow inside docker container using PyCharm)

전제 조건: PyCharm에서 프로젝트를 만들고(docker-compose.yaml) 다운로드하세요.

단계:

  1. docker-compose.yaml 수정services 섹션 아래에 다음 섹션을 추가해요:
airflow-python:
  <<: *airflow-common
  profiles:
      - debug
  environment:
      <<: *airflow-common-env
  user: "50000:0"
  entrypoint: [ "/bin/bash", "-c" ]

참고 (Note)

이 코드 조각은 PyCharm의 Python 인터프리터를 위한 **"airflow-python"**이라는 새 서비스를 만들어요. Linux 시스템에서 echo -e "AIRFLOW_UID=$(id -u)" > .env 명령을 실행했다면 PyCharm의 Unresolved reference 'airflow' 오류를 피하기 위해 airflow-python 서비스에 user: "50000:0"을 설정해야 해요.

  1. PyCharm 인터프리터 구성
    • PyCharm을 열고 Settings > Project: > Python Interpreter로 이동해요.
    • "Add Interpreter" 버튼을 클릭하고 **"On Docker Compose"**를 선택해요.
    • Configuration file 필드에서 docker-compose.yaml 파일을 선택해요.
    • Service field에서 새로 추가한 airflow-python 서비스를 선택해요.
    • **"Next"**를 클릭하고 프롬프트를 따라 구성을 완료해요.

인터프리터 인덱스 빌드는 시간이 걸릴 수 있어요. 3) python 서비스의 docker-compose/command와 actions에 exec를 추가하세요.

구성이 끝나면 컨테이너 환경 안에서 Airflow 코드를 디버깅해 로컬 설정을 흉내낼 수 있어요.

FAQ: 자주 묻는 질문 (FAQ: Frequently asked questions)

ModuleNotFoundError: No module named 'XYZ'

Docker Compose 파일은 최신 Airflow 이미지(apache/airflow)를 사용해요. 새 Python 라이브러리나 시스템 라이브러리를 설치해야 한다면 커스터마이즈하고 확장할 수 있어요.

다음은 무엇인가요? (What's Next?)

이 지점부터 Tutorials 섹션으로 가서 추가 예시를 보거나, How-to Guides 섹션으로 가서 직접 해볼 준비를 할 수 있어요.

Docker Compose가 지원하는 환경 변수 (Environment variables supported by Docker Compose)

여기 변수 이름을 이미지가 빌드될 때 설정되는 build 인자와 혼동하지 마세요. AIRFLOW_UID build arg는 이미지가 빌드될 때 50000으로 기본값이 정해지므로 이미지에 "베이크"돼요. 반면 아래 환경 변수는 컨테이너가 실행 중일 때 설정할 수 있는데, 예를 들어 id -u 명령의 결과를 사용해 이미지를 빌드할 때 알 수 없는 동적 호스트 런타임 사용자 id를 사용할 수 있게 해 줘요.

Variable Description Default
AIRFLOW_IMAGE_NAME Airflow Image to use. apache/airflow:3.3.2
AIRFLOW_UID UID of the user to run Airflow containers as.
Override if you want to use non-default Airflow
UID (for example when you map folders from host,
it should be set to result of id -u call.
When it is changed, a user with the UID is
created with default name inside the container
and home of the use is set to /airflow/home/
in order to share Python libraries installed there.
This is in order to achieve the OpenShift
compatibility. See more in the
Arbitrary Docker User, 50000

참고 (Note)

Airflow 2.2 이전에는 Docker Compose에도 AIRFLOW_GID 파라미터가 있었지만, 추가 기능을 제공하지 않고 혼란만 더했기 때문에 제거됐어요.

이 추가 변수들은 Docker Compose를 통해 Airflow 설치를 시험·테스트할 때 유용해요. 프로덕션에 사용하도록 의도된 것은 아니지만, 처음 사용자가 가장 흔한 커스터마이징으로 환경을 더 빠르게 부트스트랩하게 해 줘요.

Variable Description Default
_AIRFLOW_WWW_USER_USERNAME Username for the administrator UI account.
If this value is specified, admin UI user gets
created automatically. This is only useful when
you want to run Airflow for a test-drive and
want to start a container with embedded development
database. airflow
_AIRFLOW_WWW_USER_PASSWORD Password for the administrator UI account.
Only used when _AIRFLOW_WWW_USER_USERNAME set. airflow
_PIP_ADDITIONAL_REQUIREMENTS If not empty, airflow containers will attempt to
install requirements specified in the variable.
example: lxml==4.6.3 charset-normalizer==1.4.1.
Available in Airflow image 2.1.1 and above.

더 알아보기 (Learn more)