1. Übersicht
In diesem Lab werden Funktionen und Möglichkeiten vorgestellt, mit denen Softwareentwickler den Entwicklungsworkflow für die Entwicklung von Python-Anwendungen in einer Containerumgebung optimieren können. Bei der typischen Containerentwicklung muss der Nutzer die Details von Containern und den Container-Build-Prozess genau kennen. Außerdem müssen Entwickler in der Regel den Ablauf unterbrechen, um ihre Anwendungen in Remote-Umgebungen zu testen und zu debuggen. Mit den in dieser Anleitung erwähnten Tools und Technologien können Entwickler effektiv mit Containeranwendungen arbeiten, ohne ihre IDE zu verlassen.
Lerninhalte
In diesem Lab lernen Sie Methoden für die Entwicklung mit Containern in GCP kennen, darunter:
- Neue Python-Startanwendung erstellen
- Den Entwicklungsprozess durchgehen
- Einfachen CRUD-Restdienst entwickeln
2. Einrichtung und Anforderungen
Umgebung zum selbstbestimmten Lernen einrichten
- Melden Sie sich in der Google Cloud Console an und erstellen Sie ein neues Projekt oder verwenden Sie ein vorhandenes Projekt. Wenn Sie noch kein Gmail- oder Google Workspace-Konto haben, müssen Sie eines erstellen.
- Der Projektname ist der Anzeigename für die Projektteilnehmer. Es handelt sich um eine Zeichenfolge, die von Google APIs nicht verwendet wird und jederzeit aktualisiert werden kann.
- Die Projekt-ID muss für alle Google Cloud-Projekte eindeutig sein und ist unveränderlich. Sie kann nach dem Festlegen nicht mehr geändert werden. Die Cloud Console generiert automatisch einen eindeutigen String. ist Ihnen meist egal, was es ist. In den meisten Codelabs musst du auf die Projekt-ID verweisen, die in der Regel als
PROJECT_ID
identifiziert wird. Wenn es dir nicht gefällt, kannst du eine weitere zufällige Projekt-ID generieren. Du kannst aber auch selbst eine andere testen, um zu sehen, ob sie verfügbar ist. Dann ist es „eingefroren“ nachdem das Projekt erstellt wurde. - Es gibt einen dritten Wert, die Projektnummer, die von einigen APIs verwendet wird. Weitere Informationen zu allen drei Werten finden Sie in der Dokumentation.
- Als Nächstes müssen Sie in der Cloud Console die Abrechnung aktivieren, um Cloud-Ressourcen/APIs verwenden zu können. Dieses Codelab sollte möglichst wenig kosten. Wenn Sie Ressourcen beenden möchten, damit über diese Anleitung hinaus keine Kosten anfallen, führen Sie eine Bereinigung durch am Ende des Codelabs. Neue Google Cloud-Nutzer haben Anspruch auf eine kostenlose Testversion mit 300$Guthaben.
Cloud Shell-Editor starten
Dieses Lab wurde für die Verwendung mit dem Google Cloud Shell-Editor entwickelt und getestet. So greifen Sie auf den Editor zu:
- Rufen Sie Ihr Google-Projekt unter https://console.cloud.google.com auf.
- Klicken Sie rechts oben auf das Symbol für den Cloud Shell-Editor
- Unten im Fenster wird ein neuer Bereich geöffnet.
- Klicken Sie auf die Schaltfläche „Editor öffnen“.
- Der Editor wird mit einem Explorer auf der rechten Seite und dem Editor im mittleren Bereich geöffnet.
- Unten auf dem Bildschirm sollte außerdem ein Terminalbereich verfügbar sein.
- Wenn das Terminal NICHT geöffnet ist, verwende die Tastenkombination „Strg +“, um ein neues Terminalfenster zu öffnen
Umgebung einrichten
Legen Sie in Cloud Shell Ihre Projekt-ID und die Projektnummer für Ihr Projekt fest. Speichern Sie sie als Variablen des Typs PROJECT_ID
und PROJECT_ID
.
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
--format='value(projectNumber)')
Quellcode abrufen
- Den Quellcode für dieses Lab finden Sie auf GitHub im Container-Entwicklerworkshop der Google Cloud Platform. Klonen Sie es mit dem folgenden Befehl und wechseln Sie dann in das Verzeichnis.
git clone https://github.com/GoogleCloudPlatform/container-developer-workshop.git &&
cd container-developer-workshop/labs/python
mkdir music-service && cd music-service
cloudshell workspace .
Wenn das Terminal NICHT geöffnet ist, verwende die Tastenkombination „Strg +“, um ein neues Terminalfenster zu öffnen
In diesem Lab verwendete Infrastruktur bereitstellen
In diesem Lab stellen Sie Code in GKE bereit und greifen auf Daten zu, die in einer Spanner-Datenbank gespeichert sind. Mit dem Einrichtungsskript unten wird diese Infrastruktur für Sie vorbereitet. Die Bereitstellung dauert über 10 Minuten. Während die Einrichtung verarbeitet wird, kannst du mit den nächsten Schritten fortfahren.
../setup.sh
3. Neue Python-Startanwendung erstellen
- Erstellen Sie eine Datei mit dem Namen
requirements.txt
und kopieren Sie den folgenden Inhalt in diese Datei
Flask
gunicorn
google-cloud-spanner
ptvsd==4.3.2
- Erstellen Sie eine Datei mit dem Namen
app.py
und fügen Sie den folgenden Code in diese ein
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
@app.route("/")
def hello_world():
message="Hello, World!"
return message
if __name__ == '__main__':
server_port = os.environ.get('PORT', '8080')
app.run(debug=False, port=server_port, host='0.0.0.0')
- Erstellen Sie eine Datei mit dem Namen Dockerfile und fügen Sie Folgendes ein:
FROM python:3.8
ARG FLASK_DEBUG=0
ENV FLASK_DEBUG=$FLASK_DEBUG
ENV FLASK_APP=app.py
WORKDIR /app
COPY requirements.txt .
RUN pip install --trusted-host pypi.python.org -r requirements.txt
COPY . .
ENTRYPOINT ["python3", "-m", "flask", "run", "--port=8080", "--host=0.0.0.0"]
Hinweis: Mit FLASK_DEBUG=1 können Sie Codeänderungen an einer Python flask-Anwendung automatisch neu laden. Mit diesem Dockerfile können Sie diesen Wert als Build-Argument übergeben.
Manifeste generieren
Führen Sie in Ihrem Terminal den folgenden Befehl aus, um eine standardmäßige skaffold.yaml-Datei und einedeployment.yaml zu generieren.
- Initialisieren Sie Skaffold mit dem folgenden Befehl
skaffold init --generate-manifests
Wenn Sie dazu aufgefordert werden, bewegen Sie den Cursor mit den Pfeilen und die Leertaste, um die gewünschten Optionen auszuwählen.
Wählen Sie aus:
8080
für den Anschlussy
zum Speichern der Konfiguration
Skaffold-Konfigurationen aktualisieren
- Standard-App-Namen ändern
skaffold.yaml
öffnen- Wählen Sie den Image-Namen aus, der derzeit als
dockerfile-image
festgelegt ist - Klicken Sie mit der rechten Maustaste und wählen Sie „Alle Vorkommen ändern“ aus.
- Geben Sie den neuen Namen als
python-app
ein. - Bearbeiten Sie den Build-Abschnitt weiter,
docker.buildArgs
hinzufügen, umFLASK_DEBUG=1
zu bestehen- Einstellungen synchronisieren, um Änderungen an
*.py
-Dateien aus der IDE in den laufenden Container zu laden
Nach der Bearbeitung sieht der Build-Abschnitt in der Datei skaffold.yaml
so aus:
build:
artifacts:
- image: python-app
docker:
buildArgs:
FLASK_DEBUG: 1
dockerfile: Dockerfile
sync:
infer:
- '**/*.py'
Kubernetes-Konfigurationsdatei ändern
- Standardnamen ändern
- Datei „
deployment.yaml
“ öffnen - Wählen Sie den Image-Namen aus, der derzeit als
dockerfile-image
festgelegt ist - Klicken Sie mit der rechten Maustaste und wählen Sie „Alle Vorkommen ändern“ aus.
- Geben Sie den neuen Namen als
python-app
ein.
4. Der Entwicklungsprozess
Mit der hinzugefügten Geschäftslogik können Sie Ihre Anwendung jetzt bereitstellen und testen. Im folgenden Abschnitt wird die Verwendung des Cloud Code-Plug-ins erläutert. Dieses Plug-in lässt sich unter anderem in Skaffold einbinden, um Ihren Entwicklungsprozess zu optimieren. Wenn Sie in den folgenden Schritten ein Deployment in GKE ausführen, erstellen Cloud Code und Skaffold automatisch das Container-Image, übertragen es per Push in eine Container Registry und stellen die Anwendung dann in GKE bereit. Das geschieht im Hintergrund und abstrahiert die Details außerhalb des Entwicklungsablaufs.
In Kubernetes bereitstellen
- Wählen Sie unten im Cloud Shell-Editor den Bereich „Cloud Code“ aus.
- Wählen Sie im daraufhin angezeigten Steuerfeld Run on Kubernetes aus. Wenn Sie dazu aufgefordert werden, wählen Sie „Ja“ aus, um den aktuellen Kubernetes-Kontext zu verwenden.
Dieser Befehl startet einen Build des Quellcodes und führt dann die Tests aus. Die Ausführung des Builds und der Tests dauert einige Minuten. Diese Tests umfassen Einheitentests und einen Validierungsschritt, mit dem die für die Bereitstellungsumgebung festgelegten Regeln geprüft werden. Dieser Validierungsschritt ist bereits konfiguriert und stellt sicher, dass Sie vor Bereitstellungsproblemen eine Warnung erhalten, auch wenn Sie noch in der Entwicklungsumgebung arbeiten.
- Wenn Sie den Befehl zum ersten Mal ausführen, wird oben auf dem Bildschirm eine Eingabeaufforderung angezeigt, in der Sie gefragt werden, ob Sie den aktuellen Kubernetes-Kontext verwenden möchten. Wählen Sie „Yes“ (Ja) aus. den aktuellen Kontext akzeptieren und nutzen.
- Als Nächstes wird eine Eingabeaufforderung angezeigt, in der Sie gefragt werden, welche Container Registry verwendet werden soll. Drücken Sie die Eingabetaste, um den angegebenen Standardwert zu übernehmen
- Wähle im unteren Bereich den Tab „Output“ (Ausgabe) aus, um den Fortschritt und die Benachrichtigungen anzusehen
- Wählen Sie „Kubernetes: Run/Debug – Detail“ aus. im Drop-down-Menü „Kanal“ rechts, um zusätzliche Details und Logs aufzurufen, die live aus den Containern gestreamt werden
Wenn der Build und die Tests abgeschlossen sind, wird auf dem Tab „Ausgabe“ Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully.
angezeigt und die URL http://localhost:8080 wird aufgeführt.
- Bewegen Sie den Mauszeiger im Cloud Code-Terminal auf die erste URL in der Ausgabe (http://localhost:8080) und wählen Sie dann in der angezeigten Kurzinfo „Webvorschau öffnen“ aus.
- Ein neuer Browsertab wird geöffnet und die Meldung „
Hello, World!
“ wird angezeigt
Heiße Aufladung
- Öffnen Sie die Datei
app.py
. - Begrüßungsnachricht in
Hello from Python
ändern
Sie sehen sofort, dass der Watcher im Output
-Fenster in der Ansicht Kubernetes: Run/Debug
die aktualisierten Dateien mit dem Container in Kubernetes synchronisiert.
Update initiated Build started for artifact python-app Build completed for artifact python-app Deploy started Deploy completed Status check started Resource pod/python-app-6f646ffcbb-tn7qd status updated to In Progress Resource deployment/python-app status updated to In Progress Resource deployment/python-app status completed successfully Status check succeeded ...
- Wenn Sie zur Ansicht
Kubernetes: Run/Debug - Detailed
wechseln, werden Sie feststellen, dass Dateiänderungen erkannt werden und die App dann erstellt und noch einmal bereitgestellt wird.
files modified: [app.py]
Syncing 1 files for gcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Copying files:map[app.py:[/app/app.py]]togcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Watching for changes...
[python-app] * Detected change in '/app/app.py', reloading
[python-app] * Restarting with stat
[python-app] * Debugger is active!
[python-app] * Debugger PIN: 744-729-662
- Aktualisieren Sie Ihren Browser, um die aktualisierten Ergebnisse zu sehen.
Debugging
- Rufen Sie die Debug-Ansicht auf und beenden Sie den aktuellen Thread
.
- Klicken Sie im Menü unten auf
Cloud Code
und wählen SieDebug on Kubernetes
aus, um die Anwendung imdebug
-Modus auszuführen.
- In der Ansicht
Kubernetes Run/Debug - Detailed
des FenstersOutput
sehen Sie, dass Skaffold diese Anwendung im Debug-Modus bereitstellt.
- Wenn Sie dies zum ersten Mal ausführen, werden Sie in einer Eingabeaufforderung gefragt, wo sich die Quelle im Container befindet. Dieser Wert bezieht sich auf die Verzeichnisse im Dockerfile.
Drücken Sie die Eingabetaste, um die Standardeinstellung zu übernehmen
Es dauert einige Minuten, bis die Anwendung erstellt und bereitgestellt ist.
- Nach Abschluss des Prozesses. Sie sehen nun einen Debugger.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
- Die Farbe der unteren Statusleiste wechselt von Blau zu Orange, was darauf hinweist, dass der Debug-Modus aktiviert ist.
- Beachten Sie in der Ansicht
Kubernetes Run/Debug
, dass ein Debug-fähiger Container gestartet wird.
**************URLs***************** Forwarded URL from service python-app: http://localhost:8080 Debuggable container started pod/python-app-8bd64cf8b-cskfl:python-app (default) Update succeeded ***********************************
Haltepunkte verwenden
- Öffnen Sie die Datei
app.py
. - Suchen Sie die Anweisung
return message
. - Fügen Sie dieser Zeile einen Haltepunkt hinzu, indem Sie auf den leeren Bereich links neben der Zeilennummer klicken. Ein roter Indikator wird angezeigt, um darauf hinzuweisen, dass der Haltepunkt eingerichtet ist.
- Laden Sie Ihren Browser neu. Der Debugger stoppt den Prozess am Haltepunkt und ermöglicht es Ihnen, die Variablen und den Status der Anwendung zu untersuchen, die remote in GKE ausgeführt wird.
- Klicken Sie auf den Abschnitt VARIABLES
- Klicken Sie auf „Lokales“. Dort finden Sie die Variable
"message"
. - Doppelklicken Sie auf den Variablennamen „message“. und ändern Sie im Pop-up-Menü den Wert in einen anderen Wert, z. B.
"Greetings from Python"
. - Klicken Sie im Steuerfeld zur Fehlerbehebung auf die Schaltfläche „Weiter“
.
- Sehen Sie sich die Antwort in Ihrem Browser an. Sie enthält jetzt den aktualisierten Wert, den Sie gerade eingegeben haben.
- „Fehlerbehebung“ beenden indem Sie die Stopp-Schaltfläche
drücken. Entfernen Sie den Haltepunkt, indem Sie noch einmal auf den Haltepunkt klicken.
5. Entwickeln eines einfachen CRUD-Restdiensts
Jetzt ist Ihre Anwendung vollständig für die Containerentwicklung konfiguriert und Sie haben den grundlegenden Entwicklungsworkflow mit Cloud Code durchgegangen. In den folgenden Abschnitten üben Sie das Gelernte. Sie fügen Dienstendpunkte hinzu, die eine Verbindung zu einer verwalteten Datenbank in Google Cloud herstellen.
Restdienst programmieren
Mit dem folgenden Code wird ein einfacher Ruhedienst erstellt, der Spanner als Datenbank für die Anwendung verwendet. Erstellen Sie die Anwendung, indem Sie den folgenden Code in Ihre Anwendung kopieren.
- Erstellen Sie die Hauptanwendung, indem Sie
app.py
durch den folgenden Inhalt ersetzen
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
instance_id = "music-catalog"
database_id = "musicians"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
@app.route('/singer', methods=['POST'])
def create():
try:
request_json = request.get_json()
singer_id = request_json['singer_id']
first_name = request_json['first_name']
last_name = request_json['last_name']
def insert_singers(transaction):
row_ct = transaction.execute_update(
f"INSERT Singers (SingerId, FirstName, LastName) VALUES" \
f"({singer_id}, '{first_name}', '{last_name}')"
)
print("{} record(s) inserted.".format(row_ct))
database.run_in_transaction(insert_singers)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['GET'])
def get_singer():
try:
singer_id = request.args.get('singer_id')
def get_singer():
first_name = ''
last_name = ''
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
f"SELECT SingerId, FirstName, LastName FROM Singers " \
f"where SingerId = {singer_id}",
)
for row in results:
first_name = row[1]
last_name = row[2]
return (first_name,last_name )
first_name, last_name = get_singer()
return {"first_name": first_name, "last_name": last_name }, 200
except Exception as e:
return e
@app.route('/singer', methods=['PUT'])
def update_singer_first_name():
try:
singer_id = request.args.get('singer_id')
request_json = request.get_json()
first_name = request_json['first_name']
def update_singer(transaction):
row_ct = transaction.execute_update(
f"UPDATE Singers SET FirstName = '{first_name}' WHERE SingerId = {singer_id}"
)
print("{} record(s) updated.".format(row_ct))
database.run_in_transaction(update_singer)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['DELETE'])
def delete_singer():
try:
singer_id = request.args.get('singer')
def delete_singer(transaction):
row_ct = transaction.execute_update(
f"DELETE FROM Singers WHERE SingerId = {singer_id}"
)
print("{} record(s) deleted.".format(row_ct))
database.run_in_transaction(delete_singer)
return {"Success": True}, 200
except Exception as e:
return e
port = int(os.environ.get('PORT', 8080))
if __name__ == '__main__':
app.run(threaded=True, host='0.0.0.0', port=port)
Datenbankkonfigurationen hinzufügen
Richten Sie die Anwendung für die Verwendung von Arbeitslastidentitäten ein, um eine sichere Verbindung zu Spanner herzustellen. Dadurch kann Ihre Anwendung als eigenes Dienstkonto fungieren und individuelle Berechtigungen beim Zugriff auf die Datenbank haben.
deployment.yaml
aktualisieren. Fügen Sie am Ende der Datei den folgenden Code ein. Achten Sie dabei darauf, die Tab-Einzüge im Beispiel unten beizubehalten.
serviceAccountName: python-ksa
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: "true"
Anwendung bereitstellen und validieren
- Wählen Sie unten im Cloud Shell-Editor
Cloud Code
und dann obenDebug on Kubernetes
aus. - Wenn der Build und die Tests abgeschlossen sind, wird auf dem Tab „Ausgabe“
Resource deployment/python-app status completed successfully
angezeigt und die URL wird aufgeführt: „Forwarded URL from service python-app: http://localhost:8080“ - Fügen Sie einige Einträge hinzu.
Führen Sie im Cloud Shell-Terminal den folgenden Befehl aus:
curl -X POST http://localhost:8080/singer -H 'Content-Type: application/json' -d '{"first_name":"Cat","last_name":"Meow", "singer_id": 6}'
- Testen Sie den GET-Befehl, indem Sie den folgenden Befehl im Terminal ausführen
curl -X GET http://localhost:8080/singer?singer_id=6
- Löschen testen: Versuchen Sie nun, einen Eintrag zu löschen, indem Sie den folgenden Befehl ausführen. Ändern Sie gegebenenfalls den Wert von „item-id“.
curl -X DELETE http://localhost:8080/singer?singer_id=6
This throws an error message
500 Internal Server Error
Problem ermitteln und beheben
- Debug-Modus und suchen Sie nach dem Problem. Hier einige Tipps:
- Uns ist bewusst, dass mit der DELETE-Anfrage etwas nicht stimmt, da nicht das gewünschte Ergebnis zurückgegeben wird. In diesem Fall würden Sie den Haltepunkt in
app.py
in der Methodedelete_singer
festlegen. - Führen Sie eine Schritt-für-Schritt-Ausführung aus und beobachten Sie die Variablen bei jedem Schritt, um die Werte der lokalen Variablen im linken Fenster zu beobachten.
- Wenn Sie bestimmte Werte wie
singer_id
undrequest.args
beobachten möchten, fügen Sie diese Variablen dem Beobachtungsfenster hinzu.
- Beachten Sie, dass der Wert für
singer_id
None
ist. Ändern Sie den Code, um das Problem zu beheben.
Das feste Code-Snippet sieht dann so aus:
@app.route('/delete-singer', methods=['DELETE', 'GET']) def delete_singer(): try: singer_id = request.args.get('singer_id')
- Testen Sie die Anwendung nach dem Neustart noch einmal, indem Sie versuchen, die Anwendung zu löschen.
- Beenden Sie die Fehlerbehebungssitzung durch Klicken auf das rote Quadrat in der Debugging-Symbolleiste
.
6. Bereinigen
Glückwunsch! In diesem Lab haben Sie eine neue Python-Anwendung von Grund auf erstellt und so konfiguriert, dass sie effektiv mit Containern funktioniert. Anschließend haben Sie Ihre Anwendung in einem Remote-GKE-Cluster bereitgestellt und entsprechende Fehler behoben. Dabei folgten Sie dem Entwicklerablauf, der auch in herkömmlichen Anwendungspaketen verwendet wird.
So bereinigen Sie nach Abschluss des Labs:
- Die im Lab verwendeten Dateien löschen
cd ~ && rm -rf container-developer-workshop
- Löschen Sie das Projekt, um alle zugehörigen Infrastrukturen und Ressourcen zu entfernen.