Konfiguracja ze zmiennych środowiskowych

W poprzednim poscie pisałem o zastosowaniu warstw dockerowych w celu przekazania konfiguracji do aplikacji. Tym razem tematem będzie konfiguracja ze zmiennych środowiskowych i wspierające takie rozwiązanie mechanizmy Spring i Dockera.

Użycie zmiennych środowiskowych ma znaczącą przewagę nad wykorzystaniem warstw dockerowych. Zmiana konfiguracji nie wymaga przebudowania obrazu. Jedyne co potrzebujemy zrobić to zrestartować aplikację aby zmiany zostały zaczytane.

Wadą jest natomiast granulacja. Jedna zmienna przechowuje jedną wartość. W przypadku kiedy nasza aplikacja korzysta z wielu parametrów to musimy zdefiniować odpowiednio długą listę zmiennych – co może mieć bardzo negatywny wpływ na przejrzystość konfiguracji.

Na wstępie jeszcze chciałem podziękować Adamowi Brodziakowi, za to że zwrócił mi uwagę na to, że zaszywanie konfiguracji w obrazie dockerowym nie należy do najlepszych praktyk. Zdecydowanie lepiej jest użyć zmiennych środowiskowych.
To mnie zainspirowało do napisania tego posta.

Zmienne w plikach konfiguracyjnych

Spring w swoich plikach konfiguracyjnych potrafi dostać się do zmiennych środowiskowych. Dzięki temu możemy ich użyć w dowolnym miejscu naszej konfiguracji. Oczywiście, najlepszym miejscem wykorzystania zmiennych będą adresy usług, baz danych i wszystko to co się różni pomiędzy środowiskami.

Dla przykładu, poniżej plik konfiguracyjny zawierający zmienną SPRING_MONGO_HOST jako adres bazy danych MongoDB:

spring:
  data:
    mongodb:
      uri: mongodb://${SPRING_MONGO_HOST}/effento

Jeśli potrzebujemy zdefiniować domyślne wartości w przypadku braku zmiennej, używamy notacji ${ZMIENNA:WARTOSC_DOMYSLNA}, tak jak poniżej:

spring:
  data:
    mongodb:
      uri: mongodb://${SPRING_MONGO_HOST:localhost}/effento

Zmienne w kontenerze

Jak już mamy zmienne środowiskowe ogarnięte w aplikacji i jej konfiguracji, warto też o to zadbać poziom wyżej, czyli w kontenerze. Tutaj musimy zdefiniować listę zmiennych jakie chcemy mieć dostępne i opcjonalnie przypisać im domyślne wartości.

FROM openjdk:11

COPY target/app.jar /app/app.jar
COPY ./application.yml /app/config/application.yml

ENV SPRING_MONGO_HOST=somehost

WORKDIR /app

EXPOSE 8080
ENTRYPOINT java -jar app.jar

Następnie wystarczy uruchomić tak zbudowany obraz ustawiając mu zmienną na żądana wartość:

docker run --env SPRING_MONGO_HOST=mongodb <image-name>

W Dockerfile została użyta konstrukcja ENV inicjalizująca zmienną w kontenerze:
ENV NAZWA_ZMIENNEJ=WARTOSC_DOMYŚLNA

Następnie podczas uruchomienia, ustawiamy tą zmienną wedle uznania przy pomocy parametr
--env NAZWA_ZMIENNEJ=WARTOSC

Zmienne w docker-compose

Na koniec, jeśli używasz docker-compose np. na potrzeby postawienia lokalnego środowiska developerskiego, to tutaj tez możesz się do tych zmiennych dostać i je ustawić:

version: "3"
services:
  app:
    build: .
    links:
      - mongodb
    depends_on:
      - mongodb
    environment:
      - SPRING_MONGO_HOST=mongodb
    ports:
      - "8080:8080"
  mongodb:
    image: mongo
    hostname: mongodb

Robimy to używając sekcji environment w której po prostu definiujemy listę zmiennych wraz z ich wartościami. Jeśli wartości nie podamy, to wartość zmiennej jest przekazywana z HOSTa do kontenera.

Dodatkowe informacje


Artykuły na temat konfiguracji