Freitag, 25. September 2015

Docker: Linking Container

Linking Containers together

Verbindung mit dem Container per Port-Mapping
    docker run -P training/webapp python app.py

bei der Verwendung des -P Flags wird der interne Port 5000 auf einen zufälligen Port nach draußen gemappt.
Alternativ kann man den zu verwendeten Port des Hostssystem selbst bestimmen:
     docker run -d -p 80:5000 training/webapp python app.py

Hier wird dem Container gesagt, dass er Port 5000 auf Port 80 des Hosts mappen soll.
Dann kann der Port noch dem localhosts zugewiesen werden:
     docker run -d -p 127.0.0.1:80:5000 training/webapp python app.py

Und eine UDP Connection kann ebenfalls hinzugefügt werden:
     docker run -d -p 127.0.0.1:80:5000/udp training/webapp python app.py
 

Linken von Containern

Ein anderer Mechanismus um zwei oder mehr Container miteinander zu verbinden, ist das Linken. Hierbei wird dem Empfänger-Container selektierte Informationen des Sender-Containers zur Verfügung gestellt. Bei der Verlinkung kommen die Container-Namen zum Einsatz. An dieser Stelle sei angemerkt, dass die Namen der Container ebenfalls personalisiert angelegt werden können, unter zu Hilfename des Flags --name. Das kann hilfreich sein, wenn man in einer Umgebung mit vielen Containern den Überblick behalten möchte und z.B. die Container nach ihrer Verwendung (web, db) benennt.
     docker run -d -P --name web training/webapp python app.py

Dabei ist zu beachten, dass Container-Namen eindeutig sind und nicht mehrfach verwendet werden können.
Bei der Verlinkung von Containern wird ein sicherer Kanal installiert, über den der Empfänger Container definierte Daten des Senders bekommen kann. Um eine Verlinkung zu installieren wird als erstes der Sender-Container gestartet. Laut der Anleitung bei Docker:
      docker run -d --name db training/postgres

Hierbei handelt es sich um einen Container der eine Datenbank beinhaltet. Als nächstes wird der Empfänger-Container gestartet, direkt mit der Verlinkung auf den Source-Container:
      docker run -d -P --name web --link db:db training/webapp python app.py

Hierbei wird dem --link Flag die Information des zu verlinkenden Containers in Form des Container-Namens oder der ID übergeben. Der Bezeichner hinter dem Doppelpunkt entspricht einem Alias des Source-Containers und kann optional verwendet werden. Mit der docker inspect Funktion können wir die Verlinkung prüfen:
      docker inspect -f "{{ .HostConfig.Links }}" web

Wird dort für unser Beispiel [/db:/web/db] angezeigt, war unsere Verlinkung erfolgreich.

Bei der Verlinkung wird ein sicherer Tunnel zwischen den Containern erzeugt, der keinerlei Öffnung zum Hostsystem benötigt. Es handelt sich um eine rein interne Verbindung -> keine Angriffsmöglichkeit von außen. Dabei werden die Verbindungsinformationen des Source-Containers für den Empfänger auf zwei verschiedene Weisen bereit gestellt:
  • über so genannte Environment Variablen
  • Aktualisierung der /etc/host/ files
Environment Variablen    
Docker kreiert verschiedene Umgebungsvariablen bei der Verlinkung von Containern im Zielsystem. Auch stellt Docker den Kontakt der Variablen auf beiden Systemen her. Die Environment Variablen enthalten die Variablen aus dem Aufruf des Containers mit dem ENV Befehl und den -e, -env und -envfile Optionen in Verbindung mit dem run-Befehl. Diese Variablen erlauben die programmatische Erkundung der Quelle von dem Empfänger. 
Dabei ist unbedingt zu beachten, dass die bereitgestellten Environment Variablen des Sender-Container ALLEN Containern bereit gestellt werden, die auf den Sender verlinkt werden. Der Sicherheitsaspekt bei sensiblen Daten ist an dieser Stelle unbedingt zu beachten

Die Variablen haben dabei folgende Syntax:
<Alias>_Name=xyz
<Alias>_Port_<Port>_<Protokoll>="Adresse"

