📗

GKE上にAirflowを構築してIAPによるアクセス制御を行う

8 min read

モチベーション

マネージドAirflow(Cloud ComposerとかMWAA)は高いから自前で作って運用出来ないものか

想定している読者

  • 上記のモチベーションに共感できる
  • kubectlちょっと出来る
  • GCPちょっと出来る
  • helmちょっと出来る

事前準備

ドメインの取得

今回はGoogle Domainsにて取得した momota.dev を使用します

https://domains.google/intl/ja_jp/

Cloud DNSゾーンの作成

まず、DNSゾーンを作成します。

作成するとNSレコードが自動で作成されているので、そこに記載されているネームサーバーを、登録したドメインレジストラのカスタムネームサーバーに登録して更新をします

カスタムネームサーバーの登録(Google Domainsの場合)

このネームサーバーの変更が反映されるまでに最大48時間ほどかかるようなので事前にしておくと良いです。

https://support.google.com/domains/answer/3290309

外部IPの予約

リージョン:グローバルにて外部IPを予約します。
名前は「airflow-v2-web-static-ip」とします(後にこの名前を使用します)

gcloud compute addresses create airflow-v2-web-static-ip --global

割り当てたれたIPを先ほど作成したDNSゾーンのAレコードとして登録します。
今回は workflow.momota.dev のドメインで作成しました

登録後はnslookupでIPが表示されるか確認するとよいでしょう

nslookup workflow.momota.dev 
Server:         172.20.10.1
Address:        172.20.10.1#53

Non-authoritative answer:
Name:   workflow.momota.dev
Address: *****

Airflow環境の作成

サービスアカウント(SA)の作成

GKEが使用するSAを作成します

GKEの作成

SAの部分は置き換えてください

gcloud container clusters create gke-sandbox \
--machine-type=n1-standard-2 \
--num-nodes=1 \
--disk-size=100 \
--region=asia-northeast1 \
--preemptible \
--scopes=cloud-platform \
--enable-cloud-logging \
--enable-stackdriver-kubernetes \
--image-type "COS" \
--service-account "gke-sandbox@<your-project>.iam.gserviceaccount.com"

namespaceの作成

今回は名前空間(namespace)を作成して、そこに構築することにします。

$ kubectl create namespace airflow-v2
namespace/airflow-v2 created

$ kubectl get namespace              
NAME              STATUS   AGE
airflow-v2        Active   1s
default           Active   22m
kube-node-lease   Active   22m
kube-public       Active   22m
kube-system       Active   22m

Airflow-helmの利用

Airflowは様々なミドルウェアがあって成り立つものですが、それらのミドルウェアを管理してくれるhelmを使って構築していきます。

また、helmのchartは以下のリポジトリがすでに公開されているので、リポジトリにあるvaluesをカスタマイズして構築していきます。(Airflow2.1.2を利用するのでairflow-helmのバージョンは8.5.2です)

https://github.com/airflow-helm/charts/tree/airflow-8.5.2/charts/airflow

helm repoのインストール

$ helm repo add airflow-stable https://airflow-helm.github.io/charts
"airflow-stable" has been added to your repositories

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "airflow-stable" chart repository
Update Complete. ⎈Happy Helming!⎈

$ helm repo list  
NAME            URL                                  
airflow-stable  https://airflow-helm.github.io/charts

httpsでのアクセスを可能にする

valuesのテンプレートはこちらです。

https://github.com/airflow-helm/charts/blob/airflow-8.5.2/charts/airflow/values.yaml

その上で、テンプレを以下のように更新します(ドメイン部分の記述は workflow.momota.dev で検索して引っかかった箇所を、自分のものに置き換えてください)

https://gist.github.com/momota10s/3cfe82bd49f8ebbb5786366ab00b66dc

valuesの変更箇所は以下です

  • airflow
    • fernetKey
    • webserverSecretKey
    • config
      • AIRFLOW__WEBSERVER__BASE_URL
  • web
    • service
  • flower
    • service
  • ingress
    • enabled
    • web
    • flower
  • extramanifests
    • ManagedCertificate

