動的構成管理:ConfigMapを使用したリアルタイムアプリケーション更新

Kubernetes ConfigMapをマウントされたファイルとして使用し、ランタイム構成の更新を行う方法。伝播、subPath、アプリのリロード動作に関する注意点を含む。

動的構成管理:ConfigMapを使用したリアルタイムアプリケーション更新

Kubernetesはアプリケーションの状態を管理するための堅牢なメカニズムを提供しますが、アプリケーション設定の変更は、多くの場合、イメージの再構築やデプロイメントPodの再起動を伴います。多くのマイクロサービスでは、このダウンタイムや中断は許容できません。ここでConfigMapが非常に価値を持ちます。ConfigMapは、機密性のない構成データをキーと値のペアで保存するように設計されたKubernetesオブジェクトであり、構成をアプリケーションコードから切り離します。

ConfigMapは、アプリがファイルから設定を読み取り、リロードできる場合に、動的な構成管理に役立ちます。Kubernetes側は設定の半分に過ぎません。マウントされたConfigMapファイルはPodが実行中でも変更できますが、環境変数は変更できません。また、アプリケーションが新しい値を認識して適用する必要があります。

ConfigMapの理解:基礎

ConfigMapを使用すると、構成データを一連のキーと値として保存できます。Secretとは異なり、ConfigMapはログレベル、外部サービスエンドポイント、フィーチャーフラグなど、機密性のない構成データを対象としています。

サンプルConfigMapの作成

構成データは、YAMLマニフェスト内で直接定義するか、既存のファイルやディレクトリから作成できます。アプリケーション固有のパラメータを含むapp-settingsという名前のConfigMapを作成しましょう。

例:YAMLでのConfigMap定義

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-settings
data:
  # キーと値のペア
  LOG_LEVEL: "INFO"
  API_ENDPOINT: "https://api.default.svc.cluster.local"
  # 複数行の設定ファイル内容
  application.properties: |
    server.port=8080
    feature.toggle.new_ui=false

このConfigMapは、2つの単純なキーと値のペアと、設定ファイルをシミュレートする1つの複雑なエントリ(application.properties)の3つのデータを公開します。

Podへの構成の注入

ConfigMapは環境変数を設定できますが、動的更新の鍵は、Podのファイルシステム内にボリュームとしてマウントすることにあります。ボリュームとしてマウントされると、KubernetesはConfigMap内の各キーを指定されたディレクトリ内のファイルとして扱います。

方法1:ボリュームマウントの使用(動的アプローチ)

動的更新を実現するには、ConfigMapをPodの仕様にマウントします。

例:ConfigMapボリュームマウントを使用したPod仕様

apiVersion: v1
kind: Pod
metadata:
  name: dynamic-app-pod
spec:
  containers:
  - name: my-app
    image: my-registry/my-app:latest
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config 
  volumes:
  - name: config-volume
    configMap:
      name: app-settings

この設定では:

  1. ConfigMap app-settingsconfig-volume という名前のボリュームにリンクされます。
  2. ボリュームはコンテナ内の /etc/config にマウントされます。
  3. Kubernetesは自動的に /etc/config 内にConfigMapのキーに対応するファイルを作成します:
    • /etc/config/LOG_LEVEL には値 INFO が含まれます。
    • /etc/config/application.properties には複数行の設定が含まれます。

方法2:環境変数の使用(静的アプローチ)

より単純な静的な値の場合は、環境変数として注入できます。注:この方法で設定された環境変数は、ConfigMapが変更されても自動的に更新されません。Podを再起動する必要があります。

# Deployment仕様からの抜粋
containers:
- name: my-app
  image: my-registry/my-app:latest
  env:
  - name: LOG_LEVEL
    valueFrom:
      configMapKeyRef:
        name: app-settings
        key: LOG_LEVEL

ベストプラクティス: 動的更新の場合は、設定ファイルに常にボリュームマウントを使用してください。

リアルタイム更新の実現:変更の監視

ConfigMapが更新されると、Kubernetesは最終的にそれをボリュームとしてマウントするPodに変更を伝播します。正確なタイミングはkubeletの同期動作、キャッシュ動作、ノードの負荷に依存するため、即時のコントロールプレーンプッシュではなく、最終的な伝播として扱ってください。

Kubeletによる更新の伝播方法

