Docker in LXD-Container installieren

Auch wenn LXD Container eine gute Alternative zu Virtuellen Maschinen sind, sind sie einfach deutlich ressourcenintensiver als Docker. Daher zeige ich hier, wie man Docker in einem LXD Container installiert und betreibt.

Was ist Docker

Nun stellt sich bei dem ein oder anderen sicher die Frage, „Was ist Docker“. Ich bin bei weitem kein Experte auf dem Gebiet und kann daher nur einen sehr kurzen Vergleich zu LXD-Containern ziehen.

Docker und LXD sind beides Container Systeme, sie teilen sich also Teile des Kernels mit dem Host. Dadurch wird weniger RAM benötigt als bei Virtuellen Maschinen, bei denen alles bis zu USB Schnittstelle Virtualisiert wird.

Docker sind nun noch einmal leichter als LXD Container, weil sie flüchtiger sind. Bei einem LXD Container beginnt man mit einem Betriebssystem-Image und installiert die gewünschten Programme manuell. Bei Docker hingegen, sind alle Installationsschritte schon in dem Image vorhanden und sobald der Container gestartet wird, arbeitet der Service wie gewünscht. Dadurch kann ein Container auch problemlos ersetzt werden.

Außerdem ist es in Docker Containern üblich, immer nur einen Dienst zu betreiben und größere Applikationen auf mehrere Container aufzuteilen. Das heißt der Webserver ist ein Container, die Datenbank ist ein Container und ggf. das Backend ein weiterer.

Durch diese Aufteilung und Modularität ist es Programmen wie Kubernetes möglich Load-Balancing zu betreiben und bei Bedarf einfach neue Container zu erstellen oder alte zu löschen, ohne dass der Nutzer etwas merkt.

LXD Profil erstellen

Um Docker nun in LXD zu betreiben, benötigt unser Container besondere Berechtigungen. Diese kann man von Hand vergeben oder in einem Profil speichern. Ich habe mich für letztere entschieden, weil ich die Konfiguration so problemlos beim nächsten Container verwenden kann.

Als Ausgangspunkt dient das Default Profil. Dieses kopieren wir in ein neues Profil namens „docker“.

lxc profile copy default docker

Danach bearbeiten wird das docker Profil.

lxc profile edit docker

Im ersten Schritt habe ich den Config-Block für die Ethernet Schnittstelle gelöscht, weil ich meinen Containern immer ein MacVLan Profil geben, sodass sie eigene IP-Adressen beziehen. In dem Fall wäre eine zweite ETH Konfiguration störend.

Das funktioniert aber nur wenn Ihr über ein anderes Profil eine ETH Konfiguration vergebt. Ansonsten lasst sie im docker Profil stehen.

Danach müssen noch ein paar Dinge im Block config ergänzt werden. Danach sollte Euer Profil in etwa wie hier aussehen.

### This is a YAML representation of the profile.                                                     ### Any line starting with a '# will be ignored.                                                      ###                                                                                                   ### A profile consists of a set of configuration items followed by a set of                           ### devices.                                                                                          ###                                                                                                   ### An example would look like:                                                                       ### name: onenic                                                                                      ### config:                                                                                           ###   raw.lxc: lxc.aa_profile=unconfined                                                              ### devices:                                                                                          ###   eth0:                                                                                           ###     nictype: bridged                                                                              ###     parent: lxdbr0                                                                                ###     type: nic                                                                                     ###                                                                                                   ### Note that the name is shown but cannot be changed                                                                                                                                                        
config:                                                                                                 
  raw.apparmor: mount,                                                                                  
  raw.lxc: |-                                                                                             
    lxc.cgroup.devices.allow = c 10:237 rw                                                                
    lxc.cgroup.devices.allow = b 7:* rw                                                                 
  security.nesting: "true"                                                                              
  security.privileged: "true"                                                                         description: Default LXD profile                                                                       devices:                                                                                                
  root:                                                                                                   
    path: /                                                                                               
    pool: default                                                                                         
    type: disk                                                                                        name: docker                                                                                          used_by:

LXD Container erstellen

Nun sind wir soweit den Container zu erstellen. In meinem Fall nutze ich ein Ubuntu-Image. Solltet Ihr ein anderes Betriebssystem nutzen wollen, ist das prinzipiell möglich, allerdings müsst ihr dann an anderer Stelle nach den entsprechenden Befehlen bei der Installation schauen.

Da die aktuelle LTS Version von Ubuntu 20.04 ist, nehme ich diese auch.

lxc launch ubuntu:20.04 -p macvlan -p docker docker

