Suche
Kolumne

Docker rockt Java: Docker Multi-Host Networking

Peter Roßbach
docker-fuer-java

© Software & Support Media

Ein fehlender Baustein im Docker-Ökosystem ist der einheitliche Multi-Host-Network-Support. Dafür gibt es bisher mehrere Lösungen, die sich mit sehr speziellen Werkzeugen und Erweiterungen in einem Host integrieren lassen. Die Integration des Projekts libnetwork in die Docker Engine soll nun eine einheitliche und transparente Netzwerknutzung für Container realisieren.

Auf der DockerCon 2015 in San Francisco wurde der Docker-Network-Multi-Host-Support erstmalig vorgestellt. Die Docker-Version 1.7 basiert nun komplett auf dem Projekt libnetwork. In der Docker Engine ist der gewohnte Linux-Bridge-Support (hier und hier) [1] verfügbar. Mit dem Release 1.8 ist der Multi-Host-Support dann offiziell verfügbar. Diese Kolumne beruht auf dem Experimental-1.8-Release, das nun täglich aktuell verfügbar ist.

Ein Ziel des Multi-Host-Supports ist es, Containern auf verschiedenen Hosts zu ermöglichen, miteinander zu kommunizieren. Weiterhin wird eine Isolierung der Netzwerke von Containergruppen realisiert. Jeder Container kann nun gleichzeitig an verschiedene Netzwerke angebunden werden. Die Technologie zur Realisierung der Netzwerkkommunikation kann ausgetauscht und erweitert werden. Das Konzept der Docker-Links wird durch ein neues Servicekonzept ergänzt. Ein Service wird zur Laufzeit an einen Container und ein Netzwerk gebunden. Der Service wird durch einen Namen und die Bereitstellung verschiedener Ports definiert. Um die Informationen von Netzwerken und Services zwischen den Docker-Hosts zu koordinieren, werden diese in einem Key Value Store, bzw. Service Discovery wie Consul, Etcd oder ZooKeeper bereitgestellt (Abb. 1).

Abb. 1: Docker-Multi-Host-Network-Architektur

Abb. 1: Docker-Multi-Host-Network-Architektur

Die Aufzählung dieser neuen Eigenschaften ist beeindruckend. Im Folgenden wird beschrieben, welche Schritte praktisch erfolgen müssen, um den Multi-Host-Network-Support auf dem eigenen Notebook zu testen (hierhier und hier).

boot2docker-Network-Experiment

Als ersten Schritt müssen erstmal verschiedene Hosts mit der Docker Machine erzeugt werden [2]. Damit die neuesten Eigenschaften der Docker Engine auch auf der Basis von boot2docker bereitstehen, muss ein boot2docker-Image auf der Basis des Docker-Experimental-Release erzeugt werden. Natürlich existiert schon ein entsprechender boot2docker-Build-Container, und der Austausch des Docker-Release ist entsprechend einfach, (Listing 1). Mit dem hier verwendeten boot2docker-Build-Container lassen sich sehr schön erweiterte Projekt-Images für ein oder mehrere Teams bereitstellen.

$ cat >Dockerfile <<EOF
FROM boot2docker/boot2docker
RUN curl -L https://experimental.docker.com/builds/Linux/x86_64/docker-latest > $ROOTFS/usr/local/bin/docker \
  && chmod +x $ROOTFS/usr/local/bin/docker
RUN /make_iso.sh
CMD ["cat", "boot2docker.iso"]
EOF
$ docker build -t infrabricks/boot2docker:1.8-dev .
$ docker run --rm infrabricks/boot2docker:1.8-dev > boot2docker-1.8.iso

Mit dem nach einigen Minuten verfügbaren neuen boot2docker-Image lassen sich nun verschiedene Hosts mithilfe von Docker Machine für das Experiment erzeugen. Als Erstes benötigen wir einen Service Discovery Host, der auf dem Consul installiert wird (Listing 2). Im Beispiel wird die Consul-Konsole unter dem Port 8500 bereitgestellt.

$ docker-machine create -d virtualbox \
  —virtualbox-boot2docker-url=file://$(pwd)/boot2docker-1.8.iso consul
$ docker $(docker-machine config consul) run \
  -d -p 8500:8500 progrium/consul \
  -server -advertise $(docker-machine ip consul) \
  -ui-dir=/ui \
  -data-dir=/data \
  -bootstrap-expect 1

Docker-Host mit Multi-Network-Support erzeugen

