data engineering

customizing helm chart (bitnami/airflow)

qkqhxla1 2021. 8. 19. 13:43

이전에 다른 제목으로 비슷한 글을 쓴적이 있는데 지금 보니까 정말 별다른 영양가가 없는 글이었다. 그래서 이전 글은 지워버리고 이번에 새로 얻은 지식까지 합쳐서 다시 정리한다.
이전에도 적은것같지만 bitnami라는 회사가 있는데 오픈소스로 helm chart를 상당히 많이 만들었고, 상당히 자주 업데이트해주면서 종류도 많고 완성도도 높아서 여기서 주로 가져다가 app을 만들어서 쓴다. k8s와 helm자체에 익숙하지 않았기에 여태까지는 기본으로 제공해주는 기능만 썼는데 더 필요한 기능이 있어도 수정할줄을 모르고.. 이러다보니 반쪽짜리 지식이 되버렸다. 빡쳐서 주말동안 커스터마이징을 하기 위해 공부와 삽질하고, 얻은 지식을 정리한다. 


우선 목적을 적자면 airflow helm chart를 설치해서, airflow를 단순 공부용이 아니라 실제로 잘 쓰는게 목적이다.
1. 프로덕션 환경에서 쓰려고 하므로 소스 관리가 git 으로 되어야 한다.
2. 아주 기본적인 airflow에서의 파이썬을 사용한 일관적인 작업뿐만 아니라 spark submit을 쓸것이므로 spark를 세팅해야 한다.
3. 도커를 사용할 예정이므로 docker in docker를 해야 한다.
4. 파이썬 모듈을 새로 설치할경우에 pip install을 어떻게 할것인가의 문제. 주기적으로 cron을 돌려줄것인가? 아니면 다른 방법이 있나.


내가 설치하려고 하는 airflow는 https://artifacthub.io/packages/helm/bitnami/airflow 다.
글쓴 날짜 기준으로 가장 최신버전은 10.2.8버전이고, 이걸 커스터마이징해볼 예정이다. 

처음엔 테스트용으로 단순히 기본적인 인자만 줘서 띄워봤다.
주의할 점이 있는데 airflow는 매 테스트마다 persistent volume을 매번 지우고 새로 만들어서 테스트한다. 이전 db정보가 남아서 새로 띄울때 에러가 발생한다.

helm install airflow bitnami/airflow -n airflow `# airflow라는 이름으로 설치, -n 옵션은 네임스페이스 세팅` \
  --set global.storageClass=ebs-volume `# persistent class는 ebs-volume으로 함.(내가 이전에 등록해놓은)` \
  --set auth.username=admin `# airflow web id` \
  --set auth.password=admin `# airflow web pw`

--set 으로 설정한 변수들의 값은 위에 내가 올린 링크에서 검색해보자.

잘 올라왔다. 웹서버같은경우 현재 내부에서만 접근 가능하므로 ingress를 달거나, 아니면 권장되지 않는 방법으로 hostport로 8080포트를 열어주면 된다. 현재는 테스트이므로 hostport로 8080포트를 열어서 테스트를 진행했다.

8080포트를 포워딩하고 들어가서 admin/admin으로 로그인하면 깔끔해진듯한 ui가 잘 뜬다.
이제는 git연동을 해볼 차례이다. 위의 artifacthub에서 git으로 검색해보면 다양한 인자가 나온다. 깃과 연동을 하기 위해서는 깃에서 토큰을 발급 받아야 한다. 이 글을 참조하자. 토큰을 발급받을때 토큰에 줄 권한을 체크해야 하는데, 나같은경우 repo에 관한 모든 권한을 체크하니 작동했다. 아래처럼 만들었다.

helm install airflow bitnami/airflow -n airflow `# airflow라는 이름으로 설치, -n 옵션은 네임스페이스 세팅` \
  --set global.storageClass=ebs-volume `# persistent class는 ebs-volume으로 함.(내가 이전에 등록해놓은)` \
  --set auth.username=admin `# airflow web id` \
  --set auth.password=admin `# airflow web pw` \
  --set git.dags.enabled=true \
  --set git.dags.repositories[0].branch=master \
  --set git.dags.repositories[0].repository=https://{내 깃 아이디}:{깃 토큰}@{github.net 도메인}/{회사 아이디}/{깃 이름].git \
  --set git.dags.repositories[0].name=my-airflow