Zur Erklärung
+ lxc launch gibt den Befehl einen neuen Container zu erstellen und zu starten
+ ubuntu:20.04 ist das gewünschte Image
+ -p macvlan nutzt mein Profil für die ETH-Konfiguration. Solltet ihr die Standardkonfiguration nutzen, lasst das einfach weg.
+ -p docker nutzt unser frisch erstelltes Docker Profil
+ docker ist der Name unseres Containers. Den könnt Ihr frei wählen.

Danach könnt ihr den Container mit folgendem Befehl öffnen.

lxc exec docker bash

Docker Installation

Docker gibt es glücklicherweise im Ubuntu Repository. Daher können wir es ganz einfach installieren.

sudo apt install docker.io

Sollte das nicht funktionieren, ist hier der Link zu der Docker Dokumentation. Der Weg dort ist deutlich länger, kann aber manchmal besser funktionieren. Weiter unten gibt es dann auch noch ein Bash-Skript, dass den Prozess beschleunigt.

Und solltet Ihr weiter Probleme haben, scheut euch nicht den Container zu löschen und einen neuen zu erstellen. Auch das kann manchmal wunder wirken.

Solltet ihr mit einem anderen User als Root arbeiten, solltet ihr euch noch in die docker Gruppe aufnehmen. Andernfalls müsst Ihr jeden Befehl als sudo ausführen

sudo usermode -aG docker <Username>

Docker testen

Um zu prüfen, ob die gibt es ein kleines Test-Image mit dem typischen Namen „Hello-World“. Das startet ihr wie folgt.

docker run hello-world

Wenn im Terminal nun etwas steht wie, alles hat funktioniert, ist die Installation geglückt. Wenn nicht, habe ich unten ein paar Fehler aufgeführt, die mir unterlaufen sind. Solltet ihr weitere Fehler finden, kann ich diese gerne ergänzen.

Docker Crash Course

Nun zum Schluss noch eine kurze Einführung in die Docker Bedienung.

Den Befehl run habe ich ja gerade schon gezeigt. Dieser lässt sich aber noch mit einer Vielzahl von Parametern versehen.

-d # steht für detached. Der Container läuft im Hintergrund
-p 3000:80 # verknüpft den Port 80 auf dem Host mit dem Port 3000 im Container
--restart unless-stopped # startet den containeer immer neu, wenn ihr ihn nicht stoppt.
etc...

Möchte man nun sehen welche Container laufen, geht das wie folgt.

docker ps # zeigt alle laufenden Container
docker ps -a # zeigt laufende und gestoppte Container

Man kann Container auch starten und stoppen. Die ID sollte man dabei mit docker ps auslesen und kopieren.

docker stop <id>
docker start <id>

Toubleshooting

Docker startet nicht

Führt zu besseren Diagnose den folgenden Befehl aus.

dockerd

There are no more loopback device available.

Der Fehler bedeutet, dass der Container nicht die Berechtigung hat, ein Loopback device zu mounten. Dafür müssen zwei Parameter gesetzt werden.

lxc config set <container-name> security.privileged true
lxc config set <container-name> raw.apparmor "mount,"

Die gleichen Parameter finden sich auch oben in der Konfiguration.

Außerdem muss der loop-control file definiert werden, um einen überblick über die freien Devices zu behalten

lxc config device add <container-name> loop-control unix-char path/dev/loop-control

Danach muss der Container neu gestartet werden, damit die neue Konfiguration geladen wird.

Weitere Informationen gibt es hier.
https://gist.github.com/kaxing/f90e66a1041c8686d360a480b15be8fe

error initializing graphdriver: driver not supported

Wenn dieser Fehler auftritt sollte man unbedingt erneut prüfen, ob der Container das richtige Profil und die damit verbundenen Berechtigungen erhalten hat. In meinem Fall hat es geholfen, den Container noch einmal neu zu erstellen.

Bei diesem Fehler kommt Docker nicht mit dem Filesystem des Containers klar. In meinem Fall war das bei ZFS der Fall.

Um das Problem zu lösen, sollte man den Container in einen Pool mit einem anderen Filesystem, wie z.B. BTRFS verschieben.

Danach kann man den Storage Driver für Docker neu definieren.

nano /etc/docker/daemon.json
{
  "storage-driver": "btrfs"
}

Kommentare anzeigen

Wir nutzen Cookies

Um die Nutzung der Website zu verbessern, nutzen wir Cookies.
Desweiteren werden Google-Dienste für das schalten von Werbung verwendet. Mit der Nutzung der Website geben Sie ihr Einverständnis.
Sollte die Nutzung von Cookies abgelehnt werden, kann dies Auswirkung auf die Nutzung der Website haben.