Vier Wege in den Docker Container

Keine Kommentare

In vorherigen Artikeln [1,2,3] hat Lukas Pustina die System-Level Virtualisierung mit Docker vorgestellt. Im vorliegenden Post diskutiere ich vier verschiedene Möglichkeiten, um sich mit einem laufenden Docker Container zu verbinden und mit diesem zu interagieren. Alle Codebeispiele sind zum Ausprobieren auf GitHub verfügbar.

nsenter

Das Tool nsenter wird mit dem Paket util-linux ab Version 2.23 ausgeliefert. Es bietet die Möglichkeit, sich in den Namespace eines anderen Prozesses einzuklinken. Dafür sind root Rechte notwendig. Leider wird mit der aktuellen Ubuntu Version 14.04 das Paket util-linux noch in der etwas älteren Version 2.20 ausgeliefert. Um die neueste Version (2.24) zu installieren, sind folgende Schritte nötig:

cd /tmp
curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-
cd util-linux-2.24
./configure --without-ncurses
make nsenter
cp nsenter /usr/local/bin

Um sich nun mit einem Container zu verbinden, wird die PID des ersten Prozesses im Container benötigt. Diese lässt sich wie folgt herausfinden:

docker inspect --format "{{ .State.Pid }}"

Mit Hilfe dieser PID kann man sich nun mit dem Container verbinden:

nsenter --target $PID --mount --uts --ipc --net --pid

nsinit

Seit Version 0.9 bietet Docker eine eigene Bibliothek zur Verwaltung von Containern namens libcontainer. nsinit ist Bestandteil des libcontainers und erlaubt den direkten Zugriff auf die Linux Namespace und cgroup Kernel Features. Um es installieren zu können, muss zunächst in einem ersten Schritt die Go Laufzeitumgebung installiert werden:

apt-get install git golang-go
 
mkdir -p $HOME/go-dev/bin
mkdir -p $HOME/go-dev/src
 
echo "export GOPATH=\$HOME/go-dev" >> ~/.profile
echo "PATH=\$PATH:\$GOPATH/bin" >> ~/.profile
source ~/.profile

Im zweiten Schritt wird nsinit installiert:

mkdir -p $GOPATH/src/github.com/dotcloud
cd $GOPATH/src/github.com/dotcloud
 
git clone https://github.com/dotcloud/docker.git
cd $GOPATH/src/github.com/dotcloud/docker
 
/usr/bin/go get -v github.com/dotcloud/docker/vendor/src/github.com/docker/libcontainer/nsinit

nsinit liest die Konfigurationsdaten direkt aus dem Verzeichnis des Containers aus. Dieses befindet sich in /var/lib/docker/execdriver/native/<container-id>. Um nsinit nutzen zu können, wird zunächst in das passende Container Verzeichnis gewechselt. Hierfür werden wieder root Rechte benötigt, da das Verzeichnis /var/lib/docker nur für root lesbar ist. Die Container ID lässt sich mit Hilfe von docker ps ermitteln. Im oben genannten Verzeichnis stehend, kann dann eine Verbindung mit dem Container hergestellt werden:

nsinit exec /bin/bash

lxc(-attach)

Bis einschließlich Version 0.8.1 war LXC die Grundlage für Docker zur Verwaltung von Containern, die auch weiterhin unterstützt wird. Seit Version 0.9.0 verwendet Docker jedoch standardmäßig die eigene Bibliothek libcontainer, wodurch keine Abhängigkeit mehr zu LXC besteht. Deshalb kann auch nicht mehr lxc-attach standardmäßig verwendet werden.

Soll lxc-attach dennoch benutzt werden, muss der Docker Prozess mit der Option -e lxc neu gestartet werden. Mit dieser Option wird LXC als Container Bibliothek aktiviert – vorausgesetzt LXC ist auf dem System installiert. Der einfachste Weg besteht darin, die Datei /etc/default/docker zu erzeugen, falls sie noch nicht existiert und folgende Zeile hinzuzufügen:

DOCKER_OPTS=”-e lxc”

Anschließend muss der Docker Daemon neu gestartet werden. Um sich mit einem Container zu verbinden, muss zunächst die vollständige Container ID ermittelt werden:

docker ps --no-trunc

Nun kann man sich mit dem Container verbinden. Auch hierfür werden wieder root Rechte benötigt:

lxc-attach -n  -- /bin/bash

sshd

Die drei bisherigen Verfahren benötigen root Rechte auf dem Hostsystem. Ist dies keine Option und soll ggf. das Verbinden zu einem Container über das Netzwerk möglich sein, steht SSH als alternativer Weg zur Verfügung.

Zunächst muss der Container dafür vorbereitet werden. Dies erfordert ein eigenes Base Image, in dem ein SSH Daemon gestartet werden kann. Jedoch tritt an dieser Stelle das Problem auf, dass mit dem Docker Kommando CMD bzw. ENTRYPOINT nur ein Startbefehl angegeben werden kann. Wäre dies der sshd Prozess, gäbe es keine Möglichkeit mehr, einen weiteren Prozess des Containers zu starten. Mögliche Lösungen dafür sind ein eigenes Skript, welches dann weitere  Prozesse startet oder ein Prozessmanagement Tool wie supervisord. Für die Benutzung von supervisord existiert eine ausführliche Dokumentation auf der Docker Homepage. Sobald ein Container mit dem sshd Prozess gestartet wurde, lässt er sich wie gewohnt  mit einem ssh Client erreichen.

Fazit

Der sshd Ansatz ist wahrscheinlich am einfachsten umzusetzen und die meisten Benutzer sind gewohnt, sich per ssh mit einer virtuellen Maschine zu verbinden. Des Weiteren erfordert dieser Weg keine root Berechtigung um sich mit dem Container zu verbinden. Allerdings gibt es zurzeit sehr viele Meinungen [1,2] darüber, ob ein Container mehr als einen Prozess verwalten sollte oder nicht. Im Endeffekt erhält man pro Container einen weiteren sshd Prozess, was im Grunde nicht der Idee der Prozessvirtualisierung entspricht.

Bei den anderen 3 Möglichkeiten werden root Rechte benötigt, um sie nutzen zu können. Docker hatte bis Version 0.8.1 LXC verwendet um Container zu verwalten. Aus diesem Grund war es ziemlich einfach lxc-attach für Docker Container zu verwenden. Ab Version 0.9.0 muss der Docker Daemon mit der Option -e lxc gestartet werden, damit LXC weiterhin verwendet wird. Wenn Docker jedoch wieder LXC verwendet gilt zu beachten, dass es erneut von einer externen Komponente abhängig ist, um einwandfrei zu funktionieren.

Die Tools nsenter und nsinit sind grundsätzlich gleichwertig. Der wesentliche Unterschied zwischen den beiden Tools liegt darin, dass nsinit einen neuen Prozess im Container erzeugt und nsenter sich nur in den Namespace einklingt. Jerome Petazzoni hat dies sehr gut im Docker Blog beschrieben.

Alexander Berresch

Alexander Berresch ist Software Engineer für CenterDevice

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

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