ConfigMap PropertySource の使用

Kubernetes は、キーと値のペア、または埋め込み application.properties または application.yaml ファイルの形式でアプリケーションに渡すパラメーターを外部化する、ConfigMap (英語) という名前のリソースを提供します。Spring Cloud Kubernetes 構成 [GitHub] (英語) プロジェクトは、アプリケーションの起動時に Kubernetes ConfigMap インスタンスを使用できるようにし、監視されている ConfigMap インスタンスで変更が検出されたときに Bean または Spring コンテキストのホットリロードをトリガーします。

以下の内容は主に ConfigMaps を使用した例を参照して説明されますが、シークレットについても同様です。つまり、すべての機能が両方でサポートされています。

デフォルトの動作では、次のいずれかの metadata.name を持つ Kubernetes ConfigMap に基づいて Fabric8ConfigMapPropertySource (または KubernetesClientConfigMapPropertySource) を作成します。

  • spring.cloud.kubernetes.config.name の値

  • Spring アプリケーションの価値 (spring.application.name プロパティで定義されているとおり)

  • 文字列リテラル "application"

ただし、複数の ConfigMap インスタンスを使用できる、より高度な構成が可能です。spring.cloud.kubernetes.config.sources リストはこれを可能にします。例: 次の ConfigMap インスタンスを定義できます。

spring:
  application:
    name: cloud-k8s-app
  cloud:
    kubernetes:
      config:
        name: default-name
        namespace: default-namespace
        sources:
         # Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace
         - name: c1
         # Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2
         - namespace: n2
         # Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3
         - namespace: n3
           name: c3

前述の例では、spring.cloud.kubernetes.config.namespace が設定されていない場合、アプリケーションが実行する名前空間で c1 という名前の ConfigMap が検索されます。アプリケーションの名前空間がどのように解決されるかをより深く理解するには、名前空間の解決を参照してください。

一致する ConfigMap が見つかった場合は、次のように処理されます。

  • 個々の構成プロパティを適用します。

  • spring.application.name の値によって名前が付けられたプロパティの内容を yaml (または properties) として適用します (存在しない場合は、application.yaml/properties)

  • 上記の名前と各アクティブなプロファイルの内容をプロパティファイルとして適用します。

例を見てみると、さらにわかりやすいはずです。spring.application.name=my-app であり、k8s という単一のアクティブなプロファイルがあると仮定します。以下のような構成の場合:

kind: ConfigMap
apiVersion: v1
metadata:
  name: my-app
data:
  my-app.yaml: |-
    ...
  my-app-k8s.yaml: |-
    ..
  my-app-dev.yaml: |-
    ..
  not-my-app.yaml: |-
   ..
  someProp: someValue

最終的にロードするものは次のとおりです。

  • my-app.yaml をファイルとして扱う

  • my-app-k8s.yaml をファイルとして扱う

  •  dev はアクティブなプロファイルではないため、my-app-dev.yaml  は無視されました

  • not-my-app.yaml は spring.application.name と一致しないため無視されます

  • someProp: someValue プレーンプロパティ

プロパティを読み込む順序は次のとおりです。

  • 最初に my-app.yaml からすべてのプロパティをロードします

  • その後、すべてプロファイルベースのソースから: my-app-k8s.yaml

  • その後、すべてのプレーンプロパティ someProp: someValue

これは、プロファイルベースのソースが非プロファイルベースのソースより優先されることを意味します (バニラ Spring アプリと同様)。また、プレーンプロパティは、プロファイルベースのソースと非プロファイルベースのソースの両方よりも優先されます。以下に例を示します。

kind: ConfigMap
apiVersion: v1
metadata:
  name: my-app
data:
  my-app-k8s.yaml: |-
    key1=valueA
	key2=valueB
  my-app.yaml: |-
    key1=valueC
    key2=valueA
  key1: valueD

このような ConfigMap を処理すると、プロパティには key1=valueDkey2=valueB が表示されます。

前述のフローの 1 つの例外は、ファイルが YAML またはプロパティファイルであることを示す単一のキーが ConfigMap に含まれる場合です。その場合、キーの名前は application.yaml または application.properties である必要はなく (何でも構いません)、プロパティの値は正しく処理されます。この機能により、次のようなものを使用して ConfigMap が作成されたユースケースが容易になります。

kubectl create configmap game-config --from-file=/path/to/app-config.yaml

