Docker in rund 100 Zeilen Bash implementiert: Bocker (2015)
(github.com/p8952)- Bocker ist ein Projekt, das Docker in rund 100 Zeilen Bash implementiert und einen Docker-ähnlichen Ablauf für Image-Pull, Container-Run, Log-Anzeige, Commit und Löschen bietet
- Für die Ausführung werden btrfs-progs, curl, iproute2, iptables, libcgroup-tools, util-linux 2.25.2 oder neuer sowie coreutils 7.5 oder neuer benötigt; außerdem sind ein btrfs-Dateisystem unter
/var/bockerund einebridge0-Netzwerkkonfiguration erforderlich - Das README-Beispiel zeigt den Ablauf, bei dem ein
centos:7-Image gepullt wird, anschließend Befehle in einem Container ausgeführt werden und das Ergebnis vonyum install -y wgetper commit gespeichert wird, sodass bei späteren Ausführungen/usr/bin/wgetvorhanden ist - Bocker läuft als root und ändert Netzwerkschnittstellen, Routing-Tabellen und Firewall-Regeln; daher wird empfohlen, es in einer virtuellen Maschine auszuführen. Es gibt keine Garantie gegen mögliche Systemschäden
- Derzeit sind
docker pull,images,ps,run,exec,logs,commit,rm/rmi, Networking sowie CGroups-basierte Quotas implementiert; Data Volumes, Data-Volume-Container und Port Forwarding sind noch nicht implementiert
Zweck und Umfang von Bocker
- Bocker ist ein Projekt, das Docker in rund 100 Zeilen Bash implementiert
- Das README zeigt Docker-ähnliche Befehlsabläufe auf Bash-Basis und umfasst Funktionen wie Image-Verwaltung, Container-Ausführung, Log-Abfrage, Commit von Änderungen und Ressourcenlimits
Laufzeitvoraussetzungen
- Für die Ausführung werden folgende Pakete benötigt
-
btrfs-progs
- curl
- iproute2
- iptables
- libcgroup-tools
- util-linux 2.25.2 oder neuer
- coreutils 7.5 oder neuer
- Da die meisten Distributionen kein ausreichend aktuelles util-linux enthalten, ist es wahrscheinlich nötig, die util-linux-2.25-Quellen herunterzuladen und selbst zu kompilieren
- Das System benötigt folgende Konfiguration
- ein unter
/var/bockergemountetes btrfs-Dateisystem - eine Netzwerk-Bridge namens
bridge0mit der IP10.0.0.1/24 - aktiviertes IP-Forwarding unter
/proc/sys/net/ipv4/ip_forward - Firewall-Einstellungen, die Traffic von
bridge0an die physische Schnittstelle routen - Eine Vagrantfile ist enthalten, um die benötigte Umgebung leichter erstellen zu können
-
Hinweise zur Ausführung
- Auch wenn die Voraussetzungen erfüllt sind, wird empfohlen, Bocker in einer virtuellen Maschine auszuführen
- Bocker läuft als root und muss folgende Elemente ändern
- Netzwerkschnittstellen
- Routing-Tabellen
- Firewall-Regeln
- Das README weist ausdrücklich darauf hin, dass nicht garantiert werden kann, dass Bocker das System nicht beschädigt
Beispielhafter Nutzungsablauf
- Wenn mit
bocker pull centos 7das Imagecentos:7geholt wird, entsteht eine Image-ID wieimg_42150 bocker imageszeigt Image-ID und Quelle an- Beispielausgabe:
img_42150,centos:7
- Beispielausgabe:
bocker run img_42150 cat /etc/centos-releasegibt die CentOS-Release-Informationen im Container aus- Beispielausgabe:
CentOS Linux release 7.1.1503 (Core)
- Beispielausgabe:
bocker pszeigt die ID und den Befehl des ausgeführten Containers anbocker logs ps_42045zeigt die Ausgabelogs dieses Containers anbocker rm ps_42045entfernt den Container- Bei der ersten Ausführung von
bocker run img_42150 which wgetergibt sich, dasswgetnicht vorhanden ist - Nachdem
wgetmitbocker run img_42150 yum install -y wgetinstalliert wurde, werden die Änderungen mitbocker commit ps_42018 img_42150in das Image übernommen - Danach gibt
bocker run img_42150 which wget/usr/bin/wgetaus
Ressourcenlimits und CGroups
- Das Bocker-Ausführungsbeispiel zeigt, dass Container unter CGroups abgelegt werden
- In
/proc/1/cgrouperscheinen Einträge wiememory:/ps_42152undcpuacct,cpu:/ps_42152
- In
- Beispiele für die standardmäßigen CPU-Shares und Speicherlimits sind
/sys/fs/cgroup/cpu/ps_42152/cpu.shares:512/sys/fs/cgroup/memory/ps_42152/memory.limit_in_bytes:512000000
- Ressourcenlimits können über Umgebungsvariablen geändert werden
BOCKER_CPU_SHARE=1024BOCKER_MEM_LIMIT=1024
- Das Beispiel nach der Änderung zeigt folgende Werte
- CPU-Shares:
1024 - Speicherlimit:
1024000000
- CPU-Shares:
Implementierte und nicht implementierte Funktionen
- Derzeit sind folgende Funktionen implementiert
docker build†docker pulldocker imagesdocker psdocker rundocker execdocker logsdocker commitdocker rm/docker rmi-
Networking
- Quota Support / CGroups
- †
bocker initbietet eine sehr eingeschränkte Implementierung vondocker build - Folgende Funktionen sind noch nicht implementiert
- Data Volume Containers
- Data Volumes
- Port Forwarding
Lizenz
- Bocker ist freie Software, die unter den Bedingungen der GNU General Public License weiterverbreitet und verändert werden darf
- Als Lizenzversion kann GPL v3 oder eine spätere von der Free Software Foundation veröffentlichte Version gewählt werden
- Das Programm wird in der Hoffnung verbreitet, nützlich zu sein, jedoch ohne implizite Gewährleistung der Marktgängigkeit oder Eignung für einen bestimmten Zweck
1 Kommentare
Meinungen auf Hacker News
Ich habe einmal etwas Ähnliches mit proot gebaut, es hieß Bag [1], und ich hätte es wohl nicht als Docker-Alternative beschrieben.
Mit cgroups hatte es nichts zu tun, und auch das Command-Line-Interface war anders als bei Docker. Der Hintergrund war, dass ich zur Umgehung von Internetzensur und Deep Packet Inspection eine Proxy-Kette gebaut hatte, die wie normaler HTML-Traffic aussehen sollte. Sie musste überall weiterlaufen, aber ich wollte sie nicht als native Android-App portieren.
Ich wollte sie in Termux laufen lassen, aber damals gab es in Termux kein JDK/JRE; wenn man mit proot eine Arch-Linux-Umgebung startete, konnte man ein JDK nutzen. Die Arch-Umgebung innerhalb von Termux war insgesamt nützlicher, und es ließ sich per Skript leicht automatisieren, Wegwerf-Umgebungen mit unterschiedlichen Konfigurationen zu erstellen und zu löschen, anschließend per proot hineinzugehen und nur einen einzelnen Befehl auszuführen. Deshalb nannte ich es bag.sh, weil es etwas deutlich Kleineres als ein Frachtcontainer sein sollte.
Interessanterweise enthält bag.sh auch noch eine Roadmap/TODO, die seit fünf Jahren nicht angefasst wurde. Da ich es auf einem mobilen Bildschirm geschrieben habe und es ohne Scrollen sehen wollte, ist das meiste auf 40 Spalten umbrochen.
[1]: https://github.com/hkoosha/bag
Ich baute ein kleines Debian unter /opt, das die benötigte Software und Abhängigkeiten wie MySQL enthielt. Es funktionierte ziemlich gut und wurde genutzt, bis das Unternehmen, für das ich es gebaut hatte, etwa 2016 übernommen wurde. Allgemeiner gesagt halte ich es für eine der besten Methoden, die interne Funktionsweise zu lernen, wenn man eine grobe Version einer großen Anwendung selbst implementiert.
mkdir -p $(dirname "$2")In Kombination mit einer etwa 10 Zoll großen Bluetooth-Tastatur, die bequem in die Innentasche einer Lederjacke passt, kann man ohne Tasche das Haus verlassen und in der Ecke eines nahegelegenen Biergartens Code schreiben. Überraschenderweise ist man dabei sogar produktiv; vielleicht weil der Wechsel zu den üblichen Ablenkungen etwas mehr Reibung verursacht als am Laptop, sodass man eher einen Schluck Bier nimmt und weiter auf den Code starrt.
Ich mag solche Dinge. Ich mochte schon immer Sachen, die mit minimalem Bash gebaut sind.
Es gibt auch einen Proof of Concept für einen internen Cluster-Load-Balancer in 40 Zeilen Bash, den ich vor etwa 10 Jahren bei einem Hackathon gebaut habe, den ich organisiert hatte, um verteilte Infrastruktur wie Docker und Mesos bekannter zu machen: https://github.com/cell-os/metal-cell/blob/master/discovery/...
Wahrscheinlich ist es verloren gegangen, aber es gab auch ein redundantes und verteiltes Colo-to-Cloud-Übertragungstool auf Basis von Reverse-SSH-Tunneln. Auf Shell Fu und ähnlichen Seiten sind solche Sammlungen gut zusammengestellt: https://www.shell-fu.org/
Dass sich ein großer Teil von Docker so einfach neu implementieren lässt, ist das größte Problem, vor dem Docker als Unternehmen stand und immer noch steht. Im Kern ist es nämlich eher Glue Code, der Kernel-Funktionen miteinander verbindet.
Wo Docker tatsächlich Mehrwert schafft, ist nicht nur Docker Hub, sondern Docker for Windows und Mac. Die integrierte Erfahrung ist deutlich besser, als selbst mit VirtualBox und Vagrant herumzuhantieren, um Docker auf einer Entwicklungsmaschine laufen zu lassen.
Persönlich denke ich, dass die eigentliche Magie von Docker das Docker/OCI-Image-Format war. Es löst Caching und die Verteilung von Container-Images hervorragend, und genau das ist weiterhin der Kern dessen, was es von „vollständigen“ VMs und deren Workflows unterscheidet.
Unter Windows kann man Docker in WSL verwenden, und das funktioniert sehr gut. Ich kann schwer nachvollziehen, warum man Docker Desktop nutzt.
Stattdessen bauten sie das unausgereifte Docker Swarm, das nicht zuverlässig funktionierte, und wurden schnell von Kubernetes verdrängt.
Meine eigene Nutzung bestand nur darin, vor ein paar Jahren die virtuelle Build-Umgebung von jemand anderem zu holen, um Software zu bauen.
Im Repository stehen Formulierungen wie „noch nicht implementiert“, „TODO“ und „in Arbeit“, und wenn man sieht, dass der letzte Commit Jahre zurückliegt, ist das irgendwie gut.
Dadurch fühle ich mich etwas besser dabei, nicht zu den TODOs zurückzukehren, die ich in meinem eigenen Code verstreut habe. Das soll den Autor nicht herabsetzen, es ist einfach beruhigend.
Wenn man bei unbezahltem, freiwilligem Hobby-Code nur deshalb eine Verpflichtung verspürt, weil er öffentlich ist, macht Coding weniger Spaß, und man veröffentlicht am Ende vielleicht Code nicht, den man sonst veröffentlicht hätte.
Wenn es immer eine nächste Idee gibt, bleiben per Definition auch immer unerledigte TODOs übrig. Eigentlich sollte das der Normalzustand aller Projekte sein.
Klare Grenzen für den Scope zu setzen, ist völlig in Ordnung und oft hilfreich. So vermeidet man, dass sich das Projekt ewig „unfertig“ anfühlt, weil man ständig Nebenpfaden folgt.
Es überrascht mich, dass lazydocker noch nicht als hervorragende Alternative zu Docker Desktop erwähnt wurde. Läuft unter Linux/macOS/Windows [1]
Es ist eine recht funktionsreiche Terminal-UI und hat außerdem den Vorteil, dass man es über SSH ausführen kann.
[1] https://github.com/jesseduffield/lazydocker
Zumindest habe ich so etwas zum ersten Mal gesehen. Ich frage mich auch, ob solche Werbung nach den Nutzungsbedingungen oder der Acceptable-Use-Policy von GitHub erlaubt ist.
Ich frage mich, warum Bocker so oft auf der Startseite landet. Ist Docker 2024 immer noch so kontrovers?
Ich verstehe nicht, warum man nicht anerkennt, dass Docker tatsächlich nützliche Dinge gebracht hat, vor allem Softwareverteilung und „einfach überall ausführen“.
Docker ist eine Kombination bereits vorhandener Kernel-Technologien: Namespaces, cgroups, Union-Dateisysteme und wahrscheinlich noch ein paar Dinge mehr.
Das macht es interessant, und es ist im Grunde die perfekte HN-Geschichte.
Erst nachdem ich es ein paar Leuten vorgeführt hatte, wurde mir klar, dass sie auch einfach
/hätten verwenden können – oder dass ich ihnen genauso gut Docker hätte geben können.Als eine Art Bruder von einer anderen Mutter gibt es https://bastillebsd.org/
Bastille verwendet viele Strukturen, wie man sie von Docker erwarten würde, in Shell, um FreeBSD-Jails zu verwalten. Es hat sehr wenige Abhängigkeiten, weshalb ich es lieber mag als andere Jail-Management-Software für BSD.
Allerdings ist es trotz CLI/TUI-basierter Werkzeuge eher eine Lösung nahe am „maximalen Overkill“. Zurzeit gehe ich die Schritte durch, Jails nur mit der FreeBSD-Basiskonfiguration zu erstellen und zu verwalten, aber das ist nur eine Übergangsphase.
Ich mache das nur so lange, bis sich das Zusammenspiel ausreichend in meinem Kopf festgesetzt hat und ich beim Debugging sicher bin; danach werde ich wie ein vernünftiger Mensch aufhören, Steine aneinanderzuschlagen, und zu höherwertigen Tools zurückkehren.
Allerdings hat es eine Weile gedauert, bis ich verstanden habe, warum es Bastille heißt. La Bastille war eine Festung, die während des Hundertjährigen Kriegs gebaut wurde, um Paris gegen englische Angriffe zu verteidigen, und später in ein Gefängnis umgewandelt wurde.
Bei der Stelle „Die meisten Distributionen stellen keine ausreichend aktuelle Version von util-linux bereit, daher wird man hier den Quellcode holen und selbst kompilieren müssen“ sollte man vorsichtig sein.
Das standardmäßige Installationspräfix ist
/usr/bin, daher kann der Installationsprozess den bestehenden mount-Befehl mit einer Version überschreiben, die nicht vorhandene Libraries verlangt. Dann mountet der Kernel beim nächsten Booten das Dateisystem schreibgeschützt./usr/local/binsein.Für den Alltagsgebrauch nicht gut, aber es vermittelt ein Gefühl dafür, was Docker ist und wie es funktioniert.
Unter Linux ist Docker im Grunde ein schickes chroot.
Fun Fact: Docker begann in Bash, wechselte später zu Python und landete schließlich bei Go.
Außerdem schrieb jemand bei einem Docker-Meetup 2013 einen Docker-Klon in Bash. Leute wollen lernen, und es wäre schön, wenn solche Dinge dabei helfen.