Kubernetesにおける「ゴースト」リソースのコスト
運用するKubernetesクラスターが拡大し、エンジニアリングチームが成長するにつれ、リソースの乱立(スプロール現象)は避けられない課題となります。活発な開発(Dev)やステージング(Staging)環境では、開発者が機能テストやPRプレビューのために絶えず新しいネームスペースを作成します。問題は、タスクが終了してもリソースがアクティブなまま残り続けてしまうことです。
放置されたネームスペースは単にそこに存在するだけではありません。VPCのIPアドレスを消費し、ロードバランサーの枠を占有し、CPUやメモリの予約枠(Reservation)を奪い取ります。EKSやGKEのようなマネージドサービスでは、この無駄は非常に高価であり、クラウドコストを削減するための対策が重要です。最近のある監査では、クラスター内のノードの40%が、数週間前に終了したプロジェクトをサポートするために稼働していたことが判明しました。これは、アイドル状態のEC2インスタンスに毎月数百ドルもの無駄なコストを費やしていることを意味します。
手動クリーンアップとカスタムスクリプトが失敗する理由
多くのチームが最初に取る行動は、手動でのアプローチです。シニアエンジニアに金曜日の午後を割かせて、古いネームスペースを探し出させるかもしれません。しかし、これは高価なエンジニアの時間の使い方としては非常に非効率です。やがて、誰かがcronジョブでkubectl deleteを実行する「簡単な」bashスクリプトを書くことになります。
カスタムスクリプトは、多くの場合壊れやすく危険です。詳細なログ記録に欠け、複雑な依存関係をうまく処理できないことが多いためです。正規表現のわずかなミスが、本番環境のデータベースを誤って削除してしまうことにも繋がりかねません。私たちに必要なのは、オブジェクトのライフサイクルを管理するための、宣言的でKubernetesネイティブな方法です。Kube-janitorは、クリーンアップを作業ではなく「ポリシー」として扱うことで、この問題を解決します。
Kube-janitorのセットアップ
Kube-janitorは、Zalandoによって作成された軽量なコントローラーです。クラスターを監視し、特定のルールやメタデータに基づいてリソースを削除します。単純なスクリプトとは異なり、Kubernetesオブジェクトを理解し、安全な境界線を尊重します。
RBAC権限を適切に管理するために、Helmを使用したインストールをお勧めします。以下のコマンドを実行して開始しましょう。
# Zalandoリポジトリを追加
helm repo add kube-janitor https://zalando.github.io/kube-janitor/
helm repo update
# コントローラーをインストール
helm install kube-janitor kube-janitor/kube-janitor \
--namespace kube-janitor \
--create-namespace
インストール直後のKube-janitorは待機状態です。ConfigMapやリソースのアノテーションを通じて具体的な指示を与えるまで、勝手に何かを削除することはありません。
クリーンアップポリシーの設定
アノテーションの使用は、リソースを管理する最も効果的な方法です。これにより、リソースの寿命に関する責任を、そのリソースを作成した本人に移譲できます。私はいくつかの本番クラスターでこの手法を採用し、大きな成果を上げました。
1. 生存期間(TTL)の設定
作成からちょうど4時間後にネームスペースを削除するようKube-janitorに指示できます。これは、短命なプレビュー環境を生成するCI/CDパイプラインに最適です。マニフェストにjanitor/ttlアノテーションを追加するだけです。
apiVersion: v1
kind: Namespace
metadata:
name: feature-x-preview
annotations:
janitor/ttl: "4h"
spec: {}
2. 特定の有効期限の設定
スプリントの最終日など、テストフェーズがいつ終わるか正確に分かっている場合があります。その場合は、絶対的なタイムスタンプを使用します。これにより、あなたが休暇中であっても確実にリソースが削除されます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: temporary-worker
annotations:
janitor/expires: "2024-12-31T23:59:59Z"
spec:
# ... デプロイメントの仕様
3. グローバルルールの作成
現実には、開発者がアノテーションを付け忘れることがよくあります。values.yamlでグローバルルールを定義することで、こうした漏れをカバーできます。例えば、「test-」で始まる7日以上経過したすべてのネームスペースをターゲットにできます。
rules:
- name: "cleanup-test-namespaces"
resources:
- namespaces
condition: |
metadata.name =~ "^test-.*" and age > "7d"
action: delete
検証と安全性
クリーンアップツールを検証なしで稼働させてはいけません。Kube-janitorには、初期テストに不可欠な「ドライラン(dry-run)」モードが含まれています。破壊的なアクションを有効にする前に、必ずログを確認してください。
コントローラーが何を削除対象としているかを確認するには、K9sや次のコマンドを使用します。
kubectl logs -f deployment/kube-janitor -n kube-janitor
リソース namespaces/test-app-123 は期限切れです。削除しています...といった内容のログが表示されます。ドライランが有効な場合、ログには実際には削除せずに「削除されたはずである」という旨が表示されます。
重要なシステムの保護
kube-systemやproductionの誤削除を防ぐには、除外アノテーションを使用します。すべての基盤インフラのネームスペースに直ちに適用することをお勧めします。
kubectl annotate namespace production janitor/policy=keep
ベストプラクティス
複数のクラスターでKube-janitorを管理してきた経験から、最も効果的な3つの戦略を見つけました。まず、すべてのステージング用ネームスペースにデフォルトで14日間のTTLを設定します。これにより、リソースをそれ以上維持する必要がある場合に、チームにその正当な理由を説明させる習慣がつきます。
次に、アノテーションをCI/CDテンプレートに統合します。GitHub Actionsウェル、GitLab CIでも、デプロイスクリプト内でjanitor/ttl

