Diese Wikiseite zeigt auf wie Applikationen und Services, als Container (Containerisiert) betrieben werden können.
Sie können Applikationen und Services als Container betrieben und als Container Images für Dritte zur Verfügung stellen.
- 01 - Container
- 02 - Docker
- 03 - Netzwerk-Anbindung (optional)
- 04 - Volumes (optional)
- 05 - Image-Bereitstellung
- 06 - Reflexion
- 07 - Fragen
- 08 - LB 3 hands-on
- 09 - Quellenverzeichnis
Container ändern die Art und Weise, wie wir Software entwickeln, verteilen und laufen lassen, grundlegend.
Entwickler können Software lokal bauen, die woanders genauso laufen wird – sei es ein Rack in der IT-Abteilung, der Laptop eines Anwenders oder ein Cluster in der Cloud.
Administratoren können sich auf die Netzwerke, Ressourcen und die Uptime konzentrieren und müssen weniger Zeit mit dem Konfigurieren von Umgebungen und dem Kampf mit Systemabhängigkeiten verbringen.
Merkmale
- Container teilen sich Ressourcen mit dem Host-Betriebssystem
- Container können im Bruchteil einer Sekunde gestartet und gestoppt werden
- Anwendungen, die in Containern laufen, verursachen wenig bis gar keinen Overhead
- Container sind portierbar --> Fertig mit "Aber bei mir auf dem Rechner lief es doch!"
- Container sind leichtgewichtig, d.h. es können dutzende parallel betrieben werden.
- Container sind "Cloud-ready"!
Container sind ein altes Konzept. Schon seit Jahrzehnten gibt es in UNIX-Systemen den Befehl chroot, der eine einfache Form der Dateisystem-Isolation bietet.
Seit 1998 gibt es in FreeBSD das Jail-Tool, welches das chroot-Sandboxing auf Prozesse erweitert.
Solaris Zones boten 2001 eine recht vollständige Technologie zum Containerisieren, aber diese war auf Solaris OS beschränkt.
Ebenfalls 2001 veröffentlichte Parallels Inc. (damals noch SWsoft) die kommerzielle Containertechnologie Virtuozzo für Linux, deren Kern später (im Jahr 2005) als Open Source unter dem Namen OpenVZ bereitgestellt wurde.
Dann startete Google die Entwicklung von CGroups für den Linux-Kernel und begann damit, seine Infrastruktur in Container zu verlagern.
Das Linux Containers Project (LXC) wurde 2008 initiiert, und in ihm wurden (unter anderem) CGroups, Kernel-Namensräume und die chroot-Technologie zusammengeführt, um eine vollständige Containerisierungslösung zu bieten.
2013 lieferte Docker schliesslich die fehlenden Teile für das Containerisierungspuzzle, und die Technologie begann den Mainstream zu erreichen.
Siehe auch The Missing Introduction To Containerization
Docker nahm die bestehende Linux-Containertechnologie auf und verpackte bzw. erweiterte sie in vielerlei Hinsicht – vor allem durch portable Images und eine benutzerfreundliche Schnittstelle –, um eine vollständige Lösung für das Erstellen und Verteilen von Containern zu schaffen.
Die Docker-Plattform besteht vereinfacht gesagt aus zwei getrennten Komponenten: der Docker Engine, die für das Erstellen und Ausführen von Containern verantwortlich ist, sowie dem Docker Hub, einem Cloud Service, um Container-Images zu verteilen.
Docker wurde für 64-bit Linux Systeme entwickelt, kann jedoch auch mittels VirtualBox auf Mac und Windows betrieben werden.
Microservices YouTube Einführung
Einer der grössten Anwendungsfälle und die stärkste treibende Kraft hinter dem Aufstieg von Containern sind Microservices.
Microservices sind ein Weg, Softwaresysteme so zu entwickeln und zu kombinieren, dass sie aus kleinen, unabhängigen Komponenten bestehen, die untereinander über das Netz interagieren. Das steht im Gegensatz zum klassischen, monolithischen Weg der Softwareentwicklung, bei dem es ein einzelnes, grosses Programm gibt.
Wenn solch ein Monolith dann skaliert werden muss, kann man sich meist nur dazu entscheiden, vertikal zu skalieren (scale up), zusätzliche Anforderungen werden in Form von mehr RAM und mehr Rechenleistung bereitgestellt. Microservices sind dagegen so entworfen, dass sie horizontal skaliert werden können (scale out), indem zusätzliche Anforderungen durch mehrere Rechner verarbeitet werden, auf die die Last verteilt werden kann.
In einer Microservices-Architektur ist es möglich, nur die Ressourcen zu skalieren, die für einen bestimmten Service benötigt werden, und sich damit auf die Flaschenhälse des Systems zu beschränken. In einem Monolith wird alles oder gar nichts skaliert, was zu verschwendeten Ressourcen führt.
Docker nahm die bestehende Linux-Containertechnologie auf und verpackte und erweiterte sie in vielerlei Hinsicht – vor allem durch portable Images und eine benutzerfreundliche Schnittstelle –, um eine vollständige Lösung für das Erstellen und Verteilen von Containern zu schaffen.
Die Docker-Plattform besteht vereinfacht gesagt aus zwei getrennten Komponenten: der Docker Engine, die für das Erstellen und Ausführen von Containern verantwortlich ist, sowie dem Docker Hub, einem Cloud Service, um Container-Images zu verteilen.
Wichtig: Docker wurde für 64-bit Linux Systeme entwickelt, kann jedoch auch mittels VirtualBox auf Mac und Windows betrieben werden.
Nachfolgend sind die wichtigsten Komponenten von Docker aufgelistet:
Docker Deamon
- Erstellen, Ausführen und Überwachen der Container
- Bauen und Speichern von Images
Der Docker Daemon wird normalerweise durch das Host-Betriebssystem gestartet.
Docker Client
- Docker wird über die Kommandozeile (CLI) mittels des Docker Clients bedient
- Kommuniziert per HTTP REST mit dem Docker Daemon
Da die gesamte Kommunikation über HTTP abläuft, ist es einfach, sich mit entfernten Docker Daemons zu verbinden und Bindings an Programmiersprachen zu entwickeln.
Images
- Images sind gebuildete Umgebungen welche als Container gestartet werden können
- Images sind nicht veränderbar, sondern können nur neu gebuildet werden.
- Images bestehen aus Namen und Version (TAG), z.B. ubuntu:16.04.
- Wird keine Version angegeben wird automatisch :latest angefügt.
Container
- Container sind die ausgeführten Images
- Ein Image kann beliebig oft als Container ausgeführt werden
- Container bzw. deren Inhalte können verändert werden, dazu werden sogenannte Union File Systems verwendet, welche nur die Änderungen zum original Image speichern.
Docker Registry
- In Docker Registries werden Images abgelegt und verteilt
Die Standard-Registry ist der Docker Hub, auf dem tausende öffentlich verfügbarer Images zur Verfügung stehen, aber auch "offizielle" Images.
Viele Organisationen und Firmen nutzen eigene Registries, um kommerzielle oder "private" Images zu hosten, aber auch um den Overhead zu vermeiden, der mit dem Herunterladen von Images über das Internet einhergeht.
Der Docker Client bietet eine Vielzahl von Befehlen, die für die Bedienung der Anwendung genutzt werden können. In diesem Abschnitt werden daher jene Befehle etwas näher beleuchtet.
docker run
- Ist der Befehl zum Starten neuer Container.
- Der bei weitem komplexesten Befehl, er unterstützt eine lange Liste möglicher Argumente.
- Ermöglicht es dem Anwender, zu konfigurieren, wie das Image laufen soll, Dockerfile-Einstellungen zu überschreiben, Verbindungen zu konfigurieren und Berechtigungen und Ressourcen für den Container zu setzen.
Standard-Test:
$ docker run hello-world
Startet einen Container mit einer interaktiven Shell (interactive, tty):
$ docker run -it ubuntu /bin/bash
Startet einen Container, der im Hintergrund (detach) läuft:
$ docker run -d ubuntu sleep 20
Startet einen Container im Hintergrund und löscht (remove) diesen nach Beendigung des Jobs:
$ docker run -d --rm ubuntu sleep 20
Startet einen Container im Hintergrund und legt eine Datei an:
$ docker run -d ubuntu touch /tmp/lock
Startet einen Container im Hintergrund und gibt das ROOT-Verzeichnis (/) nach STDOUT aus:
$ docker run -d ubuntu ls -l
docker ps
- Gibt einen Überblick über die aktuellen Container, wie z.B. Namen, IDs und Status.
Aktive Container anzeigen:
$ docker ps
Aktive und beendete Container anzeigen (all):
$ docker ps -a
Nur IDs ausgeben (all, quit):
$ docker ps -a -q
docker images
- Gibt eine Liste lokaler Images aus, wobei Informationen zu Repository-Namen, Tag-Namen und Grösse enthalten sind.
Lokale Images ausgeben:
$ docker images
Alternativ auch mit ... image ls
:
$ docker image ls
docker rm und docker rmi
docker rm
- Entfernt einen oder mehrere Container. Gibt die Namen oder IDs erfolgreich gelöschter Container zurück.
docker rmi
- Löscht das oder die angegebenen Images. Diese werden durch ihre ID oder Repository- und Tag-Namen spezifiziert.
Docker Container löschen:
$ docker rm [name]
Alle beendeten Container löschen:
$ docker rm `docker ps -a -q`
Alle Container, auch aktive, löschen:
$ docker rm -f `docker ps -a -q`
Docker Image löschen:
$ docker rmi ubuntu
Zwischenimages löschen (haben keinen Namen):
$ docker rmi `docker images -q -f dangling=true`
docker start
- Startet einen (oder mehrere) gestoppte Container.
- Kann genutzt werden, um einen Container neu zu starten, der beendet wurde, oder um einen Container zu starten, der mit
docker create
erzeugt, aber nie gestartet wurde.
- Kann genutzt werden, um einen Container neu zu starten, der beendet wurde, oder um einen Container zu starten, der mit
Docker Container neu starten, die Daten bleiben erhalten:
$ docker start [id]
Container stoppen, killen
docker stop
- Stoppt einen oder mehrere Container (ohne sie zu entfernen). Nach dem Aufruf von
docker stop
für einen Container wird er in den Status »exited« überführt.
- Stoppt einen oder mehrere Container (ohne sie zu entfernen). Nach dem Aufruf von
docker kill
- Schickt ein Signal an den Hauptprozess (PID 1) in einem Container. Standardmässig wird SIGKILL gesendet, womit der Container sofort stoppt.
Informationen zu Containern
docker logs
- Gibt die "Logs" für einen Container aus. Dabei handelt es sich einfach um alles, was innerhalb des Containers nach STDERR oder STDOUT geschrieben wurde.
docker inspect
- Gibt umfangreiche Informationen zu Containern oder Images aus. Dazu gehören die meisten Konfigurationsoptionen und Netzwerkeinstellungen sowie Volumes-Mappings.
docker diff
- Gibt die Änderungen am Dateisystem des Containers verglichen mit dem Image aus, aus dem er gestartet wurde.
docker top
- Gibt Informationen zu den laufenden Prozessen in einem angegebenen Container aus.
Ein Dockerfile ist eine Textdatei mit einer Reihe von Schritten, die genutzt werden können, um ein Docker-Image zu erzeugen.
Dazu wird zuerst ein Verzeichnis erstellt und darin eine Datei mit Namen "Dockerfile".
Anschliessend kann das Image wie folgt gebuildet werden:
$ docker build -t mysql .
Starten:
$ docker run --rm -d --name mysql mysql
Funktionsfähigkeit überprüfen:
$ docker exec -it mysql bash
Überprüfung im Container:
$ ps -ef
$ netstat -tulpen
Wenn ein interner Server vorhanden ist, kann das Grundimage (ubuntu:14.04) wie folgt von dort geladen und installiert werden:
$ wget http://10.1.66.11/docker/ubuntu-14.04.tar
$ docker load -i ubuntu-14.04.tar
$ docker tag ubuntu:14.04 ubuntu:latest
$ rm ubuntu-14.04.tar
Build Context
- Der Befehl
docker build
erfordert ein Dockerfile und einen Build Context.- Der Build Context ist der Satz lokaler Dateien und Verzeichnisse, die aus ADD- oder COPY-Anweisungen im Dockerfile angesprochen werden können.
- Er wird im Allgemeinen als Pfad zu einem Verzeichnis definiert.
Layer / Imageschichten
- Jede Anweisung in einem Dockerfile führt zu einer neuen Imageschicht – einem Layer –, die wieder zum Starten eines neuen Containers genutzt werden kann.
- Die neue Schicht wird erzeugt, indem ein Container mit dem Image der vorherigen Schicht gestartet, dann die Dockerfile-Anweisung ausgeführt und schliesslich ein neues Image gespeichert wird.
- Ist eine Dockerfile-Anweisung erfolgreich abgeschlossen worden, wird der temporär erzeugte Container wieder gelöscht.
Anweisungen im Dockerfile
ADD
- Kopiert Dateien aus dem Build Context oder von URLs in das Image.
CMD
- Führt die angegebene Anweisung aus, wenn der Container gestartet wurde. Ist auch ein ENTRYPOINT definiert, wird die Anweisung als Argument für ENTRYPOINT verwendet.
COPY
- Wird verwendet, um Dateien aus dem Build Context in das Image zu kopieren. Es gibt die zwei Formen COPY src dest und COPY ["src", "dest"]. Das JSON-Array-Format ist notwendig, wenn die Pfade Leerzeichen enthalten.
ENTRYPOINT
- Legt eine ausführbare Datei (und Standardargumente) fest, die beim Start des Containers laufen soll.
- Jegliche CMD-Anweisungen oder an
docker run
nach dem Imagenamen übergebenen Argumente werden als Parameter an das Executable durchgereicht. - ENTRYPOINT-Anweisungen werden häufig genutzt, um "Start-Scripts" anzustossen, die Variablen und Services initialisieren, bevor andere übergebene Argumente ausgewertet werden.
ENV
- Setzt Umgebungsvariablen im Image.
EXPOSE
- Erklärt Docker, dass der Container einen Prozess enthält, der an dem oder den angegebenen Port(s) lauscht.
HEALTHCHECK
- Die Docker Engine prüft regelmässig den Status der Anwendung im Container.
HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1`
- Die Docker Engine prüft regelmässig den Status der Anwendung im Container.
MAINTAINER
- Setzt die "Autor-Metadaten" des Image auf den angegebenen Wert.
RUN
- Führt die angegebene Anweisung im Container aus und bestätigt das Ergebnis.
SHELL
- Die Anweisung SHELL erlaubt es seit Docker 1.12, die Shell für den folgenden RUN-Befehl zu setzten. So ist es möglich, dass nun auch direkt bash, zsh oder Powershell-Befehle in einem Dockerfile genutzt werden können.
USER
- Setzt den Benutzer (über Name oder UID), der in folgenden RUN-, CMD- oder ENTRYPOINT-Anweisungen genutzt werden soll.
VOLUME
- Deklariert die angegebene Datei oder das Verzeichnis als Volume. Besteht die Datei oder das Verzeichnis schon im Image, wird sie bzw. es in das Volume kopiert, wenn der Container gestartet wird.
WORKDIR
- Setzt das Arbeitsverzeichnis für alle folgenden RUN-, CMD-, ENTRYPOINT-, ADD oder COPY-Anweisungen.
Stellen Sie sich vor, Sie lassen einen Webserver in einem Container laufen. Wie können Sie dann der Aussenwelt darauf Zugriff gewähren?
Die Antwort ist, Ports mit den Befehlen -p oder -P zu "veröffentlichen". Dieser Befehl leitet Ports auf den Host des Containers weiter.
Beispiele
MySQL Container permanent an Host Port 3306 weiterleiten:
$ docker run --rm -d -p 3306:3306 mysql
MySQL Container mit nächsten freien Port verbinden:
$ docker run --rm -d -P mysql
Erweiterung Dockerfile
Um Ports an den Host bzw. das Netzwerk weiterzuleiten, sind diese im Dockerfile via EXPOSE einzutragen.
Beispiel MySQL-Standardport:
EXPOSE 3306
Zugriff vom Host erlauben
Um via Host auf den Container zuzugreifen sind ein paar Arbeiten zu erledigen.
Installation des MySQL Clients auf dem Host:
$ sudo apt-get install mysql-client
Freigabe des Ports in der MySQL-Config im Container, z.B. via Dockerfile:
RUN sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
SQL Freigabe, via MySQL Client im Container einrichten:
CREATE USER 'root'@'%' IDENTIFIED BY 'admin';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;
Sind alle Arbeiten durchgeführt, sollte mit folgenden Befehl vom Host auf den MySQL Server, im Docker Container, zugegriffen werden können:
$ mysql -u root -p admin -h 127.0.0.1
Bei Docker können "Netzwerke" getrennt von Containern erstellt und verwaltet werden.
Wenn man Container startet, lassen sie sich einem bestehenden Netzwerk zuweisen, sodass sie sich direkt mit anderen Containern im gleichen Netzwerk austauschen können.
Standardmässig werden folgende Netzwerke eingerichtet:
- bridge
- Das Standard-Netzwerk indem gemappte Ports gegen aussen sichtbar sind.
- none
- Für Container ohne Netzwerkschnittstelle bzw. ohne Netzanbindung.
- host
- Fügt den Containern dem internen Host-Netzwerk hinzu, Ports sind nicht nach aussen sichtbar.
Befehle
Auflisten der bestehenden Netzwerke:
$ docker network ls
Detailinformationen, inkl. der Laufenden Container zu einem Netzwerk:
$ docker network inspect bridge
Container erstellen ohne Netzwerkschnittstelle:
$ docker run --network=none -it --name c1 --rm busybox
# Kontrollieren im Container
$ ifconfig
Container erstellen mit dem Host-Netzwerk:
$ docker run --network=host -itd --name c1 --rm busybox
# Kontrollieren mittels
$ docker inspect host
Erstellen eines neuen Brigde-Netzwerk:
$ docker network create --driver bridge isolated_nw
Vorheriges MySQL- & Ubuntu-Beispiel starten und mit neuem Bridge-Netzwerk verbinden:
$ docker run --rm -d --network=isolated_nw --name mysql mysql
$ docker run -it --rm --network=isolated_nw --name ubuntu ubuntu:14.04 bash
Im Ubuntu Container, Verbindung zum MySQL Server Port überprüfen:
$ sudo apt-get update && sudo apt-get install -y curl
$ curl -f http://mysql:3306
Container-Linking (veraltet)
Docker-Links sind die einfachste Möglichkeit, Container auf dem gleichen Host miteinander reden lassen zu können. Nutzt man das Standardnetzwerk-Modell von Docker, geschieht die Kommunikation zwischen Containern über ein internes Docker-Netzwerk, so dass sie nicht im Host-Netzwerk erreichbar sind.
Beispiel:
$ docker run -it --rm --link mysql:mysql ubuntu:14.04 bash
Innerhalb des MySQL-Containers:
env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=53a8e2acc32c
MYSQL_PORT=tcp://172.17.0.2:3306
MYSQL_PORT_3306_TCP=tcp://172.17.0.2:3306
MYSQL_PORT_3306_TCP_ADDR=172.17.0.2
MYSQL_PORT_3306_TCP_PORT=3306
MYSQL_PORT_3306_TCP_PROTO=tcp
MYSQL_NAME=/tender_feynman/mysql
HOME=/root
sudo apt-get update && sudo apt-get install -y curl mysql-client
Testen ob der Port aktiv ist (auf Ubuntu):
$ curl -f http://${MYSQL_PORT_3306_TCP_ADDR}:${MYSQL_PORT_3306_TCP_PORT}
MySQL Client starten (auf Ubuntu):
$ mysql -u root -p admin -h ${MYSQL_PORT_3306_TCP_ADDR}
Bis jetzt gingen alle Änderungen im Dateisystem beim Löschen des Docker Containers komplett verloren.
Um Daten persistent zu halten, stellt Docker verschiedene Möglichkeiten zur Verfügung:
- Ablegen der Daten auf dem Host
- Sharen der Daten zwischen Container
- Eigene, sogenannte Volumes erstellen, zum Ablegen von Daten
Erweiterung im Dockerfile
Um Daten auf dem Host oder in Volumes zu speichern, sind die Verzeichnis mit den Daten via VOLUME
im Dockerfile einzutragen.
Beispiel MySQL:
VOLUME /var/lib/mysql
Volumes sind ein spezielles Verzeichnis auf dem Host in dem einer oder mehrere Container ihre Daten ablegen.
Volumes bieten mehrere nützliche Funktionen für persistente oder gemeinsam genutzte Daten:
- Volumes werden initialisiert, wenn ein Container erstellt wird.
- Wenn das Image des Containers, Daten am angegebenen Einhängepunkt enthält, werden die vorhandenen Daten nach der Volumeninitialisierung in das neue Volume kopiert.
- Volumes können gemeinsam genutzt und unter Containern wiederverwendet werden.
- Änderungen an einem "Data volumes" erfolgen direkt.
- Änderungen an einem "Data volumes" werden nicht berücksichtigt, wenn Sie ein Image aktualisieren.
- Volumes bleiben bestehen, auch wenn der Container selbst gelöscht wird.
- Volumes sind so ausgelegt, dass die Daten unabhängig vom Lebenszyklus des Containers bestehen bleiben.
- Docker löscht nie automatisch Volumes, wenn Sie einen Container entfernen, kann deshalb "Müll" übrigbleiben
Beispiele
Busybox Container starten und neues Volume /data
anlegen:
$ docker run --network=host -it --name c2 -v /data --rm busybox
# Im Container
$ cd /data
$ mkdir t1
$ echo "Test" >t1/test.txt
# CTRL + P + CTRL + Q
$ docker inspect c2
# Nach Mounts suchen, z.B.
"Mounts": [
{
"Type": "volume",
"Name": "ea99634523a0aa3d6fbf7ee02c491029170d7105f9c5404760a71e046ad55c67",
"Source": "/var/lib/docker/volumes/ea99634523a0aa3d6fbf7ee02c491029170d7105f9c5404760a71e046ad55c67/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
# Datei ausgeben (auf Host)
$ sudo cat /var/lib/docker/volumes/ea99634523a0aa3d6fbf7ee02c491029170d7105f9c5404760a71e046ad55c67/_data/t1/test.txt
Datenverzeichnis /var/lib/mysql
vom Container auf dem Host einhängen (mount):
$ docker run -d -p 3306:3306 -v ~/data/mysql:/var/lib/mysql --name mysql --rm mysql
# Datenverzeichnis
$ ls -l ~/data/mysql
Einzelne Datei auf dem Host einhängen:
$ docker run --rm -it -v ~/.bash_history:/root/.bash_history ubuntu /bin/bash
Früher wurden Datencontainer erstellt, deren einziger Zweck das gemeinsame Nutzen von Daten durch andere Container war.
Dazu musste zuerst ein Container via docker run
gestartet werden, damit andere via --volumes-from
darauf zugreifen konnten.
Diese Methode war zwar funktionsfähig aber nicht ausbaufähig.
Beispiel
Container mit Datencontainer dbdata
erstellen:
$ docker create -v /dbdata --name dbstore busybox
Zweiten Container erstellen, welcher auf den Datencontainer dbdata
zugreift:
$ docker run -it --volumes-from dbstore --name db busybox
# Im Container
$ ls -l /dbdata
Der Datencontainer dbdata
ist nun unter dem root-Verzeichnis als /dbdata
eingehängt.
Seit der Version 1.9 von Docker existiert das Kommando docker volume
zur Verwaltung von Volumes auf einem Docker Host:
- Man kann damit verschiedene Volume-Driver-Dateisysteme für Container bereitstellen.
- Ein Volume kann nun auf einem Host angelegt werden und dem verschiedenen Container bereitgestellt werden.
- Volumes können einheitlich mit diesen Befehlen verwaltet werden.
- Wenn keine Default-Dateien auf dem Volume benötigt werden, kann auf einen separaten Datencontainer verzichtet werden.
- Mit diesem Schritt können nun verschiedene Dateisysteme und Optionen effizient in Containern genutzt werden.
Beispiele
Erstelle eine Volume mysql
:
$ docker volume create mysql
Ausgabe aller vorhandenen Volumes:
$ docker volume ls
Erstellt einen Container c2
und hängt das Volume unter /var/lib/mysql
ein:
$ docker run -it --name c2 -v mysql:/var/lib/mysql --rm busybox
Die Abhängigkeit Volume Verzeichnis kann auch im Dockerfile hinterlegt werden:
VOLUME mysql:/var/lib/mysql
Hat man eigene Images erstellt, werden kann man sie auch für andere bereitstellen – sei es für Kollegen, auf Continuous-Integration-Servern oder für Endanwender.
Es gibt viele verschiedene Möglichkeiten, Images bereitzustellen: Man kann sie aus Dockerfiles neu bauen, aus einer Registry docker pull
ziehen oder sie mit docker load
aus einer Archivdatei installieren.
Namensgebung für Images
Images bestehen aus Namen und Version (TAG), z.B. ubuntu:16.04. Wird keine Version Angegeben wird automatisch :latest angefügt.
Beim Bereitstellen von Images ist es sehr wichtig, beschreibende und exakte Namen und Tags einzusetzen.
Imagenamen und -Tags werden beim Bauen der Images oder durch den Befehl docker tag
gesetzt:
$ docker build -t mysql .
$ docker build -t mysql:1.0 .
$ docker tag mysql username/mysql
Die Tag-Namen müssen sich an ein paar Regeln halten. Sie müssen aus Gross- und Kleinbuchstaben, Zahlen oder den Symbolen . und - bestehen. Sie dürfen nicht länger als 128 Zeichen sein. Beim ersten Zeichen darf es sich nicht um ein . oder - handeln.
Namen von Repositories und Tags sind ausgesprochen wichtig, wenn man einen Entwicklungs-Workflow aufbauen möchte. Docker hat nur sehr wenige Regeln für gültige Namen und erlaubt es jederzeit, Namen zu erstellen oder zu löschen. Es liegt also am Entwicklungsteam, ein vernünftiges Namensschema zu entwerfen und umzusetzen.
Warnung vor dem latest-Tag
Docker nutzt latest
als Standardwert, wenn kein Tag vergeben wurde, darüber hinaus hat es aber keine spezielle Bedeutung. Viele Repositories verwenden es als Alias für das aktuellste stabile Image, dabei handelt es sich aber nur um eine Konvention, die durch keinerlei technische Massnahmen erzwungen wird.
Bezieht sich ein docker run
oder docker pull
auf einen Imagenamen ohne Tag, wird Docker das Image verwenden, das mit latest gekennzeichnet ist. Gibt es kein solches Image, wird ein Fehler ausgegeben.
Die einfachste Möglichkeit, eigene Images bereitzustellen, ist der Einsatz des Dockers Hub.
Bei diesem handelt es sich um die von Docker Inc. angebotene Online-Registry.
Der Hub ermöglicht kostenlose Repositories für öffentliche Images, die Anwender können aber auch für private Repositories bezahlen.
Docker Hub einrichten
Um seine eigenen Images auf Docker Hub hochzuladen ist wie folgt vorzugehen:
- Acount auf Docker Hub eröffnen.
- Imagenamen mit Usernamen, laut Account auf Docker Hub, taggen:
$ docker tag mysql username/mysql
- Image hochladen:
$ docker push username/mysql
- Dashboard auf Docker Hub anwählen und Image beschreiben.
Weitere Befehle
Suchen nach Images auf Docker Hub:
$ docker search mysql
Image herunterladen, z.B. um Build-Zeiten zu vermindern:
$ docker pull ubuntu
Um Container und Images einfach nur zwischen verschiedenen Hosts hin und her zu verschieben, wird keine Registry benötigt.
Container können mittels docker export
und docker import
und Images mittels docker save
und docker load
von/nach Verzeichnisse kopiert werden.
Container
Container exportieren:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7fd371d71357 vagrant_apache "/bin/sh -c '/bin/..." 3 hours ago Up 3 hours 0.0.0.0:8080->80/tcp vagrant_apache_1
$ docker export vagrant_apache_1 -o va1.tar
$ ls -lh
total 200M
-rwxrwxrwx 1 ubuntu ubuntu 731 Feb 2 08:28 Dockerfile
-rwxrwxrwx 1 ubuntu ubuntu 200M Feb 2 12:36 va1.tar
Container importieren, z.B. auf einem anderen Host (dabei wir ein Image erzeugt):
$ docker import va1.tar va1
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
va1 latest 167ec5ca640c Less than a second ago 200 MB
Images
Eigene Images ausgeben:
/vagrant/mysql$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql latest 24be8efe0428 2 hours ago 346 MB
apache latest 4221b4f12ce8 2 hours ago 225 MB
Images im TAR-Format mit save
sichern:
/vagrant/mysql$ docker save mysql -o mysql.tar
/vagrant/mysql$ docker save apache -o apache.tar
Images mit load
wiederherstellen:
$ docker load -i mysql.tar
Es gibt neben dem Docker Hub noch ein paar weitere Möglichkeiten.
Mann könnte alles manuell machen, indem Images exportiert und wieder importiert oder einfach auf jedem Docker Host aus Dockerfiles neue Images gebaut werden.
Beide Lösungen sind suboptimal:
Das immer neue Bauen aus Dockerfiles ist langsam und kann auf den verschiedenen Hosts zu unterschiedlichen Images führen, während das Exportieren und Importieren von Images knifflig und fehleranfällig sein kann.
Die verbleibende Möglichkeit ist, eine andere Registry zu verwenden, die entweder von einem selbst oder durch eine andere Firma gehostet werden kann.
Private Docker Registry einrichten
$ sudo docker pull registry:2
$ sudo docker run -d -p 5000:5000 --restart=always --name registry \
-v /var/spool/docker-registry:/var/lib/registry registry:2
Docker Client auf Registry zusteuern
Die Docker Clients steuern per default auf Docker Hub zu. Damit sie mit der lokalen Registry arbeiten kann, ist die Datei /etc/docker/daemon.json
mit folgendem Inhalt zu erstellen und Docker neu zu starten (sudo docker restart
):
{ "insecure-registries":["{{config.docker}}:5000"] }
Anschliessend können die vorhanden Images von unserer lokalen Docker Registry geholt werden (pull):
$ docker pull {{config.docker}}:5000/ubuntu
(...) oder geschrieben werden (push):
$ docker tag ubuntu {{config.docker}}:5000/myubuntu
$ docker push {{config.docker}}:5000/myubuntu
Wichtig: {{config.docker}}
durch installierten Server ersetzen.