1. Przegląd
W tym laboratorium dowiesz się o funkcjach i możliwościach, które usprawniają przepływ pracy dla inżynierów oprogramowania, których zadaniem jest tworzenie aplikacji w Pythonie w środowisku skonteneryzowanym. Typowe tworzenie kontenerów wymaga od użytkownika znajomości szczegółów dotyczących kontenerów i procesu kompilacji kontenerów. Deweloperzy zwykle muszą też przerywać pracę i opuszczać IDE, aby testować i debugować aplikacje w środowiskach zdalnych. Dzięki narzędziom i technologiom wymienionym w tym samouczku deweloperzy mogą efektywnie pracować z aplikacjami w kontenerach bez opuszczania środowiska IDE.
Czego się nauczysz
W tym module poznasz metody tworzenia aplikacji w kontenerach w GCP, w tym:
- Tworzenie nowej aplikacji startowej w Pythonie
- Omów proces tworzenia
- Tworzenie prostej usługi REST CRUD
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
- Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.



- Nazwa projektu to wyświetlana nazwa uczestników tego projektu. Jest to ciąg znaków, który nie jest używany przez interfejsy API Google. Możesz go w dowolnym momencie zaktualizować.
- Identyfikator projektu musi być unikalny we wszystkich projektach Google Cloud i jest niezmienny (nie można go zmienić po ustawieniu). Konsola Cloud automatycznie generuje unikalny ciąg znaków. Zwykle nie musisz się nim przejmować. W większości modułów z kodem musisz odwoływać się do identyfikatora projektu (zwykle oznaczanego jako
PROJECT_ID). Jeśli Ci się nie podoba, wygeneruj inny losowy identyfikator lub spróbuj użyć własnego i sprawdź, czy jest dostępny. Po utworzeniu projektu jest on „zamrażany”. - Istnieje też trzecia wartość, czyli numer projektu, którego używają niektóre interfejsy API. Więcej informacji o tych 3 wartościach znajdziesz w dokumentacji.
- Następnie musisz włączyć płatności w konsoli Cloud, aby korzystać z zasobów i interfejsów API Google Cloud. Ukończenie tego laboratorium nie powinno wiązać się z dużymi kosztami, a nawet z żadnymi. Aby wyłączyć zasoby i uniknąć naliczenia opłat po zakończeniu tego samouczka, postępuj zgodnie z instrukcjami „czyszczenia” na końcu ćwiczenia. Nowi użytkownicy Google Cloud mogą skorzystać z bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.
Uruchamianie edytora Cloud Shell
To laboratorium zostało zaprojektowane i przetestowane pod kątem używania w edytorze Google Cloud Shell. Aby uzyskać dostęp do edytora:
- uzyskać dostęp do projektu Google na stronie https://console.cloud.google.com;
- W prawym górnym rogu kliknij ikonę edytora Cloud Shell.

- U dołu okna otworzy się nowy panel.
- Kliknij przycisk Otwórz edytor.