my-airflow에는 현재 루트에 DAGS란 폴더가 있고, 그 안에 dag_test.py라는 테스트용 소스가 하나 들어가있다.

저리설정해주면 깃에 머지할때마다 자동으로 pull받아와서 웹에 보이는 dag에 적용이 된다. 업데이트 체크를 매분 하느라 상당히 빨리 적용된다.

ui에 알아서 내가 내부에 만든 docker_dag가 포함된다. docker_dag는 아래와 같다. 테스트용으로 여러개 넣어봤다.

더보기
from airflow import DAG
from airflow.operators.dummy import DummyOperator
from airflow.operators.python import PythonOperator
from airflow.operators.bash_operator import BashOperator

from datetime import datetime

dag = DAG(
    'docker_dag',
    schedule_interval="0 0 * * 1",
    start_date=datetime(2020, 10, 19),
    catchup=False
)

def print_hello():
    return 'Hello world!'

start = DummyOperator(task_id='start', dag=dag)

end = DummyOperator(task_id='end', dag=dag)

job1 = PythonOperator(
    task_id='hello_task',
    dag=dag,
    python_callable=print_hello)

job2 = BashOperator(
    task_id='echo_test',
    bash_command='echo 1',
)

job3 = BashOperator(
    task_id='run_after_loop',
    bash_command='/my_spark/test.sh ',
)

start >> job1 >> job2 >> job3 >> end

테스트로 만든 airflow job을 실행시켜봤다. job3는 저 경로에 test.sh가 존재하지 않기에 에러를 예상했지만 나온 에러가 내 예상과 달랐다.

airflow가 분산 환경이라 문제가 생긴것같다.. 저거 하나때문에 별 난리를 다쳤는데 중간 단계가 몇단계 더 있지만 결국은 https://github.com/bitnami/bitnami-docker-airflow/issues/91 요 글에서 나온것처럼 로그를 persist하게 저장하는 방법으로 해결했다.
적어보자면 persistent volume을 새로 하나 만들어서 airflow-web, airflow-worker두 컨테이너의 동일한 위치 /ebs에 마운트했다. 이후 위 두개의 컨테이너의 환경변수 AIRFLOW__CORE__BASE_LOG_FOLDER : /ebs/logs 로 세팅해서 로그 파일 위치를 만든 ebs로 변경해주었다. 당연한 얘기이지만 로그를 설정한 경로로 airflow 를 돌리는 데몬이 쓸 권한이 있어야 한다.

이제 spark-submit을 해야하는데 그러려면 spark가 있어야 한다. 이건 어떻게 추가해야하나? 하다가 쉘로 airflow-web이나 airflow-worker컨테이너로 들어가봤는데 기본적으로 root가 아니다. uid 1001의 유저이다. 루트가 아니면 apt-get install같은게 전부 안된다. 난 airflow가 전부 올라온 후에 올라온 컨테이너에 추가로 spark를 다운받으려고 했는데 계획이 어그러졌다는 소리이다.
참고로 bitnami에서 만들어진 컨테이너의 유저 권한이 왜 root가 아닌지는 요 링크를 읽어보자. 보안에 좋다고 한다.
어쨌든 artifacthub에서 인자를 더 찾아봤는데 답이 없다. containerSecurityContext.enabled라는 옵션이 있어서 보안적인 요소를 끌수 있는데, 이걸 꺼도 primary컨테이너만 root가 되지, sidecar로 되어있는 airflow-web등은 여전히 논 루트 유저 상태이다. 이건 자세히 더 설명하기가 힘든데 궁금하면 직접 삽질해보자. 어쨌든 안되었음.

