Docker로 Airflow 설치하기
설치 환경
- OS : Linux, WSL 등 Docker 활용이 가능한 OS 또는 플랫폼 위
(1) 설치에 대한 안내
Installation of Airflow® — Airflow 3.1.8 Documentation
도커 이미지를 통해 컨테이너로 airflow를 띄울 때의 주의사항
- (1) 종속성과 확장 기능은 직접 구현해야 함
- (2) airflow, airflow provider의 데이터베이스 설정을 직접 해야 함
- (3) 자동시작, 복구, 유지관리를 직접 해야 함
- (4) 시스템 리소스 모니터링 및 관리를 직접 해야 함
(2) Apache Airflow 용 Docker Image
- Apache Airflow 커뮤니티에서는, 새로운 버전이 출시될 때마다 Docker Hub 에 이미지를 배포한다.
- https://hub.docker.com/r/apache/airflow
- Airflow Docker Image의 태깅 규칙은 아래와 같다.
| 이미지 | 설명 |
|---|---|
| apache/airflow:latest | 기본 Python 버전이 포함된 최신 Airflow 이미지 |
| apache/airflow:latest-pythonX.Y | 특정 Python 버전이 포함된 최신 Airflow 이미지 |
| apache/airflow:x.y.z | 기본 Python 버전이 포함된 특정 Airflow 이미지 |
| apache/airflow:x.y.z-pythonX.Y | 특정 Python 버전이 포함된 특정 Airflow 이미지 |
- Airflow의 필수 기능만 포함한 slim 이미지가 있다.
- slim 이미지는 Airflow Core, Task SDK 및 최소한의 필수 의존성만 가지고 있다.
- 따라서 필요시 종속성 및 추가 패키지를 직접 설치해야 한다.
| 이미지 | 설명 |
|---|---|
| apache/airflow:slim-latest | 기본 Python 버전이 포함된 최신 Airflow 이미지(코어) |
| apache/airflow:slim-latest-pythonX.Y | 특정 Python 버전이 포함된 최신 Airflow 이미지(코어) |
| apache/airflow:slim-x.y.z | 기본 Python 버전이 포함된 특정 Airflow 이미지(코어) |
| apache/airflow:slim-x.y.z-pythonX.Y | 특정 Python 버전이 포함된 특정 Airflow 이미지(코어) |
(3) Docker 기반 Airflow 설치 방법의 종류
- Docker 기반 Airflow 설치 방법은 아래 순서에 따라 살펴볼 예정이다.
| No | 설치 방법 | 설명 |
|---|---|---|
| 1 | Docker Compose | Airflow에서 제공하는 Docker Compose 설정파일을 이용하 컨테이너들을 실행 |
| 2 | Docker Build | 기본 Airflow Docker Image를 이용하되, 필요한 Provider 등을 함께 설치 |
1. Docker Compose를 이용한 설치
(1) Docker Image 탐색
- https://hub.docker.com/r/apache/airflow
- Docker Hub 에서 알맞은 Airflow 도커 이미지를 찾는다.
- 이번 실습에서는 Python3.13 버전이 포함된 Airflow3.1.8 버전 이미지를 사용한다.
(2) Docker Compose 설정파일 준비
- Docker Compose를 위한 설정파일을 준비한다.
- 표준적인 설정파일을 Airflow에서 제공하고 있으니, 아래 URL을 통해 다운로드 받는다.
- https://airflow.apache.org/docs/apache-airflow/3.1.8/docker-compose.yaml
(3) Docker Compose 설정파일 설명
- 표준적인 Airflow Docker Compose는 아래 서비스들로 구성된다.
Airflow에서도 밝히듯 이는
CeleryExecutor기준의 표준이다. LocalExecutor를 사용하는 경우, redis나 worker, flower가 불필요하다.
| 서비스 | 역할 | 설명 |
|---|---|---|
| airflow-scheduler | 스케줄러 | 모든 Task와 DAG를 모니터링한 뒤, 실행조건이 맞으면 Task를 작업 큐에 예약/실행 |
| airflow-dag-processor | DAG분석기 | DAG 파일을 읽고 해석하여 스케줄러가 사용할 수 있는 형태로 변환 |
| airflow-api-server | API서버&UI | Airflow의 웹 인터페이스(Web UI)를 제공하며, 외부 API 요청을 처리(기본 8080포트) |
| airflow-worker | 워커 | 스케줄러가 지정한 작업을 실행하는 작업자 |
| airflow-triggerer | 트리거러 | 지연 작업(Deferred tasks)을 효율적으로 처리하기 위해 비동기적으로 이벤트를 감시 |
| airflow-init | 초기화 서비스 | 컨테이너가 처음 뜰 때 DB 마이그레이션, 유저 생성, 폴더 권한 설정 등을 수행하고 종료 |
| postgres | 메타데이터DB | Airflow의 모든 설정, DAG 상태, 실행 이력 등을 저장 |
| redis | 메시지브로커 | 스케줄러가 보낸 작업 메시지를 워커에게 전달하기 위한 중간 대기소 |
| airflow-cli | 명령어도구 | airflow 명령어를 직접 입력해 관리 작업을 수행할 수 있는 디버깅용 서비스 |
| flower | 모니터링 툴 | Celery 워커들의 상태와 작업 처리 현황을 시각적으로 보여줌(기본 5555포트) |
- 주요 설정 포인트들은 아래와 같다.
| 설정 | 역할 | 설명 |
|---|---|---|
x-airflow-common |
공통 설정 | 모든 Airflow 서비스가 동일한 이미지와 환경 변수(DB 연결 정보 등)를 공유하도록 함 |
postgres-db-volume |
데이터 보존 | 컨테이너가 내려가도 DB 데이터가 사라지지 않게 설정 |
image: ${AIRFLOW_IMAGE_NAME} |
이미지 버전 | Airflow 이미지 버전 |
(4) Docker Compose 설정값 조정
- 개인의 필요에 맞춰 Docker Compose 내 설정값을 조정한다.
- 공통 설정값은
x-airflow-commo그룹에서 설정하며, 개별 서비스별 설정값은 해당 섹션에서 설정한다. - 설정값을 직접 조정하는 것 보다는,
.env파일을 이용해 설정값을 주입하는 방식을 권장한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# .env 파일을 통한 주입 예시 - Docker Compose 파일
x-airflow-common:
&airflow-common
image: ${AIRFLOW_IMAGE_NAME:-apache/airflow:3.1.8}
# build: .
env_file:
- ${ENV_FILE_PATH:-.env}
environment:
&airflow-common-env
AIRFLOW__CORE__EXECUTOR: ${AIRFLOW_CORE_EXECUTOR:-CeleryExecutor}
# AIRFLOW__CORE__AUTH_MANAGER: airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager
AIRFLOW__CORE__SIMPLE_AUTH_MANAGER_ALL_ADMINS: "True"
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://airflow:airflow@${AIRFLOW_POSTGRES_SERVICE_NAME:-postgres}/airflow
AIRFLOW__CELERY__RESULT_BACKEND: db+postgresql://airflow:airflow@${AIRFLOW_POSTGRES_SERVICE_NAME:-postgres}/airflow
AIRFLOW__CELERY__BROKER_URL: redis://:@${AIRFLOW_REDIS_SERVICE_NAME:-redis}:${AIRFLOW_REDIS_PORT:-6379}/0
AIRFLOW__CORE__FERNET_KEY: ''
AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'true'
AIRFLOW__CORE__LOAD_EXAMPLES: 'true'
AIRFLOW__CORE__EXECUTION_API_SERVER_URL: 'http://airflow-apiserver:${AIRFLOW_API_PORT:-8080}/execution/'
AIRFLOW__API_AUTH__JWT_SECRET: ${AIRFLOW__API_AUTH__JWT_SECRET:-airflow_jwt_secret}
AIRFLOW__API_AUTH__JWT_ISSUER: ${AIRFLOW__API_AUTH__JWT_ISSUER:-airflow}
AIRFLOW__SCHEDULER__ENABLE_HEALTH_CHECK: 'true'
_PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:-}
AIRFLOW_CONFIG: '/opt/airflow/config/airflow.cfg'
volumes:
- ${AIRFLOW_PROJ_DIR:-./airflow}/dags:/opt/airflow/dags
- ${AIRFLOW_PROJ_DIR:-./airflow}/logs:/opt/airflow/logs
- ${AIRFLOW_PROJ_DIR:-./airflow}/config:/opt/airflow/config
- ${AIRFLOW_PROJ_DIR:-./airflow}/plugins:/opt/airflow/plugins
user: "${AIRFLOW_UID:-50000}:0"
...
AIRFLOW__CORE__AUTH_MANAGER설정값 주석
FabAuthManager provider는 기본 설치된 provider가 아님. 이에 오류를 유발시킬 수 있어 주석처리
대신 AIRFLOW__CORE__SIMPLE_AUTH_MANAGER_ALL_ADMINS 를 활성화하여 사용자들의 로그인 허용
.env파일에 설정값을 지정하면, Docker Compose 파일에서 설정을 하나 하나 바꿀 필요 없어서 편리함- 또한, 같은 값이 여러 군데 존재하는 경우에도, 한 번에 적용할 수 있으므로 편리
1
2
3
4
5
6
7
8
# .env 파일을 통한 주입 예시 - .env 파일
AIRFLOW_IMAGE_NAME=apache/airflow:3.1.8-python3.13
AIRFLOW_CORE_EXECUTOR=LocalExecutor
AIRFLOW_POSTGRES_SERVICE_NAME=airflow-postgres
AIRFLOW_REDIS_SERVICE_NAME=airflow-redis
AIRFLOW_REDIS_PORT=6379
AIRFLOW_API_PORT=8080
AIRFLOW_PROJ_DIR=./airflow
(5) Docker Compose 실행
- 설정이 모두 완료되었다면,
docker-compose up명령어를 통해 실행
1
docker compose up
- 모든 컨테이너가 정상적으로 올라왔다면 브라우저를 통해
http://localhost:8080UI로 접속

