server:docker

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
server:docker [2018/07/12 17:50] – [docker Apparmor] stserver:docker [2023/12/27 13:12] (aktuell) – [IPv6] st
Zeile 1: Zeile 1:
 +====== Docker ======
 +
 +[[wpde>Docker]] ist eine Open-Source-Software zur Isolierung von Anwendungen mit Containervirtualisierung.
 +
 +Docker vereinfacht die Bereitstellung von Anwendungen, weil sich Container, die alle nötigen Pakete enthalten, leicht als Dateien transportieren und installieren lassen. Container gewährleisten die Trennung und Verwaltung der auf einem Rechner genutzten Ressourcen. Das beinhaltet laut Aussage der Entwickler: Code, Laufzeitmodul, Systemwerkzeuge, Systembibliotheken – alles was auf einem Rechner installiert werden kann.
 +
 +[[wpde>Docker|Quelle Wikipedia]]
 +
 +===== Docker Einsatz =====
 +
 +**Vorteile**:
 +  * Docker zieht eine Abstraktionsebene ein, d.h. die darunterliegende Struktur (LAN, Storage, Distribution und Paketabhängigkeiten) muss bei der Anwendung nicht betrachtet werden. Überall lauffähig, nur die docker-version muss beachtet werden
 +  * Ressourceneinsatz (Massenhosting)
 +    * Disk: VM (Debian): ~500-800MB (je nach installierter Komponenten), Container: je nach Basisimage
 +    * Arbeitsspeicher
 +      * Kernel: VM: ~60MB je VM (incl. rsyslog), Container: kernel vom Betriebssystem wird genutzt
 +      * Applikationsprozess nimmt genauso viel
 +      * Cache: VM -> RAM muss reserviert werden, Virtualisierung kann aber ungenutzen Speicher neu verteilen; Container -> Cache kann gemeinsam von allen Containern benutzt werden  (auf dem gleichen Host)
 +  * Skalierbarkeit (Lastspitzen abfangen)
 +  * Deployment kann schnell, häufig und stufenweise erfolgen
 +
 +
 +**Nachteile**:
 +  * in Hochsicherheitsumgebungen nicht einsetzbar
 +    * nicht zertifizierbar, da Isolierung der Anwendungen nur durch den docker-daemon erfolgt (gleicher Kernel für alle etc.)
 +    * zur Abschottung wird eine VM außendrum benötigt (oder halt [[kubernetes]] mit seinen pods)
 +    * Angriffsvektoren durch [[https://justi.cz/security/2018/09/13/alpine-apk-rce.html|alpine]] Distribution
 +    * extern gebaute Images sind ein Risiko, Einzelfallprüfung vom wem ein image gebaut wird (Signierung wäre nötig...)
 +    * [[https://de.slideshare.net/AkihiroSuda/the-state-of-rootless-containers|Rootless Containers]] oft schwierig
 +  * monolitische Software (mehrere Dienste in einem Container ...) lassen Vorteile ungenutzt
 +  * Anwendungen die stateful sind (Datenbanken, Storagecluster)
 +  * umfangreiche Umgebungsabhängigkeiten (Repository, docker registry, CI/CD-Pipeline, Orchestrierung wie docker swarm oder kubernetes)
 +  * debugging wird komplexer:
 +    * Zusammenspiel der microservices
 +    * networking
 +    * in Container hinein gehen, teilweise stehen dort debugging tools nicht zur Verfügung
 +
 +
 +==== Welche Software ist geeignet? ====
 +
 +geeignet:
 +  - eigenprogrammierte Software mit CI/CD-Deployment
 +  - microservice-Architektur
 +  - stateless services
 +
 +
 +eher nicht
 +  - Drittanbietersoftware ohne microservices
 +  - stateful-software wo Skalierung unerwünscht oder kontraproduktiv ist
 +
 +
 +==== Was sind Probleme die gelöst werden müssen? ====
 +
 +  - config via environment... boolean parsing ... keine komplexen configs (nur key-value) -> mount-points mit komplexer Config -> Clusterdateisystem?
 +  - cron (logging)
 +  - container bestehen nicht nur aus der app sondern auch die Laufzeit-umgebung: wer anderen Leuten docker-container baut ist auch für das environment (=die base-Images) verantwortlich!
 +  - Alpine veröffentlich nur Daten zu bereits zu gefixten Problemen! Updategeschwindigkeit eher schlecht
 +
 +siehe auch [[https://www.youtube.com/watch?v=RqhxphyVL88|DevOps Disasters]].
 +===== Einrichtung =====
 +
 +Bevorzugte Methode ist die Einbindung via repo, fast immer ist die bei Distributionen mitgelieferte Version zu alt.
 +
 +[[https://docs.docker.com/install/|Siehe Installationshandbuch]], z.B. [[https://docs.docker.com/install/linux/docker-ce/ubuntu/|Ubuntu]] oder [[https://docs.docker.com/install/linux/docker-ce/debian/|Debian]].
 +
 +==== docker-compose ====
 +https://docs.docker.com/compose/install/
 +
 +==== docker ohne root ausführen ====
 +
 +Aktuellen Benutzer zur Gruppe docker hinzufügen
 +
 +  sudo usermod -aG docker $USER
 +
 +-> ausloggen und einloggen nötig
 +
 +
 +==== Kernel Kompatibilität ====
 +
 +Docker braucht mindestens die Kernel Version 3.10.
 +Ob die richtigen Konfiguration aktiviert ist, lässt sich mit dem Skript check-config.sh überprüfen:
 +
 +<code bash>
 +curl https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh > check-config.sh
 +bash ./check-config.sh
 +</code>
 +
 +bei [[ubuntu:Ubuntu]] 18.04 nötig:
 +
 +''/etc/default/grub'':
 +  GRUB_CMDLINE_LINUX_DEFAULT="quiet splash cgroup_enable=memory swapaccount=1"
 +
 +<code bash>sudo update-grub</code>
 +
 +Optional:
 +  * ''CONFIG_MEMCG_SWAP_ENABLED'': missing (cgroup swap accounting is currently enabled) -> OK
 +  * ''CONFIG_RT_GROUP_SCHED'': missing https://stackoverflow.com/questions/46563332/docker-daemon-container-real-time-scheduling-with-ubuntu-linux-host
 +
 +
 +=== Testen ob cgroup-memory limit wirkt ===
 +
 +<code bash>docker run -m=4096000000 -d  -t busybox sleep 3600</code>
 +
 +''cat /sys/fs/cgroup/memory/docker/$ID/memory.limit_in_bytes''
 +
 +...mit tatsächlichem Prozess (Quelle https://stackoverflow.com/questions/20096632/limit-memory-on-a-docker-container-doesnt-work):
 +
 +<code bash>
 +sudo docker -m 512M -it ubuntu /bin/bash
 +sudo apt-get update && apt-get install -y build-essential vim
 +</code>
 +
 +-> vim foo.c:
 +
 +<file>
 +#include <stdlib.h>
 +#include <stdio.h>
 +
 +int main(void) {
 +    int i;
 +    for (i=0; i<65536; i++) {
 +        char *q = malloc(65536);
 +        printf ("Malloced: %ld\n", 65536*i);
 +    }
 +    sleep(9999999);
 +}
 +</file>
 +
 +Compile the file
 +
 +<code bash>
 +gcc -o foo foo.c
 +./foo
 +</code>
 +
 +==== lokale Netze von Docker schützen (swarm) ====
 +
 +Beispiel: lokal nur noch das Netz 10.254.0.1/16 benutzen:
 +<code bash>
 +(als root) echo '{"bip": "10.254.0.1/16"}' > /etc/docker/daemon.json
 +sudo systemctl restart docker.service
 +</code>
 +
 +  * ggf. Netzwerke aufräumen: <code bash>docker network prune</code>
 +  * routen checken
 +  * docker0 bridge da? <code bash>sudo brctl show</code>
 +
 +
 +==== Routingkonflikte mit docker networks (IPv4) ====
 +
 +Netze die sich mit Docker überlappen (172.17., ...) sind ein Problem.
 +Die Config "bip": "10.4.0.1/16" in der /etc/docker/daemon.json funktioniert nur auf swarm korrekt.
 +
 +Bei docker standalone wird diese Einstellung beim Anlegen weiterer docker networks ignoriert. Auch andere Einstellungen wie //default-address-pools// oder //fixed-cidr// funktioniered in dieser Beziehung nicht.
 +
 +Es gibt nur einen funktionierenden workaround: explizit eine route im System setzen:
 +
 +Beispiel Redhat (ens192 mit Standard-GW 172.17.0.1) z.B. mit ''/etc/sysconfig/network-scripts/route-ens192'' (ip-Befehlssyntax)): <file>172.17.0.0/16 via 172.17.0.1 dev ens192</file>
 +
 +Bei Swarm muss initial die docker_gwbridge  angepasst werden - funktioniert nur wenn docker nicht bereits Teil eines swarm-clusters ist (er behält die Einstellungen bei wenn bereits vorhanden):
 +
 +  - löschen der vorhandene bridge (falls noch vorhanden): <code bash>docker network rm docker_gwbridge</code>
 +  - neu anlegen mit anderem Netz (muss vor join erfolgen!):<file>
 +docker network create \
 +--subnet 10.4.0.0/16 \
 +--opt com.docker.network.bridge.name=docker_gwbridge \
 +--opt com.docker.network.bridge.enable_icc=false \
 +--opt com.docker.network.bridge.enable_ip_masquerade=true \
 +docker_gwbridge
 +</file>
 +
 +https://docs.docker.com/v17.09/engine/swarm/networking/#customize-the-docker_gwbridge
 +
 +
 +==== docker Apparmor ====
 +
 +docker wendet für Gäste das Profil docker-default an.
 +
 +Dazu wird beim Starten eines Containers ein [[https://github.com/moby/moby/blob/master/profiles/apparmor/template.go|docker-default template]] in tmpfs abgelegt und von dort in den Kernel geladen.
 +
 +Oder es wird das Profil benutzt, das via security-opt angegeben wurde: <code bash>docker run --rm -it --security-opt apparmor=docker-default hello-world</code>.
 +
 +Für den docker daemon selbst wird aktuell kein apparmor-Profil geladen.
 +
 +Doku: [[https://docs.docker.com/engine/security/apparmor/|AppArmor security profiles for Docker]]
 +
 +
 +===== Benutzung =====
 +
 +  * Version anzeigen: <code bash>docker -v</code>
 +
 +==== Container Laufzeitbefehle ====
 +
 +
 +Container:
 +  * start: docker start $ID
 +  * stop Container: docker stop $ID
 +  * restart: docker restart $ID
 +  * Befehle in einem Container mit $ID bash ausführen: <code bash>docker exec -ti $ID bash</code>
 +  * attach: docker attach $ID
 +  * detach (funktioniert nur wenn -ti angegeben wurde!): STRG-P STRG-Q ((Tastenkombination ändern mit: https://docs.docker.com/engine/reference/commandline/attach/#override-the-detach-sequence))
 +
 +
 +=== Container via netzwerk anbinden ===
 +
 +Container exposen via Netzwerk: <code bash>docker run -d -p host_ip:host_port:container_port --name NAME image_name</code>
 +
 +Beispiel (offizielles redis-image): <code bash>docker run -d -p 6379:6379 --name redis redis</code>
 +
 +
 +**Netzwerke**
 +  * anzeigen: <code bash>docker network ls</code>
 +  * anlegen: <code bash>docker network create my_network</code>
 +  * informationen:<code bash>docker network inspect my_network</code>
 +  * container in das Netzwerk integrieren: Parameter<code bash>--net my_network</code>oder über yml-Datei
 +
 +
 +== Container via Firewall absichern ==
 +
 +Wenn Container nach Außen exposed werden, legt Docker entsprechende [[linux:Iptables]]-Regeln an. Diese lassen sich leider nicht anpassen, nur das anlegen von iptables-Regeln abschalten mit ''--iptables=false''
 +
 +Docker ([[https://github.com/docker/libnetwork/pull/1675|ab Version 17.06]]) hat aber für iptables die chain DOCKER-USER erdacht. Dort hinterlegte Regeln werden zuerst durchlaufen und von docker in Ruhe gelassen. Dort können also Regel hinterlegt und permanent gemacht werden (mittels mit iptables-persistent).
 +
 +Beispiel für Port 9200 (Elasticsearch):
 +<code bash>
 +iptables -I DOCKER-USER 1 -i eth0 -s 91.213.91.0/24 -p TCP --dport 9200 -j ACCEPT
 +iptables -I DOCKER-USER 2 -i eth0 -p TCP --dport 9200 -j LOG --log-prefix "Port9200ExtBlock:" --log-level 6
 +iptables -I DOCKER-USER 3 -i eth0 -p TCP --dport 9200 -j REJECT
 +</code>
 +
 +Löschen wäre (hier Regel nr.1):
 +
 +iptables -D DOCKER-USER 1 usw.
 +
 +Auflistung aktuell gültiger Regeln: <code bash>iptables -L -n --line-numbers</code>
 +
 +
 +=== Diagnose /Statistiken/ Informationen ===
 +
 +
 +
 +Container auflisten:
 +  * laufende: docker container ls
 +  * alle: docker container ls --all
 +
 +  * ID anzeigen: <code bash>docker ps --no-trunc</code>
 +    * ID des zuletzt gestarteten containers anzeigen: <code bash>docker ps -l -q</code> ((Alias in der Shell anlegen: <code bash>alias dl='docker ps -l -q'</code>))
 +  * ausführliche Informationen anzeigen: docker inspect $ID
 +  * Ressourcenverbrauch laufende Container: docker stats
 +  * Prozesse eines Containers anzeigen: docker top $ID
 +
 +
 +== Logging ==
 +
 +
 +[[https://docs.docker.com/config/containers/logging/|Logging]] ist bei docker vielfältig konfigurierbar.
 +
 +<code bash>docker logs $ID</code>
 +
 +"docker logs" funktioniert abwer nicht mit anderen [[https://docs.docker.com/config/containers/logging/configure/|loggin driver]] als json-file und journald.
 +
 +== Image startet nicht ==
 +
 +überschreibt den entrypoint aus dem image, einloggen mit bash ist möglich:
 +
 +''docker-compose.yml'':
 +<file>
 +entrypoint:
 +  - "/usr/bin/tail"
 +  - "-f"
 +  - "/dev/null"
 +</file>
 +
 +
 +
 +=== Compose-file via systemd starten ===
 +
 +
 +compose-File liegt hier: /srv/compose-files/meinDocker-service.yml
 +unitfile: ''/etc/systemd/system/meinDocker.service'' :
 +
 +<file>
 +[Unit]
 +Description=meinDockerService
 +Requires=docker.service
 +After=docker.service
 +
 +[Service]
 +Restart=always
 +#User=root
 +#Group=docker
 +# add group to user: usermod -a -G docker <user>
 +# Shutdown container (if running) when unit is stopped
 +ExecStartPre=/usr/bin/docker-compose -f /srv/compose-files/meinDocker-service.yml down -v
 +# Start container when unit is started
 +ExecStart=/usr/bin/docker-compose -f /srv/compose-files/meinDocker-service.yml up
 +# Stop container when unit is stopped
 +ExecStop=/usr/bin/docker-compose -f /srv/compose-files/meinDocker-service.yml down -v
 +[Install]
 +WantedBy=multi-user.target
 +</file>
 +
 +Dienst laden, starten und autostart aktivieren:
 +<code bash>
 +systemctl daemon-reload
 +systemctl start docker-datadog.service
 +systemctl enable docker-datadog.service
 +</code>
 +
 +
 +
 +
 +
 +==== Image-handling ====
 +
 +
 +Docker images anzeigen: <code bash>docker image ls</code>
 +
 +=== image erstellen ===
 +
 +Dockerfile <-> Docker Compose file
 +image bauen <-> image deployen
 +
 +
 +Beispiele:
 +
 +  - Image "ubuntu" holen + starten (-d im Hintergrund): <code bash>docker run -d -ti ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"</code>
 +  - <code bash>docker run -d ubuntu /bin/sh -c "apt-get install -y hello"</code>
 +
 +  - <code bash>docker run hello/world</code>
 +
 +
 +[[https://github.com/wsargent/docker-cheat-sheet#dockerfile|image erstellen (mit Dockerfile)]]: 
 +
 +**image aus docker-compose-file erstellen**: <code bash>docker-compose -f $COMPOSE-FILE.yaml up</code>
 +
 +**image aus Dockerfile erstellen**:
 +  - Dockerfile anlegen und ins Verzeichnis wechseln (tag latest wird angehängt)<file>
 +FROM base
 +RUN apt-get install hello
 +CMD hello
 +</file><code bash>docker build $USER/$IMAGENAME .</code>
 +  - oder Pfad zu meinDockerfile angeben:  -> docker build -t meineHalloApp -f meinDockerfile
 +  - <code bash>docker build -t meineHalloApp .</code>
 +
 +**image aus laufendem container erstellen**
 +  * <code bash>docker run -d ubuntu /bin/sh -c "apt-get install -y hello"</code>
 +  * <code bash>docker commit -m "1st container" $ID blindguardian/hallo</code>
 +
 +=== best practises image-bau ===
 +
 +  - allgemein bei docker images: Prozess sollte als PID 1 laufen damit es die Signale bekommt (SIGTERM, ...)
 +  - möglichst wenige RUNs: (neue files, neue layers)
 +  - [[https://github.com/krallin/tini|tini]] als init-system damit die bash nicht uid 1 wird (und damit nicht loggt weil sie denkt init zu sein):
 +    - NOTE: If you are using Docker 1.13 or greater, Tini is included in Docker itself. This includes all versions of Docker CE. To enable Tini, just pass the --init flag to docker run.
 +  - ReadMe.md anlegen im git-Repo
 +
 +
 +Schlecht: 
 +  - config-file ins image und dann kein vollwertiges base-linux drinhaben (nur per export auslesbar)
 +  - config-file extern als volume einhängen (liegt auf host rum...)
 +
 +gut:
 +  - config als extra layer einbauen das das install-Image aus einer registry benutzt und dann schnell neu gebaut werden kann
 +  - jedes image kommt aus einem eigenen repository (erleichert automatisierten image neubau, was wurde wann zuletzt benutzt, gebaut?)
 +
 +
 +=== Registries benutzen ===
 +
 +neben der öffentluchen Standard-registry von hub.docker.com können weitere registries verwendet werden. Insbesondere wenn die images privat sein sollen und um zu verhindern das durch externe Fehler Applikationen ihren Betrieb einstellen.
 +
 +  - offizielle registry (öffentlich): https://hub.docker.com/explore/
 +  - privates Repo auf docker hub mit Anmeldung: 
 +      - [[https://docs.docker.com/registry/introduction/|eigene Registry]]: <code bash>docker login https://meine.registry.de</code>
 +      - mehr als ein privates Repo [[https://hub.docker.com/billing-plans/|erfordert Geldeinsatz]]
 +  - 
 +  - [[https://docs.docker.com/ee/dtr/|Docker Trusted Registry]] enthalten in Docker Enterprise Edition
 +  - [[https://docs.docker.com/registry/|Docker Registry]] als Dienst
 +  - [[https://github.com/docker/distribution|Registry 2.0]] ([[https://github.com/docker/distribution/blob/master/ROADMAP.md|Roadmap]]) soll der Nachfolger werden
 +  - weitere Software
 +    - z.B. gitlab container registry (ab v.8.8): https://about.gitlab.com/2016/05/23/gitlab-container-registry/ https://docs.gitlab.com/ee/administration/container_registry.html
 +
 +
 +== unsichere registry ===
 +
 +[[https://docs.docker.com/registry/insecure|unsichere registries]] sollten nicht benutzt werden, aber falls weder verschlüsselung noch Login gewünscht ist:
 +
 +Datei /etc/docker/daemon.json:
 +<file>   "insecure-registries": ["unsicher.registry.de:80"] }</file>
 +
 +Restart Docker: <code bash>sudo systemctl restart docker.service</code>
 +
 +
 +=== image in registry committen ===
 +
 +  * <code bash>docker commit -m "Beschreibung" $ID user/repo1</code>
 +  * image auf **private** registry hochladen:
 +    * Login: <code bash>docker login $URL</code>
 +    * push: <code bash>docker push Benutzer/projekt</code>
 +
 +
 +=== image löschen ===
 +
 +<code bash>docker rm $short_id</code>
 +
 +=== Image exportieren ===
 +
 +**Methode 1 (docker save)**:
 +<code bash>docker save --output="registry-cleanup.tar" $IMAGE</code>
 +
 +$IMAGE z.B. hello/world, :!: das tar-archiv enthält aber "nur" die einzelnen layer (in jeweils tar-Archiven)
 +
 +**Methode 2 (docker export)** (laufendes image exportieren):
 +  * in tar-Archiv: <code bash>docker export --output="latest.tar" $NAME</code>
 +  * in tar.gzip-Archiv: <code bash>docker export $NAME | gzip > NAME.tar.gz</code>
 +
 +=== Image importieren ===
 +
 +aus tar.gz-Archiv: <code bash>zcat NAME.tar.gz | docker import - NAME</code>
 +
 +
 +=== Beispiele für images ===
 +
 +  * Apache allein: https://hub.docker.com/_/httpd/
 +  * PHP mit Apache: https://hub.docker.com/_/php/ (Langversion: https://github.com/docker-library/docs/blob/master/php/README.md)
 +    * <code bash>docker pull php:5.6-apache-jessie</code>
 +    * <code bash>docker pull php</code>
 +  * Nginx: https://hub.docker.com/_/nginx/
 +  * wordpress: https://hub.docker.com/_/wordpress/
 +    * <code bash>docker pull 4.9-php7.0-apache</code>
 +    * <code bash>docker pull 4-php7.0</code>
 +  * ceph: https://hub.docker.com/r/ceph/daemon/
 +
 +
 +==== Volume-handling ====
 +
 +Im Gegensatz zu den flüchtigen Containern sind volumes geeignet permanente Daten aufzunehmen ("persistent storage").
 +
 +-v /tmp/data:/data
 +
 +
 +  * **erzeugen**: <code bash>docker volume create --name vol1</code>
 +  * **mounten**: <code bash>docker run -d -v vol1:/container/pfad/für/das/volume container_image my_Befehl</code>
 +  * **auflisten**: <code bash>docker volume ls</code>
 +  * **details**: <code bash>docker volume inspect volume_name</code>
 +  * **unbenutzte volumes anzeigen**: <code bash>docker volume ls -f dangling=true</code>
 +  * **unbenutzte volumes löschen** ((oder bzw. bei älteren Versionen:<code bash>docker volume rm $(docker volume ls -f dangling=true -q)</code>siehe auch: https://stackoverflow.com/questions/18496940/how-to-deal-with-persistent-storage-e-g-databases-in-docker?rq=1)): <code bash>docker volume prune</code> 
 +  * **bestimmtes Volume löschen**:<code bash>docker volume rm <volume name></code>
 +  * [[https://docs.docker.com/storage/volumes/#backup-restore-or-migrate-data-volumes|Backup, restore, oder migrieren von data volumes]]
 +
 +
 +
 +===== docker swarm =====
 +
 +  * docker swarm join-token manager
 +  * docker swarm join-token worker
 +  * Node entfernen:
 +    * docker swarm leave
 +    * auf manager node: docker node rm $Name -f
 +    * manager müssen zuerst heruntergestuft werden: docker node demote $Name
 +  * Nodes
 +    * anzeigen: docker node ls
 +    * detaillierter: docker node inspect $Node
 +    * laufende Dienste auf §node: docker node ps $Node
 +  * Debugging
 +    * container-ID finden: docker service ps 
 +    * docker exec -it $ContainerID /bin/sh 
 +    * als root: docker exec -ti -u root $ContainerID bash
 +
 +
 +docker secret ls
 +
 +mkfs.xfs -f -n ftype=1 $disk
 +
 +
 +  * Infos über alle laufenden dienste auf: docker service ls
 +  * Übericht der stacks: docker stack ls
 +  * Übersicht über einzelne Services eines Stacks: docker stack ps $stackname
 +  * Ausführliche Infos über einen gestarteten Service (geht auch für Container, Storage, Networks...): docker inspect $name
 +  * Logoutput einzelner Dienste ansehen: docker service logs $name
 +
 +
 +docker vsphere plugin((Achtung: wenn sich container in unterschiedlichen services/stacks die gleichen Volumes haben wollen kommt es zu cluster-Instabilitäten)): <code bash>docker plugin install --grant-all-permissions --alias vsphere vmware/vsphere-storage-for-docker:latest</code>
 +
 +==== Deployments in stacks ====
 +
 +  * Deployment: <code bash>docker stack deploy -c stack-compose.yml $stackname --with-registry-auth</code>
 +    * gucken ob der stack bereits fertig aktualisiert ist: <code bash>docker stack ps $stackname -f 'desired-state=Running' | grep Running</code>
 +
 +  * Rollback eines services: <code bash>docker service rollback $service-name</code>
 +  * löschen
 +    * stack: <code bash>docker stack rm $stackname</code>
 +    * service: <code bash>docker service rm $service-name</code>
 +  * update
 +    * eines services: <code bash>docker service update --image $docker-registry/path/to/image:$TAG $service-name --with-registry-auth</code>
 +    * <nowiki>--</nowiki>force : auch ohne Änderungen container neu deployen
 +    * <nowiki>--</nowiki>update-parallelism 1 --update-delay 30s: nur eine Instanz gleichzeitg, mit Verzögerung 30s
 +
 +traeffik
 +  * skalieren: <code bash>docker service scale $service=4</code>
 +  * 
 +==== Wartung ====
 +
 +Leider nimmt docker keine automatischen Aufräumarbeiten vor. Deshalb muss manuell (ggf. via cronjobs) nachgeholfen werden:
 +
 +''/etc/cron.d/cleanimages''
 +<code bash>0 4 * * * root docker rmi $(docker images -q) > /dev/null</code>
 +
 +etwas radikaler ist der folgende Befehl:
 +<code bash>docker system prune -a
 +WARNING! This will remove:
 +  - all stopped containers
 +  - all networks not used by at least one container
 +  - all images without at least one container associated to them
 +  - all build cache
 +
 +Are you sure you want to continue? [y/N] y
 +</code>
 +
 +
 +
 +===== IPv6 =====
 +
 +Docker hat beim Design IPv6 nicht berücksichtigt und daher schlagen dessen Simplifizierungen (Ports durch NAT via iptables nach Außen geben und interne DNS-Auflösung) in Nachteile um.
 +**docker unterstützt kein SLAAC oder DHCPv6** und kann daher nicht selbstständig Präfixe beziehen, d.h. es müssen statische IPs zugewiesen werden und diese via DNS propagiert werden (DNS auf die öffentliche IP des docker-Hosts reicht nicht mehr!).
 +Hiermit werden jedoch sämtliche Ports öffentlich zugänglich gemacht (nicht nur diese via EXPOSE) und müssen daher via firewall abgesichert werden.
 +
 +NAT66 (analog zu v4) mit Adressen aus dem Unique Local Addresses (ULA)-Bereich fd00::/8 Adressen ist eine schlechte Idee und führt zu Problemen, auch der userland-proxy ist Mist.
 +
 +Funktionierende Lösungen:
 +  * ein öffentliches /64 v6-Netz mit manueller Zuweisungen von Adressen an Container. Beispiel mit 2001:db8:1::/64: ''/etc/docker/daemon.json'': <code bash>
 +{
 +  "ipv6": true,
 +  "fixed-cidr-v6": "2001:db8:1::/64"
 +}</code> Quellen: https://docs.docker.com/network/drivers/macvlan/#use-ipv6
 +
 +  * Container direct auf die Netzwerkkarte bridgen: [[https://docs.docker.com/network/drivers/macvlan/#use-ipv6|Macvlan]]
 +
 +Siehe auch: https://heikorichter.name/post/123/docker-und-ipv6/
 +
 +:!: Für IPv6-only ist dank der Rückständigkeit bei Dritten (Docker registry, Github etc.) Krücken wie DNS64 + NAT64 nötig.
 +===== Clustering =====
 +
 +Zum orchestrieren von docker container steht das integrierte docker swarm zur Verfügung.
 +Mittlerweile hat sich [[Kubernetes]] für diese Aufgaben etabliert, da es deutlich mehr Funktionen (aber auch mehr Komplexität) mit sich bringt.
 +
 +==== docker swarm ====
 +
 +**Initialiseren**: <code bash>docker swarm init</code>
 +<file>"Swarm initialized: current node (n352jdg9eoml9nh5ak574izs5) is now a manager.
 +
 +To add a worker to this swarm, run the following command:
 +
 +<code bash>docker swarm join --token SWMTKN-1-4a8ilhha4g652ll28ecg7z4pyxdvglnicufxlj2mh5l5ly5nm3-7s7yvbki7m9pfi2yzafter6l6 10.10.0.23:2377</code>
 +
 +To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions."
 +</file>
 +In diesem Beispiel reicht zum **Beitritt**
 +  - als node: <code bash>docker swarm join --token SWMTKN-1-4a8ilhha4g652ll28ecg7z4pyxdvglnicufxlj2mh5l5ly5nm3-7s7yvbki7m9pfi2yzafter6l6 10.10.0.23:2377</code>
 +  - oder als **weiteren manager** die folgende Ausgabe auszuführen:<code bash>docker swarm join-token manager</code>
 +
 +Aus dem docker swarm **austreten**:
 +  * <code bash>docker swarm leave</code>
 +  * wenn manager: <code bash>docker swarm leave --force</code>
 +
 +***Informationen über sich selbst** anzeigen: <code bash>docker node inspect self</code>
 +
 +
 +=== Nodes ===
 +
 +**Nodes** sind
 +  - Active (neue tasks können zugewiesen werden)
 +  - Pause (keine neuen, aber bestehende tasks bleiben)
 +  - Drain (keine neuen, und existiere task werden heruntergefahren. <code bash>docker node update --availability drain node1</code>
 +
 +[[https://docs.docker.com/engine/swarm/manage-nodes/|Nodes managen]]:
 +  * Nodes auflisten: <code bash>docker node ls</code>
 +
 +=== Manager ===
 +
 +**Manager** sind
 +  - Reachable
 +  - Unavailable
 +  - Leader
 +
 +
 +<code bash>docker stack ls</code>
 +<file>NAME                SERVICES
 +content-sync        2</file>
 +
 +
 +=== Services ===
 +
 +  * global: 1x pro Node
 +  * replicated: x Instanzen
 +
 +=== Labels ===
 +
 +**Labels**: (wo fährt was hoch?), Beispiel: nur hochfahren wenn label db1 auf der node vorhanden ist:
 +<file>
 +   deploy:
 +      placement:
 +        constraints:
 +          - node.labels.db1 == TRUE
 +</file>
 +  - Label hinzufügen: <code bash>docker node update --label-add LABEL1</code>
 +  - Label updaten: <code bash>docker node update --label-add LABEL2=TEST node1</code>
 +
 +
 +
 +
 +==== Zusatztools ====
 +
 +=== docker-machine ===
 +
 +[[https://docs.docker.com/machine/overview/#why-should-i-use-it|docker-machine]] ist ein tool um docker-Hosts zu provisionieren (auf denen dann docker container laufen können).