결국 짜잘하게 bitnami에서 제공하는 인자들을 변경하기보다는 helm chart에서 사용하는 도커 이미지 자체를 내가 수정하기로 결심했다.
helm이 bitnami라는 repo에서 app을 설치하는 프로세스가 내가 helm install 로 설치할 시에 어딘가에 있는 helm chart를 참조해서 거기서 가져올 도커 이미지를 정하고, 그 도커 이미지를 순서대로 올릴거다. 그럼 일단 살펴보기위해서 내 로컬의 어딘가에 있는 helm chart위치를 찾아봐야겠다. 구글링해보니 나왔다. 스택오버플로우 링크
helm env를 입력해보니 HELM_REPOSITORY_CACHE 환경변수에 위치가 있다. 들어가보니 압축된 chart들이 많다.

.tgz로 압축된 것들이 내가 예전에 깔아봤던 chart들이다. airflow-10.2.8.tgz를 압축풀고 내부로 들어가보았다.

저기서 values.yaml이 값을 설정하는 부분이다. 내가 위에서 helm install로 설치할때 --set등으로 값을 설정했는데, 그게 여기의 values.yaml값을 덮어씌우는거다. https://helm.sh/ko/docs/intro/using_helm/ 에서 --set, --values 가 나오는 파트를 읽어보자.
어쨌든 잘 찾았으니 bitnami/airflow가 어떤 도커 이미지를 참조하는지 보자. 중간에 보면

worker:
  ## Bitnami Airflow Worker image version
  ## ref: https://hub.docker.com/r/bitnami/airflow-worker/tags/
  ## @param worker.image.registry Airflow Worker image registry
  ## @param worker.image.repository Airflow Worker image repository
  ## @param worker.image.tag Airflow Worker image tag (immutable tags are recommended)
  ## @param worker.image.pullPolicy Airflow Worker image pull policy
  ## @param worker.image.pullSecrets Airflow Worker image pull secrets
  ## @param worker.image.debug Enable image debug mode
  ##
  image:
    registry: docker.io
    repository: bitnami/airflow-worker
    tag: 2.1.2-debian-10-r16

요런 부분이 있다. airflow-worker는 저 이미지를 참조한다는거고, docker로 검색해보면 scheduler나 web은 무슨 이미지를 참조하는지 나온다. 난 worker 이미지를 수정할거므로 위의 repository인 bitnami/airflow-worker를 찾아봤다.

github : https://github.com/bitnami/bitnami-docker-airflow-worker
docker image : https://hub.docker.com/r/bitnami/airflow-worker/tags?page=1&ordering=last_updated&name=2.1.2-debian-10-r16

찾았다. 내가 원하도록 이미지를 수정하려면 Dockerfile을 수정하고 재빌드를 해서 도커 이미지를 회사 도커 허브에 올려놓기로 생각했다. 깃헙에서 2.1.2-debian을 찾아보니까 2/debian-10에 있다. 들어가보니 Dockerfile이 있다.
https://github.com/bitnami/bitnami-docker-airflow-worker/tree/master/2/debian-10
1/debian-10에도 따로 Dockerfile이 있는거보니까 파이썬 2,3버전처럼 debian 1버전과 2버전이 따로 가고 있는 상황 같다. 깃 소스를 다운받아서, 2버전 Dockerfile이 있는곳이 2버전의 홈이라고 가정하고 거기에 build.sh로 빌드 스크립트를 간단히 하나 만들었다.

#! /bin/bash
REPOSITORY="회사도커허브/my-repository/my_airflow_worker"

TAG=1

docker build -t $REPOSITORY:$TAG .
docker build -t $REPOSITORY .

docker push $REPOSITORY:$TAG
docker push $REPOSITORY

도커 빌드시 Dockerfile 위치를 따로 주지 않으면 빌드하는 위치에서 Dockerfile을 찾는다. build.sh의 위치가 2버전 Dockerfile이 있는곳이니까 알아서 이걸 참조해서 빌드할거다.
만약 이 위치와 이 파일이 맞으면 helm install시에 airflow-worker의 docker image를 bitnami의 이미지가 아니라 내가 재빌드해서올린 my_airflow_worker로 변경해도 동일하게 정상적으로 동작할 것이다.
빌드후 artifacthub에서 worker가 사용하는 도커 이미지 관련 변수가 뭔지 찾아보았다.
worker.image.registry, worker.image.repository, worker.image.tag 요 3개가 도커 주소를 설정하는것 같다.

