Docker Compose로 Airflow를 올렸는데 웹 UI(127.0.0.1:8080)가 안 열리고, 컨테이너 상태가 계속 health: starting에 머무는 경우가 있습니다. 이때 “포트 문제”로 착각하기 쉽지만, 실제 원인은 로그 디렉터리 권한(ownership) 불일치인 경우가 많습니다. 이번 글은 “왜 권한 문제가 Airflow 기동을 막는지”를 리눅스 권한 모델(Owner/Group/Other) 관점에서 기본부터 연결해 정리합니다.
1. 증상: Compose는 올라왔는데 UI가 안 열리고 starting에서 멈춤
컨테이너는 Up인데 상태가 계속 아래처럼 유지됩니다.
- airflow-webserver / scheduler / worker 등이 health: starting에서 바뀌지 않음
- http://127.0.0.1:8080/ 접속이 실패하거나 접속이 불안정함
여기서 중요한 관찰은 “포트가 열렸는지”보다 “서비스가 정상 초기화됐는지(healthy)”입니다.
2. 원인 확인: webserver 로그에 PermissionError
1️⃣ 로그 확인 커맨드
아래는 바로 실행 가능한 최소 확인 커맨드입니다.
docker logs airflow-airflow-webserver-1 --tail 50
2️⃣ 결정적 단서
이번 케이스에서는 아래 에러가 핵심이었습니다.
- PermissionError: [Errno 13] Permission denied: '/opt/airflow/logs/...'
- 이로 인해 로깅 핸들러 초기화 실패 → 설정 로딩 실패 → healthcheck 실패 → starting 고착
Airflow는 “로그 설정 초기화”가 실패하면 웹서버가 정상 기동 단계까지 못 갑니다. 비유하면, 가게 문은 열었는데(컨테이너 Up), 결제 시스템(POS)이 켜지지 않아(로깅 초기화 실패) 영업 시작(healthy)을 못 하는 상태입니다.
3. 왜 권한 문제가 생기나: Host 폴더 소유자 vs 컨테이너 실행 사용자
- 호스트의 ./logs 폴더가 컨테이너의 /opt/airflow/logs로 마운트됨
- 호스트에서 폴더를 만든 사용자는 보통 내 계정(npr)
- 하지만 Airflow 컨테이너는 종종 UID 50000 같은 별도 사용자로 실행됨
이때 “파일을 만든 사람(npr)”과 “파일을 쓰려는 사람(UID 50000)”이 다르면, 리눅스 권한 모델상 컨테이너 프로세스는 owner도 group도 아니어서 other 권한으로 평가됩니다. other에 쓰기 권한이 없으면 OS가 “너는 쓸 수 없어”라고 막고, 그게 바로 Permission denied로 터집니다.
4. 해결: logs는 Airflow가 쓰는 폴더이므로 소유권을 Airflow 실행 사용자에 맞춘다
1️⃣ 권장 해결(정석)
Airflow가 실제로 “쓰기”를 수행하는 경로는 logs이므로, logs는 컨테이너 실행 사용자 기준으로 소유자를 맞추는 게 가장 단순하고 확실합니다.
sudo chown -R 50000:0 ./logs
이 명령은 “권한을 조금 얹는” 게 아니라, 폴더의 주인(owner) 자체를 UID 50000으로 바꾸는 것입니다. 그래서 Airflow가 디렉터리 생성/파일 쓰기를 정상 수행할 수 있게 됩니다.
2️⃣ 재기동
docker compose down
docker compose up -d
이후 docker ps에서 healthy로 바뀌는지 확인합니다.
5. 부작용: dags까지 같이 바꾸면 VS Code 저장이 막힌다
1️⃣ 발생한 증상
dags까지 50000 소유로 바뀌면, 호스트에서 VS Code로 DAG 파일을 저장할 때 EACCES: permission denied가 뜹니다. 이유는 단순합니다. 이제 dags의 주인이 내 계정이 아니라 50000이기 때문입니다.
2️⃣ 권장 운영 패턴
- dags/ : 사람이 수정해야 하므로 호스트 사용자(npr)가 소유
- logs/ : Airflow가 써야 하므로 컨테이너 실행 사용자(50000)가 소유
아래처럼 분리하는 게 가장 깔끔합니다.
sudo chown -R npr:npr ./dags
sudo chown -R 50000:0 ./logs
6. “other로 열어주면 되지 않나?”에 대한 결론
1️⃣ 기술적으로는 가능
예를 들어 아래처럼 other에 쓰기 권한을 열어도 문제는 “일시적으로” 사라질 수 있습니다.
sudo chmod -R o+w ./logs
2️⃣ 하지만 권장하지 않는 이유
other는 “누구나”입니다. 누가 썼는지 책임 주체가 흐려지고, 원치 않는 프로세스/사용자도 쓰기가 가능해져 보안적으로 취약해집니다. Airflow 로그 추적이 “누가/어떤 태스크가 실행했는지”를 남기는 것과 같은 철학으로, OS 권한도 “누가 쓸 수 있는지”를 최소 단위로 명확히 하는 게 운영에 유리합니다.
7. 정리하면
docker ps에서 포트보다 healthy 여부를 본다
docker logs airflow-airflow-webserver-1 --tail 50로 PermissionError가 있는지 본다
./logs 소유권이 컨테이너 실행 사용자와 일치하는지 확인한다
./dags는 내 계정이 수정 가능하도록 소유권을 분리한다
'컨테이너·워크플로우 자동화 > Airflow로 워크플로우 자동화하기' 카테고리의 다른 글
| [트러블슈팅] BranchOperator 이후 Task가 Skipped 되는 이유와 trigger_rule (1) | 2026.01.22 |
|---|---|
| [트러블슈팅] Airflow FileSensor 실행 실패: fs_default Connection이 없을 때 (0) | 2026.01.21 |
| Airflow 세계관의 출발점 (Airflow Component) (0) | 2026.01.21 |
| 데이터 처리가 반복되기 시작했을 때, Airflow가 등장한 이유 (0) | 2026.01.21 |
| Airflow에서 PostgresOperator만으로 ETL을 한다는 것은 (0) | 2025.12.30 |