Mit dem verwendeten Beispiel bei Docker in meinem Terminal sieht das ganze dann so aus:
$ docker run --rm --name web2 --link db training/webapp env

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=014e1dc9db99
DB_PORT=tcp://172.17.0.1:5432
DB_PORT_5432_TCP=tcp://172.17.0.1:5432
DB_PORT_5432_TCP_ADDR=172.17.0.1
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_PROTO=tcp
DB_NAME=/web2/db
DB_ENV_PG_VERSION=9.3
HOME=/root


Hinweis zu den Environment Variablen:
In der Datei /etc/hosts sind die Adressen des Hosts gespeichert. Beim Start des Sender-Containers werden diese Adressen nicht automatisch aktualisiert. Es wird daher empfohlen dieses nachzuholen, um die IP Adressen der verlinkten Container aufzulösen. Diese Variabelen werden nur bei der ersten Verbindung des Containers gesetzt. Einige sshd Dienste löschen diese Daten bei der Erzeugung der Shells für die Verbindungen aus.

Updating /etc/hosts Datei

Zusätzlich zu den Environment Variablen wird noch ein Hosteintrag in der /etc/hosts Datei des kreierten Containers vorgenommen. Das kann dann folgendermaßen aussehen:
  
~$ docker run -t -i --rm --link db:webdb training/webapp /bin/bash
root@a2722b55e736:/opt/webapp# cat /etc/hosts
172.17.0.2    a2722b55e736
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.1    webdb 210d92839224 db
172.17.0.1    db
172.17.0.1    db.bridge
172.17.0.2    condescending_fermat
172.17.0.2    condescending_fermat.bridge
root@a2722b55e736:/opt/webapp#


Docker schreibt zum einen die Lokalhost Adresse in das File. Es sind aber weitere wichtige Einträge ebenfalls dort zu finden: z.B die ID des verlinkten Containers und ebenfalls die Adresse unter der der Container mit dem Alias gelistet ist. Diese Adresse kann unter anderem dafür verwendet werden, um den verlinkten Container anzupingen.

Donnerstag, 24. September 2015

Kernel-Crash-Dump unter Ubuntu installieren

Installation nach Anleitung ubuntu.com/lts/serverguide/kernel-crash-dump.html

Installation des kerne crash dump im Terminal mit:
      sudo apt-get install linux-crashdump

während der Installation wird ebenfalls das kexec-tools-Paket installiert. Während dieser Installation wird man gefragt, ob kexec-tools das Handling des Neustarts übernehmen soll? Diese Frage mit "Ja" beantworten.

als nächstes:
       sudo gedit /etc/default/kdump-tools

ändern des Eintrags:
       USE_KDUMP=1

speichern und dann neustarten!

An dieser Stelle zeigt sich dann schon, ob die kexec-tools funktionieren. Läuft der Neustarte reibungslos, kann in der Anleitung weiter gemacht werden, ansonsten erst einmal Fehlerbehebung, siehe Ende der Anleitung.

Um zu überprüfen, ob die Installation des kernel-dumps erfolgreich war, schauen wir erst einmal nach dem reservierten Speicher für den Neustart-Kernel:
       cat /proc/cmdline

In der Ausgabe gibt es einen Eintrag der z.B. so aussehen kann:       
       crashkernel=384M-2G:64M,2G-:128M

Dieser Eintrag entspricht der Syntax: 
       crashkernel=<range1>:<size1>,[<range2>:<size2>, ...][@Offset]range=start-[end]
    'start' ist inklusiv, 'end' ist exklusiv


Unser Beispiel sagt uns somit, dass bei einem verfügbaren RAM bis 2GB, 64MB dieses Speichers für den Crashkernel reserviert sind. Steht mehr als 2GB RAM zur Verfügung, werden 128MB reserviert. Ist der RAM dagegen kleiner als 384MB, dann wird kein Speicher allokiert.

Nachdem wir nun wissen, wieviel Speicher unser REchner reservieren soll, prüfen wir, ob er das auch tut:
       dmesg | grep -i crash