- Edytor otworzy się z eksploratorem po prawej stronie i edytorem w środkowej części.
- U dołu ekranu powinien być też dostępny panel terminala.
- Jeśli terminal NIE jest otwarty, użyj kombinacji klawiszy „Ctrl+`”, aby otworzyć nowe okno terminala.
Konfiguracja środowiska
W Cloud Shell ustaw identyfikator projektu i numer projektu. Zapisz je jako zmienne PROJECT_ID i PROJECT_ID.
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
--format='value(projectNumber)')
Pobieranie kodu źródłowego
- Kod źródłowy tego laboratorium znajduje się w repozytorium container-developer-workshop w GoogleCloudPlatform na GitHubie. Sklonuj go za pomocą poniższego polecenia, a następnie przejdź do katalogu.
git clone https://github.com/GoogleCloudPlatform/container-developer-workshop.git &&
cd container-developer-workshop/labs/python
mkdir music-service && cd music-service
cloudshell workspace .
Jeśli terminal NIE jest otwarty, użyj kombinacji klawiszy „Ctrl+`”, aby otworzyć nowe okno terminala.
wdrożyć infrastrukturę używaną w tym module;
W tym module wdrożysz kod w GKE i uzyskasz dostęp do danych przechowywanych w bazie danych Spanner. Poniższy skrypt konfiguracji przygotuje tę infrastrukturę. Proces obsługi administracyjnej potrwa ponad 10 minut. Podczas przetwarzania konfiguracji możesz przejść do kolejnych kroków.
../setup.sh
3. Tworzenie nowej aplikacji startowej w Pythonie
- Utwórz plik o nazwie
requirements.txti skopiuj do niego tę treść:
Flask
gunicorn
google-cloud-spanner
ptvsd==4.3.2
- Utwórz plik o nazwie
app.pyi wklej do niego ten kod:
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')
- Utwórz plik o nazwie Dockerfile i wklej do niego poniższy kod:
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"]
Uwaga: FLASK_DEBUG=1 umożliwia automatyczne ponowne wczytywanie zmian w kodzie aplikacji Flask w języku Python. Ten plik Dockerfile umożliwia przekazywanie tej wartości jako argumentu kompilacji.
Generowanie manifestów
W terminalu wykonaj to polecenie, aby wygenerować domyślne pliki skaffold.yaml i deployment.yaml:
- Zainicjuj Skaffold za pomocą tego polecenia:
skaffold init --generate-manifests
Gdy pojawi się prośba, użyj strzałek, aby przesunąć kursor, a spacji, aby wybrać opcje.
Wybierz:
8080dla portuy, aby zapisać konfigurację.
Aktualizowanie konfiguracji Skaffold
- Zmiana domyślnej nazwy aplikacji
- Otwórz:
skaffold.yaml - Wybierz nazwę obrazu, która jest obecnie ustawiona jako
dockerfile-image. - Kliknij prawym przyciskiem myszy i wybierz Zmień wszystkie wystąpienia.
- Wpisz nową nazwę w formacie
python-app. - Dalsze edytowanie sekcji kompilacji
- dodaj
docker.buildArgsdo kartyFLASK_DEBUG=1 - Synchronizowanie ustawień w celu wczytania zmian w plikach
*.pyz IDE do uruchomionego kontenera
Po wprowadzeniu zmian sekcja kompilacji w pliku skaffold.yaml będzie wyglądać tak:
build:
artifacts:
- image: python-app
docker:
buildArgs:
FLASK_DEBUG: 1
dockerfile: Dockerfile
sync:
infer:
- '**/*.py'
Modyfikowanie pliku konfiguracyjnego Kubernetes
- Zmiana domyślnej nazwy
- Otwórz plik
deployment.yaml - Wybierz nazwę obrazu, która jest obecnie ustawiona jako
dockerfile-image. - Kliknij prawym przyciskiem myszy i wybierz Zmień wszystkie wystąpienia.
- Wpisz nową nazwę w formacie
python-app.
4. Omówienie procesu tworzenia
Po dodaniu logiki biznesowej możesz wdrożyć i przetestować aplikację. W sekcji poniżej dowiesz się, jak korzystać z wtyczki Cloud Code. Ta wtyczka jest między innymi zintegrowana z narzędziem Skaffold, aby usprawnić proces tworzenia. Gdy w kolejnych krokach wdrożysz aplikację w GKE, Cloud Code i Skaffold automatycznie skompilują obraz kontenera, wypchną go do Container Registry, a następnie wdrożą aplikację w GKE. Dzieje się to w sposób niewidoczny, co pozwala deweloperowi skupić się na innych aspektach.
Wdrażanie w Kubernetes
- W panelu u dołu edytora Cloud Shell wybierz Cloud Code .

- W panelu, który pojawi się u góry, kliknij Uruchom w Kubernetes. Jeśli pojawi się taka prośba, wybierz Yes (Tak), aby użyć bieżącego kontekstu Kubernetes.

To polecenie rozpoczyna kompilację kodu źródłowego, a następnie uruchamia testy. Kompilacja i testy potrwają kilka minut. Obejmują one testy jednostkowe i etap weryfikacji, który sprawdza reguły ustawione dla środowiska wdrażania. Ten krok weryfikacji jest już skonfigurowany i zapewnia, że otrzymasz ostrzeżenie o problemach z wdrożeniem, nawet jeśli nadal pracujesz w środowisku programistycznym.
- Gdy po raz pierwszy uruchomisz to polecenie, u góry ekranu pojawi się pytanie, czy chcesz użyć bieżącego kontekstu Kubernetes. Aby zaakceptować i użyć bieżącego kontekstu, kliknij „Yes” (Tak).
- Następnie pojawi się pytanie o to, którego repozytorium kontenerów chcesz użyć. Naciśnij Enter, aby zaakceptować podaną wartość domyślną.
- Wybierz kartę Wyjście w dolnym panelu, aby wyświetlić postęp i powiadomienia.

