EKS Fargate Podsを自動停止する仕組みを実装してみる
はじめに
はじめまして、3月にウェルスナビへ新しくジョインしたシステム基盤チームでSREをしている森と申します。
日々の業務で取り組んだことについて紹介いたします。
ここ数年でドル円相場の円安基調が続いております。5年ほど前は1ドル110円程度でしたが、今年に入り150円~160円ほどまで上昇することもありました。
https://www.bk.mufg.jp/tameru/gaika/realtime/chart.html
AWSなどの海外サービスを利用していると支払いはドル建てであることが多いため、円安によりコストが増大してしまいます。
今回はコスト最適化の1つとしてEKS FargateのPods起動停止をスケジューリングすることで、夜間や休日に自動で停止させてコストを削減した取り組みについて紹介いたします。
対象読者
- コスト最適化に興味がある人
- EKS Fargateのコスト削減について関心がある人
AWSが提供するスケジューリングあれこれ
本題へ入る前にAWSのコンピューティングリソースを自動起動停止する一般的なソリューションについて紹介いたします。
EC2[1]やECS[2]、RDS[3]で自動起動停止システムを実装するならEventBridge Schedulerによるスケジュールタスクがオススメです。
EventBridge Schedulerがセットされた時間になったら指定したAPIを定期的に実行してくれますので、対象のリソースターゲットを指定して夜間になったらリソースを停めるAPIを叩くことで自動起動停止が実現できます。
EKS Fargateでは実現が難しい...
一方、EKS Fargateではどうでしょうか。
残念ながらEKS FargateにはPodsの数を変更するAPIがありません。[4]そのためStep Functions[5]でも統合サービスとしてサポートされていませんでした。[6]
他にも、ECS Fargateには提供されているFargate Spotが提供されていない点もコスト最適化を難しくさせています。[7]
ここで別の方法としてArgo Workflowsを使って自動起動停止する仕組みを実装してみました。
Argo Workflowsについて
まずは、Argo Workflowsの概要について説明いたします。
Argo Workflowsは、Kubernetes上で並列ジョブをオーケストレーションするためのワークフローエンジンです。ワークフローをKubernetesのCRD(Custom Resource Definitions)[8]機能で定義し実行すると一連の流れを自動化できます。
このArgo WorkflowsのCRDにCron Workflowsというスケジューラブルなワークフローがあり、cron形式で処理させたいジョブをセットするといったが可能になります。
アーキテクチャ
Cron Workflowsを実装したPods自動起動停止について紹介いたします。
アーキテクチャ図
弊社のEKSクラスター構成について説明しますと1つのEKSクラスター配下にプロダクト毎で区切られた複数のNamespaces[9]を配置しています。
ReplicaSet[10]の数を0にするジョブを、平日の夜9時に起動するようCron Workflowsを設定することで、EKSのPodsを自動的に停止させられます。そして翌朝9時にReplicaSetの数を元に戻すジョブを、Cron Workflowsで設定すればPodsが起動されEKS Fargateによる自動起動停止が実現できます。
課題
ただ、1つ問題がありました。弊社ではEKSへのデプロイ方法としてArgoCD[11]を使った自動デプロイ(CD[12])を採用しており、連携したGitHubリポジトリ内のマニフェスト情報を定期的に自動同期する機能を有効化していました。
連携したリポジトリを定期的にArgoCDが参照し、差分があったらEKSへ自動デプロイする
そのためPodsの数をCron Workflowsで変更する前にArgoCDの自動同期機能の無効化/再有効化ジョブも一緒にセットする必要がありました。
Pods数変更前に自動同期機能を変更するジョブを組み込む
実装コード
そうして実装したArgo Workflowsのマニフェストはこちらになります。
kind: CronWorkflow
spec:
schedule: "0 21 * * 1-5" #平日の夜9時に起動
timezone: "Asia/Tokyo"
workflowSpec:
#ArgoCDの自動同期を無効化
- name: disable-argocd-sync
image: argoproj/argocd:latest
- command
value: "argocd login $(ARGOCD_SERVER) --insecure --username $(ARGOCD_USERNAME) --password $(ARGOCD_PASSWORD) &&\
for APP in <アプリ名>; do\
argocd app set $APP --sync-policy none;\
done"
#ReplicaSetの数を0にしてPodを停止する
- name: scale-down-deployments
image: bitnami/kubectl:latest
- command
value: "DEPLOYMENTS=$(kubectl get deployments -n <Product名前空間> -o jsonpath='{.items[*].metadata.name}')
for DEPLOYMENT in $DEPLOYMENTS; do
kubectl scale deployment $DEPLOYMENT -n <Product名前空間> --replicas=0
done"
kind: CronWorkflow
spec:
schedule: "0 9 * * 1-5" #平日の朝9時に起動
timezone: "Asia/Tokyo"
workflowSpec:
#ArgoCDの自動同期を有効化
- name: disable-argocd-sync
image: argoproj/argocd:latest
- command
value: "argocd login $(ARGOCD_SERVER) --insecure --username $(ARGOCD_USERNAME) --password $(ARGOCD_PASSWORD) &&\
for APP in <アプリ名>; do\
argocd app set $APP --sync-policy automated;\
done"
#ReplicaSetの数を元に戻してPodを起動させる
- name: scale-down-deployments
image: bitnami/kubectl:latest
- command
value: "DEPLOYMENTS=$(kubectl get deployments -n <Product名前空間> -o jsonpath='{.items[*].metadata.name}')
for DEPLOYMENT in $DEPLOYMENTS; do
kubectl scale deployment $DEPLOYMENT -n <Product名前空間> --replicas=1
done"
spec.schedule
でジョブを実行させたい時間をセットし、spec.workflowSpec
で実行させたいジョブの内容を書きこみます。
ジョブの内容としてはまずArgoCD CLIコンテナを起動し、GitHubリポジトリとの自動同期設定を変更します。
その後kubectlコンテナを起動し、名前空間単位でDeployment[13]情報を取得してReplicaSetの数を変更するワンライナーコマンドを実行させます。
削減効果
実際にEKSのコストが下がったグラフはこちらです。
Cost Explorerより抜粋
金曜日に実装してみましたが、夜9時にPodsが停止され翌週月曜日の朝9時までPodsは停止したままの状態となったことで土日は約30%のコスト削減となりました。
所感
Argo Workflowsを使ったEKS FargateのPods自動起動停止を紹介しました。
Kubernetesネイティブなワークフローエンジンということもあって、Kubernetesマニフェストの記法で記述できたので実装そのものは苦労することなくすんなりできました。
今回実装したのは一部プロダクトの開発環境だけに実装しましたので他プロダクトやステージング環境にも展開してさらなるコスト削減を目指していこうと思います。
LT資料
こちらのイベントで記事を基にしたLTを実施しました。
弊社では定期的にエンジニア向けの技術イベントを開催いたしますのでよろしければconnpassのフォローをお願いいたします。
📣ウェルスナビでは一緒に働く仲間を募集しています📣
参考文献
プロフィール
森 祐太朗
システム基盤グループ システム基盤チーム所属
新卒の会社で金融機関のシステム運用を経験。その後複数の転職を経てウェルスナビ株式会社にSREとして入社。現在は資産運用サービスや新規プロダクトのインフラ環境構築を中心にサービス運用改善、監視運用、IaC開発などを担当しています。
-
https://docs.aws.amazon.com/ja_jp/eks/latest/APIReference/Welcome.html ↩︎
-
https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/welcome.html#welcome-service-integrations ↩︎
-
オンデマンドに比べて最大70%もコスト削減できるFargate Spotが使えないのは痛いところです(東京リージョン) ↩︎
-
https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/ ↩︎
-
https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ ↩︎
-
https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ ↩︎
-
Continuous deliverty(https://en.wikipedia.org/wiki/Continuous_delivery) ↩︎
-
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ ↩︎
Discussion