Docker

aus www.kruedewagen.de, Homepage von Ralf und Judith Krüdewagen (Kruedewagen)
Zur Navigation springen Zur Suche springen

Diese Seite beschäftigt sich mit Docker Containern zur Virtualisierung von Applikationen.

Allgemein

Docker Webseiten

Artikel und Infos

Datenbank und Webserver in getrennten Containern
  • Docker verwaltet LXC Container: LM 08/13 S.64
  • Docker Einführung und Panamax als GUI: siehe LU 12/14 S.78
  • Docker mit Swarm: siehe iX 03/15 S.108
  • Anwendungen mit Docker isolieren
  • Docker Report: siehe iX 05/15 S.46
  • Docker Container Einführung: siehe c't 05/16 S.108
  • Docker Container einsetzen: siehe c't 05/16 S.112
  • Systemd vs. Docker (lwn.net)
  • PHP development with Docker
  • Docker Grundlagen, Praxis, User Defined Networks: siehe c't 15/17 S.106 ff
  • Docker Container aktuell halten: siehe LM 06/18 S.48
  • Docker Images (allgemein, Auswahl): siehe c't 16/18 S.104 ff
  • Docker auf dem Raspberry Pi: siehe c't 02/19 S.149
  • Multi Stage Builds mit Docker (am Beispiel einer Node.js Applikation)
    • Indiz: Zwei oder mehrere FROM Anweisungen im Dockerfile
    • siehe c't 03/19 S.152
  • Images automatisch im Docker Hub bauen via GitHub: siehe c't 04/19 S.138 , http://ct.de/y3tz , https://github.com/ct-Open-Source/docker-autobuild-example

Ökosystem

Versionshinweise

1.3

Projekte und Verbände

Repository Server

Siehe auch "Docker Registry Frontend" in rawino.

Betriebssysteme

Besonders auf Docker abgestimmte (schlanke) Betriebssysteme (Linux):

Sicherheit

Orchestrierung

Bei der Orchestrierung geht es um Verwaltung, Skalierbarkeit und Automatisierung:

  • Container massenweise auf beliebigen Hosts (automatisch) starten
  • Container auf mehreren Hosts in ein "virtuelles" Netzwerk integrieren, mit dynamischer Vergabe von IP-Adressen und Ports (internes DNS und Service Discovery)
  • Dienste und Anwendungen aus einer Vielzahl von Container in Clustern erstellen und steuern
  • Mehrere Versionen einer Anwendung parallel laufen lassen mit schnellem Wechsel der Versionen

Siehe:

docker-compose build
docker-compose up -d
docker-compose up <name> -d
docker-compose down
docker-compose restart <name>
docker-compose logs
  • DC/OS von Mesosphere
    • siehe iX 02/17 S.42
  • OpenStack
  • Kubic
    • openSUSE MicroOS Container Operating System and the Kubic Container as a Service Platform based on MicroOS and kubernetes
  • Kleinere Tools:
    • Watchtower prüft nach neuen Versionen für Images, macht ein Pull und startet Container neu
    • Management GUIs
      • Testbericht siehe LM 09/18 S. 48 (Dockstation, Kitematic, Portainer)
      • Portainer, management user interface for your Docker environments, https://portainer.io , siehe c't 16/18 S.109 und LM 09/18 S.48

Anwendungen

openSUSE

Icinga

Training und Lernen

Literatur

  • Verschiedene Bücher von Packt.
  • "Pro Docker" vor allem mit Beispiel-Containern für Linux, Datenbanken, und Applikationen; siehe iX 10/16 S.156
  • Docker
    • "Software entwickeln und deployen mit Containern" - dpunkt
    • Docker, Rheinwerk, 2018: siehe LM 02/19 S.85
  • Kubernetes
    • Kubernetes, Dpunkt, 2018: siehe LM 02/19 S.85

Betrieb

Hilfe

man docker
man docker run
docker --help
docker run --help

Netzwerk

  • Wenn man von einem Container eine TCP-Verbindung zum Docker Host machen möchte, z.B. um eine MySQL DB auf dem Host zu nutzen, dann muss bei aktivierter Firefall das interne Docker-Netzwerk freigeschaltet werden, z.B. als "Trusted Network":
FW_TRUSTED_NETS="172.17.0.0/16"
  • Beim Start des Docker-Daemons kann Firewall-Funktion deaktiviert werden.
  • Reverse Proxy als Docker-Container für den automatischen Einsatz bei vielen Containern unter einer IP, die z.B. alle auf Port 80 und 443 erreichbar sein sollen: https://hub.docker.com/r/jwilder/nginx-proxy/
    • siehe c't 15/17 S.113
  • Software Defined Networking, z.B. mit Contiv: siehe iX 06/18 S.110

