Parametryzowanie Dockerfile

Trudno sobie dzisiaj wyobrazić rozwój dużego projektu bez wykorzystywania dobrodziejstw jakie daje nam wirtualizacja. Po prostu ilość potrzebnych komponentów, relacji między nimi, całego procesu developmentu, orkiestracji jest tak olbrzymia i skomplikowana, że bez Dockera nie dalibyśmy rady.

Jednakże narzędzia takie jak docker i docker-compose nie są panaceum na wszystkie problemy. Ostatnio stanąłem przed wyzwaniem rozdzielenia logiki w trakcie budowy obrazu w pliku Dockerfile. Generalnie, potrzebna jest inna wersja na produkcji a inna w trybie deweloperskim.

Jako programista, głównie piszący w świecie obiektowym postanowiłem rozwiązać ten problem używając dziedziczenia. Jakże było to wielkie zaskoczenie dla mnie, gdy okazało się, że pliki Dockerfile nie posiadają takiego mechanizmu. Dziedziczeniu może podlegać jedynie logika zawarta w plikach docker-compose.yml…cóż, trzeba kombinować inaczej.

Rozwiązanie jakie udało mi się zaimplementować używa parametrów na etapie budowy obrazu – komenda arg [1][2]. Wygląda to następująco.

W głównym pliku budowy obrazu Dockerfile tworzymy zmienną (owy parametr) i przypisujemy domyślną wartość. Domyślna wartość może odpowiadać zachowaniu w np. trybie produkcyjnym.

ARG some_variable_name=default_value

W dalszej części pliku Dockerfile wykorzystujemy zmienną dostarczając zachowanie w zależności od wartości tego parametru. Właściwie jest to pewnego rodzaju flaga dla nas. Przykład:

RUN apt-get install $some_variable_name

Równie dobrze, można też [3]:

RUN if [ "x$some_variable_name" = "htop" ] ; then something action ; else echo other action ; fi

Pozostaje jeszcze nadpisać domyślną wartość np. dla trybu deweloperskiego. Poniżej zawartość docker-compose-dev.yml

services:
  someImage:
    build:
      context: ./
      dockerfile: Dockerfile
      args:
        some_variable_name: "htop"

Jeszcze innym rozwiązaniem tego problemu jaki się nasuwa to skonfigurowanie domyślnego obrazu po jego budowie i ponowne zapisanie stanu przy użyciu commit [4]. Ale jakoś to takie mało eleganckie posunięcie :/

[1] https://docs.docker.com/engine/reference/builder/#arg
[2] https://vsupalov.com/docker-arg-env-variable-guide/
[3] https://stackoverflow.com/questions/43654656/dockerfile-if-else-condition-with-external-arguments
[4] https://forums.docker.com/t/docker-container-not-persisting-data-on-stop-start-or-when-committing-to-another-image-on-windows/5612