일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- flask
- docker
- 기초강의
- airflow
- ADP
- Django
- c++
- 개발언어
- Python
- 도커
- 인공지능
- C언어
- 파이썬강의
- 플라스크
- 장고 기초 강의
- 프로그래밍
- 예제프로젝트
- 개발자
- 도커 컴포즈
- 에어플로우 기초강의
- 장고 튜토리얼
- 웹개발
- 파이썬
- cpp
- 장고
- 파이썬 장고
- 쇼핑몰예제
- c
- 개발자취업
- mlops
- Today
- Total
TITEDIOS 편한 코딩
[MLOps] 6강 - Docker 설치 및 docker-compose.yaml 작성 (1) (Airflow Multi-Node System 구축 가이드 및 사례) 본문
[MLOps] 6강 - Docker 설치 및 docker-compose.yaml 작성 (1) (Airflow Multi-Node System 구축 가이드 및 사례)
TitediosKW 2025. 1. 3. 19:00목차
- Docker 설치
- Docker 설치 후 과정
- Airflow Multi-node를 위한 docker-compose.yaml 작성
- 결론
Multi-node 환경에서 Airflow를 설정하면 작업 부하를 분산하고 시스템 성능을 향상할 수 있습니다. MLOps 시스템을 만들기 위한 우리의 목적이기도 합니다. 이번 포스팅에서는 Docker를 활용하여 Airflow를 Multi-node로 구성하는 과정을 단계별로 설명하겠습니다.
1. Docker 설치
설치 전 virtualbox 가상머신에 한가지 설정이 필요합니다. 아래 그림처럼 설정하여 복사-붙여넣기 기능을 이용할 수 있도록 합니다. 하셔야.... 편합니다. 아니라면 한 땀 한 땀 작성을 해야 하기 때문입니다....
Docker 설치는 공식 문서를 참조하였습니다.
Install
Learn how to choose the best method for you to install Docker Engine. This client-server application is available on Linux, Mac, Windows, and as a static binary.
docs.docker.com
1.1. 기존 설치된 Docker 삭제
지금 우리는 Linux를 새로 설치해서 발생할 가능성이 적지만, 실제 환경에서는 custom된 docker가 설치되어 있을지도 모릅니다. 그럴 경우 충돌 문제가 발생할 수 있습니다. 이런 문제를 미연에 방지하고자 기존에 설치된 docker를 미리 삭제하는 것이 좋습니다. 물론, 삭제 전에는 확인 작업이 필수적입니다(그렇지 않다면 기존에 사용하고 있는 사용자들에게 폐가 될테니까요).
sudo dnf remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine \
podman \
runc
1.2. Docker 리포지토리 설정
이번 실습에서는 패키지 관리자를 이용해 docker를 설치할 것입니다. 패키지 관리자를 통해 docker를 설치하기 위해서는 먼저 docker의 위치를 알려주는 작업이 필요합니다.
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
1.3. Docker 패키지 설치
이제 docker를 설치합니다. 아래 명령어를 수행하면 docker에 관련한 패키지들을 모두 설치하게 됩니다. 그리고 docker
그룹을 자동으로 생성합니다.
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
1.4. Docker 엔진 시작
아래 명령어로 OS가 시작되면 자동으로 docker가 실행될 수 있도록 합니다. 혹시 항상 수작업으로 실행하고 싶으시다면 sudo systemctl start docker
명령어로 실행시키시면 됩니다.
sudo systemctl enable --now docker
1.5. hello-world image 실행을 통해 검증하기
간단한 Hello world 이미지를 실행시켜 봄으로써 docker가 잘 설치되고 동작하는지 확인해 봅니다.
sudo docker run hello-world
실행하면 아래와 같은 화면을 확인하실 수 있을 겁니다.
2. Docker 설치 후 과정
Docker는 관리자 권한이 필요합니다. 따라서 일반 사용자, 즉 non-root user가 직접 사용하려면 아래와 같은 과정을 수행해야 합니다. 역시 도커의 공식문서를 참조하였습니다.
Post-installation steps
Find the recommended Docker Engine post-installation steps for Linux users, including how to run Docker as a non-root user and more.
docs.docker.com
2.1. docker group 생성
이전에 설치에서 group이 생성된다고 했는데 또 생성하는 이유는 알 수 없지만, 공식 문서에는 group 생성을 먼저 하라고 하고 있습니다.
sudo groupadd docker
2.2. 일반 사용자를 docker 그룹에 등록
여러분의 계정을 docker 그룹에 등록해야 합니다. 아래 명령을 통해 docker 그룹에 등록해 주세요.$USER
에 여러분의 계정 이름을 넣어 주시면 됩니다.
sudo usermod -aG docker $USER
2.3. 재접속 또는 그룹 멤버십 갱신
그룹을 등록한 후 재접속을 통해 그룹을 갱신할 수 있습니다. 아니면 아래의 명령어로도 그룹 멤버십을 갱신할 수 있습니다.
newgrp docker
2.4. hello-world image 실행을 통해 검증하기
다시 한번 hello-world 이미지를 실행시켜 동작이 잘하는지 확인합니다. sudo
명령어가 없는 것에 주의합니다.
docker run hello-world
에러 발생 시
만약에 아래와 같은 에러 메시지가 나타난다면 권한 문제를 해결해야 합니다.
WARNING: Error loading config file: /home/user/.docker/config.json -
stat /home/user/.docker/config.json: permission denied
아래 명령어를 통해 ~/.docker
의 권한을 변경해 줌으로써 문제를 해결할 수 있습니다.
sudo chown "$USER":"$USER" /home/"$USER"/.docker -R
sudo chmod g+rwx "$HOME/.docker" -R
3. Airflow Multi-node를 위한 docker-compose.yaml 작성
Docker와 Docker Compose 설치를 완료했다면, 이제 Multi-node Airflow 구성을 위한 docker-compose.yaml 파일을 작성합니다.
기본 디렉토리 구조
Airflow는 기본적으로 아래와 같은 구조를 가집니다. Dag라고 하는 workflow를 가지고 있는 파일들의 집합이 있고 docker-copmose.yaml 파일이 있습니다.
.
|-- dags/
|-- docker-compose.yaml
- dags: DAG 파일을 저장하는 디렉토리
- docker-compose.yaml: Docker Compose 설정 파일
원하는 디렉토리에 dags/
폴더 하나만 만드시면 됩니다. 저는 $HOME/works/
에서 작업하기로 했습니다. 저와 같은 위치에서 작업하실 분들은 아래 명령어를 실행하시면 되겠습니다.
cd ~
mkdir -p works/dags && cd works/
docker-compose.yaml 작성
curl 명령어를 통해 docker-compose.yaml을 다운로드합니다.
curl -LfO 'https://airflow.apache.org/docs/apache-airflow/2.10.4/docker-compose.yaml'
아니면 만들어 놓은 docker-compose.yaml 파일을 아래 내용으로 채워 넣습니다. 사실, 이 내용을 넣을지 고민이 많았습니다. 너무 길거든요. 복사하시는 게 편하시다면 복사를 해도 좋고 아니라면 curl 명령어를 통해 다운로드를 하여도 괜찮습니다.
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
#under the License.
#
# Basic Airflow cluster configuration for CeleryExecutor with Redis and PostgreSQL.
#
# WARNING: This configuration is for local development. Do not use it in a production deployment.
#
# This configuration supports basic configuration using environment variables or an .env file
# The following variables are supported:
#
# AIRFLOW_IMAGE_NAME - Docker image name used to run Airflow.
# Default: apache/airflow:2.10.4
# AIRFLOW_UID - User ID in Airflow containers
# Default: 50000
# AIRFLOW_PROJ_DIR - Base path to which all the files will be volumed.
# Default: .
# Those configurations are useful mostly in case of standalone testing/running Airflow in test/try-out mode
#
# _AIRFLOW_WWW_USER_USERNAME - Username for the administrator account (if requested).
# Default: airflow
# _AIRFLOW_WWW_USER_PASSWORD - Password for the administrator account (if requested).
# Default: airflow
# _PIP_ADDITIONAL_REQUIREMENTS - Additional PIP requirements to add when starting all containers.
# Use this option ONLY for quick checks. Installing requirements at container
# startup is done EVERY TIME the service is started.
# A better way is to build a custom image or extend the official image
# as described in https://airflow.apache.org/docs/docker-stack/build.html.
# Default: ''
#
# Feel free to modify this file to suit your needs.
---
x-airflow-common:
&airflow-common
# In order to add custom dependencies or upgrade provider packages you can use your extended image.
# Comment the image line, place your Dockerfile in the directory where you placed the docker-compose.yaml
# and uncomment the "build" line below, Then run `docker-compose build` to build the images.
image: ${AIRFLOW_IMAGE_NAME:-apache/airflow:2.10.4}
# build: .
environment:
&airflow-common-env
AIRFLOW__CORE__EXECUTOR: CeleryExecutor
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://airflow:airflow@postgres/airflow
AIRFLOW__CELERY__RESULT_BACKEND: db+postgresql://airflow:airflow@postgres/airflow
AIRFLOW__CELERY__BROKER_URL: redis://:@redis:6379/0
AIRFLOW__CORE__FERNET_KEY: ''
AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'true'
AIRFLOW__CORE__LOAD_EXAMPLES: 'true'
AIRFLOW__API__AUTH_BACKENDS: 'airflow.api.auth.backend.basic_auth,airflow.api.auth.backend.session'
# yamllint disable rule:line-length
# Use simple http server on scheduler for health checks
# See https://airflow.apache.org/docs/apache-airflow/stable/administration-and-deployment/logging-monitoring/check-health.html#scheduler-health-check-server
# yamllint enable rule:line-length
AIRFLOW__SCHEDULER__ENABLE_HEALTH_CHECK: 'true'
# WARNING: Use _PIP_ADDITIONAL_REQUIREMENTS option ONLY for a quick checks
# for other purpose (development, test and especially production usage) build/extend Airflow image.
_PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:-}
# The following line can be used to set a custom config file, stored in the local config folder
# If you want to use it, outcomment it and replace airflow.cfg with the name of your config file
# AIRFLOW_CONFIG: '/opt/airflow/config/airflow.cfg'
volumes:
- ${AIRFLOW_PROJ_DIR:-.}/dags:/opt/airflow/dags
- ${AIRFLOW_PROJ_DIR:-.}/logs:/opt/airflow/logs
- ${AIRFLOW_PROJ_DIR:-.}/config:/opt/airflow/config
- ${AIRFLOW_PROJ_DIR:-.}/plugins:/opt/airflow/plugins
user: "${AIRFLOW_UID:-50000}:0"
depends_on:
&airflow-common-depends-on
redis:
condition: service_healthy
postgres:
condition: service_healthy
services:
postgres:
image: postgres:13
environment:
POSTGRES_USER: airflow
POSTGRES_PASSWORD: airflow
POSTGRES_DB: airflow
volumes:
- postgres-db-volume:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "airflow"]
interval: 10s
retries: 5
start_period: 5s
restart: always
redis:
# Redis is limited to 7.2-bookworm due to licencing change
# https://redis.io/blog/redis-adopts-dual-source-available-licensing/
image: redis:7.2-bookworm
expose:
- 6379
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 30s
retries: 50
start_period: 30s
restart: always
airflow-webserver:
<<: *airflow-common
command: webserver
ports:
- "8080:8080"
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8080/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-worker:
<<: *airflow-common
command: celery worker
healthcheck:
# yamllint disable rule:line-length
test:
- "CMD-SHELL"
- 'celery --app airflow.providers.celery.executors.celery_executor.app inspect ping -d "celery@$${HOSTNAME}" || celery --app airflow.executors.celery_executor.app inspect ping -d "celery@$${HOSTNAME}"'
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
environment:
<<: *airflow-common-env
# Required to handle warm shutdown of the celery workers properly
# See https://airflow.apache.org/docs/docker-stack/entrypoint.html#signal-propagation
DUMB_INIT_SETSID: "0"
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
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
mkdir -p /sources/logs /sources/dags /sources/plugins
chown -R "${AIRFLOW_UID}:0" /sources/{logs,dags,plugins}
exec /entrypoint airflow version
# 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_PROJ_DIR:-.}:/sources
airflow-cli:
<<: *airflow-common
profiles:
- debug
environment:
<<: *airflow-common-env
CONNECTION_CHECK_MAX_COUNT: "0"
# Workaround for entrypoint issue. See: https://github.com/apache/airflow/issues/16252
command:
- bash
- -c
- airflow
# You can enable flower by adding "--profile flower" option e.g. docker-compose --profile flower up
# or by explicitly targeted on the command line e.g. docker-compose up flower.
# See: https://docs.docker.com/compose/profiles/
flower:
<<: *airflow-common
command: celery flower
profiles:
- flower
ports:
- "5555:5555"
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:5555/"]
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
restart: always
depends_on:
<<: *airflow-common-depends-on
airflow-init:
condition: service_completed_successfully
volumes:
postgres-db-volume:
결론
이제 Docker와 Docker Compose를 사용하여 Multi-node Apache Airflow를 설정하는 방법을 어느 정도 이해하셨을 것입니다. 실제 Airflow를 실행하여 보지는 않았지만 여기까지 왔다면 거의 대부분 완료된 것이므로 너무 걱정하지 않으셔도 됩니다. 다음 포스팅에서는 Multi-node를 사용하기 위해 설정을 조정하여 프로젝트 요구 사항에 맞게 최적화하는 작업을 수행할 것입니다.
궁금한 점이나 추가로 알고 싶은 내용이 있다면 댓글로 알려주세요!
도움이 되셨다면 공감 부탁드리겠습니다. 여러분의 공감이 정말 큰 힘이 됩니다.
감사합니다!