Übung: Docker
Vorbereitung
- Auf dem eigenen Rechner: Installieren Sie Docker Desktop
- Linux-Labor: folgen Sie dieser Anleitung.
PHP-Applikation
In dieser Übung werden Sie eine eigene Applikation in ein Container-Image verpacken und als neuen Container starten.
-
Dockerfile
schreiben:FROM php:apache COPY src/ /var/www/html/
-
Applikation schreiben (
src/index.php
):<? phpinfo() ?>
-
Image bauen:
$ docker build -t php-image .
-
Container starten:
$ docker run -d --name php-container --publish 80:80 php-image
-
Applikation testen:
$ curl http://$(docker-machine ip default):80
-
Container stoppen:
$ docker kill php-container
node.js Applikation
Ähnlich dem PHP-Container können Sie auch eine node.js-Applikation als Image paketieren und als Container ausführen.
Dockerfile
schreiben
FROM node:alpine
WORKDIR /usr/src/app
ADD . /usr/src/app
CMD ["node","hello.js"]
Applikation schreiben:
var http = require("http");
var os = require("os");
var hostname = os.hostname();
const port = process.env.PORT || 3000;
http.createServer(function (request, response) {
console.log(new Date().toISOString() + " " + request.method + " " + request.url);
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello from ' + hostname + '\n');
}).listen(port);
console.log("Server listening on port " + port);
Image bauen
$ docker build --tag hello-node .
Container starten
$ docker run -it --rm --name hello-node-1 --publish 8081:8081 --env PORT=8081 hello-node
Applikation testen
$ curl http://$(docker-machine ip default):8081
Beobachten Sie in der Ausgabe des Containers, dass für jeden HTTP-Request eine neue Log-Zeile erzeugt wird.
Container stoppen
$ docker kill hello-node-1
Fragen zur Kontrolle
-
Wie wirkt sich die Änderung der Variable
PORT
aus?
Multi-Container
Viele Anwendungen bestehen aus mehreren Containern. In dieser Übung werden wir eine Ruby-Applikation und einen Postgres-Container zusammen deployen.
Anleitung
Überprüfen Sie die Verfügbarkeit von compose
als Teil der Docker-Installation:
$ docker compose version
sollte eine Ausgabe ähnlich der folgenden erzeugen:
Docker Compose version vX.Y.Z
Dockerfile
schreiben
FROM ruby:alpine
RUN apk add --no-cache \
build-base \
git \
postgresql-dev \
&& rm -rf /var/cache/apk/* \
&& rm -rf /usr/local/lib/ruby/gems/*/cache/* \
&& rm -rf ~/.gem
RUN gem install bundler --no-document
RUN bundle config --global silence_root_warning 1
WORKDIR /app
# Get the app's source code @master.
# You should actually checkout a specific branch or tag in order to get reproducibility.
RUN git clone https://github.com/uhlig-it/journal.git /app
RUN bundle config set --local without 'development test'
RUN bundle config set jobs $(nproc)
RUN bundle install
CMD rake db:migrate && bundle exec ruby app.rb -o 0.0.0.0
Wir kapseln für diese Übung die gleiche Ruby-App wie in der Vagrant-Übung, aber diesmal in einem Container. Zur Vereinfachung der Übung wird beim Bau des Docker-Images der neueste Code (master
-Branch) geklont. In der Realität sollten Sie stattdessen eine wohldefinierte Version (Commit-SHA oder Tag) auschecken.
docker-compose.yml
schreiben
In dieser Datei beschreiben Sie das Zusammenwirken (‘Orchestrierung’) mehrerer Container. Legen Sie einen Container für die Datenbank und einen für die App an. Ergänzen Sie die Stellen, die mit TODO
gekennzeichnet sind.
services:
web:
build: .
# TODO: exposed port, environment variables
db:
image: 'postgres:alpine'
# TODO: environment variables
Erster Start
- Starten Sie den Datenbank-Container mit:
$ docker compose up -d db
- Starten Sie den Web-Container:
$ docker compose up -d web
-
Geben Sie die URL zur App auf der Konsole mit
echo http://$(docker-machine ip default):4567
aus und öffnen Sie danach diese URL im Browser. -
Beobachten Sie die Logs, während Sie mit dem Browser HTTP-Anfragen starten:
$ docker compose logs -f
Alternativ können Sie die Anfragen auch in einem zweiten Terminal-Fenster starten:
$ curl http://$(docker-machine ip default):4567
Fehlermeldungen
-
ERROR: Service 'web' failed to build: ADD failed: stat /mnt/sda1/var/lib/docker/tmp/docker-builder594177452/journal: no such file or directory
Dieser Fehler tritt auf, wenn die Applikation, die in dem
Dockerfile
-StatementADD journal /app
referenziert wurde, nicht vorhanden ist. Fügen Sie die App zu dem Ordner hinzu, der dasDockerfile
enthält (siehe oben).
Fragen zur Kontrolle
-
Wie können Sie sicherstellen, dass der Datenbank-Container auf jeden Fall vor dem Web-Container gestartet wird?
-
Wie könnte eine alternative Lösung aussehen, bei der die Reihenfolge der Container-Starts keine Rolle spielt? Bedenken Sie, dass es zur Laufzeit durchaus zu vorübergehendem Ausfall des Datenbank-Containers kommen kann. Dabei soll der Web-Container weiterlaufen und eine Fehlermeldung anzeigen (statt kommentarlos zu stoppen).
-
Wie könnte die vorhandene Lösung skalieren? Was wäre notwendig, um z.B. mehrere Instanzen des
web
containers zu starten?Vergleichen Sie dazu auch den Ansatz aus der Musterlösung Virtuelle Maschinen.
Literatur
- Docker Engine - Images bauen und Container ausführen
- Dockerfile Referenz
- Docker Machine - Docker-Engine in einer VM
- Docker Compose - Multi-Container Verbund verwalten
- Musterlösung multi-container (zusammen mit dem Dockerfile)