Haftungsausschluss für Sarkasmus: Dieser Artikel ist größtenteils sarkastisch. Ich glaube nicht, dass ich tatsächlich für Dylan Thomas spreche und würde Sie niemals ermutigen, Leuten, die es nicht wollen, ein helles Thema aufzudrängen. Egal wie falsch sie liegen mögen.
Als Dylan Thomas die Worte schrieb: „Geh nicht sanft in diese gute Nacht“, sprach er vom Tod. Aber wenn er heute am Leben wäre, könnte er von Linux-Containern sprechen. Es gibt keine Möglichkeit, das sicher zu wissen, da er 1953 verstarb, aber dies ist das Internet, daher fühle ich mich äußerst zuversichtlich, autoritativ in seinem Namen zu sprechen.
Mein Selbstvertrauen rührt von einer vollständigen Überschätzung meiner Fähigkeiten und meines Intellekts her, gepaart mit der Tatsache, dass ich kürzlich versucht habe, einen Docker-Container als meine Entwicklungsumgebung zu konfigurieren. Und ich fand mich dabei, gegen das Sterben des Lichts zu toben, als Docker jeden einzelnen Versuch ablehnte, den ich machte, als wäre ich es und er König Jakob, der schrie: „Nicht in meinem Haus!“

Schmerz ist ein ausgezeichneter Lehrer. Und weil ich mich um Sie kümmere und keine anderen Hintergedanken habe, möchte ich diese Erfahrung nutzen, um Ihnen eine „sanfte“ Einführung in die Verwendung eines Docker-Containers als Entwicklungsumgebung zu geben. Aber zuerst sprechen wir darüber, warum Sie das jemals tun sollten.
Warum eigentlich?
Schließen Sie die Augen und stellen Sie sich Folgendes vor: Ein erwachsener Mann, der als Fuchs verkleidet ist.
Warten Sie. Nein. Falsches Szenario.
Stellen Sie sich stattdessen ein Projekt vor, das nicht nur Ihren Quellcode, sondern Ihre gesamte Entwicklungsumgebung sowie alle Abhängigkeiten und Laufzeiten enthält, die Ihre App benötigt. Sie könnten dieses Projekt dann jedem überall (wie dem Fuchs-Typen) geben, und er könnte Ihr Projekt ausführen, ohne Änderungen an seiner eigenen Umgebung vornehmen zu müssen.
Genau das machen Docker-Container. Eine Dockerfile definiert eine vollständige Laufzeitumgebung mit einer einzigen Datei. Alles, was Sie brauchen, ist eine Möglichkeit, innerhalb dieses Containers zu entwickeln.
Warten Sie...
VS Code und Remote – Container
VS Code verfügt über eine Erweiterung namens Remote – Containers, mit der Sie ein Projekt in einem Docker-Container laden und sich mit VS Code damit verbinden können. Das ist Stoff für Inception-Niveau. (Hat er es rausgeschafft?! DER TALISMAN HÖRT NIE AUF SICH ZU DREHEN.) Es ist leichter zu verstehen, wenn wir (und mit „wir“ meine ich Sie) es in Aktion sehen.
Hinzufügen eines Containers zu einem Projekt
Nehmen wir für einen Moment an, Sie befinden sich auf einem High-End-Gaming-PC, den Sie für Ihre Kinder gebaut haben und dann beschlossen haben, ihn für sich selbst zu behalten. Ich meine, warum genau verdienen sie einen neuen Computer? Oh, das stimmt. Sie tun es nicht. Sie können nicht einmal sonntags den Müll rausbringen, obwohl Sie es ihnen JEDE WOCHE SAGEN.
Dies ist ein frisches Windows-Maschine mit WSL2 und Docker installiert, aber das ist alles. Würden Sie versuchen, ein Node.js-Projekt auf dieser Maschine auszuführen, würde Powershell Ihnen sagen, dass es absolut keine Ahnung hat, worauf Sie sich beziehen, und Sie sich vielleicht vertippt haben. Was, ehrlich gesagt, nicht stimmt, Sie sind schlecht im Tippen. Erinnern Sie sich an die Zeit in der 4. Klasse, als Sie in der ersten Runde des Rechtschreibwettbewerbs ausgeschieden sind, weil Sie „fried“ nicht schreiben konnten. FRYED? Da ist kein „Y“ drin!

