티스토리 뷰

 

이전 글에서 Airflow란 무엇인지 알아봤습니다. 이번 글에서는 플랫폼을 구축해보고 기본적인 터미널 명령어를 살펴보도록 하겠습니다.


 

Airflow Service

 

위에 그림에 있는 것처럼 airflow를 구축하기 위해서는 webserver, scheduler, worker, database까지 함께 움직이는 서비스가 많습니다. 이것들이 조합되면 airflow라고 하는 워크플로 플랫폼이 완성되는 겁니다. 여기 있는 서비스를 하나씩 설치하면서 고생하기에는 우리의 시간이 넉넉하지 않죠? 이번 글은 airflow를 제일 빠르고 간편한 방법으로 만날 수 있는 docker-compose를 통한 설치 방법을 알아봅니다.

# docker로 airflow 설치

airflow를 운영하려는 환경에 docker-compose가 설치되어 있는지, 설치되어 있다면 버전이 뭔지 확인해주세요. 1.27.0 이하 버전이면 업그레이드가 필요합니다. MacOS 기준으로 docker desktop 애플리케이션과 같이 설치된 docker-compose를 사용 중이라면 업그레이드가 호락호락하지 않으니 pip로 설치하는 것을 추천합니다. docker destop과 같이 설치된 docker-compose 바이너리는 삭제하고 다시 설치하도록 합시다.

$ rm -rf /usr/local/bin/docker-compose
$ pip install docker-compose

혹시 어디 설치된 docker-compose가 동작하는지 모르겠다면 "which docker-compose" 명령어를 통해 설치되어 있는 경로를 확인하도록 합시다

설치가 끝났으면 버전을 확인해주세요.

$ docker-compose -v
docker-compose version 1.29.2, build unknown

 

이제 airflow 한방 세팅을 위한 docker-compose.yaml 파일을 다운로드합니다.

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

다운로드가 끝났으면 docker-compose.yaml  내용물을 살펴봐주면 좋습니다. 혹시 커스터마이징이 필요한 부분이 있으면 설정해주면 됩니다. 지금 당장 뭘 손대야 할지 몰라도 상관없습니다. 나중에 필요할 때 작업해줘도 되거든요.

이제 airflow에서 사용할 디렉터리를 미리 설정해줍니다. 여기서 생성하는 디렉터리는 container의 볼륨으로 마운트 됩니다. 마운트가 되면 container에서 동작하는 airflow task의 로그를 호스트 머신에서 생성한 logs 디렉터리에서 확인하거나, 새로운 DAG을 개발했다면 container에 넣기 위해 docker cp를 할 필요 없이 그냥 dags 디렉터리에 위치시켜주기만 하면 됩니다.

$ mkdir ./dags ./logs ./plugins
$ echo -e "AIRFLOW_UID=$(id -u)\nAIRFLOW_GID=0" > .env

 

다음으로 아래 명령어를 통해 공통 환경을 잡아주도록 합니다.

$ docker-compose up airflow-init

이때 로컬에서 5432(postgres), 6379(redis), 8080(webserver) 포트가 충돌 나지 않도록 미리미리 종료해야 합니다. 혹시 이미 포트가 점유되어 있다면 아래와 같은 오류를 만나시게 되는데 당황하지 말고 포트를 사용하고 있는 앱을 정리한 후에 다시 위에 명령어를 입력해주면 되겠습니다.

Creating airflow_redis_1 ...
Creating airflow_redis_1    ... error
WARNING: Host is already in use by another container