User Defined Networks

  • User Defined Networks: siehe c't 15/17 S.116
  • Netzwerke anzeigen:
docker network ls
  • Bridge "docker-extern" (einmalig) erstellen und einen Container aus der Standard-Bridge dort hineinfügen:
docker network create docker-extern
docker network disconnect docker0
docker network connect docker-extern mycontainer

oder beim Start des Containers mit "docker run" das Netzwerk angeben

docker run ... --network docker-extern
  • Netzwerk Alias - zur Verlinkung von Diensten/Hostnamen (z.B. einer Datenbank mit Hostnamen "db") - anstatt Link:
docker run ... --network docker-extern --name dbserver --network-alias db
  • Man kann mehrere Container im gleichen Netz denselben Alias zuweisen: Round Robin des eingebetteten DNS-Servers
  • Man kann einem Container mehrere Aliase geben: Mehrere Namen in einem Container
  • Container in mehrere User Defined Networks erreichbar machen (alias):
docker network connect --alias db docker-extern mycontainer
  • Verbindungen (Inter Container Connectivity) zwischen User Defined Networks verhindern:
docker network create -o 'com.docker.network.bridge.enable_icc=false' docker-isoliert
  • Keine Netzwerkverbindung im impliziten Netzwerk "none"
  • Keine Verbindung nach außen (Internet):
docker network create --internal docker-intern
  • Feste IP-Adressen im Netz auf im Container:
docker network create --subnet 172.20.0.0/16 --gateway 172.20.0.1 docker-extern
docker run ... --network docker-extern --ip 172.20.0.2

Konfiguration

Images landen hier:

/var/lib/docker

Info ausgeben:

docker info

Images

Handling von Images

Image suchen:

docker search debian

Ein Image herunterladen:

docker pull debian

Vorhandene (lokale) Images auflisten:

docker images

Image in Tar-Archiv umwandeln:

docker images save > myimage.tar

Image (lokal) löschen (nur möglich, solange kein Container es nutzt):

docker rmi debian

Image pushen (zuerst "Rename" des Images in Non-Root-Pfad durch Taggen [1], dann einmalig Login [2]):

docker tag meinnginx2:latest <username>/meinnginx2:latest
docker login
docker push <username>/meinnginx2
Login-Daten landen in /root/.docker/config.json

Neues Tag "v2.0" pushen auf Basis von "latest":

docker tag <username>/meinnginx2:latest <username>/meinnginx2:v2.0
docker push <username>/meinnginx2:v2.0

Eigenes Image bauen

Beispiel 1: Apache auf Basis Debian

Das folgende Beispiel setzt ein Apache-Image mit einer statischen Webseite auf Basis eines Debian "Betriebssystem-Images" auf.

1. Verzeichnis für den Bau erstellen

mkdir -p /data/docker/newimage

2. Die statische Seite(n) erstellen, die dem Image hinzugefügt werden sollen

cd /data/docker/newimage
vi index.html

3. Das Dockerfile anlegen

vi Dockerfile
FROM debian
MAINTAINER Ralf Kruedewagen <docker@kruedewagen.de>
RUN apt-get update && apt-get install -y apache2
ADD index.html /var/www/html/
EXPOSE 80
# Apache ENVs, sonst Fehlermeldung beim Start von Apache, siehe
# https://github.com/paulczar/docker-apache2/blob/master/Dockerfile
# http://tech.paulcz.net/2015/03/optimizing-your-dockerfiles/
ENV APACHE_RUN_USER    www-data
ENV APACHE_RUN_GROUP   www-data
ENV APACHE_PID_FILE    /var/run/apache2.pid
ENV APACHE_RUN_DIR     /var/run/apache2
ENV APACHE_LOCK_DIR    /var/lock/apache2
ENV APACHE_LOG_DIR     /var/log/apache2
ENV LANG               C

# Fehlermeldung mit APACHE_LOCK_DIR -> https://log.axcoto.com/article/164442852
RUN [ ! -d ${APACHE_RUN_DIR:-/var/run/apache2} ] && mkdir -p ${APACHE_RUN_DIR:-/var/run/apache2}
RUN [ ! -d ${APACHE_LOCK_DIR:-/var/lock/apache2} ] && mkdir ${APACHE_LOCK_DIR:-/var/lock/apache2} && chown ${APACHE_RUN_USER:-www-data} ${APACHE_LOCK_DIR:-/var/lock/apache2}

