드디어 Airflow의 메이저 버전 업데이트가 되었다. 25년 11월 즈음에 도커로 올려서 새롭게 변경된 UI나 여러가지 변경된 사항들을 확인했었는데, 사내에서 간단한 파이프라인을 구축하는 토이 프로젝트를 진행하였기에 기존에 사용하던 2.10.2 버전이 아닌 3.0.2 버전을 온프레미스 서버에 설치해보려고 한다.
- 버전: 3.0.2
- 설치경로: /home/airflow/venv
- LocalExecutor
- Metadatabase:MySQL
기본적으로 Airflow의 공식문서를 참고하였으며, 기존 Airflow 2버전과 설치과정 또는 구동 방식에 있어서 차이점이 있었는데 그러한 것들을 살펴보면 좋을 것 같다.
Airflow는 기존 시스템과 파이썬 충돌을 방지하기 위해, 가상환경 위에서 설치한다.
Airflow 설치(Python venv 기준)
# 이동
[root@ibmqr venv]# cd /home/airflow
# 가상환경 생성
[root@ibmqr venv]# python3 -m venv venv
[root@ibmqr venv]# source venv/bin/activate
(venv) [root@ibmqr venv]# which python
# /home/airflow/venv/bin/python 나오면 성공
# airflow 설치
(venv) [root@ibmqr venv]# AIRFLOW_VERSION=3.0.2
(venv) [root@ibmqr venv]# PYTHON_VERSION=3.12
(venv) [root@ibmqr venv]# CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt"
(venv) [root@ibmqr venv]# pip install "apache-airflow[mysql]==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}"
환경변수 설정 및 적용
처음에 각 컴포넌트를 수동으로 올릴 때는 아래에 설정된 환경변수를 잘 잡고 올라갔는데, 이후 특정 컴포넌트가 자꾸 죽는 문제가 발생해서 systemd 서비스(데몬)로 등록해서 해결했다. 하지만 이때 환경변수를 잘 바라보지 못하는 문제가 발생해서 airflow.cfg에 따로 설정해주어 해결하였다. 그 과정은 아래에서 진행하겠다.
(venv) [root@ibmqr venv]# vim ~/.bashrc
#Airflow Config#
# Airflow Home
export AIRFLOW_HOME=/home/airflow/venv
# MetaDatabase
export AIRFLOW__DATABASE__SQL_ALCHEMY_CONN="mysql+mysqldb://airflow:Penta2848%21@localhost:3306/AIRFLOW"
# Executor
export AIRFLOW__CORE__EXECUTOR=LocalExecutor
# 예제 설정 여부
export AIRFLOW__CORE__LOAD_EXAMPLES=False
# # API 인증
export AIRFLOW__API__AUTH_BACKENDS=airflow.api.auth.backend.basic_auth
# Timezone (KST)
export AIRFLOW__CORE__DEFAULT_TIMEZONE=Asia/Seoul
export AIRFLOW__CORE__DAG_TIMEZONE=Asia/Seoul
# Config Export
export AIRFLOW__WEBSERVER__EXPOSE_CONFIG=True
(venv) [root@ibmqr venv]# source ~/.bashrc
Config 적용 확인
(venv) [root@ibmqr venv]# airflow config get-value database sql_alchemy_conn
mysql+mysqldb://airflow:Penta2848!@localhost:3306/AIRFLOW
(venv) [root@ibmqr venv]# airflow config get-value core executor
LocalExecutor
(venv) [root@ibmqr venv]# airflow config get-value core load_examples
False
MySQL Airflow 전용 DB 생성
-- Airflow 전용 DB 생성
CREATE DATABASE AIRFLOW;
-- Airflow 전용 계정 생성
CREATE USER 'airflow'@'localhost'
IDENTIFIED BY 'Penta2848!';
-- 권한 부여
GRANT ALL PRIVILEGES ON AIRFLOW.* TO 'airflow'@'localhost';
FLUSH PRIVILEGES;
-- 정상 생성 확인
SHOW DATABASES LIKE 'AIRFLOW';
SELECT user, host FROM mysql.user WHERE user = 'airflow';
필수 시스템 패키지 설치 (mysqlclient 빌드 의존성 필요)
(venv) [root@ibmqr venv]# yum install -y gcc gcc-c++ make python3-devel mysql-devel libffi-devel openssl-devel
DB 초기화
(venv) [root@ibmqr venv]# airflow db migrate
[2026-01-02T11:03:02.683+0900] {migration.py:207} INFO - Context impl MySQLImpl.
[2026-01-02T11:03:02.683+0900] {migration.py:210} INFO - Will assume non-transactional DDL.
[2026-01-02T11:03:02.687+0900] {migration.py:207} INFO - Context impl MySQLImpl.
[2026-01-02T11:03:02.687+0900] {migration.py:210} INFO - Will assume non-transactional DDL.
[2026-01-02T11:03:02.689+0900] {db.py:729} INFO - Creating Airflow database tables from the ORM
[2026-01-02T11:03:04.673+0900] {migration.py:207} INFO - Context impl MySQLImpl.
[2026-01-02T11:03:04.673+0900] {migration.py:210} INFO - Will assume non-transactional DDL.
[2026-01-02T11:03:04.746+0900] {migration.py:618} INFO - Running stamp_revision -> 29ce7909c52b
[2026-01-02T11:03:04.751+0900] {db.py:740} INFO - Airflow database tables created Database migrating done!
기존 Airflow 2 버전 대에서는 airflow db init 커맨드로 Database를 초기화해주었지만, 3 버전으로 올라와서는 위의 커맨드로 변경되었다. MySQL에 메타 테이블이 생성되면 정상이다.