helm install airflow bitnami/airflow -n airflow `# airflow라는 이름으로 설치, -n 옵션은 네임스페이스 세팅` \
  --set global.storageClass=ebs-volume `# persistent class는 ebs-volume으로 함.(내가 이전에 등록해놓은)` \
  --set auth.username=admin `# airflow web id` \
  --set auth.password=admin `# airflow web pw` \
  --set git.dags.enabled=true \
  --set git.dags.repositories[0].branch=master \
  --set git.dags.repositories[0].repository=https://{내 깃 아이디}:{깃 토큰}@{github.net 도메인}/{회사 아이디}/{깃 이름].git \
  --set git.dags.repositories[0].name=my-airflow
  --set worker.image.registry={회사 도커 허브 주소} \
  --set worker.image.repository={도커 repository 위치} \
  --set worker.image.tag=latest \
  --set worker.image.pullPolicy=Always `# 이걸 안 넣어주면 이전에 한번 실패한 이미지가 있을경우 내가 새로 올려도 이미지를 안 땡겨온다. 기본이 IfNotPresent이기 때문`

이전하고 똑같이 잘 돈다. 난 rancher gui를 쓰기에 아래처럼 확인이 가능했다. 계속 테스트하다가 발견한건데 위처럼 --set으로 주면 도커 이미지를 땡겨오는데 종종 버그가 있다.(될때도 있고 안될때도 있음. 이유는 불명) helm으로 설치시 --set으로 설정하기보다는 values.yaml에 넣어놓고 -f옵션으로 참조하는 방식이 더 잘되는것 같다.

내가 이미지를 새로 빌드해서 올렸을때도 잘 동작하는걸 알았으니 이제 내가 필요한것들을 커스터마이징하자.
현재 spark 3.0.1을 사용한다. 여기에서 다운받아놓고 2/debian-10/Dockerfile에 아래 명령어를 적당한 위치에 추가하자.

RUN apt update
# install java
RUN apt install -y default-jdk
# set pyspark python path
ENV PYSPARK_PYTHON=/opt/bitnami/python/bin/python
COPY spark-3.0.1-bin-hadoop3.2 /opt/spark
# install docker cli for debian.
RUN apt-get update
RUN apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
RUN echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
RUN apt-get update
RUN apt-get install -y docker-ce docker-ce-cli containerd.io

을 적당히 위쪽에 추가해준다. 이미지를 빌드한 후 이미지로 들어가서 spark-shell을 실행시켜봤는데 에러가 발생한다..

이거는 삽질하다 발견했는데, spark-shell을 root로 실행하면 잘 실행되는데 non root계정으로 실행하면 저런 에러가 발생했다. 엄청 삽질하다가 찾아봤더니 https://stackoverflow.com/questions/62726949/how-to-launch-spark-3-0-0-kubernetes-workload-without-kerberos 에서 spark_uid관련해서 어떻게 잘 설정해주면 non root상태에서도 된다고 하는데 안된다.. 찾다가 못찾아서 그냥 기본적으로 실행되는 uid인 1001을 root그룹으로 격상시키기로 하고 USER 1001라인 위에 RUN echo "airflow:x:1001:0:root:/root:/bin/bash" >> /etc/passwd 을 추가했다. 이건 더 좋은 해결법을 찾으면 추가 예정.. airflow 데몬이 돌아가는 airflow계정의 그룹을 루트로 만들어버렸으니 보안상 결함이 생겨서 만든사람이 의도한것보다 보안이 약하게 되었는데... 다른 방법이 안보인다.

