Docker

Siehe auch

Installation

RHEL 7+:

yum -y install yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum -y install docker-ce docker-ce-cli containerd.io

systemctl start docker

# Docker Compose
curl -L "https://github.com/docker/compose/releases/download/1.28.6/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version

Docker Cheat Sheet

docker run hello-world
docker run --interactive \
    --tty=false \
    --detach=false \
    --publish 80:80 \
    onlyoffice/documentserver
docker run --name=mongo \
    mongo:4.2
docker run --name=elasticsearch \
    --env="http.host=0.0.0.0" \
    --env="discovery.type=single-node" \
    --env="ES_JAVA_OPTS=-Xms512m -Xmx512m" \
    docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2
docker run --name=graylog \
    --env=GRAYLOG_HTTP_EXTERNAL_URI="http://127.0.0.1:9000/" \
    --link=mongo --link=elasticsearch \
    --publish=9000:9000 --publish=12201:12201 --publish=1514:1514 \
     graylog/graylog:4.0
docker run --log-driver gelf –-log-opt gelf-address=udp://1.2.3.4:12201 mycontainer anyoptions

docker restart $CONTAINER

docker container ls --all
docker image ls --all
docker ps

# where are images located?
docker info

docker rm

# inspect a container, get IP address etc.
docker inspect
docker inspect --type container
docker inspect -f '{{.HostConfig.LogConfig.Type}}' 8e8323567545

# get the logs
docker logs -f ea87dde67282
docker logs -f container-name

# get a bash shell in the container
docker exec -it <container name> /bin/bash

docker stats --no-stream
docker stats --no-stream $(docker inspect -f {{.Name}} $(docker ps -q))

curl --unix-socket /var/run/docker.sock "http:/localhost/containers/<container id or name>/stats?stream=False"

docker --host=ssh://docker-host container stop $(docker --host=ssh://docker-host ps -a -q)
docker --host=ssh://docker-host container prune -f
docker --host=ssh://docker-host rmi $(docker --host=ssh://docker-host image ls -q)

Firewalling

Das Firewalling der Docker-Container ist kompliziert, da der Docker-Daemon selbst dynamisch Firewall-Regeln anlegt. Firewalling ist aber gerade bei Docker sehr wichtig, denn wenn bei --publish keine IP mitgegeben wird, hört der Port auf allen Interfaces des Hosts - inklusive Firewall-Regel, die einkommende Verbindungen erlaubt. Da dies den Usern meistens nicht bewusst ist, stellt das ein Sicherheitsrisiko dar.

Firewall Builder und Docker vertragen sich leider nicht, da beim Neustarten der Firewall alle Regeln gelöscht werden - somit auch die des Docker-Daemons. Hier ist die einzige Option, dass die Erstellung der Regeln im Docker-Daemon deaktiviert und die Regeln manuell erstellt (siehe auch einen Blog-Post von firewalld) werden. Allerdings ist das nur möglich, wenn die Docker-Container IPs und Ports bekannt sind - somit nicht für den Einsatz auf einer Workstation geeignet.

Bei firewalld ist der Reload granularer implementiert, somit werden die Docker-Regeln nicht beeinflusst. Allerdings funktioniert hierbei eine Policy mit Ingress-Zone ANY und Egress-Zone docker nicht wie erwartet, da firewalld alle DNAT-Verbindungen schon vor den Regeln der Policy akzeptiert (ct status dnat accept in der firewalld filter_FORWARD). Das Problem wird in einem GitHub-Issue thematisiert aber nicht zufriedenstellend gelöst.

Daher müssen die Regeln in der DOCKER-USER Chain abgelegt werden. Das geht mithilfe den (deprecated) Direct-Regeln in firewalld:

firewall-cmd --permanent --direct --add-chain ipv4 filter DOCKER-USER
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 0 -i lo -j ACCEPT
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -j LOG --log-level info --log-prefix "DOCKER-USER DENY "
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 2 -j DROP

So werden nur Verbindungen von den Docker-Host aus erlaubt.

DNS

Docker interessiert in der Regel nicht, welche DNS lokal im System auf der Netzwerkkarte konfiguriert sind - es soll aber gezwungen werden, einen bestimmten DNS zu verwenden?

/etc/docker/daemon.json
{
    "dns": [
        "1.1.1.1",
        "1.0.0.1"
    ]
}
systemctl restart docker

Test:

docker run busybox nslookup www.linuxfabrik.ch

Timezones

Zeitzone setzen:

docker run --env TZ=Europe/Zurich debian:jessie date

Logging mit Docker

Docker und Logserver wie Graylog: Docker besitzt eine Feldbegrenzung bei „message“ von 16KB. Mehr ist nicht möglich - laut Docker müssen die Log-Plugins eine Art von „max log size“-Option anbieten, tut aber Stand heute (2018-06) kein einziger. Ein pures Weiterleiten per GELF und anderen macht also nicht glücklich. Statt dessen müssen die Container über filebeats direkt per Beats auf den Log-Server schreiben. Die Container, die das nicht können (sollen), schreiben per journald. journalctl wird dann per journal2gelf an den Log-Server weitergeleitet.

docker run --log-driver=gelf --log-opt gelf-address=tcp://192.168.209.9:12201
alpine echo 'Hello World'

Journald als Logging-Driver:

GELF als Logging-Driver:

/etc/docker/daemon.json
{
    "log-driver": "gelf",
    "log-opts": {
        "gelf-address": "udp://192.168.209.6:12201"
    }
}

docker-compose

cd path/to/docker-compose.yml
docker-compose up

# daemonize:
docker-compose up -d

docker-compose down

Troubleshooting

unable to configure the Docker daemon with file /etc/docker/daemon.json: the following directives are specified both as a flag and in the configuration file: log-driver

In einem systemd-File befindet sich sehr wahrscheinlich genau die gleiche Config-Einstellung wie in /etc/docker. Docker führt die Anweisungen nicht zusammen.

Error starting daemon: error initializing graphdriver: /var/lib/docker contains several valid graphdrivers: devicemapper, overlay2; Please cleanup or explicitly choose storage driver (-s )
rm -rf /var/lib/docker/devicemapper
systemctl start docker

Built on 2024-07-16