Docker Container unter sich

In meinen ersten Artikeln über Docker bin ich kurz auf die kleinen Stolperfallen bei der Installation unter Ubuntu 15.04 eingegangen und habe in einem zweiten Artikel erläutert, wie Docker mit geänderten Daten umgeht. In diesem Artikel gehe ich ein wenig auf die Netz-Besonderheiten von Docker ein und zeige anhand einer einfachen Web-Applikation wie mächtig das Docker Container Linking ist. Den vorläufigen Abschluss meiner kleinen Artikelserie bildet eine Anleitung zu Remote Debugging via XDebug im Docker Container.

Auch hier der Hinweis vorweg: Ich lasse in allen Beispielen das Kommando “sudo” weg. Das dient zum Einen der Lesbarkeit, zum Anderen kann man bei der Benutzung von boot2docker sudo nicht verwenden.

Willkommen in Neuland!

Wie so häufig möchte ich ein bisschen tiefer in die Materie einsteigen als unbedingt nötig wäre um Docker einfach nur zu benutzen. Daher werde ich ein paar Sätze zum Docker-Netz sagen. Wer es noch genauer wissen möchte kann es in der offiziellen Dokumentation  nachlesen.

Docker verwendet eine Reihe von Tricks um die Sichtbarkeit von Anwendungen innerhalb der Container kontrollierbar zu machen. Die Container werden in eigenes Subnetze auf dem Host gesperrt. Darin haben alle Container eine Adresse aus einem privaten Adressebereich nach RFC 1918, Abschnitt 3. Diese Adressen werden, ähnlich wie es fast alle Router am heimischen DSL-Anschluss tun, gegenüber der großen weiten Welt verborgen. Dabei verwendet Docker nicht die bekannteren IP-Bereiche 10/8 (z.B. 10.0.4.240; die Adresse meines wlan0 hier in der Firma) und 192.168/16 (z.B. 192.168.1.2; typisch für Heimnetze) sondern 172.16/12. Mein docker0 hat z.B. die Adresse 172.17.42.1. Obwohl Docker theoretisch die Adressen von 172.16.0.0 bis 172.31.255.255 verwenden könnte beschränkt es sich auf den 16-bittigen Bereich 172.17/16 von 172.17.0.0 bis 172.17.255.255.  Die Adressen der Container innerhalb des Netzes werden dann einfach ab 172.17.0.1 hochgezählt und haben 172.17.42.1 als Gateway.

Auf dem Host selbst sorgen Routing-Regeln dafür, dass aller Verkehr zu einer der „Docker-Adressen“ über docker0 laufen. 172.17.0.43:3306 (da läuft gerade ein DB-Container) ist also von meinem Host aus erreichbar und für alle anderen Rechner um mich herum unsichtbar. Damit kommt erstmal alles raus und nichts rein… Es gibt natürlich eine Reihe von Möglichkeiten, die Sicht- und Erreichbarkeit von Containern zu verändern.

Nackt und bloß auf dem Hos… t

Wer es schnell und schmutzig mag kann das Netz eines Containers mit der Option  --net=host direkt auf dem Host laufen lassen. Die obige Datenbank wäre dann über 10.0.4.240:3306 von überall aus dem Firmennetz erreichbar und hätte umgekehrt vollen Zugriff auf meinen lokalen Netz-Stack. Nicht schlimm? Doch! Darüber sind dann nämlich auch lokale Dienste wie D-Bus erreichbar und ein  shutdown -h --no-wall now innerhalb des Containers kann dann unerwartete Auswirkungen haben: der Host wird runtergefahren. Jetzt, ohne Warnung.

You should use this option with caution. https://docs.docker.com/articles/networking/#container-networking

Egal wohin, Hauptsache erreichbar

Etwas weniger drastisch dafür aber weniger vorhersehbar ist das Ergebnis wenn man einen Container mit dem Parameter -P startet. Das Netz des Containers wird wie oben beschrieben über das docker0 Interface geführt. Alle durch den Container exponierten Ports werden auf zufällige Ports in der ephemeral port range auf dem Host gemappt. Je nach Konfiguration des Kernels liegt diese typischerweise im Bereich von 32768 bis 61000.

