FROM apache/airflow:2.11.0
RUN pip install --no-cache-dir \
"apache-airflow==2.11.0" \
"apache-airflow-providers-cncf-kubernetes==10.5.0" \
"apache-airflow-providers-standard==1.10.3" \
"apache-airflow-providers-common-compat>=1.7.2" \
"beautifulsoup4>=4.12.0" \
"lxml>=5.0.0" \
"slack-sdk>=3.27.0"
apache-airflow-providers-cncf-kubernetes : KubernetesPodOperator, SparkKubernetesOperator 사용에 필요AWS_PROFILE="<profile>"
AWS_REGION="ap-northeast-1"
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text --profile "$AWS_PROFILE")
# ECR 로그인
aws ecr get-login-password \
--region "$AWS_REGION" \
--profile "$AWS_PROFILE" \
| docker login --username AWS --password-stdin \
"${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
# 빌드 & 푸시
REPO_NAME="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/apache/airflow"
IMAGE_TAG=2.11.0-custom
docker build --platform linux/amd64 -t "${REPO_NAME}:${IMAGE_TAG}" .
docker push "${REPO_NAME}:${IMAGE_TAG}"
aws ecr describe-images \
--region "${AWS_REGION}" \
--repository-name "apache/airflow" \
--image-ids imageTag="${IMAGE_TAG}" \
--query 'imageDetails[0].imageDigest' \
--output text
apiVersion: v1
kind: Secret
metadata:
name: airflow-dag-repo-secret
namespace: airflow
type: Opaque
stringData:
GITSYNC_USERNAME: "<git_username>"
GITSYNC_PASSWORD: "<git_access_token>"
AWS_ACCESS_KEY_ID: "<aws_access_key>"
AWS_SECRET_ACCESS_KEY: "<aws_secret_key>"
AWS_DEFAULT_REGION: "ap-northeast-1"
kubectl apply -f secret.yaml
helm repo add apache-airflow https://airflow.apache.org
helm upgrade --install airflow apache-airflow/airflow \
--namespace airflow \
--create-namespace \
-f values.yaml
executor: "KubernetesExecutor"
images:
airflow:
repository: <account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/apache/airflow
tag: 2.11.0-custom
digest: sha256:<digest> # 버전 업데이트시 갱신
pullPolicy: IfNotPresent
nodeSelector:
nodegroup: "<on_demand_node_pool>"
tolerations:
- key: "nodegroup"
operator: "Equal"
value: "<on_demand_node_pool>"
effect: "NoSchedule"
workers:
nodeSelector: {} # 비워두면 Karpenter 가 자동으로 적절한 노드에 배치
tolerations: []
dags:
persistence:
enabled: false # Git Sync 사용 시 PVC 불필요
gitSync:
enabled: true
repo: "https://git.example.com/team/airflow-dag-repo.git"
branch: next
ref: next
depth: 1
period: 5s
credentialsSecret: "airflow-dag-repo-secret"
containerName: git-sync
uid: 65533
period: 5s : 5초마다 Git 변경사항 확인
credentialsSecret : 앞에서 생성한 Secret 참조
depth: 1 : shallow clone 으로 빠르게 동기화
DAG 레포지토리 구조 예시
airflow-dag-repo/
├── human_resource/
│ └── dag.py
├── game_doc_insight/
│ └── dag.py
└── ...
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: airflow-worker-spark-access
namespace: spark
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "patch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
- apiGroups: ["sparkoperator.k8s.io"]
resources: ["sparkapplications"]
verbs: ["create", "get", "list", "watch", "delete"]
- apiGroups: ["sparkoperator.k8s.io"]
resources: ["sparkapplications/status"]
verbs: ["get"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: airflow-worker-spark-access
namespace: spark
subjects:
- kind: ServiceAccount
name: airflow-worker
namespace: airflow
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: airflow-worker-spark-access
kubectl apply -f airflow-worker-spark-access.yaml
# SparkApplication 생성 가능 여부
kubectl auth can-i create sparkapplications.sparkoperator.k8s.io \
-n spark --as system:serviceaccount:airflow:airflow-worker
# Pod 로그 조회 가능 여부
kubectl auth can-i get pods/log \
-n spark --as system:serviceaccount:airflow:airflow-worker
helm delete airflow --namespace airflow