Es gibt verschiedene Ansätze, um Play-Anwendungen in ein Docker-Image zu packen. Sie können eine Dockerfile-Datei von Hand erstellen, eine bereits vorhandene Datei anpassen oder einfach ein Tool verwenden, um sie zu generieren. Da Play mit einer großartigen Paketierungsanwendung – sbt-native-packager – geliefert wird, werden wir die letzte Option verwenden.

Docker Image

In build.sbt müssen wir hinzufügen:

import com.typesafe.sbt.packager.docker._ 
dockerChmodType := DockerChmodType.UserGroupWriteExecute 
dockerPermissionStrategy := DockerPermissionStrategy.CopyChown

Dadurch werden die richtigen Dateiberechtigungen in unserem Docker-Image festgelegt.

Der nächste Schritt besteht darin, zum Projektverzeichnis zu navigieren, eine sbt-Shell zu öffnen und Folgendes auszuführen

 

docker:publishLocal

Mit diesem Befehl wird unser lokales Docker-Abbild erstellt.

Um zu überprüfen, ob das Image erstellt wurde, müssen wir ein Terminal öffnen und docker images [APP_NAME] ausführen, wobei [APP_NAME] der Name Ihrer Play-Anwendung ist. Es sollte ein Datensatz vorhanden sein, der unser Abbild mit einer TAG-Nummer darstellt, die der Anwendungsversion entspricht, die in application.conf.

Danach müssen wir das Bild mit dem Befehl ausführen:

docker run --rm -p 9000:9000 APP_NAME:TAG
  • --rm löscht den Container nach dem Beenden
  • -p 9000:9000 ordnet Port 9000 dem Container-Port 9000 zu

Mit dieser Einstellung wird Ihre Play-Anwendung mit derselben Konfigurationsdatei wie Ihre lokale Version ausgeführt. In den meisten Fällen werden Sie eine separate Konfiguration für Ihre Produktionsumgebung und für Ihre lokale Entwicklung benötigen. Um dies zu erreichen, werden wir:

  1. Kopieren Sie die Datei application.conf und benennen Sie sie in prod.conf um.
  2. Entfernen der version Informationen aus der Produktionskonfigurationsdatei
  3. Fügen Sie include "application.conf" der Produktionsdatei hinzu

Dies ermöglicht es uns, einige Einstellungen in der Produktionsumgebung zu überschreiben, indem wir prod.conf bearbeiten.

Um unsere Play-Anwendung mit der neuen Konfigurationsdatei auszuführen, müssen wir das Docker-Image neu erstellen und den Container mit einem neuen Image und einem weiteren Parameter erneut starten: -Dconfig.file=/opt/docker/conf/prod.conf.Der vollständige Befehl sollte in etwa so aussehen:

 docker run -p 9000:9000 APP_NAME:TAG -Dconfig.file=/opt/docker/conf/prod.conf 

Volumes

Um Änderungen an einer Produktionskonfigurationsdatei vorzunehmen, müssen Sie diese in Ihrer lokalen Version des Quellcodes bearbeiten, das Image neu erstellen und den Container erneut starten. Das funktioniert zwar, ist aber ziemlich mühsam. Ein besserer Weg wäre, ein Docker-Volume einzurichten. Dazu müssen wir das conf Verzeichnis von Ihrem Projekt in die Produktion kopieren und Ihr Image mit einem zusätzlichen Argument ausführen:

 docker run 
    -p 9000:9000 
    -v /full/path/to/conf/directory:/opt/docker/conf APP_NAME:TAG 
    -Dconfig.file=/opt/docker/conf/prod.conf

Mit der Option -v /full/path/to/conf/directory:/opt/docker/conf wird ein Docker-Volume erstellt, das es uns ermöglicht, Dateien zwischen dem Host-System und dem Docker-Container auszutauschen. Wenn Sie nun Änderungen an Ihren Produktionskonfigurationsdateien vornehmen, müssen Sie nur den Docker-Container neu starten.

Da wir nun die Produktionskonfiguration von unserer Entwicklungskonfiguration trennen können, können wir den docker runvereinfachen. Wir können eine application.ini Datei in unserer Produktionsumgebung erstellen und – -Dconfig.file=/opt/docker/conf/prod.conf und andere Startparameter darin einfügen. Danach können wir unser Image mit diesem Befehl starten:

 docker run 
    -p 9000:9000 
    -v /full/path/to/conf/directory:/opt/docker/conf 
    APP_NAME:TAG

Files

Die meisten Serveranwendungen müssen Datei-Uploads verarbeiten. Um das Speichern von Dateien aus der Play-Anwendung zu ermöglichen, müssen wir ein Verzeichnis erstellen. Dazu müssen wir den folgenden Code zubuild.sbt hinzufügen.

 dockerCommands ++= Seq(
    ExecCmd("RUN", "mkdir", 
        s"${(defaultLinuxInstallLocation in Docker).value}/APP_NAME_files"), 
)

Dies fügt dem generierten Dockerfile einen Befehl hinzu, der das Verzeichnis APP_NAME_files im Container erstellt.

Bei jedem Neustart wird der Docker-Container neu aufgebaut, was bedeutet, dass alle Dateien, die sich nicht in Volumes befinden, verworfen werden, einschließlich Dateien aus einem zuvor erstellten Verzeichnis. Um dies zu verhindern, müssen wir dem Befehl docker run ein weiteres Volume hinzufügen. Wenn wir schon dabei sind, können wir ein weiteres Volume für Protokolldateien hinzufügen.

 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

Tipps und Tricks

Durch Hinzufügen von dockerUpdateLatest := true  zu Ihrer build.sbt haben Sie immer Zugriff auf die neueste Version Ihres Images buy TAG latest

Wenn Sie Ihre Datenbank auf demselben Rechner wie Ihren Docker-Container hosten, können Sie vom Container aus über host.docker.internal oder über die öffentliche IP Ihres Rechners darauf zugreifen.