Trabalhando com Spring Cloud Config Server

Nesse post, vamos falar como organizar seus projetos (micro serviços) para utilizar o Spring Cloud Config Server, esta é a forma como eu acredito ser a melhor organização, a qual sempre resolveu meus problemas nesses anos de trabalho.

Precisamos começar “nivelando o terreno”.

Primeiro o obvio. Usando as configurações “dentro” da aplicação cria um problema: “A cada nova configuração, uma nova publicação (deploy) precisa ser feita. Usar uma fonte externa, é a solução para este problema, você muda a configuração e faz “restart”.

Segundo. O Spring Boot tem uma forma complexa de ler e carregar suas configurações, ele carrega de diversas fontes, faz merge (fundir) dos valores e sobrescreve os dados dependendo do seus tipo e da sua ordem.

Eu não vou explicar nesse post sobre como essa ordem funciona, mas vou deixar o link para a leitura (link). O mais importante é saber que existe uma ordem e que ela influencia no seu carregamento.

Terceiro. Para colocar tudo em pratica, você vai precisar fazer a leitura de outros 2 posts. Eles não são pré-requisitos para o entendimento deste, mas são para complementares para a solução final.

http://3.139.95.241/2021/05/03/spring-cloud-config-server-o-que-e-e-como-criar-o-seu/
http://3.139.95.241/2022/02/14/como-organizar-o-spring-boot-application-properties-monofile-e-multiple-profiles/

Agora que já aplainamos o terreno, vamos começar.

Importando as dependências

Começamos fazendo nossa aplicação ser compatível com Spring Cloud, para isso temos que importar algumas dependências (link), ou no https://start.spring.io marcar a dependência Config Client:

Para projetos Maven, você precisa configurar a properties, dependency e o plugin. Abaixo tem um exemplo dos valores para serem adicionados. Compare com o seu próprio pom.xml e adicione os faltantes no seu projeto:

<project>
	<properties>
		<java.version>11</java.version>
		<spring-cloud.version>2021.0.0</spring-cloud.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Para projetos Gradle, precisa crias os itens ext, dependencies e dependencyManagement, abaixo segue um exemplo dos valores. Adicione os faltantes no seu projeto :

ext {
	set('springCloudVersion', "2021.0.0")
}

dependencies {
	implementation 'org.springframework.cloud:spring-cloud-starter-config'
}

dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

Não tem muito o que (dizer) “escrever”, é só ter as bibliotecas do Spring Cloud e a sua versão. Só é importante nunca estar usando uma versão mais antiga que o Spring Cloud Server.

Removendo tudo de src/main/resources

A primeira coisa que faço, é remover todos os arquivos existentes no diretório:

src/main/resources

Isso mesmo, apago tudo, tiro todos, deixo a casa vazia. 🙂

Criando o arquivo src/main/resources/bootstrap.yml

Em sequencia, crio o arquivo:

src/main/resources/bootstrap.yml

Este arquivo é o que “substitui” os arquivos application (yaml ou propreties) quando você esta usando as funções do Spring Cloud, mais informações em link.