어쨌든 주석처리하니 spark는 위처럼 root그룹으로 실행이 잘 되었고, 이제 airflow에서 도커를 사용하기 위해 docker in docker를 세팅할 예정이다.(사실 위 Dockerfile에 이미 추가했는데 지금 적음.) docker in docker의 개념은 요 블로그 글에 가장 잘 정리되어있다. 추가로 요 스택오버플로우 글도 읽어보자.
docker in docker의 원리를 간단하게 적어보자면 도커가 설치되면 '도커 데몬' 과 '도커 CLI'가 있는데 '도커 데몬'이 빌드하거나 컨테이너를 돌리는 등 실질적인 모든 역할을 수행한다. '도커 CLI'는 명령을 받아서 '도커 데몬'으로 전달하는 역할을 한다. 명령을 전달할때 사용되는게 /var/run/docker.sock소켓이다.
결국 도커 외부의 도커 소켓을 공유받아서 도커 내부에서 사용하는 방식이고 내가 위에 링크한 스택오버플로우 글에서처럼 단순하게 소켓만 같은 위치에 공유하면 되는게 아니라 도커 CLI를 설치해야 한다. 도커 설치 공식 홈페이지(우분투)
왜 도커 안에 도커를 설치해서 쓰는 방식이 아니라 외부의 소켓을 공유하는 방식을 쓰는지는 이 글을 읽어보자.

쿠버네티스에서 도커 컨테이너는 pod이라는 개념 위에서 돌아가더라도 결국 노드 위에 있으니 그냥 일반적인 docker in docker를 하듯이 /var/run/docker.sock을 마운트로 공유해주고 도커 CLI를 설치해주면 된다.
https://applatix.com/case-docker-docker-kubernetes-part-2/ 이 글도 읽어보자.

도커 CLI 설치는 위 Dockerfile에 이미 적혀있다. 마운트한 gui 캡쳐본을 한번 올린다.

airflow-log는 새로 만든 persistent volume(aws ebs)으로 위에서 AIRFLOW__CORE__BASE_LOG_FOLDER : /ebs/logs를 설명할때 추가해주었다. 아래는 도커 소켓을 마운트해준거다.
그리고 아래에 docker라는 이름으로 /var/run/docker.sock을 컨테이너 내부로 포워딩해준다. 저런식으로 포워딩해주고 내부에 도커 CLI를 설치한뒤 docker ps로 확인했는데 권한이 없다고 에러가 뜬다.
요 글이 가장 도움이 되었다 : docker in docker for non root
원인은 희안하게 cat /etc/group | grep docker으로 docker그룹의 gid를 출력해보면 999가 나오는데, ls -al /var/run/docker.sock으로 도커 소켓의 그룹을 확인해보면 1101이라는 존재하지 않는 gid로 만들어져있다. 내가 만든 airflow 계정이 1101 그룹 안에 속해있어야 한다.
RUN groupadd -o -g 1101 airflow-docker
RUN usermod -aG airflow-docker airflow
을 Dockerfile에 추가해주었다. 최종적으로 사용한 airflow-worker Dockerfile은 맨 아래에 있다.

이제 pip 설치문제를 해결해야 한다. 처음에는 crontab을 설치해준 후에 5분마다 내 깃에서 가져온 특정 위치의 requirements.txt를 pip install해주기로 했다. 근데 이게 도커 내부로 들어가니까 쉬운문제가 아니다.
Dockerfile에 RUN으로 크론을 실행해주면 RUN은 도커 이미지가 만들어지는 경우에만 동작하므로 이미지가 만들어지는동안에 떴다가 바로 죽어버린다. 내가 도커 컨테이너를 실행시킨후 cron을 다시 수동으로 올려줘야 한다는건데 그러면 의미가 없다. https://stackoverflow.com/questions/58583067/docker-container-crontab-not-running
이후에도 entrypoint.sh스크립트 안에서 실행해보는등 별 난리를 쳐봤는데 cron process는 돌고있는데 크론탭이 실행이 안되는등 버그가 많아서 그냥 https://artifacthub.io/packages/helm/bitnami/airflow에 /bitnami/python/requirements.txt위치에 넣어두면 자동으로 컨테이너가 올라올때마다 pip install을 해준다고 해서 저 위치에 내 깃을 추가로 마운트하는 방식으로 해결했다.
이러면 python package가 추가되면 worker들을 리디플로이해서 추가하는 방법밖에 없는데 일단 어느정도 합리적이어서 이리 처리해둠.