da sollte eine Ausgabe erscheinen, die in etwa so aussehen könnte:
       ...[  0.000000] Reserving 64MB of memory at 800MB for  crashkernel ... 

mit dieser Meldung wissen wir, dass entsprechender Speicher zur Verfügung steht.

Nun wollen wir Überprüfen, ob auch der Crash Dump Mechanismus funktioniert. Bei diesem Test wird das System rebooted, daher sollte man alle nicht notwendigen Anwendungen schließen und Daten vorher sichern. Vor dem eigentlichen Test checken wir noch folgende Einstellung:
      cat /proc/sys/kernel/sysrq

Der nun angezeigte Value sollte größer 0 sein. Am besten ist die Einstellung 1, da somit alle Einstellung der "magsichen Tasten" freigegeben werden. Es handelt sich hierbei um Tastenkombinationen, die einen koordinierten reboot auslösen. Soll heißen, wenn sich das System aus irgendwelchen Gründen so aufhängt, dass keinerlei Eingaben mehr möglich sind, ermöglichen die "magischen Tasten" einen reboot, bei dem vorher das System ordnungsgemäß herunter gefahren wird. Sie ermöglichen aber auch die Simulation eines kernelcrashs oder andere Eingriffe ins System auf Kernelebene. (Genauere Erläuterungen findet man hier: https://www.kernel.org/doc/Documentation/sysrq.txt)

Um den Wert 1 einzustellen, gibt man folgenden Befehl im Terminal ein:
      sudo sysctl -w kernel.sysrq=1

so, nun wirds Ernst. Als erstes müssen wir nun root werden, da der Aufruf über sudo hier nicht ausreicht:
      sudo -i

danach wird folgender Befehl ausgeführt, der versucht ein Zeichen (Charakter) in eine Binärdatei zu schreiben:
      echo c > /proc/sysrq-trigger

Nach dem erfolgten reboot findet man die log-Datei des Kernel unter /var/crash/ . Die Datei des Kernel fängt mit "linux-image-..." an.

So viel zu der Theorie. Auf meinem Desktop-Rechner mit einer recht frischen Installation Ubuntu 15.04 hat das alles ganz gut funktioniert. Ich habe zwar auch hier die Installation 2x vorgenommen, da es nach dem ersten Mal beim reboot zu Systemabstürzen kam, aber nach der 2. Installation funktionierte der Mechanismus einwandfrei. 
Bei einem reboot erscheint kurz ein schwarzer Bildschirm mit sehr kleiner weißer Schrift, auf dem man noch wählen kann, ob man das kexec-tool verwenden möchte oder nicht.

Fehlerbeschreibung:
Anders stellt sich die Sache auf meinem Laptop mit einer Ubunut 14.04 Installation dar, die nun schon seit einem 3/4 Jahr in Gebrauch ist und ständig Veränderung erfährt. Aktueller Stand ist, dass die kexec-tools nicht funktionieren. Nach einem reboot sehe ich zum einen nicht den schwarzen Bildschirm mit der Asuwahlmöglichkeit. Zum anderen fährt der Rechner bis zum Anmeldebilschirm hoch, ist dann aber weiter nicht mehr zu gebrauchen. Jegliche Tastatureingabe verhallt im Nirvana und zeigt keinerlei Effekt.
Ich habe inzischen mehrfach die Tools deinstalliert und wieder installiert. Als derzeit letzte Installation habe ich nur das kexec-tools Paket installiert, ohne den Kernel Dump. Aber wieder der gleiche Effekt. Leider finde ich im Internet keinerlei Hinweise auf diesen Fehler.

To be continued...

 

 

Sonntag, 20. September 2015

Docker: Get started with images


Get started with images (https://docs.docker.com/userguide/dockerimages/)
  • docker images: Auflistung aller verfügbaren Images auf dem Host-Rechner
  • docker pull [Image]: Download eines neuen Images. Im Guide steht, dass würde schneller gehen, als über den run Befehl, dass kann ich aber nicht bestätigen. Es ist wohl eher so, dass der pull Befehl in dem run Befehl enthalten ist, wenn der entsprechende Container noch nicht vorhanden ist.
  • Um ein passendes Image zu finden, gibt es zwei Möglichkeiten:
    • Über die Docker Hub Website: https://hub.docker.com/
      Hier gibt man die Bezeichnung des gesuchten Images ein und gibt im Terminal dann entsprechend den „Docker pull command“ ein
    • Es kann aber auch direkt über das Terminal gesucht werden mit der Eingabe docker search [Suchbegriff]. Allerdings ist auffällig, dass die beiden Suchen nicht das gleiche Ergebnis ergeben. Die Suche nach „sinatra“ im Docker Hub ergab 1400 Ergebnisse, bei der Suche im Terminal kam ich gerade mal auf 20 Ergebnisse. Und das Image „Training/sinatra“ war nicht dabei. Auffällig war auch, dass nur „Automated Build“ Images angezeigt wurden. Vielleicht finde ich ja später noch irgendwelche Informationen dazu..
  • Es gibt unterschiedliche Arten von Images: Die Basics, die von Docker.Inc bereitgestellt werden. Zu erkennen sind diese an den Bezeichnern „base“ oder „root“. Dann gibt es die noch die User-kreierten Images, die immer den Usernamen mit einem Slash voran gestellt im Bezeichner haben. Die User sind alle Mitglieder im Docker Hub und verantwortlich für die Erzeugung und Wartung des Images
Creating your own image
Es gibt zwei Möglichkeiten ein Image selbst zu erzeugen: Man erweitert ein bestehendes, oder man erzeugt ein neues unter zu Hilfename von „Dockerfile“
  • Erweiterung eines bestehendes Images: Zuerst wird das zu erweiternde Image in einem Container geöffnet. Dann wird es entsprechend angepasst (Installation neuer Software, etc). Danach wird der Container verlassen. Mit dem Befehl docker commit -m [„Kommentar zur Erläuterung“] -a [„Author“] \ [ID des veränderten Containers] [Name des neuen Images] („docker commit -m „Addes json gem“ -a „Kate Smith“ \ 0b26162vkwfhoij ouruser/sinatra:v2“) wird ein neues Images lokal auf dem Hostrechner erzeugt.
  • Neues Image erstellen: Um ein neues Image zu erstellen wird ein Dockerfile benötigt. Dafür kann es sinnvoll sein, erst einmal einen Ordner für das neue Image anzulegen (mkdir [Ordner]). Dann wird ein Dockerfile angelegt (in der Anleitung wurde dafür der „touch“ Befehl verwendet: touch Dokerfile). Danach diese Textdatei öffnen und die benötigten Schritte zur Erzeugung des Images eintragen. Im Beispiel wurde ein Image auf Grundlage von Ubunut14.04 erzeugt, in das anschließend ruby und sinatra installiert wird. Die Datei speichern und schließen. Mein Beispiel-Image wurde nach folgendem Skript erzeugt: # This is a comment
    FROM ubuntu:14.04
    MAINTAINER Papermouse <papermouse1973@gmail.com>
    RUN apt-get update && apt-get install -y ruby ruby-dev
    RUN gem install sinatra

    Abschließend wird das Image mit folgender Kommandozeile erzeugt: docker build -t ouruser/sinatra:v2 . Ganz Wichtig ist der Punkt, der definiert, dass das Dockerfile aus dem aktuellen Pfad genommen werden soll. Es kann aber auch ein konkreter Pfad angegeben werden. Die Erzeugung des Images nimmt einiges an Zeit in Anspruch und es kommt auch zu Fehlermeldungen, die aber offensichtlich nicht wichtig sind. Nun können wir das Image, welches wiederum lokal auf dem Hostrechner liegt, starten.
  • In der Beschreibung wird noch erläutert, dass man Tags setzen kann: docker tag. Das habe ich erst mal nur zur Kenntnis genommen. Außerdem werden digest erwähnt. Die Thematik habe ich GARNICHT verstanden. Weder die Bedeutung, noch alles weitere. Bei Gelegenheit mal rechieren.
  • Dann habe ich das Image zum Hub geschickt. Dabei musste ich feststellen, dass ich hier wieder das sudo davor setzen muss. Sonst wird mir der Zugriff verweigert. In diesem Zusammenhang habe ich aus dem Dokerfile noch ein Image erzeugt, welches den Namen papermouse/sinatra bekam. Dieses Mal ging das Erstellen ganz schnell. sudo docker push papermouse/sinatra
  • Entfernen eines Image vom Host: docker rmi [Name des Image] („docker rmi ouruser/sinatra“). Bei meinen Versuchen auf meinem Rechner Images zu löschen, bekam ich bei JEDEM Image die Meldung, dass dieses noch von einem anderen Container verwendet wird. Löschen mit dem Flag -f (force) geht. Aber woher kommen die Meldungen? Selbst das Hello-World Image kann nicht einfach gelöscht werden und das habe ich ja  nicht weiter verwendet.

Docker Using Guide


Docker Using Guide  

Als nächstes habe ich mir die Anleitung "Docker Using Guide" (https://docs.docker.com/userguide/) vorgenommen. Dort habe ich als erstes die "Dockerizing applications: A Hello World" (https://docs.docker.com/userguide/dockerizing/) Guide aufgerufen.
 

Dockerizing applications: A Hello World

Und da es mir auf die Nerven ging, immer das sudo mit einzugeben, habe ich meinen User der Gruppe "docker" hinzugefügt, was die sudo Eingabe überflüssig macht. Allerdings muss ich feststellen, dass es dann immer eine Fehlermeldung bezgl. des Zugriffs auf eine Datei gibt, was der Funktionalität der Container jedoch nicht entgegen steht.
  • Aufruf eines Befehls innerhalb eines Container:Jegliche Aufrufe in Bezug zu einem Container erfolgen mit run. Ist der Container auf dem Rechner noch nicht vorhanden, wird er erst herunter geladen. Danach wird der Befehl ausfgeführt (hier: echo 'Hello World') und der Container wird beendet.
  • Nächster Aufruf war ein Terminal im Container. Nicht uninteressant, da ich hier endlich erfahren konnte, wie man einen Container beendet (hatte ja gestern einfach das Terminal beendet :-(). Container beenden mit exit. Außerdem Erläuterung der Flags -t (erzeugen eines Terminals) und -i (interactive unter Verwendung der stdin)
  • Aufruf des Containers mit Flag -d (als Daemon im Hintergrund). Die angezeigte lange Zahl stell die Unique ID des Containers dar.
  • docker ps: Statusanzeige des/ der laufenden Containers. Angezeigt werden eine gekürzte Container ID, der Image Name, mit welchem Befehl der Container ausgeführt wird, wann er erzeugt wurde, Status und ein Name der von Docker generiert wird
  • um zu sehen, was der Daemon so macht, rufen wir das Log unter zu Hilfename des Image Namens aus dem Log auf: dockers logs xyz
  • Stoppen des Daemon: docker stop xyz es dauert eine Weile, bis er beendet ist, dann wird der Name noch einmal ausgegeben

Working with Container (https://docs.docker.com/userguide/usingdocker/)

  • docker version: Anzeige der installierten Komponenten, incl. der Versionen der Programmiersprache Go
  • docker --help: Hilfe, es werden alle Befehle aufgelistet; docker [Befehl] --help Hilfe zu dem Befehl
  • docker run -d -P training/webapp python app.py: Nun wird es ernst! Laden der ersten Web-Applikation in einem Container. Flag -d ist ja schon bekannt (im Hintergrund), Flag -P sagt dem Container, dass er alle benötigten Netzwerk Ports innerhalb des Containers zum Host mappen soll. Darüber kann dann die Web Applikation angezeigt werden. Weitere Erläuterungen zu -p folgen unten.
  • docker ps -l: den letzten laufenden Container anzeigen
  • docker ps -a: ALLE Container anzeigen, inkl. der gestoppten (auch die von vor Tagen)
  • docker ps -n=x: Anzeige der letzten x Container inkl. der gestoppten
  • Flag -p: Wird das Flag mit keiner genaueren Spezifizierung verwendet, nimmt es den default Port. In unserem Testfall handelt es sich um Port 5000, da dies der default-Port von Python ist. Möchte man den Host-Port selbst bestimmen, kann man das als Option an -p anhängen, z.b. docker run -d -p 80:5000 training/... Das Portmapping ist notwändig, da dadurch mehrere Applikationen parallel laufen und getestet werden können, ohne dass sie auf den gleichen Port zu greifen. Achtung: soll der Default-Port verwendet werden wird das -P groß geschrieben. Soll der Port spezifiziert werden, wird -p klein geschrieben
  • docker port [name des Containers] [Port innerhalb des Containers]: Rückgabe des Ports auf dem Host, der dem Containerport zu gewiesen wurde. Allerdings ist mir aktuell nicht der Sinn dieses Befehls schlüssig, da ich über docker ps ja den Namen des Containers recherchieren muss. Dort kann ich dann auch den verwendeten Hostport sehen (?!)
  • docker logs -f xyz: Aufruf der Log Funktion in Liveaufzeichnung. Das heißt, bei Aktivitäten im Container wird das Log erweitert. Es wird dabei aber ebenfalls das schon vorhandene Log angezeigt. Ctrl + C zum Verlassen.
  • docker top xyz: Anzeige der PID der verwendeten Prozesse innerhalb des Containers. Funktioniert bei mir leider nicht einwandfrei. Ich bekomme zwar den Prozess "python app.py" angezeigt, aber keine PID dazu. Dort wird nur ein ? gelistet.
  • docker inspect xyz: Ausgabe eines JSON Protokoll mit allen möglichen Informationen zu dem Container. Die Informationen können auch einzeln abgerufen werden unter zu Hilfename des Flags -f: z.B. "docker inspect -f '{{ .NetworkSettings.IPAddress }}' nostalgic_morse". Aber wie man sehen kann, muss man wissen, nach was mam sucht ;-)
  • docker start xyz: Hat man einen Container beendet und möchte ihn wieder starten, kann man das über den start Befehl realisieren. Es wird dann der gleiche Container (gleicher Name) erneut gestarte, der Port wird aber um eins inkrementiert. 
  • docker restart xyz: Hier wird der Container einmal neu gestartet, wobei er ebenefalls einen neuen (inkrementierten) Port zugewiesen bekommt. 
  • docker rm xyz: Löschen eines Containers aus dem System. Dieser Vorgang ist final und kann nicht mehr rückgängig gemacht werden. Der Container muss vorher gestoppt werden.
     

Freitag, 18. September 2015

Docker Start

http://docs.docker.com/linux/started/
  • Installation: Interessanterweise musste ich feststellen, dass es Unterschiede in der Linux-Installation gibt (Distributionsabhängig). Das wurde jedoch im "Getting Started" Dokument nicht berücksichtigt. Bei der 1. Installation auf meinem Laptop habe ich wget zur Installation benutzt, bei der 2. Installation auf dem Desktop-Rechner curl. Beides funktioniert ;-)   
  • $ wget -q0- https://get.docker.com/ | sh Das ist alles, danach sollte die Installation erledigt sein
  • Bei der Curl Installation musste ich jedoch den Darmon nicht von Hand starten.
  • Sollte nach der Installation die Fehlermeldung "no such file or directory" erscheinen, muss der Daemon gestartet werden:
    sudo service docker start 
  • Befehl $ docker run hello-world muss mit sudo gestartet werden 
  • Die Anleitung der Dockers Seite ist nicht mehr ganz up to date. Anstatt wie beschrieben, klicked man nicht auf "Browes and Search" sondern auf Explore in der linken oberen Ecke:
     
  • Der Pull Pfad aus der Anleitung ist auch nicht mehr korrekt. Es muss der Pfad "docker pull docker/whalesay" verwendet werden. Der Download nimmt einiges an Zeit in Anspruch (zumindest bei mir)
  • Die Oberfläche zum Anlegen eigener Repositories sieht auch nicht mehr aus, wie in der Anleitung. Man geht nicht mehr über "Add Repository" sonder über "Create Repository". Es erscheint dann folgende Maske:

    Es muss darauf geachtet werden, dass die Repository "public" ist...
  •