ボリュームとして使用されるConfigMapが変更された場合:

  1. kubeletは同期サイクル中に定期的に更新をチェックし、ローカルキャッシュからデータを提供する場合があります。
  2. 更新が検出されると、kubeletはホストのファイルシステム内のマウントされたファイルを更新します。
  3. 実行中のコンテナの場合、ConfigMapボリューム内のファイルは、Kubernetesのprojected-volumeメカニズムを通じて更新されます。

一般的な例外が1つあります。subPathを使用して単一のConfigMapキーをマウントした場合、ConfigMapが変更されても、そのマウントされたファイルは更新されません。ランタイム更新を期待する場合は、通常のConfigMapボリュームマウントを使用してください。

アプリケーション側の検出

重要なステップは、コンテナ内で実行されているアプリケーションコードが、これらのファイル変更を検出して対応するように設計されていることです。

例:ファイル監視のためのアプリケーションロジック(概念的なPython)

最近のアプリケーションのほとんどは、内部メカニズムやライブラリを使用してファイルシステムイベント(Linuxのinotifyなど)を監視します。

import time
import os

CONFIG_PATH = "/etc/config/application.properties"

def load_config(path):
    # ファイルの内容を読み取り、解析する関数
    with open(path, 'r') as f:
        print(f"\n--- 構成がリロードされました ---\n{f.read()}")
        # 新しい設定を使用してサービスを再初期化するロジック

# 初期読み込み
load_config(CONFIG_PATH)

# 継続的な監視ループ
last_modified = os.path.getmtime(CONFIG_PATH)

while True:
    current_modified = os.path.getmtime(CONFIG_PATH)
    if current_modified != last_modified:
        print("ファイル変更を検出しました。構成をリロードしています...")
        load_config(CONFIG_PATH)
        last_modified = current_modified
    time.sleep(5) # 5秒ごとにチェック

この例では、ファイルの変更時刻(mtime)をポーリングしています。kubeletがファイルを更新すると、アプリケーションが変更を検出し、構成を動的にリロードできます。

ファイルウォッチャーに関する注意: ConfigMapボリュームの更新により、マウントされたディレクトリ下のシンボリックリンクターゲットが置き換えられる可能性があります。ウォッチャーが開いている1つのファイルハンドルのみを追跡する場合、更新を見逃す可能性があります。即時リロードよりも信頼性が重要な場合は、ディレクトリを監視するか、ファイルの内容をポーリングしてください。

動的更新ワークフロー:ステップバイステップの例

実行中のPodに触れずに、LOG_LEVELINFOからDEBUGに更新する手順を見てみましょう。

ステップ1:初期状態

Podが実行中で、ボリュームマウントを介してConfigMapを消費していることを確認します。

ステップ2:ConfigMapの更新

kubectl editまたはkubectl applyを使用して、既存のConfigMapを変更します。

# kubectl editを使用して値を直接変更
kubectl edit configmap app-settings

# 次の行を見つけて変更:
# LOG_LEVEL: "INFO"
# を次のように変更:
LOG_LEVEL: "DEBUG"

ステップ3:伝播の監視

kubeletが変更を伝播するのを待ちます。クラスタによっては、これに数秒以上かかる場合があります。

アプリケーションが/etc/config/LOG_LEVELを監視している場合:

  1. kubeletが基になるファイルを更新します。
  2. アプリケーションが変更を検出します(監視メカニズムに基づく)。
  3. アプリケーションが内部のログ設定をDEBUGにリロードします。

重要なのは、Pod自体は変更されず、サービスが中断されないことです。

構成管理のまとめと考慮事項

ConfigMapをボリュームマウントと共に使用することは、Kubernetesで動的な構成更新を実現するための標準的な方法です。ただし、次の点に注意してください:

  • セキュリティ: ConfigMapはデータをプレーンテキストで保存します。機密情報にはSecretを使用してください。
  • 不変性: 重要な構成については、作成後にConfigMapを不変(仕様でimmutable: true)にして、誤ったランタイム変更を防ぐことを検討してください。
  • アプリケーションの認識: 動的な更新は、実行中のコンテナが設定ファイルを監視およびリロードする方法を知っている場合にのみ可能です。
  • ロールバック: 構成変更のロールバックには、ConfigMapを以前の状態に戻し、アプリケーションが検出するのを待つ必要があります。

構成をデプロイメントアーティファクトから切り離し、ボリュームマウントを活用することで、Kubernetesワークロードの構成パラメータに対する堅牢でダウンタイムのない更新が可能になります。