Snowflake provider 설치
Airflow를 가동하기 전에 필요한 provider는 먼저 설치하도록 한다.
(venv) [root@ibmqr venv]# pip install apache-airflow-providers-snowflake
Airflow 기동
(venv) [root@ibmqr venv]# airflow api-server --port 8080
(venv) [root@ibmqr venv]# airflow scheduler
(venv) [root@ibmqr venv]# airflow triggerer
(venv) [root@ibmqr venv]# airflow dag-processor
네 가지 핵심 컴포넌트의 역할은 아래와 같다.
1. airflow api-server --port 8080
- 역할: Airflow의 새로운 얼굴이자 통로
- 상세 설명: 기존 2.x 버전의 webserver를 대체하는 컴포넌트. 사용자가 접속하는 웹 UI를 제공할 뿐만 아니라, Airflow의 모든 기능을 제어할 수 있는 REST API의 중심점 역할.
- 핵심 기능: DAG 상태 확인, 수동 실행(Trigger), 로그 열람, 커넥션 설정 등을 처리.
2. airflow scheduler
- 역할: Airflow의 두뇌 (스케줄 관리 및 작업 할당)
- 상세 설명: 모든 DAG와 Task의 실행 타이밍을 결정. 데이터베이스를 지속적으로 확인하며 "지금 실행해야 할 작업이 무엇인가?"를 판단.
- 핵심 기능: 실행 조건이 충족된 Task를 Executor의 큐에 넣음. Airflow 3.0부터는 DAG 파일을 직접 읽는 부하를 줄이고, 오로지 "스케줄링"에만 집중하도록 설계됨.
3. airflow trigger
- 역할: 비동기 작업의 대기소 (효율성 극대화)
- 상세 설명: Deferrable Operators(지연 가능한 오퍼레이터)를 위해 존재함. 예를 들어, Snowflake에서 쿼리가 끝나길 1시간 동안 기다려야 한다면, 이 Task는 Worker 점유를 해제하고 triggerer로 넘어감.
- 핵심 기능: 수천 개의 Task가 외부 작업(Snowflake, S3 등)을 기다릴 때, 리소스를 거의 쓰지 않고 비동기적으로 모니터링하다가 작업이 완료되면 다시 스케줄러에게 알림.
4. airflow dag-processor
- 역할: Python 코드를 해석하는 번역가
- 상세 설명: Airflow 3.0에서 별도 프로세스로 완전히 독립된 매우 중요한 컴포넌트임. 사용자가 작성한 .py 파일(DAG 폴더)을 주기적으로 읽어(Parsing) 스케줄러가 이해할 수 있는 메타데이터 형태로 변환하여 DB에 저장함.
- 핵심 기능: 스케줄러와 DAG 해석 프로세스를 분리함으로써, 특정 DAG 코드에 에러가 있거나 해석에 시간이 오래 걸려도 전체 스케줄링 시스템이 멈추지 않도록 보안과 안정성을 강화함.
airflow standalone 커맨드를 사용하면 한 번에 다 띄워주니 편하지만 운영엔 불리하다. 해당 커맨드는 로컬 테스트 용도로 사용하도록 하자. airflow standalone 으로 기동하니 초기 admin 비밀번호가 생성되었다. simple_auth_manager_passwords.json.generated
위 과정까지 수행하고 각 컴포넌트들이 정상적으로 올라간 것을 확인했는데 혹여나 웹 UI 접근이 안된다면 방화벽(firewalld) 포트를 확인해보자.
(venv) [root@ibmqr venv]# systemctl status firewalld
(venv) [root@ibmqr venv]# firewall-cmd --list-ports
8083/tcp 9092/tcp 9999/tcp
(venv) [root@ibmqr venv]# firewall-cmd --add-port=8080/tcp --permanent
(venv) [root@ibmqr venv]# firewall-cmd --reload
(venv) [root@ibmqr venv]# firewall-cmd --list-ports
8080/tcp 8083/tcp 9092/tcp 9999/tcp
이후 아래처럼 정상적으로 UI 접근이 가능하다.

