Sansan Tech Blog

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

Kubernetesクラスタ更新時のマニフェスト差分をGitのブランチで吸収する

研究開発部 Architectグループ ML PlatformチームのKAZYこと新井です。

名古屋にある中部支店に所属しています。

Kubernetesのマニフェスト管理方法とクラスタのバージョン更新時の運用方法を変更したため、共有します。

TL;DR

マニフェスト管理をするリポジトリのディレクトリ構造を変更しました。 具体的にはクラスタごとにディレクトリを作成するのをやめて環境ごとに1つにしました。

それにより、クラスタのバージョンを利用者が意識しなくて良い設計になりました。

結果、

クラスタ利用者: 認知負荷が減少

クラスタ運用者: クラスタ移行時のファイル修正量の削減

につながりました。

その反面、クラスタのバージョン更新に伴うシステム移行作業がやや複雑になりました。

背景

Circuitについて

研究開発部では2022年頃からアプリケーション実行基盤のCircuitを運用しています。

その存在意義は以前スライドにまとめています。

speakerdeck.com

CircuitはKubernetesというコンテナオーケストレーション技術を用いています。

研究開発部の生産性を大きく上げたいという気持ちから生まれました。

Kubernetesは平均して4カ月に一度、新しいバージョンがリリースされます。

クラスタ更新戦略

CircuitではBlue/Greenなバージョン更新戦略を採用しています。

新たにクラスタを作った後、トラフィック移行するためロールバックが容易な戦略です。

運用方法

CircuitではArgoCDというツールを用いてGitOpsと呼ばれる運用方法を用いています。

Gitのリポジトリに置いたマニフェストファイル(YAML)がクラスタにデプロイされます。 これにより宣言的にリソース管理を可能にしています。

さて、クラスターの更新では新旧クラスタでマニフェストを変更するケースがあります。

例:

  • Kubernets APIバージョンの変更
  • クラスタごとに認証認可を行っている設定ファイル

これらを バージョン間差分 と呼ぶこととします。

先ほど述べた、Blue/Greenなバージョン更新戦略を取ろうと思うと一時的に両方のマニフェストをGit上で両立させる必要があります。

これまでのバージョン間差分対応

クラスタごとに固有のディレクトリで、クラスタ差分を分けていました。

これで一時的に2つのクラスタを別のマニフェストで稼働させられます。

また Kustomizeを用いてdev/stg/prodといった環境間の共通化も行っています。

具体的には次のようなディレクトリ構成です。

services                 
└── namespace
    └── sample-app
        ├── base                          # クラスタと環境をまたいで共通の設定
        │   ├── deployment.yaml
        │   └── kustomization.yaml
        └── overlays                      # 命名規則:環境差分-クラスタ差分
            ├── production-v1-24 # Kubernetes v1.24クラスタ用のマニフェスト置き場 (本番環境)
            │   ├── deployment.yaml
            │   └── kustomization.yaml
            ├── production-v1-27 # Kubernetes v1.27クラスタ用のマニフェスト置き場(本番環境)
            │   ├── deployment.yaml
            │   └── kustomization.yaml
            ├── staging-v1-24
            │   ├── deployment.yaml
            │   └── kustomization.yaml
            └── staging-v1-27
                ├── deployment.yaml
                └── kustomization.yaml

課題

このディレクトリを用いた方法にはいくつか課題がありました。

ディレクトリとファイルを作成する手間

新しいクラスタを作る度にディレクトリとファイルを作成する必要がありました。

一つひとつは大した作業ではないですが、サービス数が増えてくると大きな手間となります。

また、クラスタ差分がないものも一貫して新規ディレクトリとファイルを作成する無駄もありました。

services                 
└── namespace
    └── sample-app
        ├── base
        │   ├── deployment.yaml
        │   └── kustomization.yaml
        └── overlays                     
            ├── production-v1-24
            │   ├── deployment.yaml         ← クラスタ差分がないと内容が同じ
            │   └── kustomization.yaml      ← クラスタ差分がないと内容が同じ
            ├── production-v1-27
            │   ├── deployment.yaml         ← クラスタ差分がないと内容が同じ
            │   └── kustomization.yaml      ← クラスタ差分がないと内容が同じ 
            ︙略