Nun, das ist kein großes Problem – Sie könnten immer wegspringen und Node.js installieren. Aber sagen wir mal für eine Sekunde, Sie können sich nicht dazu durchringen und Sie sind sich ziemlich sicher, dass Springen nichts ist, was Erwachsene tun.
Stattdessen können wir dieses Projekt so konfigurieren, dass es in einem Container ausgeführt wird, auf dem Node.js bereits installiert ist. Nun, wie ich bereits erwähnt habe, habe ich keine Ahnung, wie man Docker benutzt. Ich kann kaum die Mikrowelle bedienen. Glücklicherweise konfiguriert VS Code Ihr Projekt für Sie – bis zu einem gewissen Grad.
Über die Befehlspalette gibt es den Befehl „Entwicklungscontainer-Konfigurationsdateien hinzufügen…“. Dieser Befehl betrachtet Ihr Projekt und versucht, die richtige Containerdefinition hinzuzufügen.

In diesem Fall weiß VS Code, dass ich hier ein Node-Projekt habe, also wähle ich einfach Node.js 14. Ja, mir ist bewusst, dass 12 derzeit LTS ist, aber es wird in [prüft die Uhr] einem Monat 14 sein und ich bin ein Early Adopter, wie mein Interesse an Containertechnologie gerade jetzt im Jahr 2020 beweist.

Dies fügt einen Ordner .devcontainer mit einigen Assets hinzu. Einer davon ist eine Dockerfile, die das Node.js-Image enthält, das wir verwenden werden, und der andere ist eine devcontainer.json, die einige projektspezifische Konfigurationen enthält.
Nun, bevor wir etwas anfassen und alles kaputt machen (wir kommen noch dazu, vertrauen Sie mir), können wir über die Befehlspalette „Neu aufbauen und im Container neu öffnen“ auswählen. Dies startet VS Code neu und beginnt mit dem Erstellen des Containers. Sobald dies abgeschlossen ist (was beim ersten Mal eine Weile dauern kann, wenn Sie keinen High-End-Gaming-PC haben, dessen Freuden Ihre Kinder nie kennenlernen werden), wird das Projekt innerhalb des Containers geöffnet. VS Code ist mit dem Container verbunden, und das wissen Sie, weil es in der unteren linken Ecke steht.

Wenn wir jetzt das Terminal in VS Code öffnen, fehlt Powershell auffällig, weil wir nicht mehr unter Windows sind, Dorothy. Wir sind jetzt in einem Linux-Container. Und wir können sowohl npm install als auch npm start in diesem magischen Land tun.

Dies ist eine Express-App, daher sollte sie auf Port 3000 laufen. Aber wenn Sie versuchen, diesen Port zu besuchen, wird er nicht geladen. Das liegt daran, dass wir einen Port im Container auf 3000 auf unserem Localhost mappen müssen. Wie man so schön sagt.
Glücklicherweise gibt es dafür eine Benutzeroberfläche.
Die Remote Containers-Erweiterung platziert ein Symbol für den „Remote Explorer“ in der Aktionsleiste. Die sich für Sie auf der linken Seite befindet, für mich aber auf der rechten Seite. Weil ich sie verschoben habe und Sie es auch tun sollten.

Hier gibt es drei Abschnitte, aber schauen Sie sich den untersten an, der „Portweiterleitung“ sagt. Ich bin nicht das Sandwich mit dem meisten Salat, aber ich bin mir ziemlich sicher, dass wir hier das wollen. Sie können auf „Port weiterleiten“ klicken und „3000“ eingeben. Wenn wir nun versuchen, von unserem Browser auf die App zuzugreifen…

Die meisten Dinge haben „einfach funktioniert“. Aber die Konfiguration ist auch ziemlich einfach. Schauen wir uns an, wie wir mit der Automatisierung einiger Aspekte des Projekts selbst beginnen können. Projektspezifische Konfigurationen werden in der Datei devcontainer.json vorgenommen.
Automatisierung der Projektkonfiguration
Zunächst können wir die Portweiterleitung automatisieren, indem wir eine Variable forwardPorts hinzufügen und 3000 als Wert angeben. Wir können auch den Befehl npm install automatisieren, indem wir die Eigenschaft postCreateCommand angeben. Und seien wir ehrlich, wir alle könnten mindestens eine npm install weniger gebrauchen.
{
// ...
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [3000],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm install",
// ...
}
Zusätzlich können wir VS Code-Erweiterungen einbeziehen. Das VS Code, das im Docker-Container läuft, erhält nicht automatisch jede installierte Erweiterung. Sie müssen sie im Container installieren oder einfach wie hier einbeziehen.
Erweiterungen wie Prettier und ESLint sind perfekt für diese Art von Szenario. Wir können diese Gelegenheit auch nutzen, um jedem ein helles Thema aufzuzwingen, denn es stellt sich heraus, dass dunkle Themen schlechter für das Lesen und Verständnis sind. Ich fühle mich wie ein Prophet.
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.128.0/containers/javascript-node-14
{
// ...
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"GitHub.github-vscode-theme"
]
// ...
}
Wenn Sie sich fragen, wo Sie diese Erweiterungs-IDs finden, erscheinen sie in der Intellisense (Strg/Cmd + Umschalt), wenn Sie sie installiert haben. Wenn nicht, suchen Sie im Erweiterungsmarktplatz, klicken Sie mit der rechten Maustaste auf die Erweiterung und wählen Sie „Erweiterungs-ID kopieren“. Oder noch besser, wählen Sie einfach „Zur devcontainer.json hinzufügen“.