매번 커맨드를 네 개나 입력하는 건 번거롭기 때문에 리눅스 서비스로 등록해주도록 하자.
systemd 등록
리눅스 서비스로 등록해두면 서버가 재부팅되어도 자동으로 Airflow가 올라온다. 또한, 로그가 파일 여기저기 흩어지지 않고 시스템 로그(journalctl)로 통합되어 관리가 편해진다. airflow-api.service, airflow-scheduler.service 등으로 파일을 만들어 관리해보자. /etc/systemd/system/ 디렉토리에 생성한다.
airflow-api.service
[Unit]
Description=Airflow 3.0 API Server
After=network.target mysql.service
[Service]
User=root
Group=root
Type=simple
Environment="AIRFLOW_HOME=/home/airflow/venv"
Environment="AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=mysql+mysqldb://airflow:Penta2848%21@localhost:3306/AIRFLOW"
Environment="AIRFLOW__CORE__EXECUTOR=LocalExecutor"
Environment="AIRFLOW__CORE__LOAD_EXAMPLES=False"
Environment="AIRFLOW__API__AUTH_BACKENDS=airflow.api.auth.backend.basic_auth"
Environment="AIRFLOW__CORE__DEFAULT_TIMEZONE=Asia/Seoul"
Environment="AIRFLOW__CORE__DAG_TIMEZONE=Asia/Seoul"
Environment="AIRFLOW__WEBSERVER__EXPOSE_CONFIG=True"
Environment="PATH=/home/airflow/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/bin"
ExecStart=/home/airflow/venv/bin/airflow api-server --port 8080
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
시스템에서 환경변수를 읽을 수 있도록 다 넣어줬고 ExecStart에 실제 수행될 명령어를 기재한다. 또한 컴포넌트가 죽으면 5초 후에 재기동 할 수 있도록 설정하였다. 나머지 컴포넌트 파일도 반복해서 생성해주자. 위 파일의 내용을 복사해서 아래 파일들을 추가로 만든다.(ExecStart 부분만 바꾸면 된다)
- airflow-scheduler.service: ExecStart=... airflow scheduler
- airflow-triggerer.service: ExecStart=... airflow triggerer
- airflow-processor.service: ExecStart=... airflow dag-processor
서비스 활성화 및 실행
# 1. 기존 airflow 프로세스 완전 종료
(venv) [root@ibmqr system]# pkill -9 -f airflow
# 2. 시스템 데몬 설정 새로고침
(venv) [root@ibmqr system]# systemctl daemon-reload
# 3. 서버 부팅 시 자동 시작 설정
(venv) [root@ibmqr system]# systemctl enable airflow-api airflow-scheduler airflow-triggerer airflow-processor
# 4. 서비스 시작
(venv) [root@ibmqr system]# systemctl start airflow-api airflow-scheduler airflow-triggerer airflow-processor
# 5. 상태 확인
(venv) [root@ibmqr system]# systemctl status airflow-scheduler

