Zum Hauptinhalt springen

Fehlerbehebung und weiterführende Themen

So funktioniert Deploio

Ein Verständnis des Backend-Prozesses hilft bei der Fehlerbehebung von Deployment-Problemen. Bei einer erfolgreichen App-Erstellung führt Deploio folgende Schritte aus:

  • Klont das Git-Repository in der angegebenen Revision
  • Erkennt die Programmiersprache der App
  • Erstellt und verpackt die App in einen OCI-Container mit sprachspezifischen Tools
  • Lädt das erstellte App-Image in die Deploio-Image-Registry hoch
  • Erstellt ein Release, das das erstellte Image ausführt
  • Stellt die Anwendung an einem HTTP-Endpunkt bereit

In den Build- und Release-Schritten treten die meisten Probleme auf. Bei einem Fehler während des Klonens oder Builds zeigt nctl die Build-Logs zur Fehlerbehebung an. Wenn der Build erfolgreich ist, aber ein Release nicht bereit wird, prüfen Sie die App-Logs auf Hinweise zum Problem. Falls Ihre App beim Start ohne Fehlermeldung abstürzt, kann das App-Log leer sein.

Build wiederholen

Builds können aus verschiedenen Gründen fehlschlagen. Meistens behebt eine Änderung am Applikationscode oder das Hinzufügen einer fehlenden Umgebungsvariable das Problem. Allerdings kann auch ein temporärer interner Systemfehler die Ursache sein. In solchen Fällen wiederholen Sie den Build mit nctl:

$ nctl update app go-example --retry-build

Release wiederholen

Mit dem Release-Trigger starten Sie manuell ein neues Release ohne Code-Änderungen oder erneuten Build. Dies ist besonders hilfreich, wenn ein Release aufgrund externer Faktoren, Infrastrukturproblemen oder temporären Netzwerkfehlern fehlgeschlagen ist. Wenn beispielsweise der Release-Prozess aufgrund einer fehlerhaften Datenbank-Migration gescheitert ist und Sie das Problem auf Datenbank-Ebene behoben haben, verwenden Sie die Release-Wiederholung, um den bestehenden Build erneut bereitzustellen:

$ nctl update app go-example --retry-release

Build-Output lokal betrachten und ausführen

Da der Build-Output ein OCI-/Docker-Image ist, können Sie es zur Inspektion auf Ihr lokales Gerät herunterladen. Dies hilft, wenn der Build erfolgreich ist, aber das Release die App nicht starten kann. Sie können Images nur zum Debugging herunterladen; die Registry akzeptiert keine Uploads.

$ nctl get build go-example-build-1 --pull-image
Pulling image of build go-example-build-1
739cb80086f0: Download complete
1bfd697887fa: Download complete
aea73d1e202c: Download complete
e4fd482e7de7: Download complete
✓ Pulled image deploio.296dc8b.registry.nineapis.ch/nine/go-example 💾

Nach dem Image-Download können Sie Docker oder Podman (bzw. jegliche Tools, welche OCI-Images unterstützen) nutzen, um das Image lokal auszuführen.

$ docker run deploio.296dc8b.registry.nineapis.ch/nine/go-example

Shell oder Befehl in einer Deploio-Applikation ausführen

note

In einigen Deploio-Applikations-Images, insbesondere solchen, die mit einem Dockerfile aus distroless oder scratch erstellt wurden (z. B. die Sample Dockerfile App), ist keine Shell enthalten, was die Befehlsausführung verhindert. Verwenden Sie in solchen Fällen alternative Debugging-Tools und -Techniken.

Sie können nach einem erfolgreichen Release eine Shell in Ihrer Deploio-Applikation starten. Ihre Applikation muss in einem stabilen Zustand laufen, damit eine Shell gestartet werden kann. Wenn Ihre Applikation aufgrund eines Fehlers ständig neu startet, ist das Starten einer Shell nicht möglich.

Starten Sie eine Shell mit nctl. Dies startet eine Shell in der ersten verfügbaren Deploio-Replika.

$ nctl get app
NAME HOSTS UNVERIFIED_HOSTS
rails rails.7f0b629.deploio.app none

$ nctl exec app rails
cnb@rails-5fcc67cc-89fd2:/workspace$

Sie können auch einen einzelnen Befehl starten indem Sie diesen durch -- vom Rest des Kommandos abtrennen.

$ nctl exec app rails -- hostname
rails-5fcc67cc-89fd2