최종 Dockerfile.

더보기
FROM docker.io/bitnami/minideb:buster
LABEL maintainer "Bitnami <containers@bitnami.com>"

ENV BITNAMI_PKG_EXTRA_DIRS="/opt/bitnami/airflow/dags" \
    HOME="/" \
    OS_ARCH="amd64" \
    OS_FLAVOUR="debian-10" \
    OS_NAME="linux"

COPY prebuildfs /
# Install required system packages and dependencies

RUN install_packages acl ca-certificates curl gzip libbsd0 libbz2-1.0 libc6 libcom-err2 libedit2 libffi6 libgcc1 libgmp10 libgnutls30 libgssapi-krb5-2 libhogweed4 libicu63 libidn2-0 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 libldap-2.4-2 liblzma5 libmariadb3 libncursesw6 libnettle6 libp11-kit0 libreadline7 libsasl2-2 libsqlite3-0 libssl1.1 libstdc++6 libtasn1-6 libtinfo6 libunistring2 libuuid1 libxml2 libxslt1.1 locales netbase procps tar zlib1g
RUN . /opt/bitnami/scripts/libcomponent.sh && component_unpack "wait-for-port" "1.0.0-3" --checksum 7521d9a4f9e4e182bf32977e234026caa7b03759799868335bccb1edd8f8fd12
RUN . /opt/bitnami/scripts/libcomponent.sh && component_unpack "python" "3.8.11-0" --checksum 28b91ef5db9ad93e704881400703e4085bd82f016be15e3cf8760df044da9490
RUN . /opt/bitnami/scripts/libcomponent.sh && component_unpack "postgresql-client" "10.18.0-0" --checksum bc507be929b72ee456f46c031a5c2ab4b6433175d2bbb6fc6a74da565ab3cb08
RUN . /opt/bitnami/scripts/libcomponent.sh && component_unpack "ini-file" "1.4.0-0" --checksum 88093e848950fd09e80eb26cac55caa11e77aa78f118b5dc67faa38a3836381d
RUN . /opt/bitnami/scripts/libcomponent.sh && component_unpack "gosu" "1.13.0-0" --checksum fd7257c2736164d02832dbf72e2c1ed9d875bf3e32f0988520796bc503330129
RUN . /opt/bitnami/scripts/libcomponent.sh && component_unpack "airflow-worker" "2.1.2-0" --checksum 48f73b91766f036923aeb072611a7ec0adef8d840d53624a1d17dfb39c0da3a7
RUN chmod g+rwX /opt/bitnami
RUN localedef -c -f UTF-8 -i en_US en_US.UTF-8
RUN update-locale LANG=C.UTF-8 LC_MESSAGES=POSIX && \
    DEBIAN_FRONTEND=noninteractive dpkg-reconfigure locales
RUN echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen && locale-gen

COPY rootfs /
RUN /opt/bitnami/scripts/airflow-worker/postunpack.sh
RUN /opt/bitnami/scripts/locales/add-extra-locales.sh
ENV AIRFLOW_HOME="/opt/bitnami/airflow" \
    BITNAMI_APP_NAME="airflow-worker" \
    BITNAMI_IMAGE_VERSION="2.1.2-debian-10-r27" \
    C_FORCE_ROOT="True" \
    LANG="en_US.UTF-8" \
    LANGUAGE="en_US:en" \
    LD_LIBRARY_PATH="/opt/bitnami/python/lib/:/opt/bitnami/airflow/venv/lib/python3.8/site-packages/numpy.libs/:$LD_LIBRARY_PATH" \
    LIBNSS_WRAPPER_PATH="/opt/bitnami/common/lib/libnss_wrapper.so" \
    LNAME="airflow" \
    NSS_WRAPPER_GROUP="/opt/bitnami/airflow/nss_group" \
    NSS_WRAPPER_PASSWD="/opt/bitnami/airflow/nss_passwd" \
    PATH="/opt/bitnami/common/bin:/opt/bitnami/python/bin:/opt/bitnami/postgresql/bin:/opt/bitnami/airflow/venv/bin:$PATH"

