JUST WRITE

Kubernetes환경에서 Airflow를?!?! 본문

MLOps/Airflow

Kubernetes환경에서 Airflow를?!?!

천재보단범재 2023. 6. 28. 21:56

Helm으로 Airflow 설치

Kubernetes환경에서 Airflow를?!?!

요즘 가장 핫한 Workflow Tool은 Airflow입니다.

python으로 개발되어서 설치도 PyPl로 간편하게 설치할 수 있습니다.

하지만 디테일하게 사용하려면 Metastore, Celery Worker 등 설정할게 많습니다.

이러던 중 Kubernetes에 Airflow를 설치해야 될 업무를 맡게 되었습니다.

이번 포스팅에서는 Airflow를 Kubernetes 환경에 설치하는 것을 정리해 보았습니다.

Helm으로 Airflow 설치

Airflow에서 공식 Helm을 제공해 주기 때문에 해당 Helm으로 설치를 진행하였습니다.

다른 버전인 User-community Helm도 존재하니 참고해 주시길 바랍니다.

Airflow Helm Chart를 다운로드합니다.

$ helm repo add apache-airflow https://airflow.apache.org
"apache-airflow" has been added to your repositories

$ helm repo list
NAME                    URL                                                                     
apache-airflow          https://airflow.apache.org

$ helm search repo apache-airflow
NAME                    CHART VERSION   APP VERSION     DESCRIPTION                                       
apache-airflow/airflow  1.9.0           2.5.3           The official Helm chart to deploy Apache Airflo...

$ helm pull apache-airflow/airflow
$ ll
total 180K
drwxrwxr-x  6 ec2-user ec2-user   84 Jun 26 15:59 .
drwx------ 14 ec2-user ec2-user 4.0K Jun 26 15:27 ..
-rw-r--r--  1 ec2-user ec2-user 166K Jun 26 15:59 airflow-1.9.0.tgz

$ tar xzf airflow-1.9.0.tgz

git-sync 설정

Airflow는 dag 파일들을 git Repository에 연계해서 관리할 수 있습니다.

기본은 Airflow가 설치된 local path에서 dag 파일을 저장합니다.

dag 파일을 local path에서 관리하게 되면 삭제돼도 복구가 힘듭니다.

하지만 git Repository에서 관리하게 되면 복구는 물론 히스토리 관리까지 가능합니다.

이번 포스팅에서는 개인 github과 연계해 보겠습니다.

SSH Key 생성

SSH로 Github과 연결해야 되기 때문에 SSH Key를 먼저 생성하겠습니다.

Key 생성과 관련해서는 공식 Document에서 잘 정리되어 있습니다.

RSA 알고리즘으로 Key를 생성하도록 하겠습니다.

$ ssh-keygen -t rsa -b 4096 -C "perfectwan8765@gmail.com" 

Generating public/private rsa key pair.
Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa): /home/ec2-user/1_k8s_deploy/airflow-1.9.0-2.5.3/ssh/id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ec2-user/1_k8s_deploy/airflow-1.9.0-2.5.3/ssh/id_rsa.
Your public key has been saved in /home/ec2-user/1_k8s_deploy/airflow-1.9.0-2.5.3/ssh/id_rsa.pub.
The key fingerprint is:
SHA256:sgqv3PLFVyKzI9dm/8pQZBueMeuxCl5DbfRnJJFpZGY perfectwan8765@gmail.com
The key's randomart image is:
+---[RSA 4096]----+
|           .Eo   |
|           ++.   |
|          B.. .  |
|         * O o   |
|      + S @ . o  |
|     . O * o o   |
|  . . O O o      |
| ..+ * B *       |
|  o+= . . +o.    |
+----[SHA256]-----+


$ ll
total 12K
drwxrwxr-x 2 ec2-user ec2-user   38 Jun 27 16:22 .
drwxrwxr-x 8 ec2-user ec2-user 4.0K Jun 27 16:19 ..
-rw------- 1 ec2-user ec2-user 1.7K Jun 27 16:22 id_rsa
-rw-r--r-- 1 ec2-user ec2-user  389 Jun 27 16:22 id_rsa.pub