CMD ["/usr/sbin/apache2", "-D", "FOREGROUND"]
# alternativ:
# ENTRYPOINT ["/usr/sbin/apache2"]
# CMD ["-D", "FOREGROUND"]

4. Das Image bauen

docker build -t meinapache /data/docker/newimage/

5. Container anlegen und starten

docker run -d --name meinapachecontainer -p 8080:80 meinapache

Mehr Infos zu Apache und Docker:

Beispiel 2: Nginx auf Basis Debian

Genau so wie bei Apache mit einigen Änderungen im Dockerfile:

FROM debian
MAINTAINER Ralf Kruedewagen <docker@kruedewagen.de>
RUN apt-get update && apt-get install -y nginx
ADD index.html /var/www/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Beispiel 3: Parsoid mit Node.js

Parsoid wird für den Visual Editor von MediaWiki benötigt und ist ein webbasierter Dienst.

Voraussetzungen / Bemerkungen:

  • MediaWiki läuft auf dem Host selbst (Dockerhost). Für das Ansprechen namensbasierter virtueller Webserver sind FQDN-Einträge in uri nötig.
  • Parsoid soll in einem Container laufen, daher benötigt der Dockerhost Zugriff auf den Parsoid-Port im Container und im Gegenzug benötigt Parsoid Zugriff auf das Wiki im Dockerhost.
  • wie man den Dockerhost aus dem Container ansprechen kann (Eintrag in hosts Datei mit --add-host beim Starten des Containers) erklärt https://github.com/docker/docker/issues/1143.

/data/docker/parsoid/config.yaml (only the "conf" section):

       mwApis:
        - # This is the only required parameter,
          # the URL of you MediaWiki API endpoint.
          uri: 'https://dockerhost/w/api.php'
          domain: 'localhost'  # optional
        - # This is the only required parameter,
          # the URL of you MediaWiki API endpoint.
          uri: 'http://www.example.org/w/api.php'
          domain: 'example.org'  # optional

        # Use selective serialization (default false)
        useSelser: true

        # Allow override of port/interface:
        serverPort: 8142
        #serverInterface: '127.0.0.1'

        # Require SSL certificates to be valid (default true)
        # Set to false when using self-signed SSL certificates
        strictSSL: false
};

/data/docker/parsoid/Dockerfile:

FROM debian
MAINTAINER Ralf Kruedewagen <docker@kruedewagen.de>
# for HTTPS sources
RUN apt-get update && apt-get install -y apt-transport-https
# Install Node.js
RUN apt-get install -y curl
RUN curl -sL https://deb.nodesource.com/setup_5.x | bash -
RUN apt-get update && apt-get install -y nodejs
# Add Parsoid repo
RUN apt-key advanced --keyserver keys.gnupg.net --recv-keys 664C383A3566A3481B942F007A322AC6E84AFDD2
RUN echo "deb https://releases.wikimedia.org/debian jessie-mediawiki main" > /etc/apt/sources.list.d/parsoid.list
# Install Parsoid
RUN apt-get update && apt-get install -y parsoid
# Copy config
ADD config.yaml /etc/mediawiki/parsoid/
EXPOSE 8142
CMD ["/usr/bin/nodejs", "/usr/lib/parsoid/src/bin/server.js", "-c", "/etc/mediawiki/parsoid/config.yaml"]

Image bauen:

docker build -t parsoid /data/docker/parsoid/

Container starten (IP des Dockerhost einsetzen):

docker run -d --name parsoid -p 8142:8142 --add-host=dockerhost:172.17.0.1 parsoid

oder mit zwei URLs:

docker run -d --name parsoid -p 8142:8142 --add-host=dockerhost:172.17.0.1 --add-host=www.example.org:172.17.0.1 parsoid

oder inkl. automatischem Restart:

docker run -d --name parsoid -p 8142:8142 --add-host=dockerhost:172.17.0.1 --add-host=www.example.org:172.17.0.1 --restart=always parsoid

optional mit "--restart=unless-stopped"

Images erstellen nach Änderungen im Container

Man kann Änderungen im Container in ein neues Image "committen". Dabei wird aus dem Basis-Image plus den Änderungen ein neues Image erstellt.

1. Basis-Image holen

2. Container darauf aufsetzen

3. Änderungen im Container vornehmen (z.B. im o.g. Beispiel die Webseite ändern)

4. Container ID feststellen