- Aby wyświetlić dodatkowe szczegóły i logi przesyłane strumieniowo na żywo z kontenerów, w menu po prawej stronie wybierz „Kubernetes: Run/Debug - Detailed” (Kubernetes: uruchamianie/debugowanie – szczegółowe).

Po zakończeniu kompilacji i testów na karcie Wyniki pojawi się komunikat Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully., a adres URL http://localhost:8080 zostanie wyświetlony.
- W terminalu Cloud Code najedź kursorem na pierwszy adres URL w danych wyjściowych (http://localhost:8080), a następnie w wyświetlonej etykiecie narzędzia wybierz Otwórz podgląd w przeglądarce.
- Otworzy się nowa karta przeglądarki z komunikatem
Hello, World!.
Gorące przeładowanie
- Otwórz plik
app.py. - Zmień wiadomość powitalną na
Hello from Python
Zauważ, że w oknie Output, w widoku Kubernetes: Run/Debug, obserwator synchronizuje zaktualizowane pliki z kontenerem w Kubernetes.
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 ...
- Jeśli przejdziesz do widoku
Kubernetes: Run/Debug - Detailed, zauważysz, że rozpoznaje on zmiany w pliku, a następnie kompiluje i ponownie wdraża aplikację.
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
- Aby zobaczyć zaktualizowane wyniki, odśwież przeglądarkę.
Debugowanie
- Otwórz widok debugowania i zatrzymaj bieżący wątek
. - Kliknij
Cloud Codew menu u dołu i wybierzDebug on Kubernetes, aby uruchomić aplikację w trybiedebug.
- W widoku
Kubernetes Run/Debug - DetailedoknaOutputzauważ, że Skaffold wdroży tę aplikację w trybie debugowania.
- Przy pierwszym uruchomieniu pojawi się prompt z pytaniem, gdzie w kontenerze znajduje się źródło. Ta wartość jest powiązana z katalogami w pliku Dockerfile.
Aby zaakceptować wartość domyślną, naciśnij Enter.

Kompilacja i wdrożenie aplikacji zajmie kilka minut.
- Po zakończeniu procesu. Zauważysz, że dołączony jest debugger.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
- Dolny pasek stanu zmieni kolor z niebieskiego na pomarańczowy, co oznacza, że jest w trybie debugowania.
- W widoku
Kubernetes Run/Debugzobaczysz, że uruchomiono kontener z możliwością debugowania.
**************URLs***************** Forwarded URL from service python-app: http://localhost:8080 Debuggable container started pod/python-app-8bd64cf8b-cskfl:python-app (default) Update succeeded ***********************************
Wykorzystywanie punktów przerwania
- Otwórz plik
app.py. - Znajdź zdanie
return message - Dodaj punkt przerwania do tego wiersza, klikając puste miejsce po lewej stronie numeru wiersza. Pojawi się czerwony wskaźnik, który oznacza, że punkt przerwania został ustawiony.
- Odśwież przeglądarkę i zwróć uwagę, że debuger zatrzymuje proces w punkcie przerwania i umożliwia zbadanie zmiennych i stanu aplikacji, która jest uruchomiona zdalnie w GKE.
- Kliknij sekcję ZMIENNE.
- Kliknij Zmienne lokalne, aby znaleźć zmienną
"message". - Kliknij dwukrotnie nazwę zmiennej „message” i w wyskakującym okienku zmień wartość na inną, np.
"Greetings from Python" - W panelu sterowania debugowaniem kliknij przycisk Dalej.

- Sprawdź odpowiedź w przeglądarce, w której powinna się teraz wyświetlać wpisana przez Ciebie zaktualizowana wartość.
- Zatrzymaj tryb „Debugowanie”, naciskając przycisk zatrzymania
, i usuń punkt przerwania, klikając go ponownie.
5. Tworzenie prostej usługi REST CRUD
Na tym etapie aplikacja jest w pełni skonfigurowana pod kątem tworzenia skonteneryzowanych aplikacji, a Ty znasz już podstawowy przepływ pracy programisty w Cloud Code. W kolejnych sekcjach przećwiczysz zdobytą wiedzę, dodając punkty końcowe usługi REST, które łączą się z zarządzaną bazą danych w Google Cloud.
Kodowanie usługi REST
Poniższy kod tworzy prostą usługę REST, która używa Spannera jako bazy danych obsługującej aplikację. Utwórz aplikację, kopiując do niej ten kod.
- Utwórz główną aplikację, zastępując
app.pyponiższą treścią.
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)
Dodawanie konfiguracji bazy danych
Aby bezpiecznie połączyć się z usługą Spanner, skonfiguruj aplikację tak, aby korzystała z tożsamości obciążeń. Dzięki temu aplikacja może działać jako własne konto usługi i mieć indywidualne uprawnienia dostępu do bazy danych.
- Zaktualizuj urządzenie
deployment.yaml. Na końcu pliku dodaj ten kod (pamiętaj, aby zachować wcięcia w przykładzie poniżej):
serviceAccountName: python-ksa
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: "true"
Wdrażanie i weryfikowanie aplikacji
- W panelu u dołu edytora Cloud Shell kliknij
Cloud Code, a następnie u góry ekranu kliknijDebug on Kubernetes. - Po zakończeniu kompilacji i testów na karcie Wyniki pojawi się komunikat
Resource deployment/python-app status completed successfullyi adres URL: „Forwarded URL from service python-app: http://localhost:8080”. - Dodaj kilka wpisów.
W terminalu Cloud Shell uruchom to polecenie:
curl -X POST http://localhost:8080/singer -H 'Content-Type: application/json' -d '{"first_name":"Cat","last_name":"Meow", "singer_id": 6}'
- Przetestuj żądanie GET, uruchamiając w terminalu to polecenie:
curl -X GET http://localhost:8080/singer?singer_id=6
- Testowanie usuwania: spróbuj teraz usunąć wpis, uruchamiając to polecenie. W razie potrzeby zmień wartość identyfikatora produktu.
curl -X DELETE http://localhost:8080/singer?singer_id=6
This throws an error message
500 Internal Server Error
Identyfikowanie i rozwiązywanie problemu
- Użyj trybu debugowania, aby znaleźć problem. Oto kilka porad:
- Wiemy, że z poleceniem DELETE jest coś nie tak, ponieważ nie zwraca ono oczekiwanego wyniku. Punkt przerwania należy ustawić w
app.pyw metodziedelete_singer. - Uruchom wykonywanie krok po kroku i obserwuj zmienne na każdym etapie, aby zobaczyć wartości zmiennych lokalnych w oknie po lewej stronie.
- Aby obserwować konkretne wartości, takie jak
singer_idirequest.args, dodaj te zmienne do okna Obserwuj.
- Zwróć uwagę, że wartość przypisana do
singer_idtoNone. Aby rozwiązać problem, zmień kod.
Poprawiony fragment kodu będzie wyglądać tak:
@app.route('/delete-singer', methods=['DELETE', 'GET'])
def delete_singer():
try:
singer_id = request.args.get('singer_id')
- Po ponownym uruchomieniu aplikacji spróbuj usunąć plik.
- Zakończ sesję debugowania, klikając czerwony kwadrat na pasku narzędzi debugowania
.
6. Czyszczenie
Gratulacje! W tym module udało Ci się utworzyć od podstaw nową aplikację w Pythonie i skonfigurować ją tak, aby skutecznie działała z kontenerami. Następnie wdrożyliśmy i debugowaliśmy aplikację w zdalnym klastrze GKE, korzystając z tego samego przepływu pracy dewelopera, który jest stosowany w tradycyjnych stosach aplikacji.
Aby zwolnić miejsce po ukończeniu modułu:
- Usuwanie plików użytych w laboratorium
cd ~ && rm -rf container-developer-workshop
- Usuwanie projektu w celu usunięcia całej powiązanej infrastruktury i zasobów