ERROR: for airflow_redis_1  Cannot start service redis: driver failed programming external connectivity on endpoint airflow_redis_1 (d4d2df678155e4d2bc51f8f6c1767102571bfacc38812103ad881429Creating airflow_postgres_1 ... done

ERROR: for redis  Cannot start service redis: driver failed programming external connectivity on endpoint airflow_redis_1 (d4d2df678155e4d2bc51f8f6c1767102571bfacc38812103ad881429b249e889): Bind for 0.0.0.0:6379 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.

혹시 아래와 같은 에러가 발생한다면 docker가 설치되어 있지 않은 경우입니다.

$ docker-compose up airflow-init
Traceback (most recent call last):
  File "/home/ec2-user/.local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 706, in urlopen
    chunked=chunked,
  File "/home/ec2-user/.local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 394, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/lib64/python3.7/http/client.py", line 1277, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/lib64/python3.7/http/client.py", line 1323, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/usr/lib64/python3.7/http/client.py", line 1272, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/usr/lib64/python3.7/http/client.py", line 1032, in _send_output
    self.send(msg)
  File "/usr/lib64/python3.7/http/client.py", line 972, in send
    self.connect()
  File "/home/ec2-user/.local/lib/python3.7/site-packages/docker/transport/unixconn.py", line 43, in connect
    sock.connect(self.unix_socket)
FileNotFoundError: [Errno 2] No such file or directory

During handling of the above exception, another exception occurred

각자에 환경에 맞게 docker를 인스톨해주고 다시 docker-compose up airflow-init 명령을 실행해줍시다.

초기화가 끝나면 터미널에서 아래와 같은 메시지가 확인됩니다.

airflow-init_1       | 2.1.0
airflow_airflow-init_1 exited with code 0

 

docker 커맨드를 통해 postgres, redis container 두 개가 정상적으로 실행되어 있는 것을 확인합니다.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                   PORTS                               NAMES
33ee4c7fee15        postgres:13         "docker-entrypoint.s…"   5 minutes ago       Up 5 minutes (healthy)   5432/tcp                            airflow_postgres_1
e905d62b28f5        redis:latest        "docker-entrypoint.s…"   5 minutes ago       Up 3 minutes (healthy)   0.0.0.0:6379->6379/tcp              airflow_redis_1

 

이제 airflow 서비스를 올려봅시다. -d 옵션(detached모드)을 사용해주세요. 그렇지 않으면 명령이 실행된 터미널이 종료되거나 키보드에 Ctrl+C 가 입력되는 경우 airflow 관련 컨테이너가 모두 종료돼버립니다.  

$ docker-compose up -d

docker 커맨드를 통해 확인할 수 있는 최종 상태입니다. airflow 관련 컨테이너 4개와 postgres, redis가 시작됐다면 성공입니다.

$ docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED      STATUS                PORTS                                                 NAMES
43c87ea9ed3f   apache/airflow:2.1.0   "/usr/bin/dumb-init …"   3 days ago   Up 3 days (healthy)   8080/tcp                                              madflow_airflow-scheduler_1
0f1bd1a23c20   apache/airflow:2.1.0   "/usr/bin/dumb-init …"   3 days ago   Up 3 days (healthy)   0.0.0.0:5555->5555/tcp, :::5555->5555/tcp, 8080/tcp   madflow_flower_1
aea0d679c877   apache/airflow:2.1.0   "/usr/bin/dumb-init …"   3 days ago   Up 3 days (healthy)   8080/tcp                                              madflow_airflow-worker_1
d94be19d944b   apache/airflow:2.1.0   "/usr/bin/dumb-init …"   3 days ago   Up 3 days (healthy)   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp             madflow_airflow-webserver_1
bfbf922bf99d   postgres:13            "docker-entrypoint.s…"   3 days ago   Up 3 days (healthy)   5432/tcp                                              madflow_postgres_1
7c20b4caf07f   redis:latest           "docker-entrypoint.s…"   3 days ago   Up 3 days (healthy)   0.0.0.0:6379->6379/tcp, :::6379->6379/tcp             madflow_redis_1

 

airflow에 존재하는 각각의 서비스는 아래와 같은 역할을 합니다.

  • airflow-scheduler
    • The scheduler monitors all tasks and DAGs, then triggers the task instances once their dependencies are complete.
    • 스케줄러는 모든 작업과 DAG를 모니터링 한 다음 종속성이 완료되면 작업 인스턴스를 트리거합니다.
  • airflow-webserver 
    • The webserver available at http://localhost:8080.
    • airflow 웹서버입니다. localhost:8080으로 접속해서 사용 가능합니다.
  • airflow-worker
    • The worker that executes the tasks given by the scheduler.
    • 스케줄러가 제공한 작업을 실행하는 작업자입니다.
  • airflow-init
    • The initialization service.
    • 초기화 서비스입니다.
  • flower
    • The flower app for monitoring the environment. It is available at http://localhost:5555.
    • 환경 모니터링을 위한 flower 애플리케이션입니다. localhost:5555에서 사용할 수 있습니다.
  • postgres
    • 데이터베이스입니다
  • redis
    • The redis - broker that forwards messages from scheduler to worker.
    • 스케줄러에서 작업자로 메시지를 전달하는 브로커입니다.

이제 localhost:8080으로 접속해서 airflow를 만나보시면 됩니다. 로그인 계정은 airflow / airflow로 접속해주세요.

Hello Airflow !!

 

# 사용한 리소스 정리

아래 명령어를 통해 지금까지 실습한 모든 내용을 삭제합니다.

$ docker-compose down --volumes --rmi all

완전 정리가 아니라 컨테이너만 내리고 싶을 수 있습니다. scheduler와 worker가 CPU 자원을 많이 사용하거든요. 이때는 docker-compose에 down 옵션을 사용해줍시다. 

$ docker-compose down
Stopping airflow_airflow-scheduler_1 ... done
Stopping airflow_flower_1            ... done
Stopping airflow_airflow-worker_1    ... done
Stopping airflow_airflow-webserver_1 ... done
Stopping airflow_postgres_1          ... done
Stopping airflow_redis_1             ... done
Removing airflow_airflow-scheduler_1 ... done
Removing airflow_flower_1            ... done
Removing airflow_airflow-worker_1    ... done
Removing airflow_airflow-webserver_1 ... done
Removing airflow_airflow-init_1      ... done
Removing airflow_postgres_1          ... done
Removing airflow_redis_1             ... done
Removing network airflow_default

 

# 소소한 팁

터미널 좋아하시는 분은 아래와 같이 airflow.sh 파일을 다운로드하시고..

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

컨테이너 bash 환경으로 접속하실 수 있습니다. 

$ ./airflow.sh bash

이렇게 bash 환경(컨테이너)으로 접속하면 airflow 커맨드를 사용할 수 있습니다. 

default@c32c93815025:/opt/airflow$ airflow --help
usage: airflow [-h] GROUP_OR_COMMAND ...

positional arguments:
  GROUP_OR_COMMAND

    Groups:
      celery         Celery components
      config         View configuration
      connections    Manage connections
      dags           Manage DAGs
      db             Database operations
      jobs           Manage jobs
      kubernetes     Tools to help run the KubernetesExecutor
      pools          Manage pools
      providers      Display providers
      roles          Manage roles
      tasks          Manage tasks
      users          Manage users
      variables      Manage variables

    Commands:
      cheat-sheet    Display cheat sheet
      info           Show information about current Airflow and environment
      kerberos       Start a kerberos ticket renewer
      plugins        Dump information about loaded plugins
      rotate-fernet-key
                     Rotate encrypted connection credentials and variables
      scheduler      Start a scheduler instance
      sync-perm      Update permissions for existing roles and optionally DAGs
      version        Show the version
      webserver      Start a Airflow webserver instance

optional arguments:
  -h, --help         show this help message and exit

굳이 컨테이너에 접속하지 않고 호스트에서 아래와 같이 pip를 통해 airflow 커맨드를 설치하는 방법도 있지만 호불호가 갈립니다. 일단 컴퓨터에 뭔가 자꾸 설치되는 게 싫을 수 있고, python 환경에 따라 airflow 커맨드가 설치되기 때문이죠. 근데 호스트에서 DAG 개발하려면 설치해야 합니다 (웃음). 인프라 환경이 아닌 이상에는 설치해주는 게 낫겠습니다.

$ pip install apache-airflow

아, bash 뿐만 아니라 마찬가지로 python 프롬프트로 접속도 가능합니다. DAG이 실제 동작하는 python 버전을 확인하거나 간단한 코드를 테스트해볼 수 있습니다.

$ ./airflow.sh python

 

# 마무리

설치가 끝났습니다. 꽤 간단하죠? 사실 Airflow Executor를 변경하거나 config를 수정하는 등 튜닝에 들어가면 설치부터 한없이 복잡해질 수 있습니다. 여기서는 모두 기본 값으로 선택해서 설치를 진행했습니다. 기본 환경을 충분히 경험하시고 넘어가시기를 바랍니다. 플랫폼을 깊이 있게 이해하면 나중에 어떤 환경으로 가던지 동작을 머릿속으로 그릴 수 있기 때문이죠. 

아무튼, 위의 과정을 진행하면서 딱히 예외상황도 없을 겁니다. 준비되어 있는 yaml 파일을 docker-compose로 한방에 설치했기 때문이죠. 혹시 있을만한 예외는 docker ps로 확인했을 때 컨테이너의 상태가 unhealthy인 경우가 있겠습니다.

$ docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS                                 PORTS                              NAMES
6f5660a7ff68        apache/airflow:2.1.0   "/usr/bin/dumb-init …"   18 hours ago        Up 9 hours (unhealthy)                 8080/tcp                           airflow_airflow-scheduler_1
56c71a4161e2        apache/airflow:2.1.0   "/usr/bin/dumb-init …"   18 hours ago        Up 2 minutes (health: starting)        0.0.0.0:5555->5555/tcp, 8080/tcp   airflow_flower_1
6a1b99e4da4c        apache/airflow:2.1.0   "/usr/bin/dumb-init …"   18 hours ago        Up 9 hours (unhealthy)                 8080/tcp                           airflow_airflow-worker_1
aa8f8611463f        apache/airflow:2.1.0   "/usr/bin/dumb-init …"   18 hours ago        Up About a minute (health: starting)   0.0.0.0:8080->8080/tcp             airflow_airflow-webserver_1
33ee4c7fee15        postgres:13            "docker-entrypoint.s…"   18 hours ago        Up 16 hours (healthy)                  5432/tcp                           airflow_postgres_1
e905d62b28f5        redis:latest           "docker-entrypoint.s…"   18 hours ago        Up 16 hours (healthy)                  0.0.0.0:6379->6379/tcp             airflow_redis_1

일반적이지는 않지만 대부분 worker 때문인데 container를 재시작해주면 해결됩니다. webserver가 unhealthy더라도 원인 파악에 어려움이 있다면 worker를 의심하고 재시작해주세요. 

$ docker restart 6a1b99e4da4c
6a1b99e4da4c
$ docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS                        PORTS                              NAMES
6f5660a7ff68        apache/airflow:2.1.0   "/usr/bin/dumb-init …"   18 hours ago        Up 2 minutes (healthy)        8080/tcp                           airflow_airflow-scheduler_1
56c71a4161e2        apache/airflow:2.1.0   "/usr/bin/dumb-init …"   18 hours ago        Up 4 minutes (healthy)        0.0.0.0:5555->5555/tcp, 8080/tcp   airflow_flower_1
6a1b99e4da4c        apache/airflow:2.1.0   "/usr/bin/dumb-init …"   18 hours ago        Up About a minute (healthy)   8080/tcp                           airflow_airflow-worker_1
aa8f8611463f        apache/airflow:2.1.0   "/usr/bin/dumb-init …"   18 hours ago        Up 4 minutes (healthy)        0.0.0.0:8080->8080/tcp             airflow_airflow-webserver_1
33ee4c7fee15        postgres:13            "docker-entrypoint.s…"   18 hours ago        Up 16 hours (healthy)         5432/tcp                           airflow_postgres_1
e905d62b28f5        redis:latest           "docker-entrypoint.s…"   18 hours ago        Up 16 hours (healthy)         0.0.0.0:6379->6379/tcp             airflow_redis_1

심도 있게 파악하려면 container의 로그를 살펴보시면 됩니다. e.g., docker logs [CONTAINER-ID]. 제 경우에는 Mac 잠자기에서 깨어날 때 worker에서 redis 쪽 pub/sub연결이 되지 않아서 unhealthy가 유지되는 걸 확인했습니다. 꼭 mac 깨우기가 아니더라도 airflow가 MacOS에서 실행이 깔끔하지 않기 때문에 가급적 *NIX 시스템 위에서 사용하는 게 좋습니다. 자, 그럼 다음 편에서는 GUI의 구성을 살펴보고 실제 DAG이 어떻게 동작하는지 살펴보도록 하겠습니다.

그런데 혹시.. 눈치채셨나요? postgres와 redis를 제외하고 다른 서비스는 모두 같은 이미지(airflow:2.1.0)를 사용하고 있답니다. entrypoint만 다르게 설정되어 있죠. 그렇기 때문에 어떤 컨테이너에 접속하든 같은 디렉터리 구조를 확인하실 수 있을 겁니다. 세부 내용이 궁금하신 분들은 아래 명령어를 통해 확인해보세요.

$ docker ps --no-trunc

 

# reference

'개발 > Apache Airflow' 카테고리의 다른 글

airflow 파라미터 튜닝  (4) 2021.07.05
docker-compose로 Airflow 한방에 설치하기  (0) 2021.06.21
Hello, Apache Airflow  (4) 2021.06.16
댓글
댓글쓰기 폼