(REVISÃO 2022, abril – Bootstrap se tornou opcional (https://github.com/spring-cloud/spring-cloud-config/issues/1695#issuecomment-693482499), desta forma, precisa ser habilitado ou migrar para o novo modelo. Contudo, até o momento desta revisão a documentação oficial esta em transição, ou seja, tem coisas escritas no modelo antigo e coisas escritas no modelo novo. Recomendo, manter no antigo até ele se tornar depreciado.)

O conteúdo deste arquivo vai ser:

spring:
  profiles:
    active:
      - local
  application:
    name: NOME_DA_MINHA_APP
  cloud:
    config:
      name: CONFIGURAÇÃO_COMUM_UM,CONFIGURAÇÃO_COMUM_DOIS,CONFIGURAÇÃO_COMUM_N,NOME_DA_MINHA_APP
      uri: ${CONFIG_SERVER_URI:https://endereço.padrão.do.meu.config.server}
      username: ${CONFIG_SERVER_USER:usuário.do.config.server}
      password: ${CONFIG_SERVER_PASS:senha.forte.do.config.server}

Explicando o seu conteúdo:

spring.profiles.active

Esta configuração representa qual é o profile ativo por padrão. Recomendado o valor ser local.

spring.application.name

Aqui fica o nome do seu projeto (micro serviço / aplicação), esta atributo é muito utilizado por outras bibliotecas em identificar “quem é a aplicação” em execução.

spring.cloud.config.name

Este atributo é quem cria um pouco de “dificuldade” no seu entendimento. Dá a impressão que é o mesmo que o atributo anterior: spring.application.name, mas não é.

Este atributo representa os nomes dos arquivos ou diretórios que vão ser usados para compor o objeto que o Spring Cloud Config Server vai produzir.

No nosso exemplo, ele ira solicitar todas as configurações do profile local para todos os arquivos:

  • CONFIGURAÇÃO_COMUM_UM;
  • CONFIGURAÇÃO_COMUM_DOIS;
  • CONFIGURAÇÃO_COMUM_N;
  • NOME_DA_MINHA_APP.

Depois disso, ele vai fazer um fusão (merge) dos valores, e entregar os atributos de cada elemento.

Este é a grande “sacada” desse modelo, pois você pode ter pré configurações para resolver assuntos específicos e especializar quando precisa.

Por exemplo, supondo que no lugar de CONFIGURAÇÃO_COMUM_UM, este arquivo tivesse o nome, MySQLCommon. Nele, você poderia já tratar todos os seus atributos de configurações para MySQL como:

  • Tamanho do Connection Pool
  • Query SQL de Teste de conexão
  • Habilitar a conexão com o servidor precisa de SSL

Desta forma, qualquer projeto que definir o uso do MySQLCommon, já vai estar com estas configurações “base”. E se por acaso, uma aplicação precisar trocar um valor, basta colocar o atributo e seu valor dentro do arquivo da própria aplicação.

A ordem dos itens nesse atributo é muito importante, pois é ela quem dita como ira ocorrer a fusão (merge) dos atributos, sendo assim, o arquivo da aplicação precisa se sempre o ultimo para ter a prioridade em sobrepor o valor.

spring.cloud.config.uri/username/password

Este atributos representam a forma de como se conectar no Spring Cloud Config Server. Nada de mais, endereço, usuário e senha.

Configuração com valor padrão

Um “adendo” é sobre configurar valores padrões para os atributos, como por exemplo: ${CONFIG_SERVER_URI:https://endereço.padrão.do.meu.config.server}

Esta é uma sintaxe do Spring que diz:

  • Se existir a variável de ambiente (env) CONFIG_SERVER_URI, utilize ela.
  • Se não, utilize o valor https://endereço.padrão.do.meu.config.server

Esse tipo de configuração também é muito útil, pois define um valor padrão que pode ser alterado facilmente. Exemplo, no desenvolvimento local (maquina do desenvolvedor) o atributo utiliza o valor padrão, nos ambientes é passado por parâmetro o valor.

Fazer tudo via Spring Cloud Config Server

Neste modelo, todas as configurações são feitas usando o Spring Cloud Config Server, nenhuma configuração fica dentro da aplicação. Mesmo as configurações usadas para a maquina do desenvolvedor (profile “local”).

Durante o desenvolvimento as configurações já são criadas e enviada no repositório. Assim evita o “Ops! Esqueci de…”

Conclusão

Desta forma, conseguimos trocar toda a responsabilidade de parametrizar as nossas aplicações para um local fora do nosso artefato (build/deploy). Temos uma forma organizada de reutilização de configurações e podemos fazer ajustes sem precisar trocar o programa que esta em execução.

Nos vemos nos próximos posts.