Damit der Raum für Experimente vergrößert wird, erzeugen wir auf dem ersten Network-Host gleich einen SWARM Master. Dazu wird ein SWARM-Token auf dem lokalen Service-Discovery-Host erzeugt. Die Engine wird mit der Consul Service Discovery verbunden und das Overlay Network auf das Interface eth1 gebunden. Mit der Option default-network=overlay werden nun alle Container statt an die lokale Docker Bridge docker0 direkt mit dem Overlay Network verbunden. Es kommt der VXLAN Driver von libnetwork zum Einsatz, der ursprünglich als Basis des Projekts SocketPlane entstammt. Der Driver basiert auf Open vSwitch. Der Swarm-Master und -Agent müssen leider noch manuell gestartet werden, da Docker Machine 0.3 die neuen Networkoptionen noch nicht unterstützt. Beide Container werden an die lokale Network Bridge mit der neuen Docker-Engine-Option –net=bridge gebunden (Listing 3). Mit der mehrfachen Verwendung der Option –net können weitere Netzwerkschnittstellen an einen Container angebunden werden. Einen weiteren Host im Overlay Network zu erzeugen, geschieht durch die Nutzung derselben Service Discovery und desselben Swarm Tokens (Listing 4). Eigentlich sollte die Verwendung derselben Service Discovery ausreichen, aber in meiner Docker-1.8-Experimental-Version war eine stabile Kommunikation zwischen zwei Hosts nur mit der zusätzlichen Konfiguration des Labels com.docker.network.driver.overlay.neighbor_ip möglich.

export SWARM_TOKEN=$(docker $(docker-machine config consul) run --rm swarm create)
$ docker-machine create -d virtualbox \
  --virtualbox-boot2docker-url=file://$(pwd)/boot2docker-1.8.iso \
  --engine-opt="default-network=overlay:multihost" \
  --engine-opt="kv-store=consul:$(docker-machine ip consul):8500" \
  --engine-label="com.docker.network.driver.overlay.bind_interface=eth1" \
  swarm-master
$ docker $(docker-machine config swarm-master) \
  run -d --restart="always" --net="bridge" \
  swarm:latest join \
  --addr "$(docker-machine ip swarm-master):2376" \
  "token://$SWARM_TOKEN"
$ docker $(docker-machine config swarm-master) \
 run -d --restart="always" \
 --net="bridge" -p "3376:3376" \
 -v /var/lib/boot2docker:/var/lib/boot2docker \
 swarm:latest manage \
 --tlsverify \
 --tlscacert=/var/lib/boot2docker/ca.pem \
 --tlscert=/var/lib/boot2docker/server.pem \
 --tlskey=/var/lib/boot2docker/server-key.pem \
 -H "tcp://0.0.0.0:3376" \
 --strategy spread \
 "token://$SWARM_TOKEN"
$ docker-machine create -d virtualbox \
 --virtualbox-boot2docker-url=file://$(pwd)/boot2docker-1.8.iso \
 --engine-opt="default-network=overlay:multihost" \
 --engine-opt="kv-store=consul:$(docker-machine ip consul):8500" \
 --engine-label="com.docker.network.driver.overlay.bind_interface=eth1" \
 --engine-label="com.docker.network.driver.overlay.neighbor_ip=$(docker-machine ip swarm-master)" \
 swarm-node-001
$ docker $(docker-machine config swarm-node-001) \
  run -d --restart="always" --net="bridge" \
  swarm:latest join \
  --addr "$(docker-machine ip swarm-node-001):2376" \
  "token://$SWARM_TOKEN"

Docker-Network erzeugen und mit Container-Services verbinden

Mit dem Docker-Release 1.8 werden die beiden neuen Kommandos network und service verfügbar (Listing 5). Ein Netzwerk kann so auf der Basis des entsprechenden Treibers erzeugt, beauskunftet, zugewiesen und natürlich wieder gelöscht werden. Netzwerke sind aber eigentlich aus Sicht einer Anwendung nur Mittel zum Zweck der Bereitstellung und Erreichbarkeit von Services. Deshalb kann nun ein Service veröffentlicht und an ihn ein Container gebunden werden. Mithilfe dieser Eigenschaft sollen nun Gruppen von Containern in jeweils isolierten Netzwerken über Hostgrenzen hinweg miteinander kommunizieren. Aktuell werden die IP-Adressen der Services eines Netzwerks in die /etc/hosts aller Container, die Zugang zu dem Netzwerk haben, eingetragen und aktualisiert. Bisher ist nicht definiert, wie eine Anwendung an die Informationen der gebundenen Ports der jeweiligen Services kommt.

