Mirai Translate TECH BLOG

株式会社みらい翻訳のテックブログ

Apache Airflow (MWAA) から EKS の Pod を起動・停止して AWS コストを削減する

この記事はみらい翻訳 Advent Calendar 2023 の 22日目です。

こんにちは!プラットフォーム開発部 SRE チームの jeff です。

Amazon Managed Workflows for Apache Airflow (MWAA) から EKS の Pod を起動・停止できるようにして AWS コストの削減を行なったので記事に書いていこうと思います。

みらい翻訳で開発・運用している MiraiTranslator の開発環境は AWS 上に構築されており、MWAA で起動・停止を行なっています。

これは開発環境が常に起動している必要がないための制御として入れてます。

起動は開発者の任意のタイミングで DAG(有向非巡回グラフ: Directed Acyclic Graph) を実行、停止は毎日夜に自動的に DAG を実行しています(停止漏れが起きないようにする処置です)。

Airflow での起動・停止の基本

以前はアプリケーションを実行する環境が EC2 がほとんどを占めており、以下のような処理で起動・停止を制御していました。AutoScalingGroup構成のため、その制御で起動・停止を行なっています。

import boto3

def change_autoscalinggroup_instance_count(**kwargs):
    asg_client = boto3.client('autoscaling', region_name=region) 
    result = asg_client.update_auto_scaling_group(
        AutoScalingGroupName=asg_name,
        MinSize=min,
        MaxSize=max,
        DesiredCapacity=desired,
    )

start_instance = PythonOperator(
    task_id="start_instance",
    python_callable=change_autoscalinggroup_instance_count,
    op_kwargs={
        'asg_name': 'asg_name',
        'min': 1,
        'max': 1,
        'desired': 1,
        'region': 'ap-northeast-1',
    },
)

以下の部分が起動・停止の台数制御になってます。起動の場合はそれぞれ 1 以上の値を指定(何かの条件でオートスケールする場合は max のみ変更)、停止する場合は全て 0 を指定します。

        'min': 1,
        'max': 1,
        'desired': 1,

EKS の起動・停止

弊社内で最近はサービスの実行環境として EKS の利用が増えてきました。

そのため開発環境でも EKS の利用があり、 EC2 の時と同じく起動・停止を行う必要がありました。 CronHPAkubernetes 側で台数を制御する方法も考えました。ですがサービスやDBなどの外部リソースと連携して Pod を上げ下げしたい、起動は任意のタイミング(必要がある時にだけ起動)で行いたいというのを考えると今までの Airflow に乗っかる方向で対応しました。

Airflow で起動停止できるようにするまで

すでにAirflowのリソースは作成されているものとすると以下のような流れです。

  • EKS に認証情報追加
  • DAG で読み込む kubeconfig 作成
  • DAG 作成

EKS に認証情報追加

Pod 数を操作したい EKS の aws-auth Configmap に Airflow に設定している IAM ロールのマッピングを追加します。

apiVersion: v1
data:
  mapRoles: |
   ・・・
    - groups:
        - system:masters
      rolearn: arn:aws:iam::XXXXXXXXXXXX:role/airflow-role # Airflow の IAM ロール ARN を指定
      username: airflow-role:{{SessionName}}
   ・・・

DAG で読み込む kubeconfig 作成

DAG で Pod 数を操作する際にどのクラスタか判別するために kubeconfig を作成します。Airflow 上で使用するため、認証に使用する IAM ロール = Airflow のロールを指定します。

aws eks update-kubeconfig \
  --name {EKS クラスタ名}
  --role-arn {Airflow の IAM ロール ARN}

これを実行すると .kube/config が作成されるので Airflow がファイルとして取り込めるように S3 にアップロードもしくはパラメーターストアに内容を保存します(取り込めれば他の方法でももちろん可)。

DAG 作成

kubeconfig まで準備できたら DAG を作成します python 用の kubernetes クライアントを使用しますので事前に Airflow で使用できるようにする準備が必要になります。

import boto3
from kubernetes import client, config

def update_eks_deployment_replicas(**kwargs):
    # kubeconfig 初期化
    # ssm から kubeconfig を読み込んでファイルに落とし込む
    ssm = boto3.client('ssm')
    kubeconfig = ssm.get_parameters(
        Names=[
           "kubeconfig",
        ],
        WithDecryption=True
    )['Parameters'][0]['Value']

    with open(".kube/config", mode='w+') as f:
        f.write(kubeconfig)
    f.close()
    config.load_kube_config()

    # pod 台数変更
    v1 = client.CoreV1Api()
    v1.patch_namespaced_deployment_scale(
        kwargs["app"], 
        kwargs["namespace"], 
        {
            "spec": {
                "replicas": kwargs["replicas"]
            }
        }
    )

start_eks_app = PythonOperator(
    task_id="start_eks_app",
    python_callable=update_eks_deployment_replicas,
    op_kwargs={
        'namespace': 'ns',
        'app': 'app',
        'replicas': 1,
    },
)

'replicas': 1 の部分が Pod 数になります。起動の場合は 1 以上を指定し、停止の場合は 0 を指定します。 これで DAG を実行することで Pod 数の変更ができるようになりました。 不要な時に Pod 数を減らすことで EKS のコストも削減できるようになりました。

とある日の EKS コストのグラフです。(一部追加直後のコンテナがあり停止対応ができていないので落ち切っていないですが)夜間時間帯はコストが下がっていることが確認できます。

最後に

今回 Airflow で EKS の Pod 数変更を実現してみました。弊社では Airflow を使っていたのでそれを流用した形を取りましたが、Pod 数変更を含んだ環境の立ち上げ方法は他に色々とありますので合った方法で試してみてください。基本的には kubeconfig とクラスタへの認証ができれば操作はできるかと思います。

みらい翻訳ではSREを募集しています

EKS に興味がある方、その他運用改善など SRE に興味がある方を募集しております。 ご興味がおありの方は下記のリンクからご応募・お問い合わせをお待ちしております。

miraitranslate.com