Standardmäßig sind in dem Node.js-Container, den VS Code bereitstellt, Dinge wie Git und cURL bereits installiert. Was fehlt, ist „cowsay“. Und wir können keine Linux-Umgebung ohne cowsay haben. Das steht in den Linux-Gesetzen (stimmt nicht). Ich mache die Regeln nicht. Wir müssen diesen Container anpassen, um das hinzuzufügen.
Automatisierung der Umgebungskonfiguration
Hier sind die Dinge für mich schiefgelaufen. Um Software zu einem Entwicklungcontainer hinzuzufügen, müssen Sie die Dockerfile bearbeiten. Und Linux hat keine Toleranz für Ihre Spielereien oder Fehler.
Der Basis-Docker-Container, den Sie mit den Container-Konfigurationen in VS Code erhalten, ist Debian Linux. Debian Linux verwendet den Paketmanager apt-get.
apt-get install cowsay
Wir können dies am Ende der Dockerfile hinzufügen. Jedes Mal, wenn Sie etwas von apt-get installieren, führen Sie zuerst ein apt-get update aus. Dieser Befehl aktualisiert die Liste der Pakete und Paket-Repos, sodass Sie die aktuellste Liste im Cache haben. Wenn Sie dies nicht tun, schlägt der Container-Build fehl und meldet, dass er „cowsay“ nicht finden kann.
# To fully customize the contents of this image, use the following Dockerfile instead:
# https://github.com/microsoft/vscode-dev-containers/tree/v0.128.0/containers/javascript-node-14/.devcontainer/Dockerfile
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-14
# ** Install additional packages **
RUN apt-get update \
&& apt-get -y install cowsay
Ein paar Dinge sind hier zu beachten…
- Der Befehl
RUNist eine Docker-Funktion und erstellt eine neue „Schicht“. Schichten sind, wie der Container weiß, was sich geändert hat und was im Container aktualisiert werden muss, wenn Sie ihn neu erstellen. Sie sind ein bisschen wie Kuchenschichten, außer dass Sie nicht viele davon wollen, weil riesige Kuchen großartig sind. Riesige Container sind es nicht. Sie sollten versuchen, zusammengehörige Logik in demselbenRUN-Befehl zu gruppieren, um keine unnötigen Schichten zu erstellen. - Das
\kennzeichnet einen Zeilenumbruch am Ende einer Zeile. Sie benötigen es für mehrzeilige Befehle. Lassen Sie es weg und Sie werden den Schmerz vieler fehlgeschlagener Docker-Builds erfahren. - Das
&&ist, wie Sie einen zusätzlichen Befehl zur ZeileRUNhinzufügen. Um Gottes willen, vergessen Sie das\in der vorherigen Zeile nicht. - Das Flag
-yist wichtig, da apt-get standardmäßig nachfragt, ob Sie wirklich installieren möchten, was Sie gerade zu installieren versucht haben. Dies führt zum Scheitern des Container-Builds, da niemand da ist, umYoderNzu sagen. Das Flag-yist die Kurzform für „nerven Sie mich nicht mit Ihren albernen Bestätigungsaufforderungen“. Angeblich soll das jeder schon wissen. Ich wusste es bis vor etwa vier Stunden nicht.
Verwenden Sie die Befehlspalette, um „Container neu erstellen“ auszuwählen…

Und schon, im Handumdrehen…