$ docker-machine ssh swarm-master
> docker network create -d overlay prod
> docker network ls
NETWORK ID          NAME                TYPE
61714d7d2cff        multihost           overlay
b0e252ffee89        prod                overlay
906111b848a9        none                null
b5b841887fc1        host                host
c126f2234459        bridge              bridge
> docker network info prod
> docker service publish db1.prod
> cid=$(docker run -itd -p 8000:8000 ubuntu)
> docker service attach $cid db1.prod
## in einer zweiten Shell
$ docker-machine ssh swarm-001
> docker network ls
> docker network info prod
> docker run -itd --publish-service db2.prod -p 8001:8000 ubuntu
> docker service ls
SERVICE ID          NAME   NETWORK     CONTAINER
0771deb5f84b        db2    prod        0e54a527f22c
aea23b224acf        db1    prod        4b0a309ca311

Docker-Plug-in-Services

Eine weitere Neuerung in Docker ist die Möglichkeit, die Docker Engine gezielt mit Plug-ins zu erweitern. In Docker 1.8 werden Volume-Management und Netzwerk als Plug-ins bereitgestellt (Abb. 2). Die Plug-ins werden mit UNIX Socket bereitgestellt und mit HTTP/JSON angesprochen. Als eine der ersten Implementierungen existiert das Weave-Docker-Network-Plug-in, (Listing 6). Die Entscheidung für diese Lösung liegt einerseits daran, dass die Programmiersprache GO keine Shared Libraries unterstützt und anderseits, dass man in jeder Programmiersprache HTTP und JSON zur Programmierung eines Plug-ins verwenden kann. Gesicherte und autorisierte Kommunikation kann in den Plug-in-.json-Dateien vereinbart werden. Noch steht der Weave-Netzwerk-Plug-in-Container nicht offiziell bereit, aber er kann ohne Probleme aus dem GitHub Repository übersetzt werden. Mit einem entsprechenden Skript kann die Weave-Infrastruktur erzeugt und die Anbindung an die Docker Engine via Plug-in hergestellt werden. Sobald das Weave-Plug-in läuft, können nun Netze auf der Basis von Weave mit der Standard Docker CLI, bzw. API verwaltet werden. Das Plug-in sorgt dafür, dass im Container mit einem Weave-Netzwerk ein entsprechendes Ethernetinterface erzeugt und verwaltet wird. Die Anbieter VMware und Cisco, aber auch die Netzwerkprojekte Calico und Flannel haben eine Docker-Netzwerkintegration angekündigt.

Abb. 2: Docker-Plug-in-Architektur

Abb. 2: Docker-Plug-in-Architektur

$ eval $(docker-machine env swarm-node-001)
$ git clone https://github.com/weaveworks/docker-plugin
$ cd docker-plugin
$ docker run -ti --rm \
 -v /usr/local/bin/docker:/usr/local/bin/docker \
 -v $(pwd):/go/src/github.com/weaveworks/docker-plugin \
 -v /var/run/docker.sock:/var/run/docker.sock \
 -w /go/src/github.com/weaveworks/docker-plugin \
 golang:1.4
> go clean -i net
> go install -tags netgo std
> make
> CTRL-C
$ docker load < plugin.tar
$ docker-machine ssh swarm-node-001 'sudo mkdir -p /usr/share/docker/plugins'
$ ./start-all.sh
$ docker run -tid --publish-service=serviceA.networkA.weave ubuntu
$ docker network ls
NETWORK ID          NAME                TYPE
c55ccf14d332        networkA            weave
61714d7d2cff        multihost           overlay
b0e252ffee89        prod                overlay
906111b848a9        none                null
b5b841887fc1        host                host
c126f2234459        bridge              bridge

Fazit

Ein weiterer Meilenstein im Docker-Ökosystem, der transparenten Netzwerk-Multi-Host-Support ermöglicht, scheint bald erreicht zu sein. Die ersten Eindrücke des kommenden Docker-1.8-Releases sind sehr hoffnungsvoll. Nun lassen sich auch komplexere Netzwerk-Set-ups schon in der Entwicklung modellieren und auf die Produktion einfacher Netzwerk-Set-ups übertragen. Allerdings gilt es noch die Hürden der Zugriffskontrolle, Einschränkungen durch Firewalls, Lastverteilung, Verteilung von Zertifikaten oder Autorisierungen zu klären. Eine erste wirklich stabile Version des Multi-Host-Netzwerk-Supports und der Plug-ins erwarte ich erst mit dem Release 1.9.

Geschrieben von
Peter Roßbach
Peter Roßbach
Peter Roßbach ist ein Infracoder, Systemarchitekt und Berater vieler Websysteme. Sein besonderes Interesse gilt dem Design und der Entwicklung von komplexen Infrastrukturen. Er ist Apache Tomcat Committer und Apache Member. Mit der bee42 solutions gmbh realisiert er Infrastrukturprodukte und bietet Schulungen auf der Grundlage des Docker-Ökosystems, aktuellen Webtechnologien, NoSQL-Datenbanken und Cloud-Plattformen an.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: