Centralizzare le configurazioni: Config Server con Spring Cloud

C

 

In un ambiente distribuito o in un architettura a microservizi dove possono esserci decine di applicazioni da gestire, potrebbe essere poco pratico, se non addirittura sbagliato come approccio, manutenere per ogni ambiente e singole applicazione le relative configurazioni.
Uno dei progetti Spring Cloud, nello specifico Spring Cloud Config, viene incontro a questo requisito permettendo in pochi passi l’implementazione di un Configuration Server per centralizzare ed esternalizzare le configurazioni, permettendo di suddivide e richiamarle per ambiente.
Le nostre applicazioni saranno cosi indipendenti dall’ambiente in cui vengono eseguite. Se sono implementate con Spring Boot sarà ancora più semplice poiché basterà avviarle col profilo corretto dell’ambiente in cui girano.

Volendo elencare le principali funzionalità che fornisce Spring Cloud Config:

  • esternalizzazione e gestione centralizzata delle configurazioni
  • supporto dei seguenti tipi di storage da cui leggere le configurazioni
    • Git repository
    • Version Control Backend Filesystem Use
    • File system
    • Vault
    • JDBC
    • Redis
    • AWS S3 Backend
    • CredHub Backend
  • configurazioni esposte tramite API HTTP

Nell’esempio che segue verrà mostrata l’implementazione di un Config Server che legge da un repository Git. Verranno definite configurazioni per differenti ambienti. Vedremo poi come queste possono essere lette da una semplice applicazione Spring Boot.

Config Server

L’implementazione di un Config Server con Spring Cloud non è altro che un’applicazione Spring Boot che usa la dipendenza spring-cloud-config-server ed è annotata con @EnableConfigServer.

@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {

  public static void main(String[] args) {
    SpringApplication.run(ConfigApplication.class, args);
  }
}

Questa è la configurazione che faremo nel file application.yml

spring:  
  application:    
    name: config-server
  cloud:    
    config:      
      server:        
        git:          
          uri: https://github.com/username/your-config-repo.git
server:
  port: ${PORT:8060}

A questo punto il nostro server esporrà le seguenti interfacce per recuperare le configurazioni:

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

dove il significato dei placeholder è il seguente:

  • {application} si riferisce alla configurazione “spring.application.name” sul client
  • {profile} si riferisce alla configurazione “spring.profiles.active” sul client (comma separated list)
  • {label} il quale è una feature del server da usare in caso di “versionamento” di un insieme di configurazioni (ad esempio il nome del branch)

Ipotizziamo ora che nel nostro repository ci siano i questi file configurati come segue:

  • application.properties
  • myapp-dev.properties
  • myapp-prod.properties

application.properties

common.config=A common configuration

myapp-dev.properties

env.config=Development config

myapp-prod.properties

env.config=Production config
common.config=A common "overridden" configuration

Potremmo leggere la configurazione dall’applicazione “myapp” eseguita col profilo “dev” eseguendo

curl localhost:8060/myapp/dev

la risposta sarà la seguente:

{
   "name":"myapp",
   "profiles":[
      "dev"
   ],
   "label":null,
   "version":"d4c8b2f2027f9c081251e3db436fdb1087801b5d",
   "state":null,
   "propertySources":[
      {
         "name":"https://github.com/alessiofiore/spring-cloud-conf.git/myapp-dev.properties",
         "source":{
            "common.config":"A common configuration"
         }
      },
      {
         "name":"https://github.com/alessiofiore/spring-cloud-conf.git/application.properties",
         "source":{
            "common.config":"A common configuration"
         }
      }
   ]
}

Come possiamo notare a riga 17 è stata letta anche la configurazione del file application.properties, questo perché Spring per default cerca file col nome application* (application.propertiesapplication.ymlapplication-*.properties, e cosi via) che sono condivisi tra i client. Questa caratteristica può essere utilizzata per definire proprietà globali che possono comunque essere sovrascritte ridefinendo la property nel file di una specifica applicazione. E’ comunque opzionale, quindi laddove non è utile possiamo evitare di definire un file application*.

Client side

A questo punto per implementare un client Spring Boot che riesca  leggere le configurazioni dal server è sufficiente che l’applicazione abbia la dipendenza spring-cloud-starter-confige il suo file bootstrap.yml sia configurato come segue:

spring:
  application:
    name: myapp
  cloud:
    config:
      uri: http://localhost:8060

La configurazione della parte cloud viene fatta in fase di creazione del bootstrap context, precedente alla fase di creazione dell’application context. Nella fase di bootstrap Spring utilizza le configurazioni presenti nel file bootstrap.yml o bootstrap.properties.

Vediamo una semplice implementazione

@SpringBootApplication
public class MyApplication {

    @Value("${common.config}")
    private String common;

    @Value("${env.config}")
    private String env;

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Bean
    public CommandLineRunner runner() {
        return (args) -> {
            System.out.println(common);
            System.out.println(env);
        };
    }
}

A questo punto lanciando l’applicazione come segue:

java -jar -Dspring.profiles.active=dev target/config-client.jar

vedremo l’output seguente:

A common configuration
Development config

Lanciando ora l’applicazione col profilo “prod”

java -jar -Dspring.profiles.active=prod target/myapp.jar

avremo invece  l’output seguente:

A common "overridden" configuration
Production config

Come possiamo notare la property common.config è stata sovrascritta in quando ridefinita nel file myapp-prod.properties.

Altre funzionalità

Come Spring insegna le possibilità e le potenzialità del framework e dei singoli progetti vanno ben oltre. Il progetto Spring Cloud Config infatti fornisce molte altre funzionalità e possibilità di configurarlo per scopi specifici.

Oltre a quelli già elencati all’inizio dell’articolo di seguito ne elenchiamo soltanto alcuni:

  • aggiungere autenticazione alle API
  • configurazione mista di storage come sorgenti configurazione per pattern {application}/{profile} differenti
  • cifratura e decifratura dei valori (simmetrica e asimmetrica)
  • push notification sulle applicazioni usando MoM
  • possibilità di configurare lato client più URL di Config Server

Per la documentazione completa rimando alla pagina ufficiale.

Repository

Su questo repository è possibile trovare  i sorgenti degli esempi mostrati in questo articolo:
https://github.com/alessiofiore/ic-spring-cloud-config

A proposito di me

Alessio Fiore

Grande appassionato di sviluppo software e linguaggi di programmazione ha una grande conoscenza nel mondo Java e framework come Spring e Hibernate.
Laureato magistrale in Ingegneria Informatica lavora come sviluppatore software in ambito Telco principalmente lato backend, ma coltivando sempre molto interesse su tecnologie frontend.
Ha una grande esperienza su system integration, architetture software e sistemi distribuiti.

I nostri Partner

Gli articoli più letti

Articoli recenti

Commenti recenti