그럼 Private Key와 Public Key가 생성됩니다.

Public Key를 복사하여 Github에 등록해 줍니다.

Github SSH Public Key 등록
dag git repository

그리고 dag 파일을 관리할 Repository를 생성합니다.

예시 dag 파일(example.py)도 하나 생성하였습니다.

Private Key는 secret object로 생성합니다.

# namespace 생성
$ kubectl create namespace airflow
namespace/airflow created

$ kubectl get ns
NAME                   STATUS   AGE
airflow                Active   3s
default                Active   124d
kube-flannel           Active   124d
kube-node-lease        Active   124d
kube-public            Active   124d
kube-system            Active   124d
kubernetes-dashboard   Active   124d

# secret 생성
$ kubectl create secret generic \
  airflow-ssh-git-secret \
  --from-file=gitSshKey=/home/ec2-user/1_k8s_deploy/airflow-1.9.0-2.5.3/ssh/id_rsa \
  --namespace airflow

$ kubectl describe secret -n airflow airflow-ssh-git-secret
Name:         airflow-ssh-git-secret
Namespace:    airflow
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
gitSshKey:  1679 byte

Webserver Secret Key 생성

Airflow에서 WebServer로 flask를 사용합니다.

flask에서 session ID를 관리하기 위해서 필요합니다.

난수를 만들어서 secret object로 생성합니다.

$ python3 -c 'import secrets; print(secrets.token_hex(16))'
bc318d8aec88278e583ac029d99a6627

$ kubectl create secret generic airflow-webserver-secret --from-literal="webserver-secret-key=bc318d8aec88278e583ac029d99a6627" -n airflow

$ k get secret -n airflow
NAME                       TYPE     DATA   AGE
airflow-ssh-git-secret     Opaque   1      2m43s
airflow-webserver-secret   Opaque   1      2m29s

values-override yaml 생성

이제 helm 설정값인 values 파일을 세팅합니다.

values-override.yaml을 생성해서 필요한 부분만 override 되도록 합니다.

$ vi values-override.yaml

executor: "KubernetesExecutor" 
webserverSecretKey: webserver-secret-key
webserverSecretKeySecretName: airflow-webserver-secret
data:
  metadataConnection:
    user: user
    pass: password
    db: airflow
dags:
  gitSync:
    enabled: true
    repo: git@github.com:test/airflow-test.git
    branch: main
    rev: HEAD
    depth: 1
    maxFailures: 3
    subPath: dags
    sshKeySecret: "airflow-ssh-git-secret"
    wait: 60
scheduler:
  livenessProbe:
    initialDelaySeconds: 10
    timeoutSeconds: 120
    failureThreshold: 20
    periodSeconds: 60
  replicas: 2
webserver:
  service:
    type: NodePort
    ports:
       - name: airflow-ui
         port: "{{ .Values.ports.airflowUI }}" 
         targetPort: "{{ .Values.ports.airflowUI }}" 
         nodePort: 31151
postgresql:
  enabled: true
  image:
    tag: 11.22.0
  auth:
    enablePostgresUser: true
    postgresPassword: postgres
    username: user 
    password: password
    database: "airflow" 
  primary:
    service:
      type: NodePort
      nodePorts:
        postgresql: 30032
    persistence:
      size: 20Gi
redis:
  enabled: false
env:
  - name: "AIRFLOW__LOGGING_REMOTE_LOGGING"
    value: "True"
  - name: "AIRFLOW__LOGGING__REMOTE_LOG_CONN_ID"
    value: "S3Conn"
  - name: "AIRFLOW__LOGGING__REMOTE_BASE_LOG_FOLDER"
    value: "s3://{bucket명}/airflow/logs"
  - name: "AIRFLOW__LOGGING__ENCRYPT_S3_LOGS"
    value: "False"
  - name: "AIRFLOW__CORE__DEFAULT_TIMEZONE"
    value: "Asia/Seoul"