次のプロパティを使用してスレッドプール構成を読み取る demo という名前の Spring Boot アプリケーションがあるとします。

  • pool.size.core

  • pool.size.maximum

これは、次のように yaml 形式で設定マップに外部化できます。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  pool.size.core: 1
  pool.size.max: 16

個々のプロパティはほとんどの場合に問題なく機能します。ただし、場合によっては、組み込み yaml の方が便利です。この場合、次のように、application.yaml という名前の単一プロパティを使用して yaml を埋め込みます。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  application.yaml: |-
    pool:
      size:
        core: 1
        max:16

次の例も機能します。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  custom-name.yaml: |-
    pool:
      size:
        core: 1
        max:16

ラベルに基づいて検索が行われるように定義することもできます。例:

spring:
  application:
    name: labeled-configmap-with-prefix
  cloud:
    kubernetes:
      config:
        enableApi: true
        useNameAsPrefix: true
        namespace: spring-k8s
        sources:
          - labels:
              letter: a

これにより、名前空間 spring-k8s 内でラベル {letter : a} を持つすべての構成マップが検索されます。ここで注意すべき重要な点は、名前で構成マップを読み取る場合とは異なり、複数の構成マップが読み取られる可能性があるということです。通常どおり、同じ機能がシークレットに対してサポートされています。

ConfigMap の読み取り時にマージされるアクティブなプロファイルに応じて、Spring Boot アプリケーションを異なる構成にすることもできます。次のように、application.properties または application.yaml プロパティを使用し、それぞれ独自のドキュメント (--- シーケンスで示される) でプロファイル固有の値を指定することにより、異なるプロファイルに異なるプロパティ値を提供できます。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  application.yml: |-
    greeting:
      message: Say Hello to the World
    farewell:
      message: Say Goodbye
    ---
    spring:
      profiles: development
    greeting:
      message: Say Hello to the Developers
    farewell:
      message: Say Goodbye to the Developers
    ---
    spring:
      profiles: production
    greeting:
      message: Say Hello to the Ops

前述のケースでは、development プロファイルを使用して Spring アプリケーションにロードされる構成は次のとおりです。

  greeting:
    message: Say Hello to the Developers
  farewell:
    message: Say Goodbye to the Developers

ただし、production プロファイルがアクティブな場合、構成は次のようになります。

  greeting:
    message: Say Hello to the Ops
  farewell:
    message: Say Goodbye

両方のプロファイルがアクティブな場合、ConfigMap 内で最後に表示されるプロパティによって、それより前の値が上書きされます。

もう 1 つのオプションは、プロファイルごとに異なる構成マップを作成することです。spring boot は、アクティブなプロファイルに基づいてそれを自動的に取得します。

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  application.yml: |-
    greeting:
      message: Say Hello to the World
    farewell:
      message: Say Goodbye
kind: ConfigMap
apiVersion: v1
metadata:
  name: demo-development
data:
  application.yml: |-
    spring:
      profiles: development
    greeting:
      message: Say Hello to the Developers
    farewell:
      message: Say Goodbye to the Developers
kind: ConfigMap
apiVersion: v1
metadata:
  name: demo-production
data:
  application.yml: |-
    spring:
      profiles: production
    greeting:
      message: Say Hello to the Ops
    farewell:
      message: Say Goodbye

どの profile を有効にする必要があるかを Spring Boot に伝えるには、Spring Boot ドキュメントを参照してください。Kubernetes にデプロイするときに特定のプロファイルをアクティブにするオプションの 1 つは、コンテナー仕様で PodSpec で定義できる環境変数を使用して Spring Boot アプリケーションを起動することです。デプロイリソースファイルは次のようになります。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-name
  labels:
    app: deployment-name
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deployment-name
  template:
    metadata:
      labels:
        app: deployment-name
	spec:
		containers:
		- name: container-name
		  image: your-image
		  env:
		  - name: SPRING_PROFILES_ACTIVE
			value: "development"

同じプロパティ名を持つ複数の構成マップが存在する状況が発生する可能性があります。例:

kind: ConfigMap
apiVersion: v1
metadata:
  name: config-map-one
data:
  application.yml: |-
    greeting:
      message: Say Hello from one

および

kind: ConfigMap
apiVersion: v1
metadata:
  name: config-map-two
data:
  application.yml: |-
    greeting:
      message: Say Hello from two

これらを bootstrap.yaml|properties に配置する順序によっては、予期しない結果が発生する可能性があります (最後の構成マップが優先されます)。例:

spring:
  application:
    name: cloud-k8s-app
  cloud:
    kubernetes:
      config:
        namespace: default-namespace
        sources:
         - name: config-map-two
         - name: config-map-one

プロパティ greetings.message は Say Hello from one になります。

useNameAsPrefix を指定することで、このデフォルト構成を変更する方法があります。例:

spring:
  application:
    name: with-prefix
  cloud:
    kubernetes:
      config:
        useNameAsPrefix: true
        namespace: default-namespace
        sources:
          - name: config-map-one
            useNameAsPrefix: false
          - name: config-map-two

このような構成では、次の 2 つのプロパティが生成されます。

  • greetings.message は Say Hello from one に等しい。

  • config-map-two.greetings.message と Say Hello from two は等しい

spring.cloud.kubernetes.config.useNameAsPrefix の優先順位は spring.cloud.kubernetes.config.sources.useNameAsPrefix よりも低いことに注意してください。これにより、すべてのソースに対して "default" 戦略を設定できると同時に、いくつかのソースのみをオーバーライドすることができます。

構成マップ名の使用がオプションでない場合は、explicitPrefix という別の戦略を指定できます。これは選択する明示的なプレフィックスであるため、sources レベルにのみ提供できます。同時に、useNameAsPrefix よりも高い優先順位を持ちます。次のエントリを含む 3 番目の構成マップがあるとします。

kind: ConfigMap
apiVersion: v1
metadata:
  name: config-map-three
data:
  application.yml: |-
    greeting:
      message: Say Hello from three

以下のような構成です。

spring:
  application:
    name: with-prefix
  cloud:
    kubernetes:
      config:
        useNameAsPrefix: true
        namespace: default-namespace
        sources:
          - name: config-map-one
            useNameAsPrefix: false
          - name: config-map-two
            explicitPrefix: two
          - name: config-map-three

その結果、次の 3 つのプロパティが生成されます。

  • greetings.message は Say Hello from one に等しい。

  • two.greetings.message は Say Hello from two に等しい。

  • config-map-three.greetings.message は Say Hello from three に等しい。

configmap のプレフィックスを設定するのと同じ方法で、シークレットに対しても行うことができます。名前に基づくシークレットとラベルに基づくシークレットの両方。例:

spring:
  application:
    name: prefix-based-secrets
  cloud:
    kubernetes:
      secrets:
        enableApi: true
        useNameAsPrefix: true
        namespace: spring-k8s
        sources:
          - labels:
              letter: a
            useNameAsPrefix: false
          - labels:
              letter: b
            explicitPrefix: two
          - labels:
              letter: c
          - labels:
              letter: d
            useNameAsPrefix: true
          - name: my-secret

プロパティソースを生成する場合、構成マップの場合と同じ処理ルールが適用されます。唯一の違いは、ラベルでシークレットを検索すると、複数のソースが見つかる可能性があることです。このような場合、プレフィックス ( useNameAsPrefix で指定した場合) は、それらの特定のラベルで見つかったすべてのシークレットの名前になります。

もう 1 つ留意すべき点は、シークレットごとではなくソースごとに prefix をサポートしていることです。これを説明する最も簡単な方法は、次の例です。

spring:
  application:
    name: prefix-based-secrets
  cloud:
    kubernetes:
      secrets:
        enableApi: true
        useNameAsPrefix: true
        namespace: spring-k8s
        sources:
          - labels:
              color: blue
            useNameAsPrefix: true

このようなラベルに一致するクエリの結果として、secret-a と secret-b という 2 つのシークレットが提供されるとします。これらのシークレットは両方とも、color=sea-blue および color=ocean-blue という同じプロパティ名を持ちます。どの color がプロパティソースの一部になるかは未定義ですが、そのプレフィックスは secret-a.secret-b (自然にソートされた連結、シークレットの名前) になります。

より詳細な結果が必要な場合は、ラベルを追加してシークレットを一意に識別することもできます。

デフォルトでは、sources 構成で指定された構成マップを読み取るほかに、Spring は「プロファイル対応」ソースからすべてのプロパティを読み取ろうとします。これを説明する最も簡単な方法は、例を使用することです。アプリケーションで "dev" というプロファイルが有効になっており、次のような構成があるとします。

spring:
  application:
    name: spring-k8s
  cloud:
    kubernetes:
      config:
        namespace: default-namespace
        sources:
          - name: config-map-one