Es funktioniert nicht.
Dies ist die erste Lektion in dem, was ich gerne „Linux-Schwindel“ nenne. Es gibt so viele Linux-Distributionen und sie gehen nicht alle auf die gleiche Weise damit um. Es kann schwierig sein herauszufinden, warum Dinge an einem Ort (Mac, WSL2) funktionieren und an anderen nicht. Der Grund, warum „cowsay“ nicht verfügbar ist, ist, dass Debian „cowsay“ in /usr/games legt, das nicht in der Umgebungsvariable PATH enthalten ist.
Eine Lösung wäre, es zur PATH in der Dockerfile hinzuzufügen. So…
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-14
RUN apt-get update \
&& apt-get -y install cowsay
ENV PATH="/usr/games:${PATH}"

AUSGEZEICHNET. Wir lösen hier echte Probleme, Leute. Leute mögen Kuh-Einzeiler. Ich glaube, ich habe das irgendwo gehört.
Zusammenfassend lässt sich sagen, dass die Projektkonfiguration (Portweiterleitung, Installation von Projektbibliotheken usw.) in der devcontainer.json und die Umgebungskonfiguration (Installation von Software) in der „Dockerfile“ erfolgen. Nun werden wir mutig und versuchen etwas etwas Anspruchsvolleres.
Erweiterte Konfiguration
Nehmen wir für einen Moment an, Sie haben ein wunderschönes, aufgemotztes Terminal-Setup, das Sie auch in den Container einbringen möchten. Ich meine, nur weil Sie in einem Container entwickeln, heißt das nicht, dass Ihr Terminal langweilig sein muss. Aber Sie möchten auch nicht Ihre prätentiöse zsh-Einrichtung für jedes Projekt neu konfigurieren, das Sie öffnen. Können wir das auch automatisieren? Finden wir es heraus.
Glücklicherweise ist zsh bereits im Image installiert, das Sie erhalten. Das einzige Problem ist, dass es nicht die Standard-Shell ist, wenn der Container geöffnet wird. Es gibt viele Möglichkeiten, zsh zur Standard-Shell in einem normalen Docker-Szenario zu machen, aber keine davon wird hier funktionieren. Das liegt daran, dass Sie keine Kontrolle darüber haben, wie der Container erstellt wird.
Schauen Sie stattdessen wieder in die vertrauenswürdige Datei devcontainer.json. Darin gibt es einen Block „settings“. Tatsächlich gibt es bereits eine Zeile, die Ihnen zeigt, dass das Standardterminal auf „/bin/bash“ gesetzt ist. Ändern Sie dies zu „/bin/zsh“.
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/zsh"
}
Übrigens können Sie dort JEDE VS Code-Einstellung vornehmen. Wie zum Beispiel die Verschiebung der Seitenleiste auf die rechte Seite. Da – ich habe es für Sie repariert.
// Set default container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/zsh",
"workbench.sideBar.location": "right"
},
Und was ist mit diesen prätentiösen Plugins, die Sie besser als alle anderen machen? Dafür benötigen Sie Ihre Datei .zshrc. Der Container hat bereits oh-my-zsh darin, und es ist im „root“-Ordner. Sie müssen nur sicherstellen, dass Sie den Pfad zu ZSH am Anfang der .zshrc festlegen, damit er auf root zeigt. So…
# Path to your oh-my-zsh installation.
export ZSH="/root/.oh-my-zsh"
# Set name of the theme to load --- if set to "random", it will
# load a random theme each time oh-my-zsh is loaded, in which case,
# to know which specific one was loaded, run: echo $RANDOM_THEME
# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
ZSH_THEME="cloud"
# Which plugins would you like to load?
plugins=(zsh-autosuggestions nvm git)
source $ZSH/oh-my-zsh.sh
Dann können Sie diese sexy .zshrc-Datei in den root-Ordner in der Dockerfile kopieren. Ich habe diese .zshrc-Datei in den Ordner .devcontainer in meinem Projekt gelegt.
COPY .zshrc /root/.zshrc
Und wenn Sie ein Plugin herunterladen müssen, bevor Sie es installieren, tun Sie dies in der Dockerfile mit einem RUN-Befehl. Denken Sie nur daran, all diese in einem Befehl zusammenzufassen, da jeder RUN eine neue Schicht ist. Sie sind jetzt fast ein Container-Experte. Der nächste Schritt ist, einen Blog-Beitrag darüber zu schreiben und Leute in die Wege von Docker einzuweisen, als hätten Sie das Ding erfunden.
RUN git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
Schauen Sie sich das schöne Terminal an! Bewundern Sie die Farben! Das Git-Plugin, das Ihnen den Branch anzeigt und ein Blitz-Emoji hinzufügt! Nichts sagt mehr „Ich weiß, was ich tue“ als ein benutzerdefiniertes Terminal. Ich nehme meins gerne mit nach Starbucks und lasse die Leute es in Aktion sehen und sich fragen, ob ich eine Berühmtheit bin.

