SIer だけど技術やりたいブログ

Spring Cloud Configのリファレンス読んだ

SpringBoot Java Spring

Spring Cloud Configとは

複数アプリケーション(同一サービス)間で共通の設定を提供するプロダクト。
クライアント-サーバ型のアーキテクチャ。

  • Configサーバ(githubやファイルシステム上のgitリポジトリから設定を取得してクライアントに配布する)
  • Configクライアント(サーバに要求して設定を取得する)

何がいいの?

  • 複数アプリケーション(同一サービス)間の設定の不一致を避けられる。
  • 再起動なしで設定を再配布できる。

サンプル書いた

実装方法

Configサーバ

pom.xmlで必要なjarを指定する。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

@EnableConfigServerをつける。

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

クライアントに配布する設定ファイルの配置場所をapplication.propertiesで指定する。portは8888が一般的っぽい。

server.port = 8888
spring.cloud.config.server.git.uri = https://github.com/kimullaa/spring-cloud-config-repo.git

githubでもローカルのファイルシステム上にあるgitリポジトリでもok。publicでもprivateなリポジトリでもok。sshでもok。特に制約なし。

リポジトリはアプリごとに1つ用意するのがシンプルでよい。
ファイル名は{app名}-{profile}にする。

https://github.com/kimullaa/spring-cloud-config-repo

Configサーバといっても、以下のようなエンドポイントを持ったAPサーバ。
(labelはdefaultがmasterで省略可能)

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

そのため、curlで設定を確認できる。

$ curl -X GET http://localhost:8888/app/production
{
    "name":"app",
    "profiles":[
        "production"
    ],
    "label":null,
    "version":"1469d0351becdfcc a1bffa98f4a07ee685af8255",
    "propertySources":[
        {
            "name":"https://github.com/kimulla men/spring-cloud-config-repo.git/app-production.properties",
            "source":{
                "greeting":"production"
            }
        }
    ]
}
$ curl -X GET http://localhost:8888/app-development.properties
greeting: development

Configクライアント

pom.xmlで必要なjarを指定する。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

bootstrap.propertiesにconfigサーバのURIを指定する。

spring.cloud.config.uri = http://localhost:8888
spring.application.name = app 
spring.profiles.active = production

bootstrap.propertiesはBootstrapContext※を生成するときに利用するファイル。
Configサーバから取得した設定内容を読み込んだクラスが生成される。

※BootstrapContextはApplicationContextの親コンテキスト。詳細はリファレンスを参照する。

設定を取得できてるか確認するためのControllerを実装する。
@Valueでpropertiesファイルの値を取得できる。(:not-foundは見つからなかったときのデフォルト値)

@RestController
public class GreetingRestController {
    @RequestMapping("/greeting")
    public String greeting(@Value("${greeting:not-found}") String greeting) {
        return greeting;
    }
}

クライアントから見たときのファイル名とアプリの関連性は?

{app名}-{profile}-{label}.properties

app名spring.application.name
profilespring.active.profiles
labelgitのbranch名(デフォルトmaster)

設定変更の反映

いくらgitのファイルを更新しても、アプリ側が設定ファイルを再度読み込むまでは値が反映されない。設定ファイルを再度読み込むためには、/refreshエンドポイントにPOSTすればよい。

細かい理由

  • @ConfigurationPropertiesアノテーションが付与されているクラスは@RefreshScopeになる
  • @RefreshScopeのBeanは/refreshエンドポイントにPOSTするとBeanが再生成される
  • ConfigClientAutoConfigurationクラス内でConfigServicePropertySourceLocatorという設定ファイル読み込み用のクラスが@RefreshScopeになっているため/refreshエンドポイントにPOSTすれば更新されるっぽい
$ curl -X POST localhost:8080/refresh
["greeting"]

でも全部のConfigクライアントに/refreshなんてしたくない

Spring Cloud Busというプロダクトを使えば、Configクライアントから他のConfigクライアントへ更新通知を伝搬できるようになる。~~また今度調べる。~~調べた。
SpringCloudBusで簡単にConfigの更新をアプリにブロードキャストする - SIerだけど技術やりたいブログkimulla.hatenablog.com

参考にしたサイト