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
- Mechanizm konfiguracji w Spring Boot
- Instrukcja ENV w Dockerfile
- Zmienne środowiskowe w Docker Compose
Artykuły na temat konfiguracji
- Konfiguracja w Kontenerze – wykorzystanie warstw Dockerowych do przechowywania konfiguracji
- Konfiguracja ze zmiennych środowiskowych – wykorzystanie zmiennych środowiskowych do wstrzykiwania parametrów do konfiguracji
- Konfiguracja z serwera konfiguracji – wykorzystanie Spring Cloud Config w celu utworzenia serwera konfiguracji
- 4 sposoby na organizację konfiguracji w repozytorium – porównanie kilku strategii organizacji konfiguracji w repozytorium GIT