Der Port 80 meines Containers wurde hier auf den Port 49153 meines Host gemappt und wäre so von außerhalb zu erreichen. Natürlich kann ich vom Host aus weiter direkt auf den Container zugreifen.

Auf dem Host ist localhost:49153 also identisch mit 172.17.0.45:80. Aus Sicht des Containers gibt es gar keinen wahrnehmbaren Unterschied weil beide Zugriffe für ihn von 172.17.42.1 kommen. Aber irgendwie ist es lästig immer wieder nachschauen zu müssen auf welchem Port oder welcher IP ein Container erreichbar ist.

I choose you Port!

Noch mehr Kontrolle über das Port Mapping gewährt der Parameter -p (oder –publish). Hierüber kann bestimmt werden welcher Port auf welchem Interface des Hosts auf einen Port im Container führt.

Im ersten Fall wäre der Container nur lokal über Port 8080 erreichbar, im zweiten von jedem Rechner aus, der Zugriff auf meinen Port 8080 hat. Das klingt so langsam nach produktivem Einsatz, oder? Es ist natürlich möglich, den Parameter -p mehrfach zu verwenden um mehrere Port Mappings zu definieren.

Container unter sich

Docker Container haben noch eine weitere Möglichkeit miteinander zu kommunizieren: Container Linking. Hierbei handelt es sich nach meiner Meinung um eine der coolsten Funktionen von Docker überhaupt. Wer meinen Artikel über Data Volumes gelesen hat erinnert sich vielleicht noch an den Container ‚db3‘ in dem eine MySQL-Datenbank läuft. Zur Erinnerung: Die Container für Daten und DB wurden erzeugt mit

Um jetzt aus meinem Application Container ‚web‘ auf die Datenbank in ‚db3‘ zuzugreifen könnte ich natürlich dem web-Container die IP und den Port der Datenbank explizit mitteilen. Da sich die Container untereinander alle erreichen können wäre der Zugriff dann gar kein Problem. Aber es ist schon wieder umständlich! Viel einfacher wird es mit

phpmysqli?

‚phpmysqli‘ ist ein Image von mir das php:apache um mysqli- und mbstring-Unterstützung erweitert. Um es zu verwenden braucht man nur eine Datei namens ‚Dockerfile‘ in einem sonst leeren Verzeichnis:

In dem Verzeichnis  docker build -t phpmysqli . aufrufen und schon erzeugt Docker basierend auf php:apache ein neues Image namens phpmysqli.

Weiter im Text!

In das Verzeichnis auf dem Host (/home/cgd/Projects/Docker/Example) habe ich eine einfache PHP-Datei gelegt:

In der Datenbank befinden sich die passende Tabelle ‚testo‘ mit drei Einträgen:

Und wie es der Zufall will…

Wie kann das funktionieren? Durch den –link Parameter erzeugt Docker im Zielcontainer eine Reihe von Umgebungsvariablen über die man den Port und weiteres in Erfahrung bringen kann sowie einen Eintrag in /etc/hosts für ‚db‘.

Werfen wir doch einen kurzen Blick in den Container:

Es gibt für jede Umgebungsvariable in db (dem Link-Alias von db3) einen entsprechende Variable in web mit dem Präfix ‚DB_ENV_‘. Da der Container db3 mit den Parametern MYSQL_DATABASE usw. erzeugt wurde und mit diesen automatisch eine passende Datenbank angelegt hat kann der web-Container die daraus abgeleiteten Variablen für den Zugriff auf die Datenbank in db3 verwenden.

Jetzt steht dem Entwickeln einer komplexen Web-Anwendung aus mehreren Containern nichts mehr im Wege. Viel Spaß beim Nachbauen!

 

Das Titelbild stammt von https://www.flickr.com/photos/xmodulo/14098888813 und steht unter der CC BY 2.0 Lizenz.

Das könnte Dich auch interessieren...

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Durch die weitere Nutzung der Seite stimmst du der Verwendung von Cookies zu. Weitere Informationen

Die Cookie-Einstellungen auf dieser Website sind auf "Cookies zulassen" eingestellt, um das beste Surferlebnis zu ermöglichen. Wenn du diese Website ohne Änderung der Cookie-Einstellungen verwendest oder auf "Akzeptieren" klickst, erklärst du sich damit einverstanden.

Schließen