executor는 LocalExecutor, LocalKubernetesExecutor, CeleryExecutor, KubernetesExecutor, CeleryKubernetesExecutor 등이 있습니다.

이번 포스팅에서는 KubernetesExecutor로 진행하겠습니다.

아까 생성한 Webserver secret도 설정합니다.

executor: "KubernetesExecutor" 
webserverSecretKey: webserver-secret-key
webserverSecretKeySecretName: airflow-webserver-secret

dag 파일을 git repository인 github에서 가져오도록 설정합니다.

Private Key로 생성한 secret를 설정합니다.

dags:
  gitSync:
    enabled: true
    repo: git@github.com:test/irflow-test.git
    branch: main
    rev: HEAD
    depth: 1
    maxFailures: 3
    subPath: dags
    sshKeySecret: "airflow-ssh-git-secret"
    wait: 60

Metastore는 PostgreSQL를 사용합니다.

Production으로 사용하는 거면 외부 PostgreSQL로 사용하는 것을 권장합니다.

이번 포스팅에서는 Airflow helm chart dependency로 설정된 bitnami PostgreSQL로 구성하였습니다.

 

postgresql 12.5.8 · bitnami/bitnami

PostgreSQL (Postgres) is an open source object-relational database known for reliability and data integrity. ACID-compliant, it supports foreign keys, joins, views, triggers and stored procedures.

artifacthub.io

data:
  metadataConnection:
    user: user
    pass: password
    db: airflow
postgresql:
  enabled: true
  image:
    tag: 11.22 
  auth:
    enablePostgresUser: true
    postgresPassword: postgres
    username: user 
    password: password
    database: "airflow" 
  primary:
    service:
      type: NodePort
      nodePorts:
        postgresql: 30032
    persistence:
      size: 20Gi

Scheduler의 설정값을 일부 조정하였습니다.

default값으로 scheduler가 자주 restart가 되었습니다.

airflow scheduler의 liveness 응답이 늦어져 죽었다고 판단해 restart가 빈번하게 발생하였습니다.

아래 airflow github issue를 참고해서 설정하였습니다.

 

Slow liveness probe causes frequent restarts (scheduler and triggerer) · Issue #19001 · apache/airflow

Apache Airflow version 2.2.0 (latest released) Operating System official docker image Versions of Apache Airflow Providers No response Deployment Official Apache Airflow Helm Chart Deployment detai...

github.com

scheduler:
  livenessProbe:
    initialDelaySeconds: 10
    timeoutSeconds: 120
    failureThreshold: 20
    periodSeconds: 60
  replicas: 2

 

WebServer의 Service를 NodePort로 설정하여 외부에서도 접근하도록 설정하였습니다.

webserver:
  service:
    type: NodePort
    ports:
       - name: airflow-ui
         port: "{{ .Values.ports.airflowUI }}" 
         targetPort: "{{ .Values.ports.airflowUI }}" 
         nodePort: 31151

Airflow log를 Kubernetes pv가 아닌 바로 remote로 S3 같은 Storage에 저장 가능합니다.

환경변수로 아래 설정값들을 추가해 줍니다.

  • AIRFLOW__LOGGING_REMOTE_LOGGING
  • AIRFLOW__LOGGING_REMOTE_LOG_CONN_ID
  • AIRFLOW__LOGGING_REMOTE_BASE_LOG_FOLDER
  • AIRFLOW__LOGGING_ENBRYPT_S3_LOGS

추가적으로 환경변수 설정을 통해서 Timezone 설정을 합니다.

env:
  - name: "AIRFLOW__LOGGING_REMOTE_LOGGING"
    value: "True"
  - name: "AIRFLOW__LOGGING__REMOTE_LOG_CONN_ID"
    value: "S3Conn"
  - name: "AIRFLOW__LOGGING__REMOTE_BASE_LOG_FOLDER"
    value: "s3://{bucket명}/airflow/logs"
  - name: "AIRFLOW__LOGGING__ENCRYPT_S3_LOGS"
    value: "False"
  - name: "AIRFLOW__CORE__DEFAULT_TIMEZONE"
    value: "Asia/Seoul"

