ist jetzt verfügbar! Lesen Sie über die neuen Funktionen und Fehlerbehebungen vom November.

Debuggen von Node.js in einem Container

Beim Hinzufügen von Docker-Dateien zu einem Node.js-Projekt werden Aufgaben und Startkonfigurationen hinzugefügt, um die Anwendung in einem Container debuggen zu können. Aufgrund des großen Ökosystems rund um Node.js können diese Aufgaben jedoch nicht jeden Anwendungsframework oder jede Bibliothek abdecken, was bedeutet, dass einige Anwendungen eine zusätzliche Konfiguration erfordern.

Konfiguration des Container-Einstiegspunkts

Die Container Tools-Erweiterung leitet den Einstiegspunkt des Containers ab – d. h. die Befehlszeile zum Starten der Anwendung im Debug-Modus innerhalb des Containers – über Eigenschaften von package.json ab. Die Erweiterung sucht zuerst nach dem start-Skript im scripts-Objekt. Wenn es gefunden wird und mit einem node- oder nodejs-Befehl beginnt, wird dieser zum Erstellen der Befehlszeile zum Starten der Anwendung im Debug-Modus verwendet. Wenn es nicht gefunden wird oder kein erkannter node-Befehl ist, wird die Eigenschaft main in package.json verwendet. Wenn weder gefunden noch erkannt wird, müssen Sie die Eigenschaft dockerRun.command der zum Starten des Containers verwendeten Aufgabe docker-run explizit festlegen.

Einige Node.js-Anwendungsframeworks enthalten CLIs zur Verwaltung der Anwendung und werden zum Starten der Anwendung im start-Skript verwendet, was die zugrunde liegenden node-Befehle verschleiert. In diesen Fällen kann die Container Tools-Erweiterung den Startbefehl nicht ableiten und Sie müssen den Startbefehl explizit konfigurieren.

Beispiel: Konfiguration des Einstiegspunkts für eine Nest.js-Anwendung

{
  "tasks": [
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": ["docker-build"],
      "dockerRun": {
        "command": "nest start --debug 0.0.0.0:9229"
      },
      "node": {
        "enableDebugging": true
      }
    }
  ]
}

Beispiel: Konfiguration des Einstiegspunkts für eine Meteor-Anwendung

{
  "tasks": [
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": ["docker-build"],
      "dockerRun": {
        "command": "node --inspect=0.0.0.0:9229 main.js"
      },
      "node": {
        "enableDebugging": true
      }
    }
  ]
}

Automatisches Starten des Browsers zur Einstiegsseite der Anwendung

Die Container Tools-Erweiterung kann den Browser automatisch zur Einstiegsseite der Anwendung starten, nachdem diese im Debugger gestartet wurde. Diese Funktion ist standardmäßig aktiviert und wird über das Objekt dockerServerReadyAction der Debug-Konfiguration in launch.json konfiguriert.

Diese Funktion hängt von mehreren Aspekten der Anwendung ab

  • Die Anwendung muss Protokolle in die Debug-Konsole ausgeben.
  • Die Anwendung muss eine "Server bereit"-Nachricht protokollieren.
  • Die Anwendung muss eine durchsuchbare Seite bereitstellen.

Während die Standardeinstellungen für eine Express.js-basierte Anwendung funktionieren mögen, erfordern andere Node.js-Frameworks möglicherweise eine explizite Konfiguration eines oder mehrerer dieser Aspekte.

Sicherstellen, dass Anwendungsprotokolle in die Debug-Konsole geschrieben werden

Diese Funktion hängt davon ab, dass die Anwendung ihre Protokolle in die Debug-Konsole des angehängten Debuggers schreibt. Nicht alle Protokollierungsframeworks schreiben jedoch in die Debug-Konsole, selbst wenn sie für die Verwendung eines konsolenbasierten Protokollierers konfiguriert sind (da einige "Konsolen"-Protokollierer tatsächlich die Konsole umgehen und direkt in stdout schreiben).

Die Lösung variiert je nach Protokollierungsframework, erfordert aber im Allgemeinen das Erstellen/Hinzufügen eines Protokollierers, der *tatsächlich* in die Konsole schreibt.

Beispiel: Konfiguration von Express-Anwendungen zur Ausgabe in die Debug-Konsole

Standardmäßig verwendet Express.js das debug-Protokollierungsmodul, das die Konsole umgehen kann. Dies kann gelöst werden, indem die Protokollfunktion explizit an die debug()-Methode der Konsole gebunden wird.

var app = require('../app');
var debug = require('debug')('my-express-app:server');
var http = require('http');

// Force logging to the debug console.
debug.log = console.debug.bind(console);

Beachten Sie auch, dass der debug-Protokollierer Protokolle nur schreibt, wenn er über die Umgebungsvariable DEBUG aktiviert ist, die in der docker-run-Aufgabe festgelegt werden kann. (Diese Umgebungsvariable wird standardmäßig auf * gesetzt, wenn Docker-Dateien zur Anwendung hinzugefügt werden.)

{
  "tasks": [
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": ["docker-build"],
      "dockerRun": {
        "env": {
          "DEBUG": "*"
        }
      },
      "node": {
        "enableDebugging": true
      }
    }
  ]
}