今回は gke-sandbox-values.yaml としてvaluesを作成し、変更後はhelm installでデプロイします

$ helm install airflow \
airflow-stable/airflow \
--values gke-sandbox-values.yaml \
--version 8.5.2 \
--namespace airflow-v2

デプロイ後の動作確認

  1. GKEのコンソールからワークロード、Service、Ingress全てのコンポーネントがグリーンであることを確認します
  2. managedcertificateがActiveになっていることを確認します
  3. managedcertificateがActiveになったあと、イングレスのフロントエンド画面にあるリンクからアクセスできることを確認します
$ kubectl get managedcertificate -n airflow-v2
NAME           AGE   STATUS
managed-cert   20m   Active

ワークロード

Services

Ingress

アクセスの確認

マネージドSSL証明書の詳細

https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs?hl=ja

認証情報の初期設定

OAuth同意画面を作成します。ユーザーの種類は内部にしておいてください

IAPの有効化

Airflowの構成が正常にデプロイされてるなら、Identity-Aware ProxyのページでIAPが無効になっているリソース( airflow-v2/airflow-web )が出現するはずなので、これを有効にします。

その後、 ログインを許可させるgoogleアカウントに IAP-secured Web App User の権限を付与します。

作成されたoauth認証情報を元にkubectl create secretする

IAPが有効になった後、「OAuth 2.0 クライアント ID」が作成されているので、これの詳細画面から確認して、secretの変数として定義してcreateします

IAPを有効にすると作成される

クライアントID, クライアントシークレットをコピーする

以下を実行

# create
kubectl create secret generic airflow-iap-secret \
--from-literal=client_id=<your-client-id> \
--from-literal=client_secret=<your-client-secret> \
-n airflow-v2

# check
kubectl get secret -n airflow-v2
NAME                             TYPE                                  DATA   AGE
airflow-iap-secret               Opaque                                2      20s
...

BackendConfigの定義

先ほど共有したvaluesにて config-default でgrepすると3ヶ所出てくるのですが、そこのコメントアウトを外します。

web:
  ...
  service:
    # annotations: {}
    annotations:
      cloud.google.com/backend-config: '{"default": "config-default"}'
flower:
  ...
  service:
    # annotations: {}
    annotations:
      cloud.google.com/backend-config: '{"default": "config-default"}'
extraManifests:
  - apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: managed-cert
      namespace: airflow-v2
    spec:
      domains:
        - workflow.momota.dev
  - apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: config-default
      namespace: airflow-v2
    spec:
      iap:
        enabled: true
        oauthclientCredentials:
          secretName: airflow-iap-secret

上のvaluesを見ていただくとわかるかと思いますが、このvaluesでBackendConfigを定義することによりIAPを利用したアクセスが可能になります。

また、ここまでのGKEにおけるIAPの有効化については以下に詳細が書いています

https://cloud.google.com/iap/docs/enabling-kubernetes-howto

valuesを編集したらhelm upgradeを実行して構成を更新します。

$ helm upgrade airflow \
airflow-stable/airflow \
--values gke-sandbox-values.yaml \
--version 8.5.2 \
--namespace airflow-v2

デプロイ後の動作確認

  1. IAP-secured Web App User を付与したgoogleアカウントでログインできることを確認する
  2. IAP-secured Web App User を付与してないgoogleアカウントでは403となることを確認する

最後に

  • この運用がうまくいくとマネージドAirflowよりコストを抑えることが出来るのでGKEとかhelmとかちょっと頑張れる余力がある場合はおすすめです。
  • valuesに定義してるimageは repository: apache/airflow ですが、これは自身が作成したDAGとDockerfileでbuildし、GCRにpushしたものを使用することも可能です。
  • この記事で作成したsandboxは全部消しました。

Discussion

ログインするとコメントできます