Helm Install

이제 설정이 끝나고 Helm으로 Install 하겠습니다.

$ helm install airflow -n airflow -f values-override.yaml ./

NAME: airflow
LAST DEPLOYED: Tue Jun 27 16:56:31 2023
NAMESPACE: airflow
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Thank you for installing Apache Airflow 2.5.3!

Your release is named airflow.
You can now access your dashboard(s) by executing the following command(s) and visiting the corresponding port at localhost in your browser:

Airflow Webserver:     kubectl port-forward svc/airflow-webserver 8080:8080 --namespace airflow
Default Webserver (Airflow UI) Login credentials:
    username: *****
    password: *****
Default Postgres connection credentials:
    username: ********
    password: ********
    port: 5432

You can get Fernet Key value by running the following:

    echo Fernet Key: $(kubectl get secret --namespace airflow airflow-fernet-key -o jsonpath="{.data.fernet-key}" | base64 --decode)

WARNING:
    Kubernetes workers task logs may not persist unless you configure log persistence or remote logging!
    Logging options can be found at: https://airflow.apache.org/docs/helm-chart/stable/manage-logs.html
    (This warning can be ignored if logging is configured with environment variables or secrets backend)

###########################################################
#  WARNING: You should set a static webserver secret key  #
###########################################################

You are using a dynamically generated webserver secret key, which can lead to
unnecessary restarts of your Airflow components.

Information on how to set a static webserver secret key can be found here:
https://airflow.apache.org/docs/helm-chart/stable/production-guide.html#webserver-secret-key


$ kubectl get all -n airflow
NAME                                     READY   STATUS    RESTARTS        AGE
pod/airflow-postgresql-0                 1/1     Running   1 (4m21s ago)   9h
pod/airflow-scheduler-6fd5969f4b-x5skw   3/3     Running   3 (4m21s ago)   9h
pod/airflow-statsd-59cf4979b6-9cb8n      1/1     Running   1 (4m21s ago)   9h
pod/airflow-triggerer-876bb488d-jq2nx    3/3     Running   3 (4m21s ago)   9h
pod/airflow-webserver-84cdfb5dc9-xlrs6   1/1     Running   1 (4m21s ago)   9h

NAME                            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
service/airflow-postgresql      NodePort    10.97.226.10   <none>        5432:30032/TCP      9h
service/airflow-postgresql-hl   ClusterIP   None           <none>        5432/TCP            9h
service/airflow-statsd          ClusterIP   10.97.74.187   <none>        9125/UDP,9102/TCP   9h
service/airflow-webserver       NodePort    10.103.30.10   <none>        8080:31151/TCP      9h

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/airflow-scheduler   1/1     1            1           9h
deployment.apps/airflow-statsd      1/1     1            1           9h
deployment.apps/airflow-triggerer   1/1     1            1           9h
deployment.apps/airflow-webserver   1/1     1            1           9h

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/airflow-scheduler-6fd5969f4b   1         1         1       9h
replicaset.apps/airflow-statsd-59cf4979b6      1         1         1       9h
replicaset.apps/airflow-triggerer-876bb488d    1         1         1       9h
replicaset.apps/airflow-webserver-84cdfb5dc9   1         1         1       9h

NAME                                  READY   AGE
statefulset.apps/airflow-postgresql   1/1     9h

admin 계정의 default password는 admin입니다.

WebServer에 접속하면 git Repository에 있는 dag를 확인할 수 있습니다.

WebServer UI

구성한 Airflow를 활용해 보면서 좀 더 Airflow에 대해서 살펴보도록 하겠습니다.

[참고사이트]

더보기
728x90
반응형

'MLOps > Airflow' 카테고리의 다른 글

뭐야?! No Space left on device?! - Airflow db clean  (0) 2023.09.20
Airflow Variables 세팅 - 전역변수 설정  (0) 2023.07.23
How Airflow works?  (0) 2022.03.24
What is Airflow?  (0) 2022.03.23
Comments