後述する環境内差分を共通化する設計がなされていないことも、手間の要因としてありました。

クラスタ間差分の共通化設計がなかった

Kustomizeを用いて環境間の設定をbaseディレクトリで共通しています。

しかし、同一環境でのクラスタ間差分を共通化するための構造を設計していませんでした。

そのため、クラスタのバージョン更新により非推奨になったKubernetes APIのバージョンの書き換えに非常に手間がかかる設計になっていました。

services                 
└── sansan
    └── sample
        ├── **base**                        #   環境間差分の共通化のみ共通化。 環境内のクラスタ間差分は吸収できない。
        │   ├── deployment.yaml
        │   └── kustomization.yaml
        └── overlays                     
            ├── randd-production-v1-24 
            │   ├── deployment.yaml        
            │   └── kustomization.yaml
            ├── randd-production-v1-27 
            │   ├── deployment.yaml
            │   └── kustomization.yaml
            ︙略

Circuit利用者がクラスタを意識してしまう

多くのクラスタ利用者からしたら、クラスタのバージョンは大きな関心ごとではありません。

しかし、どのバージョンのクラスタにデプロイするかを意識させる設計になってしまっていました。

特にクラスタの移行中は複数のバージョンディレクトリが共存するため、利用者の認知負荷が上がっていました。

services                 
└── sansan
    └── sample
        ├── base
        │   ├── deployment.yaml
        │   └── kustomization.yaml
        └── overlays                     
            ├── randd-production-**v1-24**  ← クラスタ更新のステータスによって変更先を選ぶ
            │   ├── deployment.yaml        
            │   └── kustomization.yaml
            ├── randd-production-**v1-27**  ← クラスタ更新のステータスによって変更先を選ぶ
            │   ├── deployment.yaml
            │   └── kustomization.yaml
            ︙略

やったこと

クラスタ間差分をGitのブランチで管理

ArgoCDはGitの特定のブランチ/タグをトラッキングする機能を持っています。

  • 例: main-v1.27-prod ブランチに新クラスタのマニフェストを用意していく

新クラスタ構築後に 新クラスタ用ブランチ(例:main-v1.27-prod) をmainにマージさせてクラスタ更新は完了する。

  • 旧クラスタのマニフェストはtagをつけて更新を停止 → 破壊

ブランチを用いてクラスタ間差分を吸収する。

ディレクトリからクラスタ間差分を削除

services                 
└── sansan
    └── sample
        ├── base
        │   ├── deployment.yaml
        │   └── kustomization.yaml
        └── overlays                     
            ├── randd-production
            │   ├── deployment.yaml        
            │   └── kustomization.yaml
            ├── randd-staging
            │   ├── deployment.yaml
            │   └── kustomization.yaml
            ︙略

移行の様子

良い効果

利用者の認知負荷が減少

利用者はデプロイする環境のみを意識すれば良くなりました。

クラスタの移行中であってもクラスタのバージョンをもう意識する必要はありません。

例えば、本番環境でsample appに修正を加えるときは、常にservices/sansan/sample/app/overlays/randd-production に変更を加えれば良くなりました。

services                 
└── sansan
    └── sample-app
        ├── base
        │   ├── deployment.yaml
        │   └── kustomization.yaml
        └── overlays                     
            ├── randd-production # クラスタのバージョンに関わらず、ここに変更を加える。
            │   ├── deployment.yaml        
            │   └── kustomization.yaml
            ├── randd-staging
            │   ├── deployment.yaml
            │   └── kustomization.yaml
            ︙略

クラスタ移行時の大量コピペが減少

クラスタ移行時のマニフェスト作成が、クラスタ間差分へのマニフェスト修正のみで済むようになりました。

今後の課題

運用方法を変えることで出てきた課題もあります。

クラスタ間差分の管理が曖昧

クラスタ間差分に集中すれば良くなった一方、クラスタ間差分の確認方法が明らかではなくなりました。 クラスタごとに変更が必要なリソースにラベルをつけるなどして対応していけたらなと考えています。

© Sansan, Inc.