Konfiguration, wann die Anwendung "bereit" ist

Die Erweiterung ermittelt, dass die Anwendung "bereit" ist, HTTP-Verbindungen zu empfangen, wenn sie eine Nachricht der Form Listening on port <number> in die Debug-Konsole schreibt, wie es Express.js standardmäßig tut. Wenn die Anwendung eine andere Nachricht protokolliert, sollten Sie die Eigenschaft pattern des dockerServerReadyAction-Objekts der Debug-Startkonfiguration auf einen JavaScript-Regulären Ausdruck setzen, der dieser Nachricht entspricht. Der Reguläre Ausdruck sollte eine Erfassungsgruppe enthalten, die dem Port entspricht, auf dem die Anwendung lauscht.

Nehmen wir zum Beispiel an, die Anwendung protokolliert die folgende Nachricht

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
  debug('Application has started on ' + bind);
}

Das entsprechende pattern in der Debug-Startkonfiguration (in launch.json) lautet

{
  "configurations": [
    {
      "name": "Containers: Node.js Launch",
      "type": "docker",
      "request": "launch",
      "preLaunchTask": "docker-run: debug",
      "platform": "node",
      "dockerServerReadyAction": {
        "pattern": "Application has started on port (\\d+)"
      }
    }
  ]
}

Beachten Sie die (\\d+)-Erfassungsgruppe für die Portnummer und die Verwendung von \ als JSON-Escape-Zeichen für den Backslash in der \d-Zeichenklasse.

Konfiguration der Anwendungseinstiegsseite

Standardmäßig öffnet die Container Tools-Erweiterung die "Haupt"-Seite des Browsers (wie auch immer diese von der Anwendung bestimmt wird). Wenn der Browser auf eine bestimmte Seite geöffnet werden soll, sollte die Eigenschaft uriFormat des dockerServerReadyAction-Objekts der Debug-Startkonfiguration auf eine Node.js-Formatzeichenfolge gesetzt werden, mit einem Zeichenfolgen-Token, das angibt, wo der Port ersetzt werden soll.

Das entsprechende uriFormat in der Debug-Startkonfiguration (in launch.json), um die Seite about.html anstelle der Hauptseite zu öffnen, wäre

{
  "configurations": [
    {
      "name": "Containers: Node.js Launch",
      "type": "docker",
      "request": "launch",
      "preLaunchTask": "docker-run: debug",
      "platform": "node",
      "dockerServerReadyAction": {
        "uriFormat": "https://:%s/about.html"
      }
    }
  ]
}

Zuordnung von Container-Quelldateien zum lokalen Arbeitsbereich

Standardmäßig geht die Container Tools-Erweiterung davon aus, dass sich die Quellcodedateien der Anwendung im laufenden Container im Ordner /usr/src/app befinden, und der Debugger ordnet diese Dateien dann dem Stammverzeichnis des geöffneten Arbeitsbereichs zu, um Breakpoints vom Container zurück in Visual Studio Code zu übersetzen.

Wenn sich die Quellcodedateien der Anwendung an einem anderen Ort befinden (z. B. verschiedene Node.js-Frameworks haben unterschiedliche Konventionen), entweder innerhalb des Containers oder innerhalb des geöffneten Arbeitsbereichs, dann sollten eine oder beide der Eigenschaften localRoot und remoteRoot des node-Objekts der Debug-Startkonfiguration auf die Stammquellverzeichnisse innerhalb des Arbeitsbereichs bzw. des Containers gesetzt werden.

Wenn die Anwendung stattdessen in /usr/my-custom-location liegt, wäre die entsprechende remoteRoot-Eigenschaft

{
  "configurations": [
    {
      "name": "Containers: Node.js Launch",
      "type": "docker",
      "request": "launch",
      "preLaunchTask": "docker-run: debug",
      "platform": "node",
      "node": {
        "remoteRoot": "/usr/my-custom-location"
      }
    }
  ]
}

Fehlerbehebung

Container-Image-Build oder -Start schlägt aufgrund fehlender node_modules fehl

Dockerfiles sind oft so aufgebaut, dass sie entweder die Build-Zeit des Images, die Größe des Images oder beides optimieren. Jedoch unterstützt nicht jedes Node.js-Anwendungsframework alle typischen Node.js-Dockerfile-Optimierungen. Insbesondere für einige Frameworks muss der node_modules-Ordner ein unmittelbarer Unterordner des Anwendungsstammordners sein, während die Container Tools-Erweiterung ein Dockerfile generiert, in dem sich der node_modules-Ordner auf einer über- oder nachgeordneten Ebene befindet (was von Node.js im Allgemeinen erlaubt ist).

Die Lösung besteht darin, diese Optimierung aus dem Dockerfile zu entfernen

FROM node:lts-alpine
ENV NODE_ENV=production
WORKDIR /usr/src/app
COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
# Remove the `&& mv node_modules ../` from the RUN command:
# RUN npm install --production --silent && mv node_modules ../
RUN npm install --production --silent
COPY . .
EXPOSE 3000
RUN chown -R node /usr/src/app
USER node
CMD ["npm", "start"]
© . This site is unofficial and not affiliated with Microsoft.