Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

EKSにおけるNamespaceごとにCloudWatchとEC2のコスト按分方法

研究開発部 Architectグループ ML Platformチームのジャン(a.k.a jc)です。今回はKubernetes(EKS)におけるコスト按分のお話しをします。

背景

2022年に弊社研究開発部でAWS EKS上にCircuitというアプリケーション基盤を導入しました。

speakerdeck.com

より多くのアプリケーションがCircuitを使うようになり、コストが増加してきました。 そのためNamespaceごとにコストを按分することで、アプリケーションの費用対効果を把握しておきたいと考えました。

ネットワークのコスト按分は難しいため、コスト割合の大きいCloudWatchとEC2を按分することにしました。今回はそれぞれの方法を紹介します。

CloudWatchのコスト按分

まずはCloudWatchのコスト按分から始めます。Namespaceごとにlog groupを作成し、AWSタグをつけることでログコストの按分を実現できます。

Circuitでは、Fluent Bitを使ってログをCloudWatchに連携しているため、Fluent Bitのプラグインcloudwatchの引数log_group_name/eks/$(kubernetes['Namespace_name'])に指定することで各Namespaceをログ専用のlog groupに送信できます。

[OUTPUT]
    Name                cloudwatch
    Match               application.*
    region              ${AWS_REGION}
    log_group_name      /eks/$(kubernetes['Namespace_name'])
    log_stream_name     $(kubernetes['pod_name'])/$(kubernetes['container_name'])
    auto_create_group   true
    extra_user_agent    container-insights
    log_retention_days  90
    new_log_group_tags  Billing=infra

ただ現時点(2024/8/14)では変数を使ってタグをつけられない(=引数new_log_group_tagsは変数に対応していない)ため、

  • アプリケーション関連Namespaceはlog groupsを事前にterraformを作っておき、タグをつける
  • インフラ関連(=addonやkube-systemなど)のNamespaceはプラグインcloudwatchでlog groupを自動作成し、Billing=infraというタグをつける

注意点としては、プラグインcloudwatch_logcloudwatchのリプレイスとはいえ、new_log_group_tagsの引数がないため、引数new_log_group_tagsを利用したい場合はcloudwatchを使う必要があります。

Cloudwatch logs created with tags · Issue #365 · aws/amazon-cloudwatch-logs-for-fluent-bit · GitHub

最終的には、以下のConfigMapを作成して、AWS公式のFluent Bitのyamlに上書きした後、 Namespaceごとのlog groupにタグをつけられました。

apiVersion: v1
kind: ConfigMap
metadata:
  name: fluent-bit-config
data:
  application-log.conf: |
    [INPUT]
        Name                tail
        Tag                 application.*
        Exclude_Path        /var/log/containers/cloudwatch-agent*, /var/log/containers/fluent-bit*, /var/log/containers/aws-node*, /var/log/containers/kube-proxy*
        Path                /var/log/containers/*.log
        multiline.parser    docker, cri
        DB                  /var/fluent-bit/state/flb_container.db
        Mem_Buf_Limit       50MB
        Skip_Long_Lines     On
        Refresh_Interval    10
        Rotate_Wait         30
        storage.type        filesystem
        Read_from_Head      ${READ_FROM_HEAD}
    
    [FILTER]
        Name                kubernetes
        Match               application.*
        Kube_URL            https://kubernetes.default.svc:443
        Kube_Tag_Prefix     application.var.log.containers.
        Merge_Log           On
        Merge_Log_Key       log_processed
        K8S-Logging.Parser  On
        K8S-Logging.Exclude Off
        Labels              On
        Annotations         On
        Use_Kubelet         On
        Kubelet_Port        10250
        Buffer_Size         0
    
    [OUTPUT]
        Name                cloudwatch
        Match               application.*
        region              ${AWS_REGION}
        log_group_name      /eks/$(kubernetes['Namespace_name'])
        log_stream_name     $(kubernetes['pod_name'])/$(kubernetes['container_name'])
        auto_create_group   true
        extra_user_agent    container-insights
        log_retention_days  90
        new_log_group_tags  Billing=infra

AWS Billing and Cost ManagementでCloudWatchのコストを確認すると、Namespaceごとにコストが分かれていることが確認できます。

CloudWatchのコスト按分

EC2のコスト按分

EKS Split Cost Allocation

AWSが先日EKSのコストを按分するEKS Split Cost Allocationという機能をリリースしました。 調査した結果、EKS Split Cost Allocationのメリットとデメリットを以下にまとめました。

Pros

  • EKS側の追加設定は不要
  • 最小粒度podまでEC2のコスト按分ができる

Cons

  • 按分結果を表示するためにBilling and Cost Managementの他に別途専用のダッシュボードを作成する必要がある
  • また、このダッシュボード作成するのに、コストデータをS3に出力してAthenaでクエリを実行するという手間がかかる。それに伴うデータのエキスポートとクエリの実行というデータパイプラインの実装・運用が必要になる

KarpenterのNodeClassによる按分

EC2 nodeを手動管理するのは大変なので、CircuitではKarpenterというオープンソースのnodeスケジューラを利用しています。Karpenterの詳細はこちらを参照してください。

KarpenterのNodeClassesにタグをつけると、EC2関連のリソース(EC2 Instances, EBS volumesとLaunch Templates)にAWSタグがつくようになります。 また、NodePoolsで設定したlabelはEC2 nodeに反映されますが、AWSタグをつけるオプションがないため、NamespaceごとにNodeClassを作成します。この方法のメリットとデメリットを以下にまとめました。

Pros

  • NamespaceごとにKapenterのNodeClassを作れば、EC2のコスト按分ができる
  • 新しくデータパイプラインやダッシュボードを作成・運用する必要がない

Cons

  • DeploymentにnodeSelectorやtolerationsなどでNodeを指定しておく必要がある
  • 異なるNamespaceのPodが同じNodeにスケジューリングされないので、Namespace間のnodeの相乗り効果を享受できなくなる。コストを抑えるためにはより綿密にリソースを調整する必要がある

データパイプラインとダッシュボードの運用・管理コストを考慮すると、KarpenterのNodeClassによる按分が現状では最適な方法だと考えています。

CloudWatchのコスト按分と同様に、AWS Billing and Cost Managementのコストを確認すると、Namespaceごとにコストが分かれていることが確認できます。

EC2のコスト按分

まとめ

AWSタグを使ったKubernetes(EKS)のEC2とCloudWatchコスト按分方法を紹介しました。ご参考になれば幸いです。

より明確的にアプリケーションごとの費用対効果を把握するためには、アプリケーションごとにコスト按分が必要です。Log groupの粒度をさらに細くすれば良いですが、EC2のコスト按分は難しいです。そのため、今後はserviceごとに按分できるOpencostの導入を検討しています。

研究開発部ではMLOps/DevOpsエンジニア・プラットフォームエンジニアを募集しています。

open.talentio.com

open.talentio.com

© Sansan, Inc.