Automatisierte Erstellung von Docker Containern


Im letzten Docker-Tutorial hat Olli gezeigt, wie man mit Rocker ein Docker-Image aus R-Base-Skripten erstellt und diese in einem Container ausführt. Darauf aufbauend werde ich erläutern, wie man diesen Prozess mit Hilfe eines Bash-/Shell-Skripts automatisieren kann. Da wir bei statworx in der Regel Container für das Deployment unserer Apps verwenden, habe ich eine kleine Test-App mit R-Shiny erstellt, die in einem Test-Container gespeichert wird. Selbstverständlich ist es auch möglich, jede andere Anwendung mit diesem automatisierten Skript zu speichern, wenn man möchte. Ich habe außerdem ein Repository auf unserem Blog-GitHub erstellt, in dem sich alle Dateien sowie die Test-App befinden.
Feel free, den Inhalt zu testen und zu verwenden. Wenn du daran interessiert bist, selbst eine Setup-Skriptdatei zu schreiben, sei angemerkt, dass es auch möglich ist, alternative Programmiersprachen wie Python zu verwenden.
Die Idee dahinter
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
Dataiku - virtualbox Stopped Unknown
default - virtualbox Stopped Unknown
ShowCase - virtualbox Stopped Unknown
SQLworkshop - virtualbox Stopped Unknown
TestMachine - virtualbox Stopped Unknown
$ docker-machine start TestMachine
Starting "TestMachine"...
(TestMachine) Check network to re-create if needed...
(TestMachine) Waiting for an IP...
Machine "TestMachine" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.
$ eval $(docker-machine env --no-proxy TestMachine)
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED
cfa02575ca2c testimage "/sbin/my_init" 2 weeks ago
STATUS PORTS NAMES
Exited (255) About a minute ago 0.0.0.0:2000->3838/tcp testcontainer
$ docker start testcontainer
testcontainer
$ docker ps
...
Docker-Images immer wieder neu zu bauen, jedes Mal wenn man Änderungen an seiner Anwendung vornimmt, kann mit der Zeit etwas mühsam werden – besonders, wenn man ständig dieselben alten Befehle eintippt. Olli hat bereits den Vorteil beschrieben, ein Zwischen-Image für die zeitaufwendigsten Prozesse – wie etwa das Installieren von R-Paketen – zu erstellen, um den Prozess der Inhaltserstellung zu beschleunigen. Das ist eine hervorragende Praxis, die man bei jedem geeigneten Projekt anwenden sollte. Aber wie wäre es, wenn man auch die Containerisierung selbst beschleunigen könnte? Man braucht dazu nur ein kleines Helferlein – ein Tool, das, einmal geschrieben, die gesamte Arbeit für einen übernimmt.
Building and rebuilding Docker images over and over again every time you make some changes to your application can get a little tedious at times, especially if you type in the same old commands all the time. Olli discussed the advantage of creating an intermediary image for the most time-consuming processes, like installing R packages to speed things up during content creation. That's an excellent practice, and you should try and do this for every project viable. But how about speeding up the containerisation itself? A small helper tool is needed that, once it's written, does all the work for you.
Die Werkzeuge, die man benötigt
Um Docker-Images und -Container zu erstellen, muss Docker auf deinem Rechner installiert sein. Wenn du das in diesem Blogpost und auf unserem Blog-GitHub bereitgestellte Material testen oder verwenden möchtest, solltest du außerdem VirtualBox, R und RStudio installieren – sofern noch nicht geschehen. Wenn du Windows (10) als Betriebssystem nutzt, musst du zusätzlich das Windows Subsystem für Linux installieren. Alternativ kannst du deine eigenen Skriptdateien auch mit PowerShell oder einem ähnlichen Tool erstellen.

