Docker Tutorial [Teil 5 - Netzwerk (Grundlagen)]

Datum

Die Standard Netzwerke

Bei allen docker Installationen wird das Netzwerk Interface docker0 erstellt, welches ein bridge Netzwerk ist und sich in der Regel an das erste Netzwerk-Interface und das loopbackInterface bindet.
Dieses verwendet ein /16 Netz für die Container.

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:3d:cc:65:07 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:3dff:fecc:6507/64 scope link 
       valid_lft forever preferred_lft forever

Eine Übersicht über die vorhandenen Netzwerke erhält man mit docker network ls

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
d3ba53468648        bridge              bridge              local
4b043328757f        host                host                local
6a16d77c03b6        none                null                local

bridge
Die bridge erstellt ein eigenes privates Netzwerk auf dem host um es Containern zu ermöglichen über dieses Netzwerk zu kommunizieren.
Mit Hilfe der im letzten Teil der Tutorial Reihe vorgestellten --expose Option ist auch ein Zugriff auf die Container außerhalb des privaten Netzwerkes möglich.

Bei der Erstellung eines solchen Netzwerkes kümmert sich docker im Hintergrund um das Anlegen der notwendigen Linux bridges, internen Interfaces, iptables Regeln und Host Routen.
Weitere Argumente für das Anlegen eines benutzerdefinierten bridge Netzwerkes findet man hier: Use bridge networks

host
Laut Dokumentation erlaubt das host Netzwerk, dass ein Container sich den Netzwerk-Stack mit dem Host teilt. Dies soll eine bessere Netzwerk Performance bringen.
Wenn man also einen Container mit Nginx und dem host Netzwerk startet, ist der Nginx auf dem Host auf Port 80 erreichbar.
docker run --rm -d --network host --name mein_nginx nginx

$ curl -I localhost:80
HTTP/1.1 200 OK
Server: nginx/1.17.0
Date: Thu, 13 Jun 2019 18:42:53 GMT
...

none
Hierbei hat ein Container keinerlei externe ROuten und es ist lediglich das loopback Device aktiv.

Anmerkung:
Die Einzelheiten jedes dieser Netzwerke in der Liste kann man sich mit docker network inspect <NETWORK ID/NAME> anschauen.

Beispiel:

$ docker network inspect host
[
    {
        "Name": "host",
        "Id": "4b043328757f12838d47535cd6660c466a41c6fb6e36dfc8c5624e914764e786",
        "Created": "2019-06-11T14:08:25.862917584Z",
        "Scope": "local",
        "Driver": "host",
        ...

docker network …

Die entsprechende docker-Dokumentation findet sich hier: Docker container networking

Sofern nichts extra angegeben wird, wird jeder neu erstellte Container automatisch zum bridge Netzwerk hinzugefügt.

Um zu schauen welches Netzwerk ein Container verwendet, sucht man per grep in der entsprechenden Ausgabe des Befehls docker container inspect <CONTAINER ID/Containername>:

"Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    ...
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    ...

Ein Container mit bridge Netzwerk hat auch automatisch eine Route ins Internet.

Zum testen erstelle ich mir einen Container aus dem aktuellsten CentOS Image und lasse dort beim Start eine bash starten.
docker run -d -it --name centos centos bash

$ docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                              NAMES
b44b6b38b319        centos                    "bash"                   3 seconds ago       Up 3 seconds                                           centos

Nun können wir über die bash im eben erstellten Container versuchen eine externe Domain aufzurufen:

$ docker attach centos
[root@b44b6b38b319 /]# ping joinmastodon.org
PING joinmastodon.org (104.18.41.107) 56(84) bytes of data.
64 bytes from 104.18.41.107 (104.18.41.107): icmp_seq=1 ttl=42 time=10.5 ms
...

Des weiteren kann das Host System auch den Container üer seine, von docker vergebene, IP erreicht werden. Hierzu sucht man sich wieder per inspect und grep die entsprechende IP-Adresse des Containers und pingt diesen an:

$ ping 172.17.0.4
PING 172.17.0.4 (172.17.0.4) 56(84) bytes of data.
64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.078 ms
64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.054 ms

Welche Befehle der docker network Befehl kennt, erfährt man mit docker network --help

$ docker network --help

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.
rm

Mit docker network rm <NETWORK ID/NAME> lassen Netzwerke auch wieder entfernen.
Sollte das zu löschende Netzwerk noch von einem Container aktiv genutzt werden, so gibt es eine entsprechenden Warnung:

$ docker network rm br0
Error response from daemon: error while removing network: network br0 id c6ea95f50f39e381968968a4a01e35da21f72b030fc3d12680aa4e07c348771d has active endpoints
prune

Das docker network prune Kommando löscht alle Netzwerke, welche von keinem Container verwendet werden. Hierbei sollte man immer Vorsicht walten lassen, da im Vorfeld nicht ersichtlich ist welche Netzwerke gelöscht werden.

$ docker network prune
WARNING! This will remove all networks not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Networks:
newbridge00
create

Mit dem Befehl docker network create <Netzwerkname> kann ein weiteres Netzwerk hinzufügen. Gibt man keine weiteren Optionen an wird ein weiteres bridge Netzwerk erzeugt.
Dokumentaion: docs.docker.com

docker network create newbridge00

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
...
a341c965b43d        newbridge00         bridge              local
...
$ docker network inspect newbridge00 
[
    {
        "Name": "newbridge00",
        "Id": "a341c965b43da2eac324cfa8fbc76b79d314a6bbef18ebc3ed88a2bbf23aa661",
        "Created": "2019-06-13T17:31:29.381566066Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                    ...

Nach der Erstellung findet sich auf dem Host ein entsprechendes bridge Interface, welches den Namen br-<NETWORK ID der Bridge> hat.

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
c6ea95f50f39        br0                 bridge              local
...
$ ip a | grep c6ea95f50f39
12: br-c6ea95f50f39: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    inet 172.28.5.254/16 brd 172.28.255.255 scope global br-c6ea95f50f39

Mit der Möglichkeit eigene (benutzerdefinierte) bridge Netzwerke zu erstellen bietet sich die Möglichhkeit Container (netzwerktechnisch) in Gruppen anzuordnen, wo die einzelnen Container nur mit anderen Containern im gleichen bridge Netzwerk kommunizieren können aber nicht mit Containern in anderen bridge Netzwerken.

Im folgenden Beispiel erstelle ich ein neues bridge Netzwerk mit Namen br0 und erstelle 2 Container, welche ich diesem neuen Netzwerk mit Hilfe der --network Option zuordne.

$ docker network create --subnet=172.28.0.0/16 --ip-range=172.28.5.0/24 --gateway=172.28.5.254 br0

Die möglichen Optionen erfährt man auch wieder mit docker network create --help.
Anmerkung: Bei der Vergabe benutzerdefinierter IPadressen und IP-Ranges sollte man immer darauf achten nur private IP-Adressen zu verwenden.

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
c6ea95f50f39        br0                 bridge              local

docker container run -d -p 8081:8080 --name httpd_centos --network br0 centos/httpd-24-centos7
docker container run -d -p 8080:80 --name nginx --network br0 nginx

docker inspect nginx | grep -i ipaddress
                    "IPAddress": "172.28.5.1",
$ docker container inspect httpd_centos | grep Networks -A 1
            "Networks": {
                "br0": {

Die beiden eben erstellten Container nginx und httpd_centos können nun untereinander kommunizieren…

$ docker exec -it httpd_centos /bin/bash
bash-4.2$ curl -I nginx
HTTP/1.1 200 OK
Server: nginx/1.17.0
...
bash-4.2$ ping nginx
PING nginx (172.28.5.1) 56(84) bytes of data.
64 bytes from nginx.br0 (172.28.5.1): icmp_seq=1 ttl=64 time=0.054 ms
...

Und auch das Hostsystem kann mit den Containern im bridge Netzwerk br0 problemlos kommunizieren.

Mit den Optionen --ip in Kombination mit --network kann man einem Container bei der Erstellung auch eine benutzerdefinierte IP-Adresse zuordnen, man sollte aber darauf achten, dass diese auch in der IP-Range des entsprechenden bridge Netzwerkes ist.

connect

Möchte man einen bestehenden Container einem weiteren docker-Netzwerk zuordnen verwendet man den Befehl docker network connect <docker-Netzwerk> <CONTAINER ID/Containername>

Hierzu legen wir uns erst wieder einen neuen Container per docker run -d --name nginx02 nginx an und schauen welchem docker-Netzwerk dieser zugeordnet ist:

$ docker container inspect nginx02 | grep Networks -A 1
            "Networks": {
                "bridge": {

Nun fügen wir diesen Container dem neuen docker-Netzwerk per docker network connect br0 nginx02 zu und prüfen dann erneut:

$ docker container inspect nginx02 
              ...
            "Networks": {
                "br0": {
                ...
                bridge": {
                ...

Damit ist der Container über 2 verschiedenen IPadressen bzw. docker-Netzwerke ansprechbar.

disconnect

Möchte man einen Container wieder aus einem bestimmten docker-Netzwerk entfernen verwendet man den Befehl docker network disconnect <docker-Netzwerk> <CONTAINER ID/Containername>

Beispiel: docker network disconnect br0 nginx02

Autor
Kategorien container, docker

PRTG Map