docker ps -l

5. Neues Images aus laufendem Container bauen:

docker commit <CONTAINER ID> <NEUES IMAGE>
docker commit 05c85da33c4a meinnginx2
docker commit -m="Webseite angepasst + vim installiert" -a "Ralf Kruedewagen" 05c85da33c4a meinnginx2

6. Neues Image inspizieren

docker inspect meinnginx2
Image auf Docker Hub erstellen
  • Git Repository (z.B. aus GitHub), das Dockerfile und weiteren Dateien enthält, in Docker Hub referenzieren
  • Nach jedem Commit (Push) im Git Repo wird neues Images erstellt.
Weitere Steuerungsmöglichkeiten
  • Script kann über Variablen das Verhalten der Container steuern

Dockerfile

Siehe:

Container

  • siehe c't 15/17 S.120 (Beispiel MySQL in Container packen, X-Anwendung im Container mit SSH), http://ct.de/yqws

Anlegen und Starten

Container in einem Rutsch anlegen und starten (und auch Image herunterladen falls nötig):

docker run --name meindebian -it debian
Wordpress mit MySQL
mkdir /data/mysqlcontainer
docker run -d --name meinmysql -v /data/mysqlcontainer/:/var/lib/mysql/ -e MYSQL_ROOT_PASSWORD=xxx mysql
docker run -d --name meinwordpress --link meinmysql:mysql -p 8080:80 wordpress
Parameter: "--link" erstellt die MySQL-Konfig im Wordpress Container gemäß Daten/Status des MySQL Containers (Interface, IP, Port) -> "Docker Networks" ersetzt "--link"
"-v" reicht Verzeichnisse vom Host in den Container durch (kann auch im Dockerfile fest vorgegeben sein)

Container (nur) anlegen:

docker create --name=meindebian -it debian
Parameter: i = interaktiv, t = terminal (nötig weil es ein Basis-Image mit "Bash" als Dienst ist)

Container starten:

docker start -ia meindebian
Parameter: i = interaktiv, a = Ausgabeumlenkung / Konsole verbinden
Exit aus Bash stoppt den Container

Container stoppen (mehrere Container können angegeben werden):

docker stop meindebian

Container löschen (Daten im Container gegen verloren, Image bleibt unberührt):

docker rm meindebian

Managen von Containern

Laufende Container zeigen ("-a" zeigt auch nicht-laufende):

docker ps
docker ps -a

Shell in laufendem Container starten:

docker exec -it meindebian bash

Shell in einem Container starten (dabei "CMD" übergehen):

docker run -it --entrypoint=/bin/bash <image> -i

Etwas im Container installieren:

docker run meindebian apt-get install -y dovecot

Ausgaben auf Konsole anzeigen (Logging):

docker logs meindebian

In syslog loggen mit Namen statt ID des Containers:

docker run ... --log-driver=syslog --log-opt tag="mycontainer"

Kommandos in Image einbauen zur Verwendung im Container

docker exec gitweb addauth test test

Debugging

  • siehe LM 03/18 S.58
docker logs -f
docker top
docker pause | unpause
docker exec -it /bin/bash
docker history
docker stats
docker inspect

Volumes

Volumes auflisten:

docker volume
docker volume inspect <VOLUME_ID>

Volume eines Containers:

docker inspect -f 'Vorlage:.Mounts' <CONTAINER_ID>

Volumes erben (hilfreich um laufenden Container zu ersetzen, zuerst laufenden Container umbenennen):

--volumes-from mycontainer

Aufräumen

Nicht mehr benötigte Container entfernen, die im Status "exited" sind:

docker rm -v $(docker ps -a -q -f status=exited)

Images löschen, die nicht in Gebrauch sind:

docker rmi $(docker images -f "dangling=true" -q)

Überflüssige Volumes finden und löschen:

docker volume ls --filter "dangling=true"
docker volume prune

Unbenutze Container, Networks und Images löschen:

docker system prune

Auch unbenutzte Volumes löschen:

docker system prune --all --force --volumes

Weblinks / Quellen (u.a. auch zu Tipps zu Volumes):

Tools

Troubleshooting

Best Pratices - Tipps & Tricks

zuerst Nummer des Interfaces im Container herausfinden:
cat /sys/class/net/eth0/iflink
6
Dann auf dem Host nach dieser Nummer suchen:
grep -l "^6$" $(find /sys/devices/virtual/net -name "ifindex")
/sys/devices/virtual/net/veth034c9d0/ifindex

Tools

Monitoring

Siehe auch