Das Tool selbst ist ein Bash-/Shell-Skript, das für dich Docker-Container baut und ausführt. Alles, was du tun musst, um es zu verwenden, ist, die ausführbare Datei docker_setup
in dein Projektverzeichnis zu kopieren und sie auszuführen. Das Einzige, was das Tool danach von dir verlangt, ist eine Eingabe zur Benennung.
Falls die Ausführung aus irgendeinem Grund fehlschlägt oder Fehler erzeugt, versuche, das Tool über das Terminal auszuführen.
source ./docker_setup
Um selbst ein Bash-/Shell-Skript zu erstellen oder zu replizieren, öffne deinen bevorzugten Texteditor, erstelle eine neue Textdatei, füge ganz oben die Präambel #!/bin/bash
ein und speichere sie ab. Öffne danach dein Terminal, navigiere zu dem Verzeichnis, in dem du dein Skript gespeichert hast, und ändere den Modus mit dem Befehl chmod +x dein_skriptname
. Um zu testen, ob es korrekt funktioniert, kannst du z. B. die Zeile echo 'it works!'
unter die Präambel schreiben.
#!/bin/bash
echo 'it works!'
Wenn du alle verfügbaren Modus-Optionen überprüfen möchtest, besuche das Wiki, und für eine vollständige Anleitung das „Linux Shell Scripting Tutorial“.
Der Code, der das Ganze ausführt
Wenn du die ausführbare Datei docker_setup
mit deinem bevorzugten Texteditor öffnest, kann der Code anfangs etwas überwältigend oder verwirrend wirken – aber er ist ziemlich unkompliziert.
#!/bin/bash
# This is a setup bash for docker containers!
# activate via: chmod 0755 setup_bash or chmod +x setup_bash
# navigate to wd docker_contents
# excute in terminal via source ./setup_bash
echo ""
echo "Welcome, You are executing a setup script bash for docker containers."
echo ""
echo "Do you want to use the Default from the global configurations?"
echo ""
source global_conf.sh
echo "machine name = $machine_name"
echo "container = $container_name"
echo "image = $image_name"
echo "app name = $app_name"
echo "password = $password_name"
echo ""
docker-machine ls
echo ""
read -p "What is the name of your docker-machine [default]? " machine_name
echo ""
if [[ "$(docker-machine status $machine_name 2> /dev/null)" == "" ]]; then
echo "creating machine..."
&& docker-machine create $machine_name
else
echo "machine already exists, starting machine..."
&& docker-machine start $machine_name
fi
echo ""
echo "activating machine..."
eval $(docker-machine env --no-proxy $machine_name)
echo ""
docker ps -a
echo ""
read -p "What is the name of your docker container? " container_name
echo ""
docker image ls
echo ""
read -p "What is the name of your docker image? (lower case only!!) " image_name
echo ""
Die Hauptstruktur des Codes basiert auf verschachtelten if-Anweisungen. Im Gegensatz zu einer manuellen Docker-Einrichtung über das Terminal muss das Skript viele verschiedene Möglichkeiten berücksichtigen und sogar eine gewisse Fehlertoleranz zulassen. Die erste if-Anweisung zum Beispiel – wie im obigen Bild dargestellt – prüft, ob eine angeforderte Docker-Maschine bereits existiert. Falls die Maschine nicht existiert, wird sie erstellt. Existiert sie bereits, wird sie einfach gestartet und verwendet.
Die verwendeten Code-Elemente oder Befehle sind dabei noch direkter. Der Befehl echo
gibt eine Information oder eine Leerzeile zur besseren Lesbarkeit aus. Der Befehl read
ermöglicht es, eine Benutzereingabe auszulesen und als Variable zu speichern, die anschließend in allen weiteren Codeabschnitten verwendet wird. Die meisten anderen Code-Elemente sind Docker-Befehle und im Grunde identisch mit denen, die manuell über das Terminal eingegeben werden. Wenn du mehr über Docker-Befehle erfahren möchtest, wirf einen Blick in die Dokumentation und Ollis großartigen Blogbeitrag.
Das Git-Repository
Der zentrale Punkt des Git-Repositories auf unserem Blog-GitHub ist das automatisierte Docker-Setup, aber es enthält auch einige andere praktische Hilfsmittel und soll hoffentlich zu einer umfassenden Sammlung nützlicher Skripte und Bash-Dateien heranwachsen. Mir ist bewusst, dass es für alles im Repository möglicherweise bessere, schnellere und komfortablere Lösungen gibt, aber wenn wir es als Übung und Form des kreativen Austauschs betrachten, denke ich, dass wir einiges daraus gewinnen können.

Die ausführbare Datei docker_error_logs
ermöglicht eine schnelle Fehlersuche und das Speichern von Logdateien, falls dein Programm oder deine App innerhalb deines Docker-Containers nicht funktioniert.
Die ausführbare Datei git_repair
ist noch nicht vollständig getestet und sollte mit Vorsicht verwendet werden. Die Idee dahinter ist, schnell zu prüfen, ob dein lokales Projekt oder Repository mit einem entsprechenden GitHub-Repository verbunden ist – basierend auf einer URL – und gegebenenfalls diese Verbindung zu „reparieren“. Zudem kann sie Git-Pulls, Commits und Pushes für dich verwalten – aber auch hier bitte mit Bedacht nutzen.
Kommende Projekte
Wie bereits erwähnt, plane ich, die Sammlung und den Nutzen unseres Blog-GitHubs bald weiter auszubauen. Im nächsten Schritt werde ich dem Docker-Setup mehr Komfort hinzufügen, indem ich eine separate Datei einfüge, die die Möglichkeit bietet, Standardwerte für wiederholte Ausführungen zu speichern und zu verwenden. Also bleib dran und schau bald wieder auf unserem statworx Blog vorbei. Bis dahin – happy coding.