Jeder Befehl, den Sie starten, wird auf Ihr Arbeitsspeicher-Quota angerechnet, das von der konfigurierten Deploio-Applikationsgrösse abhängt. Bei zu hohem Speicherverbrauch beendet Deploio die gesamte Applikations-Replika und Sie sehen einen Exit-Code von 137:

nctl: error: command terminated with exit code 137

Ebenso beendet Deploio Ihre Applikation sofort, wenn sie ihr lokales Ephemeral-Storage-Limit überschreitet. Die Sitzung wird zwangsweise getrennt und die folgende Fehlermeldung erscheint:

nctl: error: command terminated with exit code 137

Alle Änderungen an lokalen Dateien in einer Shell-Sitzung gehen verloren, wenn die Deploio-Replika neu startet.

Let's-Encrypt-Zertifikate

Deploio stellt Applikationen standardmässig über eine zufällig generierte URL bereit, sodass Sie während der Entwicklung ohne eigene Domain darauf zugreifen können. Deploio sichert die Standard-URL mit einem Let's-Encrypt-TLS-Zertifikat, das automatisch bei der App-Erstellung generiert wird. Für Let's-Encrypt-Zertifikate verwendet Deploio den HTTP-01-Challenge-Typ. Zeigen Sie den Zertifikatsstatus für die Standard-URL mit nctl an:

nctl get app <APP NAME> -o yaml

kind: Application
apiVersion: apps.nine.ch/v1alpha1
...
status:
atProvider:
...
defaultHostsCertificateStatus: Issued

Wenn Sie eigene Hostnamen zu Ihrer Deploio-Applikation hinzufügen, stellt Deploio ein entsprechendes Let's-Encrypt-TLS-Zertifikat für alle Ihre eigenen Hostnamen aus. Zeigen Sie den Zertifikatsstatus mit nctl an:

nctl get app <APP NAME> -o yaml

kind: Application
apiVersion: apps.nine.ch/v1alpha1
...
status:
atProvider:
...
customHostsCertificateStatus: Pending

Da Deploio den Let's-Encrypt-HTTP-01-Challenge-Typ verwendet, wird das Zertifikat erst ausgestellt, wenn alle Ihre eigenen Hostnamen auf die Deploio-Infrastruktur zeigen. Deploio verwendet einen optimierten DNS-Auflösungspfad, um schnell auf DNS-Änderungen zu reagieren, aber die Zertifikatsausstellung kann dennoch einige Minuten dauern. Dies ist besonders wichtig bei der Migration einer anderswo gehosteten Applikation zu Deploio. Da der Übergang mehrere Minuten dauern kann, sollten Sie die Migration ausserhalb der Geschäftszeiten durchführen.

Let's Encrypt bevorzugt IPv6-DNS-Einträge gegenüber IPv4. Wenn Sie DNS-AAAA-Einträge für Ihre eigenen Hostnamen haben, löschen Sie diese bei der Migration zu Deploio, da Deploio derzeit kein IPv6 unterstützt.

Lokale Ephemeral-Storage-Beschränkungen

Ephemeral Storage ist ein temporärer Speichermechanismus, den der Container Ihrer App während der Laufzeit verwendet. Deploio begrenzt den lokalen Ephemeral Storage auf 2 GiB pro Applikation. Diese Limits verhindern, dass eine einzelne Applikation übermässig viele Ressourcen verbraucht, und gewährleisten eine faire Verteilung im System.

Was umfasst Ephemeral Storage?

Container verwenden lokalen Ephemeral Storage für temporäre Dateien, Caching und Logs. Das Schreiben von Daten durch eine exec-Sitzung in das Dateisystem einer laufenden App zählt ebenfalls zum gesamten Ephemeral-Storage-Verbrauch. Das Überschreiten des Speicherlimits kann einen Neustart der App verursachen, wodurch alle Ephemeral-Storage-Daten verloren gehen.

Best Practices für Ephemeral Storage

Um Ephemeral Storage effektiv zu verwalten:

  • Minimieren Sie Schreibvorgänge in der beschreibbaren Schicht
  • Vermeiden Sie exzessives Logging und unnötige temporäre Dateien
  • Speichern Sie kritische Daten in persistentem Speicher, um Datenverlust zu verhindern
note

Das Ephemeral Storage-Limit umfasst nicht die Grösse des Deploio-Applikations-Images.

