Istnieje kilka różnych podejść do pakowania aplikacji Play w obraz Dockera. Możesz stworzyć plik Dockerfile ręcznie, dostosować istniejący plik lub po prostu użyć jakiegoś narzędzia do jego wygenerowania. Ponieważ Play posiada świetną aplikację do pakowania – sbt-native-packager – użyjemy tej ostatniej opcji.
Docker Image
W build.sbt
musimy dodać:
import com.typesafe.sbt.packager.docker._
dockerChmodType := DockerChmodType.UserGroupWriteExecute
dockerPermissionStrategy := DockerPermissionStrategy.CopyChown
To ustawi prawidłowe uprawnienia plików wewnątrz naszego Docker Image.
Następnym krokiem jest przejście do katalogu projektu, otwarcie powłoki sbt i uruchomienie
docker:publishLocal
To polecenie buduje nasz lokalny obraz Dockera.
Aby sprawdzić czy obraz został utworzony musimy otworzyć terminal i uruchomić docker images [APP_NAME]
to nazwa Twojej aplikacji Play. Powinien pojawić się rekord reprezentujący nasz obraz z numerem TAG takim samym jak wersja aplikacji podana w pliku application.conf
.
Po tym musimy uruchomić obraz za pomocą polecenia:
docker run --rm -p 9000:9000 APP_NAME:TAG
--rm
usunie pojemnik po wyjściu-p 9000:9000
mapuje port 9000 na port kontenerów 9000
Przy takim ustawieniu Twoja aplikacja Play będzie działać z tym samym plikiem konfiguracyjnym, co Twoja lokalna wersja. Przez większość czasu będziesz potrzebował oddzielnego configu dla swojego środowiska produkcyjnego i dla swojego lokalnego rozwoju. Aby to osiągnąć, będziemy:
- Skopiuj plik
application.conf
i zmień jego nazwę naprod.conf
- Usuń informację
version
o wersji z pliku konfiguracyjnego produkcji - Dodaj
include "application.conf"
nad plikiem produkcyjnym
Dzięki temu będziemy mogli nadpisać niektóre ustawienia w środowisku produkcyjnym poprzez edycję prod.conf
.
Aby uruchomić naszą aplikację Play z nowym plikiem konfiguracyjnym musimy przebudować obraz dockera i ponownie uruchomić kontener z nowym obrazem i jeszcze jednym parametrem: -Dconfig.file=/opt/docker/conf/prod.conf
. Pełne polecenie powinno wyglądać podobnie do tego:
docker run -p 9000:9000 APP_NAME:TAG -Dconfig.file=/opt/docker/conf/prod.conf
Volumes
Aby wprowadzić zmiany w pliku konfiguracyjnym produkcji, będziesz musiał edytować go w swojej lokalnej wersji kodu źródłowego, przebudować obraz i ponownie uruchomić kontener. Chociaż działa, jest to dość uciążliwe. Lepszym sposobem byłoby skonfigurowanie woluminu Dockera. Aby to zrobić, musimy skopiować katalog conf z twojego projektu do produkcji i uruchomić swój obraz, ale z dodatkowym argumentem:
docker run
-p 9000:9000
-v /full/path/to/conf/directory:/opt/docker/conf APP_NAME:TAG
-Dconfig.file=/opt/docker/conf/prod.conf
Opcja -v /full/path/to/conf/directory:/opt/docker/conf
utworzy wolumin Dockera, który pozwala nam na współdzielenie plików pomiędzy systemem hosta a kontenerem Dockera. Teraz jeśli dokonamy zmian w plikach konfiguracyjnych produkcji wystarczy ponownie uruchomić kontener Docker.
Teraz, gdy możemy łatwo oddzielić konfigurację produkcyjną od naszej konfiguracji deweloperskiej, możemy uprościć docker run
. Możemy stworzyć plik application.ini
w naszym środowisku produkcyjnym i umieścić w nim -Dconfig.file=/opt/docker/conf/prod.conf
i inne parametry uruchamiania. Po tym możemy uruchomić nasz obraz za pomocą tego polecenia:
docker run
-p 9000:9000
-v /full/path/to/conf/directory:/opt/docker/conf
APP_NAME:TAG
Files
Większość aplikacji serwerowych musi obsługiwać wysyłanie plików. Aby umożliwić zapisywanie plików z aplikacji Play musimy utworzyć katalog. Aby to zrobić musimy dodać poniższy kod do build.sbt
.
dockerCommands ++= Seq(
ExecCmd("RUN", "mkdir",
s"${(defaultLinuxInstallLocation in Docker).value}/APP_NAME_files"),
)
Dzięki temu do wygenerowanego pliku Dockerfile zostanie dodane polecenie, które utworzy katalog APP_NAME_files
w kontenerze.
Przy każdym restarcie kontener Docker zostaje przebudowany, co oznacza, że wszystkie pliki, które nie znajdują się w woluminach są wyrzucane, w tym pliki z wcześniej utworzonego katalogu. Aby temu zapobiec, musimy dodać kolejny wolumin do polecenia docker run
. Podczas gdy jesteśmy przy tym, możemy dodać kolejny wolumin dla plików dziennika.
docker run
-p 9000:9000
-v /full/path/to//conf:/opt/docker/conf
-v /full/path/to/files:/opt/docker/APP_NAME_files
-v /full/path/to/logs:/opt/docker/YOUR_LOG_DIR
APP_NAME:TAG
Tips and Tricks
Dodając dockerUpdateLatest := true
do swojego build.sbt
będziesz miał zawsze dostęp do najnowszej wersji swojego obrazu przez TAG latest
Jeśli hostujesz swoją bazę danych na tej samej maszynie co kontener Docker, możesz uzyskać do niej dostęp z wnętrza kontenera za pomocą host.docker.internal
lub wskazując na publiczne IP maszyny.