config-map-one の読み取りに加えて、Spring は config-map-one-dev の読み取りも試行します。この特定の順序で各アクティブなプロファイルは、プロファイル対応構成マップを生成します。

アプリケーションがそのような構成マップの影響を受けることはありませんが、必要に応じて無効にすることができます。

spring:
  application:
    name: spring-k8s
  cloud:
    kubernetes:
      config:
        includeProfileSpecificSources: false
        namespace: default-namespace
        sources:
          - name: config-map-one
            includeProfileSpecificSources: false

以前と同様に、このプロパティを指定できるレベルは 2 つあります。つまり、すべての構成マップに対して、または個別の構成マップに対してです。後者の方が優先されます。

セキュリティ構成セクションを確認する必要があります。pod 内から構成マップにアクセスするには、正しい Kubernetes サービスアカウント、ロール、ロールバインディングが必要です。

ConfigMap インスタンスを使用するもう 1 つのオプションは、Spring Cloud Kubernetes アプリケーションを実行し、Spring Cloud Kubernetes にファイルシステムからインスタンスを読み取らせることで、ConfigMap インスタンスを Pod にマウントすることです。

この機能は非推奨であり、将来のリリースでは削除される予定です (代わりに spring.config.import を使用してください)。この動作は、spring.cloud.kubernetes.config.paths プロパティによって制御されます。前述のメカニズムに加えて、またはその代わりにこれを使用できます。ディレクトリは再帰的に解析されないため、spring.cloud.kubernetes.config.paths は各プロパティファイルへのフルパスのリストを期待します。例:
spring:
  cloud:
    kubernetes:
      config:
        paths:
          - /tmp/application.properties
          - /var/application.yaml
spring.cloud.kubernetes.config.paths または spring.cloud.kubernetes.secrets.path を使用する場合、自動リロード機能は動作しません。/actuator/refresh エンドポイントに対して POST リクエストを行うか、アプリケーションを再起動 / 再デプロイする必要があります。

場合によっては、アプリケーションが Kubernetes API を使用して ConfigMaps の一部をロードできないことがあります。このような場合にアプリケーションが起動プロセスに失敗するようにしたい場合は、アプリケーションの起動が例外で失敗するように spring.cloud.kubernetes.config.fail-fast=true を設定できます。

失敗した場合に、アプリケーションで ConfigMap プロパティソースのロードを再試行するようにすることもできます。まず、spring.cloud.kubernetes.config.fail-fast=true を設定する必要があります。次に、spring-retry と spring-boot-starter-aop をクラスパスに追加する必要があります。spring.cloud.kubernetes.config.retry.* プロパティを設定することで、最大試行回数、初期間隔、乗数、最大間隔などのバックオフオプションなどの再試行プロパティを構成できます。

何らかの理由ですでにクラスパス上に spring-retry および spring-boot-starter-aop があり、フェイルファストを有効にしたいが、再試行は有効にしたくない場合。spring.cloud.kubernetes.config.retry.enabled=false を設定することで、ConfigMap PropertySources の再試行を無効にできます。
表 1: プロパティ:
名前 タイプ デフォルト 説明

spring.cloud.kubernetes.config.enabled

Boolean

true

ConfigMaps PropertySource を有効にする

spring.cloud.kubernetes.config.name

String

${spring.application.name}

検索する ConfigMap の名前を設定します

spring.cloud.kubernetes.config.namespace

String

クライアント名前空間

ルックアップ先の Kubernetes 名前空間を設定します

spring.cloud.kubernetes.config.paths

List

null

ConfigMap インスタンスがマウントされるパスを設定します

spring.cloud.kubernetes.config.enableApi

Boolean

true

API を介した ConfigMap インスタンスの消費を有効または無効にする

spring.cloud.kubernetes.config.fail-fast

Boolean

false

ConfigMap のロード中にエラーが発生した場合のアプリケーションの起動の失敗を有効または無効にします

spring.cloud.kubernetes.config.retry.enabled

Boolean

true

構成の再試行を有効または無効にします。

spring.cloud.kubernetes.config.retry.initial-interval

Long

1000

ミリ秒単位の初期再試行間隔。

spring.cloud.kubernetes.config.retry.max-attempts

Integer

6

最大試行回数。

spring.cloud.kubernetes.config.retry.max-interval

Long

2000

バックオフの最大間隔。

spring.cloud.kubernetes.config.retry.multiplier

Double

1.1

次の区間の乗数。