Was passiert bei Überschreitung des Ephemeral Storage?

Wenn eine Applikation das Ephemeral-Storage-Limit überschreitet, beendet Deploio den Container und gibt den Exit-Code 137 zurück.

Auswirkungen auf exec-Sitzungen

Wenn eine exec-Sitzung in einem Container aktiv ist, der sein Ephemeral-Storage-Limit überschreitet, beendet Deploio den Container sofort. Die Sitzung wird zwangsweise getrennt und die folgende Fehlermeldung erscheint:

nctl: error: command terminated with exit code 137

Beschreibbare Schicht

Die beschreibbaren Pfade und das Verhalten im App-Container hängen davon ab, ob Sie die Applikation mit Buildpacks (Standard) oder einem Dockerfile erstellt haben. Unterschiedliche Ansätze führen zu unterschiedlichen Einschränkungen und Berechtigungen für beschreibbare Verzeichnisse.

Mit Buildpacks erstellte Applikationen (Standard)

Buildpacks definieren eine strenge Menge beschreibbarer Pfade, basierend auf Konventionen zur Verbesserung von Sicherheit und Reproduzierbarkeit. In den meisten mit Buildpacks erstellten Apps sind beschreibbare Pfade auf bestimmte Verzeichnisse beschränkt, typischerweise:

/workspace
/tmp

Buildpacks erstellen unveränderliche Schichten für Applikationsabhängigkeiten und Basisdateien. Änderungen zur Laufzeit sollten nur in temporären Verzeichnissen erfolgen, um die Container-Integrität zu gewährleisten.

Die beschreibbaren Verzeichnisse in einem mit Buildpacks erstellten Container unterliegen dem Ephemeral-Storage-Limit, was bedeutet, dass exzessive Schreibvorgänge den verfügbaren Speicher erschöpfen können.

Mit Dockerfile erstellte Applikationen

Wenn Sie eine Applikation mit einem Dockerfile erstellen, hängen die beschreibbaren Pfade und das Verhalten von Ihren Entscheidungen ab und können je nach Applikationsanforderungen stark variieren. Ähnlich wie bei Buildpacks unterliegen die beschreibbaren Pfade einer mit Dockerfile erstellten Applikation den Ephemeral-Storage-Beschränkungen.

Prüfen, welcher Benutzer den Container ausführt

Bevor Sie die Schreibbarkeit testen, ermitteln Sie, welcher Benutzer den Container ausführt:

id

Beispielausgabe:

uid=1000(cnb) gid=1000(cnb) groups=1000(cnb)

Die User-ID kann sich zwischen Build-Zeit und Laufzeit unterscheiden, abhängig von der Buildpack-Architektur. Einige Buildpacks verwenden unterschiedliche Benutzer für Build und Laufzeit, während andere denselben Benutzer beibehalten. Dies kann zu unterschiedlichen Laufzeitberechtigungen führen. Weitere Informationen finden Sie in der Cloud Native Buildpack Policy. Dockerfile-basierte Builds geben Ihnen volle Kontrolle über den Benutzer, und Konfigurationen können stark variieren.

Beschreibbare Verzeichnisse in Ihrer App ermitteln

Starten Sie zunächst eine Shell in Ihrer Deploio-Applikation. Es gibt keinen direkten Befehl, um nur beschreibbare Verzeichnisse aufzulisten, aber Untersuchungen können helfen, diese zu identifizieren. Die folgenden Tipps können helfen.

Um Schreibrechte zu prüfen:

find / -writable -type d 2>/dev/null | sort

Dieser Befehl ist möglicherweise nicht in allen Container-Images verfügbar. Falls find fehlt, aber ls vorhanden ist, prüfen Sie die Verzeichnisberechtigungen manuell:

ls -ld /path/to/directory

Wenn Sie sich bei den beschreibbaren Verzeichnissen unsicher sind, testen Sie manuell durch Erstellen einer Datei:

touch /tmp/testfile && echo "/tmp is writable" || echo "/tmp is not writable"

Falls touch nicht verfügbar ist, testen Sie das Schreiben in eine Datei mit echo:

echo "test" > /tmp/testfile && echo "/tmp is Writable" || echo "/tmp is NOT Writable"
rm -f /tmp/testfile

Alternativ können Sie mkdir verwenden:

mkdir /tmp/testdir && echo "/tmp is Writable" || echo "/tmp is NOT Writable"
rmdir /tmp/testdir