Fehlerbehebung und weiterführende Themen
Was sich hinter den Kulissen verbirgt
Um Probleme beim Deployment Ihrer Applikation zu verstehen und zu beheben, ist es hilfreich, etwas darüber zu wissen, was sich im Backend abspielt. Bei der erfolgreichen Applikationserstellung kommt es im Wesentlichen zu folgenden durchgeführten Schritten:
- Das git Repository wird in der festgelegten Revision geklont
- Die Programmiersprache bzw. das Framework der Applikation wird erkannt
- Die Anwendung wird erstellt und mit den für die Sprache passenden Tools in einen OCI Container verpackt
- Das erstellte Anwendungs-Image wird in die Deploio-Image Registry hochgeladen
- Ein Release wird erstellt, welches das zuvor erstellte Image ausführt
- Die Anwendung wird an einem HTTP Endpunkt bereitgestellt
Während der Build- und Release-Phasen kann es zu unterschiedlichen Fehlern
kommen. Wenn ein Fehler oder eine Inkompatibilität während des Klonens oder des
Builds auftritt, zeigt nctl
die Build Logs an, um die Fehlerbehebung zu
erleichtern. Wenn der Build erfolgreich ist, aber der Release nicht
bereitgestellt werden kann, können die Applikations-Logs einen Hinweis auf das
Problem geben. Falls die Anwendung allerdings direkt beim Start fehlschlägt,
kann dies zu einem leeren Applikations-Log führen.
Einen Build wiederholen
Build-Prozesse können aus verschiedenen Gründen zu Fehlern führen. Meistens
können diese Fehler durch einen Fix im Applikations-Code oder durch das
Hinzufügen einer fehlenden Umgebungsvariablen behoben werden. Es kann aber auch
zu temporären Fehlern im internen Deploio-System kommen. In derartigen Fällen
können Sie die Wiederholung eines Builds mittels nctl
anstossen:
$ nctl update app go-example --retry-build
Einen Release wiederholen
Mit dem Release-Trigger können Sie manuell einen neuen Release starten, ohne dass Code-Änderungen oder ein erneuter Build der Anwendung erforderlich sind. Dies ist besonders hilfreich, wenn ein Release zuvor aufgrund externer Faktoren, Infrastrukturproblemen oder temporären Netzwerkfehlern fehlgeschlagen ist. Wenn beispielsweise der Release-Prozess aufgrund einer fehlerhaften oder inkorrekten Datenbank-Migration gescheitert ist und Sie das Problem inzwischen direkt auf Datenbank-Ebene behoben haben, können Sie die Wiederholung eines Releases direkt ausführen, um den bestehenden Build erneut bereitzustellen:
$ nctl update app go-example --retry-release
Den Build Output lokal betrachten und ausführen
Da der Deploio-Build-Prozess ein OCI-/Docker-Image erzeugt, ist es möglich, sich dieses Container Image auf Ihr lokales Gerät herunter zu laden. Das kann hilfreich sein, wenn der Build erfolgreich ist, aber die Applikation dennoch nicht gestartet werden kann. Bitte beachten Sie, dass es nur möglich ist, Images für Fehlerbehebungszwecke herunterzuladen. Das Hochladen von Images in die Registry ist nicht möglich.
$ 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
Ausführen einer Shell oder eines Befehls in einer Deploio-Applikation
Sobald mindestens ein erfolgreiches Release einer Deploio-Applikation erstellt wurde, können Sie einen Befehl oder eine Shell in der Applikation ausführen. Bitte beachten Sie dass sich das Release in einem stabilen Zustand befinden muss. Sollte Ihre Applikation aufgrund eines Fehlers wiederholt neustarten, so wird es nicht möglich sein, einen Befehl oder eine Shell zu starten.
Für die Ausführung können Sie nctl
nutzen. Standardmässig wird dabei eine
Shell in der ersten Replika der Deploio-Applikation gestartet.
$ 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
Bitte beachten Sie, dass jeder Befehl, welcher gestartet wird, Ihrem
Arbeitsspeicher-Quota angerechnet wird. Dieses hängt von der gewählten Deploio-
Applikationsgrösse ab. Sollte der Befehl zu viel Arbeitsspeicher verbrauchen,
so wird die Deploio-Applikations-Replika beendet (OOM) und der nctl
-Befehl
wird mit einem Exit Code von 137 beendet.
nctl: error: command terminated with exit code 137
Ebenso wird Ihre Applikation sofort beendet, 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
Beachten Sie bitte weiterhin, dass sämtliche Änderungen, welche an lokalen Dateien durchgeführt werden, nur temporär verfügbar sind. Nach einem Neustart der Deploio-Applikations-Replika gehen die gemachten Änderungen verloren.
Lets Encrypt-Zertifikate
Applikationen, welche auf Deploio laufen, werden von Haus aus über eine
generierte URL zugänglich gemacht. Auf diesem Weg können Sie an Ihrer
Applikation entwickeln und testen, ohne dass eine eigene Domain/Hostname genutzt
werden muss. Die Kommunikation wird zusätzlich durch ein TLS-Zertifikat von Lets
Encrypt, welches direkt bei der Deploio-Applikationserstellung ausgestellt wird,
verschlüsselt. Für die Erstellung von Lets Encrypt-Zertifikaten nutzen wir
generell den HTTP-01 Challenge
Typ. Um den
Status des Standard-TLS-Zertifikates zu sehen, können Sie nctl
nutzen:
nctl get app <APP NAME> -o yaml
kind: Application
apiVersion: apps.nine.ch/v1alpha1
...
status:
atProvider:
...
defaultHostsCertificateStatus: Issued
Sobald Sie eigene Host- oder Domainnamen zu
ihrer Deploio-Applikation hinzufügen, wird ein zusätzliches Lets Encrypt-
Zertifikat, welches alle eigenen Hostnamen beinhaltet, ausgestellt. Um den
Status dieses Zertifikats zu sehen, können Sie wieder nctl
nutzen:
nctl get app <APP NAME> -o yaml
kind: Application
apiVersion: apps.nine.ch/v1alpha1
...
status:
atProvider:
...
customHostsCertificateStatus: Pending
Da wir den HTTP-01 Challenge-Typ verwenden, um alle Domain-/Hostnamen von Lets Encrypt verifizieren zu lassen, kann das TLS-Zertifikat nur erfolgreich ausgestellt werden, sobald alle eigenen Host-/Domainnamen korrekt auf die Deploio-Infrastruktur zeigen. Unsere Prozesse zur Ausstellung des Zertifikats verwenden bereits eine optimierte DNS-Auflösung, um möglichst schnell auf Änderungen reagieren zu können. Beachten Sie bitte, dass es trotzdem einige Minuten dauern kann, bis das TLS-Zertifikat korrekt erstellt wird. Dies ist besonders wichtig, falls eine bereits vorhandene Applikation von einem anderen Anbieter zu Deploio migriert werden soll. Da die Erstellung des TLS-Zertifikats einige Minuten dauern kann, sollte die Migration besser zu Randzeiten, wie beispielsweise nachts, durchgeführt werden.
Es gilt weiterhin zu beachten, dass Lets Encrypt eventuell vorhandene IPv6 DNS- Einträge bevorzugt. Sollten Sie daher gleichnamige A und AAAA DNS-Einträge für Ihre Applikation angelegt haben, so bitten wir Sie, die AAAA-Einträge zu löschen, um die Zertifikatserstellung zu ermöglichen (Deploio unterstützt derzeit kein IPv6).
Lokale Ephemeral-Storage-Beschränkungen für Deploio-Applikationen
Ephemeral Storage ist ein temporärer Speichermechanismus, der von Ihrer Applikation, oder genauer gesagt, von ihrem Container während der Laufzeit genutzt wird. Derzeit begrenzen wir den lokalen Ephemeral Storage auf 2 GiB pro Deploio-Applikation. Diese Beschränkungen sind notwendig, um zu verhindern, dass eine einzelne Applikation übermässig viele Ressourcen verbraucht und um eine faire Verteilung im System sicherzustellen.
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 Applikation zählt ebenfalls zum gesamten
Ephemeral Storage-Verbrauch. Wird das Speicherlimit überschritten, kann die
Applikation neu gestartet werden, wodurch alle Ephemeral Storage-Daten verloren
gehen.
Best Practices für den Umgang mit Ephemeral Storage
Um Ephemeral Storage effizient zu verwalten, sollten Nutzer Schreibvorgänge in der beschreibbaren Schicht minimieren. Exzessives Logging und unnötige temporäre Dateien sollten vermieden werden. Kritische Daten sollten in persistentem Speicher abgelegt werden, um Datenverlust zu verhindern.
Das Ephemeral Storage-Limit umfasst nicht die Grösse des Deploio-Applikations-Images.
Was passiert, wenn das Ephemeral Storage-Limit überschritten wird?
Wenn eine Applikation das Ephemeral Storage-Limit übersteigt, wird ihr Container
beendet und es wird der Exit-Code 137
zurückgegeben.
Auswirkungen auf exec
-Sitzungen
Wenn eine exec
-Sitzung
in einem Container aktiv ist, der sein Ephemeral Storage-Limit übersteigt, wird
der Container sofort beendet. Die Sitzung wird zwangsweise getrennt und die
folgende Fehlermeldung erscheint:
nctl: error: command terminated with exit code 137
Die beschreibbare Schicht der Deploio-Applikation
Die beschreibbaren Pfade und das Verhalten im App-Container hängen davon ab, ob die Applikation mit Buildpacks (Standard) oder einem Dockerfile erstellt wurde. Unterschiedliche Methoden führen zu unterschiedlichen Einschränkungen und Berechtigungen für beschreibbare Verzeichnisse.
Applikationen, die mit Buildpacks erstellt wurden (Standard)
Buildpacks definieren eine strenge Reihe von beschreibbaren Pfaden, die auf Sicherheits- und Reproduzierbarkeitsrichtlinien basieren. In den meisten mit Buildpacks erstellten Apps sind die beschreibbaren Pfade auf spezifische Verzeichnisse beschränkt, oft auf:
/workspace
/tmp
Warum diese Einschränkung? Buildpacks sind darauf ausgelegt, unveränderliche Schichten für Applikationsabhängigkeiten und Basisdateien zu erstellen. Alle Änderungen zur Laufzeit sollten nur in temporären Verzeichnissen erfolgen, um die Integrität des Containers 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.
Applikationen, die mit einem Dockerfile erstellt wurden
Wenn eine Applikation mit einem Dockerfile erstellt wurde, hängen die beschreibbaren Pfade und das Verhalten von den Entscheidungen des Entwicklers ab. Die Konfiguration kann stark variieren, je nach den Anforderungen der Applikation. Ähnlich wie bei Buildpacks unterliegen die beschreibbaren Pfade einer mit einem Dockerfile erstellten Applikation ebenfalls den Ephemeral Storage-Beschränkungen.
Überprüfen, welcher Benutzer den Container ausführt
Vor dem Testen der Schreibbarkeit ist es hilfreich, herauszufinden, welcher Benutzer den Container ausführt. Dies kann durch folgenden Befehl erfolgen:
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 erlauben die vollständige Kontrolle durch den Benutzer, und die Konfigurationen können stark variieren.
Bestimmen der beschreibbaren Verzeichnisse in deiner App
Zuerst müssen Sie eine Shell starten in Ihrer Deploio-Applikation. Es gibt keinen direkten Befehl, um nur beschreibbare Verzeichnisse aufzulisten, aber einige Untersuchungen können helfen, diese zu identifizieren. Hier sind einige hilfreiche Befehle.
Ein nützlicher Befehl zur Überprüfung der Schreibrechte ist:
find / -writable -type d 2>/dev/null | sort
Falls find
nicht verfügbar ist, kann ls
verwendet werden, um die
Berechtigungen manuell zu überprüfen:
ls -ld /path/to/directory
Falls Sie unsicher sind, welche Verzeichnisse beschreibbar sind, können Sie dies manuell testen, indem Sie eine Datei erstellen:
touch /tmp/testfile && echo "/tmp is writable" || echo "/tmp is not writable"
Falls touch
nicht verfügbar ist, können Sie mit echo
eine Datei schreiben:
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
In einigen Deploio-Applikationen, insbesondere solchen, die mit einem Dockerfile
aus distroless
oder scratch
erstellt wurden
(z. B. unsere Sample Dockerfile App),
kann die Shell fehlen, sodass keine Befehle ausgeführt werden können. In solchen
Fällen sollten alternative Debugging-Methoden und -Techniken verwendet werden.