# install java
RUN apt update
RUN apt install -y default-jdk
# set pyspark python path. python path in 'airflow' check.
ENV PYSPARK_PYTHON=/opt/bitnami/airflow/venv/bin/python
COPY spark-3.0.1-bin-hadoop3.2 /opt/spark
# install docker CLI
RUN apt-get update
RUN apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release \
    vim  # install vi
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
RUN echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
RUN apt-get update
RUN apt-get install -y docker-ce docker-ce-cli containerd.io

# uid 1001 to root group
RUN echo "airflow:x:1001:0:root:/root:/bin/bash" >> /etc/passwd
# for pip install.
RUN mkdir -m775 /.local
# for docker executable. # ls -al /var/run/docker.sock, cat /etc/group
RUN groupadd -o -g 1101 airflow-docker
RUN usermod -aG airflow-docker airflow

EXPOSE 8793
USER 1001
ENTRYPOINT [ "/opt/bitnami/scripts/airflow-worker/entrypoint.sh" ]
CMD [ "/opt/bitnami/scripts/airflow-worker/run.sh" ]

커스터마이징은 완료되었는데 airflow worker말고 다른 이미지는 private한 registry에 저장해야한다고 한다. 현재 사용하는 이미지 중 하나는 다음과 같다 : bitnami/airflow:2.1.4-debian-10-r5
커스터마이징을 추가로 할 필요는 없고, 단순히 공용 registry에서 private registry로 옮겨주기만 하면 되므로..
검색해본다 : https://hub.docker.com/search?q=bitnami%2Fairflow&type=image
들어가서 tag를 검색해본다 : https://hub.docker.com/r/bitnami/airflow/tags?page=1&name=2.1.4-debian-10-r5
이미지를 받아와 작업한다.

$ docker pull bitnami/airflow:2.1.4-debian-10-r5  # 이미지를 받아옴.
$ docker image ls | grep airflow  # tag확인
bitnami/airflow         2.1.4-debian-10-r5             3588ac2a1d1c   3 weeks ago    1.93GB
$ docker image tag 3588ac2a1d1c {private registry주소}/app/airflow:2.1.4-debian-10-r5  # rename해준다.
$ docker image push {private registry주소}/app/airflow:2.1.4-debian-10-r5  # private registry로 push

후에 airflow가 사용하는 values.yaml에서 이미지를 받아올 주소를 추가해준다.

................................
web:
  image:
    registry: {private registry주소}
    repository: /app/airflow
    tag: 2.1.4-debian-10-r5
.................................

이후 values.yaml을 사용해서 빌드하면 private registry를 사용해서 땡겨가는걸 알 수 있음. --set을 사용하는것보다 values.yaml을 사용하는게 유지보수상 확실히 맞다. 이후 제대로 만들어지면 values.yaml은 깃에 보관해두자.

요약.
1. airflow log 관련 에러.
새로운 PV를 만든 후에 PV에 로그를 저장하도록 한다. airflow-web, airflow-worker둘다 설정 필요.
2. spark non root실행 관련.
java를 root로 설치하였지만 root 가 아닌 유저로 spark를 실행시키는 경우 non root유저의 gid를 root로 설정해준다.
3. docker in docker non root 관련.
non root일 경우 현재 계정이 /var/run/docker.sock의 gid에 속해 있으면 된다.
4. 나머지 부가적인 설정은 https://artifacthub.io/packages/helm/bitnami/airflow 를 보고 설정하고, 여기에 없거나 세부적으로 조정이 더 필요하면 도커파일을 새로 빌드해서 그걸 갖다 쓰자.
5. --set으로 인자를 설정하기보다는 values.yaml파일을 만들어서 쓰자.