※ 주의 사항
만약 나중에 포트를 변경하거나(-- port 8081 등), 가상환경 경로를 수정하게 되면 이 파일들을 수정한 후 반드시 아래 명령어를 쳐야 시스템에 반영된다.
(venv) [root@ibmqr system]# systemctl daemon-reload
(venv) [root@ibmqr system]# systemctl restart airflow-api # 수정된 서비스 재시작
서비스 상태 및 로그 확인
# 1. 상태 확인
(venv) [root@ibmqr system]# systemctl status airflow-scheduler
# 2. 실시간 로그 확인
(venv) [root@ibmqr system]# journalctl -u airflow-scheduler -f
하지만 각 컴포넌트들이 정상적으로 올라가지 않고 에러가 발생했었는데 나의 경우는 권한 문제와 SELinux 관련이었다.
# venv 폴더와 그 안의 모든 파일/폴더에 대해 실행 권한 확인
(venv) [root@ibmqr system]# chmod -R 755 /home/airflow/venv
# SELinux 상태 확인 (Enforcing이면 켜져 있는 것)
(venv) [root@ibmqr system]# getenforce
# 임시로 끄기
(venv) [root@ibmqr system]# setenforce 0
# 서비스 다시 시작
(venv) [root@ibmqr system]# systemctl restart airflow-api airflow-scheduler airflow-processor airflow-triggerer
권한 문제를 해결해주니 아래와 같은 에러가 발생했다.
ERROR: You need to initialize the database. Please run airflow db migrate.
이미 위에서 Database 초기화를 진행했었는데 해당 과정을 다시 해야 한다는게 이해되지 않았다.
아마도 수동으로 실행할 때는 airflow 관련 환경변수를 정확히 읽어서 기존 DB에 잘 붙었지만, systemd 서비스로 실행하면서 airflow가 엉뚱한 곳을 보고 있었던 것 같다. 예를 들면, Airflow가 기존 MySQL이 아닌 기본값인 SQLite를 새로 만드려고 시도하는 경우이다. 나의 경우엔 위에서처럼 환경변수로 설정해두었지만 어디에선가 꼬인 문제가 발생하는 것 같아서 가장 확실한 방법으로 airflow.cfg 파일을 수정했다.
(venv) [root@ibmqr venv]# vim airflow.cfg
# 수정 전: sql_alchemy_conn = sqlite:////home/airflow/venv/airflow.db
sql_alchemy_conn = mysql+mysqldb://airflow:Penta2848!@localhost:3306/AIRFLOW
# 수정 전: executor = SequentialExecutor
executor = LocalExecutor
# 이하 필요 설정 수정
설정 파일을 직접 수정하였으니, 이제 환경 변수 없이도 db migrate 명령어가 MySQL을 바라보게 된다. 잘 바라보는지 확인해보자.
# 환경변수 다 무시하고 cfg 파일 내용만으로 DB 접속이 확인되는지 테스트
(venv) [root@ibmqr venv]# unset AIRFLOW__DATABASE__SQL_ALCHEMY_CONN
(venv) [root@ibmqr venv]# airflow config get-value database sql_alchemy_conn
mysql+mysqldb://airflow:Penta2848!@localhost:3306/AIRFLOW
이후 마이그레이션 후 서비스를 재시작하면 정상적으로 올라오게 된다.
(venv) [root@ibmqr venv]# airflow db migrate
(venv) [root@ibmqr venv]# systemctl daemon-reload
(venv) [root@ibmqr venv]# systemctl restart airflow-*
'Airflow' 카테고리의 다른 글
| [MWAA] Airflow Unable to read remote logs from CloudWatch (0) | 2025.12.02 |
|---|---|
| [Airflow] Airflow Webserver Daemon TroubleShooting (0) | 2023.06.21 |