Gehen Sie sanft
Hoffentlich sind Sie bis hierher gekommen und dachten: „Mensch, dieser Kerl übertreibt wirklich. Das ist nicht so schwer.“ Wenn ja, habe ich Sie erfolgreich gerettet. Sie sind willkommen. Kein Dank nötig. Ja, ich habe eine Amazon-Wunschliste.
Für weitere Informationen zu Remote Containers, einschließlich wie Sie beispielsweise eine Datenbank hinzufügen oder Docker Compose verwenden, lesen Sie die offiziellen Remote Container Docs, die wesentlich mehr Klarheit mit 100 % weniger neurotischem Kommentar bieten.
Die Schreibweise hat mir gefallen.
Habe etwas über Remote-Container gelernt.
das hier.
(wie wir sagen).
Schmerz ist ein ausgezeichneter Lehrer, denn Splitter hat im nächsten Jahr in den Playoffs gegen LBJ dasselbe getan, mit dem Sieg der Spurs haha.
Mann, ich bin kein Entwickler, nur ein Systemadministrator, aber ich wollte sagen, du schreibst toll. Urkomische Lektüre. Danke.
Echt jetzt??? Dann ist das die wahre Geschichte. Sieh mal – du hättest diesen Artikel schreiben sollen und das hätte der epische Abschluss sein können.
Ich sollte mich wirklich mit Sportbällen beschäftigen.
Ha! ich fühle den Schmerz und ich liebe die Darstellung. ich habe mich mit diesem ganzen VSC Docker-Kram beschäftigt und Powershell ist verdammt frustrierend. Es ist übrigens by-law, bye bye.
Tolle Einführung, um Remote-Container einzurichten. Ich liebe deinen Sinn für Humor!
Obwohl ich dunklen Themen widerspreche – es geht mir mehr um Nostalgie, denke ich. Ich möchte das Gefühl haben, dass ich programmiere und nicht ein Word-Dokument schreibe, und das dunkle Thema versetzt mich mehr in diesen Modus.
Ich erkenne, dass ich eine bedeutende Minderheit bin, wenn es um helle Themen geht. Es ist nur so, dass ich sie seit so vielen Jahren verkaufe. Ich glaube, das ist bekannt als der „Sunk-Cost-Fehler“.
Danke für den Beitrag! Das ist super aufschlussreich, ich hatte keine Ahnung, dass VSCode das kann! Eine Frage, die ich hatte, war, ob dies auf eine webbasierte Sandbox angewendet werden könnte, ähnlich wie bei codesandbox.io?
Hallo hallo
Dieses .devcontainer-Konfigurationsschema ist dasselbe, das auch GitHub Codespaces antreibt. Wenn Sie also einen .devcontainer-Ordner in Ihr Repository hochladen und ihn in einem Codespace öffnen, verwendet der Codespace diese Konfiguration, um Ihre Umgebung zu erstellen.
Ich hätte das wahrscheinlich in den Artikel aufnehmen sollen.
Großartig, ich mag diesen Sarkasmus
Können Sie einen Beitrag über die Verwendung von Trumpscript in einem echten Projekt erstellen?
Ich habe das Gefühl, dieser Beitrag schreibt sich jeden Tag von selbst
Dieser Link zu VS Code ist tot.
Es macht mich wahnsinnig, nicht zu wissen, warum ich meine Seitenleiste nach rechts verschieben sollte!!!
Toller Artikel übrigens.
Danke für den Hinweis! Der Link sollte jetzt funktionieren. :)
Nein, sie bringen den Müll nicht raus, auch wenn es ihr EINZIGER JOB ist. Manche Leute haben Kinder…
Das war eine urkomische und tatsächlich lehrreiche Lektüre. Ich liebe es. Ich weiß mehr darüber, wie man meine Entwicklungsumgebung containerisiert, als ich dachte.
„Ich bin nicht das Sandwich mit dem meisten Salat, aber ich bin mir ziemlich sicher, dass wir hier das wollen.“ Meine Seiten! Ich habe den Artikel geliebt!
Danke dafür :)
1. Fandest du es träge/langsamer?
2. Hätte dies diese armen (jetzt ärmeren) Seelen geschützt, die ein npm-Paket installierten, das Bitcoin-Wallets stahl?
Mit freundlichen Grüßen aus Dänemark