- 위와 같이 UI가 정상적으로 보인다면 설치 완료
커스텀 Docker Image Build
(1) Provider
- Airflow 생태계에는 Airflow Core에서 제공하지 않는 유용한 추가 기능들이 갖춰져있다.
- 이러한 추가 기능들을
provider라고 부르며, Airflow에서는 이들을 쉽게 연결할 수 있는 체계가 갖춰져있다. - 더욱 자세한 내용은 포스팅 중 Airflow Provider 에 대한 포스팅을 참고하기 바란다.
(Provider와 Extras)
(2) Dockerfile 작성
- 커스텀 도커 이미지를 빌드하기 위해 Dockerfile에 세부 스펙을 명세한다.
1
2
3
4
5
6
7
8
# Dockerfile.airflow
ARG AIRFLOW_ORIGIN_IMAGE_NAME=apache/airflow:3.1.8-python3.13 # .env 파일로부터 IMAGE 이름 로딩
FROM ${AIRFLOW_ORIGIN_IMAGE_NAME}
USER airflow
ARG AIRFLOW_EXTRAS # .env 파일로부터 설치할 EXTRAS 로딩
RUN pip install --no-cache-dir "apache-airflow[${AIRFLOW_EXTRAS}]"
- env 파일에 설치할 EXTRAS에 대해 명시한다.
1
2
3
# .env 파일
AIRFLOW_ORIGIN_IMAGE_NAME=apache/airflow:3.1.8-python3.13
AIRFLOW_EXTRAS=postgres,mysql,docker,elasticsearch,pgvector,redis,apache-kafka,apache-spark,grpc,http,opensearch
(3) Dockerfile을 이용해서 빌드
- 이제 Airflow 이미지를 빌드해서 사용하면 된다. 여기에는 두 가지 방법이 있다.
- (a) docker compose 파일에서 이미지명 대신 build 키워드를 이용
- (b)
docker build명령어로 이미지를 빌드한 뒤 사용
(a) docker compose 파일에서 build 키워드 사용
- image 키워드 대신 build 키워드를 사용하고, build에 필요한 컨텍스트와 인자를 정의한다.
1
2
3
4
5
6
7
8
x-airflow-common:
&airflow-common
# image: ${AIRFLOW_IMAGE_NAME:-apache/airflow:3.1.8} # 이미지 대신
build: # build 키워드 사용
context: .
args:
- AIRFLOW_ORIGIN_IMAGE_NAME=${AIRFLOW_ORIGIN_IMAGE_NAME}
- AIRFLOW_EXTRAS=${AIRFLOW_EXTRAS}
- 이후
docker compose up명령어를 통해 컨테이너를 실행시키면 된다
(b) docker build로 도커 이미지 만들기
- 또 다른 방법은
docker build명령어로 도커 이미지를 만드는 것이다. - 인터넷이 안되는 폐쇄망 환경에서 docker compose 를 사용해 컨테이너를 실행해야 하는 환경 등에 유용하다.
- 가장 먼저 env 파일에 환경변수를 세팅한다.
1
2
3
4
# .env 파일에 이미지명 등 환경변수 세팅
AIRFLOW_ORIGIN_IMAGE_NAME=apache/airflow:3.1.8-python3.13 # base image 이름
AIRFLOW_IMAGE_NAME=apache/airflow:3.1.8-python3.13-custom # 빌드하는 이미지 이름
AIRFLOW_EXTRAS=postgres,mysql,docker,elasticsearch,pgvector,redis,grpc,http,opensearch
- env 파일에 세팅한 환경변수를 현재 쉘에 등록한다.
1
2
# 현재 폴더의 .env 파일의 변수를 환경변수에 등록
export $(grep -v '^#' .env | xargs)
- 이미지를 빌드한다.
1
2
3
4
5
6
# 도커 이미지 빌드
docker build \
--build-arg AIRFLOW_ORIGIN_IMAGE_NAME="$AIRFLOW_ORIGIN_IMAGE_NAME" \
--build-arg AIRFLOW_EXTRAS="$AIRFLOW_EXTRAS" \
-t apache/airflow:3.1.8-python3.13-custom \
-f Dockerfile.airflow .
- 빌드가 완료되면 지정한 태그의 도커 이미지가 생성된 것을 볼 수 있다.
1
2
3
4
$ sudo docker images
IMAGE ... DISK USAGE CONTENT SIZE EXTRA
apache/airflow:3.1.8-python3.13 ... 3.04GB 646MB
apache/airflow:3.1.8-python3.13-custom ... 3.06GB 648MB U
docker compose up명령어를 통해 컨테이너들을 실행시킨다.- docker compose 파일에서 airflow 이미지 이름이 빌드한 이미지와 일치하는지 반드시 확인한다.
1
2
3
x-airflow-common:
&airflow-common
image: ${AIRFLOW_IMAGE_NAME}
Further More
1. LocalExecutor를 사용하는 경우 제외해도 되는 서비스들
- 표준 docker compose 파일을 열어보면 많은 서비스들이 있다.
- airflow-api, worker, scheduler … 등등 10개나 된다.
- Airflow 공식 DOC에서도 밝히듯, 이 서비스들은
CeleryExecutor기반의 환경에 맞춰 설계되었다. LocalExecutor를 사용하는 경우는 일부 서비스를 제외해도 된다.
| 서비스 | 제외 가능 여부 | 설명 |
|---|---|---|
| airflow-scheduler | 제외불가 | 스케줄링에 필요한 필수 서비스 |
| airflow-dag-processor | 제외불가 | 스케줄러와 함께 필요한 필수 서비스 |
| airflow-api-server | 제외불가 | 핵심 API 서버로 제외 불가 |
| postgres | 제외불가 | LocalExecutor 사용시 필수 |
| airflow-init | 제외불가 | 필수 초기화 태스크 포함 |
| airflow-triggerer | 옵셔널 | deferred task를 사용하는 경우 필요 |
| airflow-cli | 가능 | CLI 명령어 전용 작업 컨테이너이므로 제거 가능 편의용으로, Celery 사용 여부에 관계 없이 제거 가능 |
| airflow-worker | 가능 | Celery 환경에서 필요한 서비스임 |
| redis | 가능 | Celery 환경에서 필요한 서비스임 |
| flower | 가능 | Celery 환경에서 필요한 서비스임 |
LocalExecutor 를 사용할 경우 Docker Compose
- docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
---
x-airflow-common:
&airflow-common
image: ${AIRFLOW_IMAGE_NAME:-apache/airflow:3.1.8-python3.13-custom}
# build: .
env_file:
- ${ENV_FILE_PATH:-.env}
environment:
&airflow-common-env
AIRFLOW__CORE__EXECUTOR: ${AIRFLOW_CORE_EXECUTOR:-LocalExecutor}
# AIRFLOW__CORE__AUTH_MANAGER: airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager
AIRFLOW__CORE__SIMPLE_AUTH_MANAGER_ALL_ADMINS: "True"
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://airflow:airflow@${AIRFLOW_POSTGRES_SERVICE_NAME:-postgres}/airflow
AIRFLOW__CELERY__RESULT_BACKEND: db+postgresql://airflow:airflow@${AIRFLOW_POSTGRES_SERVICE_NAME:-postgres}/airflow
AIRFLOW__CELERY__BROKER_URL: redis://:@${AIRFLOW_REDIS_SERVICE_NAME:-redis}:${AIRFLOW_REDIS_PORT:-6379}/0
AIRFLOW__CORE__FERNET_KEY: ''
AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'true'
AIRFLOW__CORE__LOAD_EXAMPLES: 'true'
AIRFLOW__CORE__EXECUTION_API_SERVER_URL: 'http://airflow-apiserver:${AIRFLOW_API_PORT:-8080}/execution/'
AIRFLOW__API_AUTH__JWT_SECRET: ${AIRFLOW__API_AUTH__JWT_SECRET:-airflow_jwt_secret}
AIRFLOW__API_AUTH__JWT_ISSUER: ${AIRFLOW__API_AUTH__JWT_ISSUER:-airflow}
AIRFLOW__SCHEDULER__ENABLE_HEALTH_CHECK: 'true'
_PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:-}
AIRFLOW_CONFIG: '/opt/airflow/config/airflow.cfg'
volumes:
- ${AIRFLOW_PROJ_DIR:-./airflow}/dags:/opt/airflow/dags
- ${AIRFLOW_PROJ_DIR:-./airflow}/logs:/opt/airflow/logs
- ${AIRFLOW_PROJ_DIR:-./airflow}/config:/opt/airflow/config
- ${AIRFLOW_PROJ_DIR:-./airflow}/plugins:/opt/airflow/plugins
- /var/run/docker.sock:/var/run/docker.sock
user: "${AIRFLOW_UID:-50000}:0"
depends_on:
&airflow-common-depends-on
airflow-postgres:
condition: service_healthy
services:
airflow-postgres:
image: postgres:16
environment:
POSTGRES_USER: airflow
POSTGRES_PASSWORD: airflow
POSTGRES_DB: airflow
volumes:
- ${AIRFLOW_POSTGRES_DB_VOLUME_NAME:-postgres-db-volume}:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "airflow"]
interval: 10s
retries: 5
start_period: 5s
restart: always
airflow-apiserver:
<<: *airflow-common
command: api-server
ports:
- "${AIRFLOW_API_PORT:-8080}:8080"
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8080/api/v2/monitor/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
restart: always
depends_on:
<<: *airflow-common-depends-on
airflow-init:
condition: service_completed_successfully
airflow-scheduler:
<<: *airflow-common
command: scheduler
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8974/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
restart: always
depends_on:
<<: *airflow-common-depends-on
airflow-init:
condition: service_completed_successfully
airflow-dag-processor:
<<: *airflow-common
command: dag-processor
healthcheck:
test: ["CMD-SHELL", 'airflow jobs check --job-type DagProcessorJob --hostname "$${HOSTNAME}"']
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
restart: always
depends_on:
<<: *airflow-common-depends-on
airflow-init:
condition: service_completed_successfully
airflow-triggerer:
<<: *airflow-common
command: triggerer
healthcheck:
test: ["CMD-SHELL", 'airflow jobs check --job-type TriggererJob --hostname "$${HOSTNAME}"']
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
restart: always
depends_on:
<<: *airflow-common-depends-on
airflow-init:
condition: service_completed_successfully
airflow-init:
<<: *airflow-common
entrypoint: /bin/bash
# yamllint disable rule:line-length
command:
- -c
- |
if [[ -z "${AIRFLOW_UID}" ]]; then
echo
echo -e "\033[1;33mWARNING!!!: AIRFLOW_UID not set!\e[0m"
echo "If you are on Linux, you SHOULD follow the instructions below to set "
echo "AIRFLOW_UID environment variable, otherwise files will be owned by root."
echo "For other operating systems you can get rid of the warning with manually created .env file:"
echo " See: https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#setting-the-right-airflow-user"
echo
export AIRFLOW_UID=$$(id -u)
fi
one_meg=1048576
mem_available=$$(($$(getconf _PHYS_PAGES) * $$(getconf PAGE_SIZE) / one_meg))
cpus_available=$$(grep -cE 'cpu[0-9]+' /proc/stat)
disk_available=$$(df / | tail -1 | awk '{print $$4}')
warning_resources="false"
if (( mem_available < 4000 )) ; then
echo
echo -e "\033[1;33mWARNING!!!: Not enough memory available for Docker.\e[0m"
echo "At least 4GB of memory required. You have $$(numfmt --to iec $$((mem_available * one_meg)))"
echo
warning_resources="true"
fi
if (( cpus_available < 2 )); then
echo
echo -e "\033[1;33mWARNING!!!: Not enough CPUS available for Docker.\e[0m"
echo "At least 2 CPUs recommended. You have $${cpus_available}"
echo
warning_resources="true"
fi
if (( disk_available < one_meg * 10 )); then
echo
echo -e "\033[1;33mWARNING!!!: Not enough Disk space available for Docker.\e[0m"
echo "At least 10 GBs recommended. You have $$(numfmt --to iec $$((disk_available * 1024 )))"
echo
warning_resources="true"
fi
if [[ $${warning_resources} == "true" ]]; then
echo
echo -e "\033[1;33mWARNING!!!: You have not enough resources to run Airflow (see above)!\e[0m"
echo "Please follow the instructions to increase amount of resources available:"
echo " https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#before-you-begin"
echo
fi
echo
echo "Creating missing opt dirs if missing:"
echo
mkdir -v -p /opt/airflow/{logs,dags,plugins,config}
echo
echo "Airflow version:"
/entrypoint airflow version
echo
echo "Files in shared volumes:"
echo
ls -la /opt/airflow/{logs,dags,plugins,config}
echo
echo "Running airflow config list to create default config file if missing."
echo
/entrypoint airflow config list >/dev/null
echo
echo "Files in shared volumes:"
echo
ls -la /opt/airflow/{logs,dags,plugins,config}
echo
echo "Change ownership of files in /opt/airflow to ${AIRFLOW_UID}:0"
echo
chown -R "${AIRFLOW_UID}:0" /opt/airflow/
echo
echo "Change ownership of files in shared volumes to ${AIRFLOW_UID}:0"
echo
chown -v -R "${AIRFLOW_UID}:0" /opt/airflow/{logs,dags,plugins,config}
echo
echo "Files in shared volumes:"
echo
ls -la /opt/airflow/{logs,dags,plugins,config}
# yamllint enable rule:line-length
environment:
<<: *airflow-common-env
_AIRFLOW_DB_MIGRATE: 'true'
_AIRFLOW_WWW_USER_CREATE: 'true'
_AIRFLOW_WWW_USER_USERNAME: ${_AIRFLOW_WWW_USER_USERNAME:-airflow}
_AIRFLOW_WWW_USER_PASSWORD: ${_AIRFLOW_WWW_USER_PASSWORD:-airflow}
_PIP_ADDITIONAL_REQUIREMENTS: ''
user: "0:0"
volumes:
airflow-postgres-db-volume:
- env 환경변수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Airflow
AIRFLOW_UID=50000
AIRFLOW_ORIGIN_IMAGE_NAME=apache/airflow:3.1.8-python3.13
AIRFLOW_IMAGE_NAME=apache/airflow:3.1.8-python3.13-custom
AIRFLOW_CORE_EXECUTOR=LocalExecutor
AIRFLOW_POSTGRES_SERVICE_NAME=airflow-postgres
AIRFLOW_REDIS_PORT=6379
AIRFLOW_API_PORT=8080
AIRFLOW_FLOWER_PORT=5555
AIRFLOW_PROJ_DIR=./airflow
AIRFLOW_POSTGRES_DB_VOLUME_NAME=airflow-postgres-db-volume
_AIRFLOW_WWW_USER_USERNAME=1234
_AIRFLOW_WWW_USER_PASSWORD=1234
AIRFLOW_EXTRAS=postgres,mysql,docker,elasticsearch,pgvector,redis,apache-kafka,apache-spark,grpc,http,opensearch
- Dockerfile
1
2
3
4
5
6
7
ARG AIRFLOW_ORIGIN_IMAGE_NAME=apache/airflow:3.1.8-python3.13 # .env 파일로부터 IMAGE 이름 로딩
FROM ${AIRFLOW_ORIGIN_IMAGE_NAME}
USER airflow
ARG AIRFLOW_EXTRAS # .env 파일로부터 설치할 EXTRAS 로딩
RUN pip install --no-cache-dir "apache-airflow[${AIRFLOW_EXTRAS}]"
2. 예시 DAG들을 제거하기

- airflow를 처음 접속해보면 위 사진과 같이 많은 예제 DAG들을 볼 수 있다.
- 이런 예제들을 제거하려면, 설정파일을 수정해주면 된다.
1
2
# airflow.cfg
load_examples = False # True -> False 수정
Trouble Shooting
1. ModuleNotFoundError: No module named ‘airflow.providers.fab’
(1) 원인
- Airflow 3.0부터는 기존에 기본으로 포함되어 있던 UI 관리자(Flask App Builder, FAB)가 별도의 프로바이더 패키지로 완전히 분리됨
- Airflow 표준 Docker Compose 파일에는
AIRFLOW__CORE__AUTH_MANAGER설정값이airflow.providers.fab로 지정되어있으나, 이는 기본 패키지가 아님 - 따라서 의존성 확보 실패로 인해 서비스가 실행되지 않음
(2) 해결
- 1안 :
AIRFLOW__CORE__AUTH_MANAGER를 비활성화하고AIRFLOW__CORE__SIMPLE_AUTH_MANAGER_ALL_ADMINS를 활성화해 모든 접속을 허용 - 2안 :
AIRFLOW__CORE__AUTH_MANAGER대신AIRFLOW__CORE__SIMPLE_AUTH_MANAGER_USERS사용 - 3안 :
airflow.providers.fabprovider를 포함하여 airflow 이미지 빌드
Reference
https://airflow.apache.org/docs/docker-stack/index.html
https://airflow.apache.org/docs/apache-airflow/stable/extra-packages-ref.html
https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html
https://airflow.apache.org/docs/apache-airflow/stable/configurations-ref.html
Comments