1. Omówienie
W tym module przedstawiamy funkcje i możliwości zaprojektowane w celu usprawnienia procesu programowania dla inżynierów, których zadaniem jest tworzenie aplikacji w języku Python w skonteneryzowanym środowisku. Typowe tworzenie kontenerów wymaga, aby użytkownik znał szczegóły kontenerów i proces ich tworzenia. Poza tym deweloperzy zwykle muszą przerwać przepływ pracy, wychodząc z IDE, aby przetestować i debugować aplikacje w środowiskach zdalnych. Dzięki narzędziom i technologiom wspomnianym w tym samouczku deweloperzy mogą wydajnie pracować z aplikacjami skonteneryzowanymi bez opuszczania IDE.
Czego się nauczysz
W tym module nauczysz się, jak tworzyć aplikacje z wykorzystaniem kontenerów w GCP, takich jak:
- Tworzenie nowej aplikacji startowej w języku Python
- Omów proces programowania.
- Opracuj prostą usługę przechowywania CRUD
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
- Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub wykorzystaj już istniejący. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.
- Nazwa projektu jest wyświetlaną nazwą uczestników tego projektu. To ciąg znaków, który nie jest używany przez interfejsy API Google i w każdej chwili możesz go zaktualizować.
- Identyfikator projektu musi być unikalny we wszystkich projektach Google Cloud i nie można go zmienić (nie można go zmienić po ustawieniu). Cloud Console automatycznie wygeneruje unikalny ciąg znaków. zwykle nieważne, co ona jest. W większości ćwiczeń w Codelabs musisz odwoływać się do identyfikatora projektu (który zwykle nazywa się
PROJECT_ID
), więc jeśli Ci się nie podoba, wygeneruj kolejny losowy projekt lub wypróbuj swój własny identyfikator i sprawdź, czy jest dostępny. Potem urządzenie jest „zawieszone”. po utworzeniu projektu. - Występuje trzecia wartość – numer projektu – używany przez niektóre interfejsy API. Więcej informacji o wszystkich 3 wartościach znajdziesz w dokumentacji.
- Następnie musisz włączyć płatności w konsoli Cloud, aby móc korzystać z zasobów i interfejsów API Cloud. Ukończenie tego ćwiczenia z programowania nie powinno kosztować zbyt wiele. Aby wyłączyć zasoby, aby nie naliczać opłat po zakończeniu tego samouczka, wykonaj czynności „wyczyść” znajdziesz na końcu tego ćwiczenia. Nowi użytkownicy Google Cloud mogą skorzystać z programu bezpłatnego okresu próbnego o wartości 300 USD.
Uruchom edytor Cloud Shell
Ten moduł został opracowany i przetestowany pod kątem użycia z edytorem Google Cloud Shell. Aby uzyskać dostęp do edytora:
- wejdź na stronę swojego projektu Google na https://console.cloud.google.com.
- W prawym górnym rogu kliknij ikonę edytora Cloud Shell.
- Na dole okna otworzy się nowy panel
- Kliknij przycisk Otwórz edytor
- Edytor otworzy się z eksploratorem po prawej stronie i edytorem w obszarze środkowym.
- Okienko terminala powinno być też dostępne u dołu ekranu
- Jeśli terminal NIE jest otwarty, użyj kombinacji klawiszy „Ctrl+”, aby otworzyć nowe okno terminala
Konfiguracja środowiska
W Cloud Shell ustaw identyfikator 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 modułu znajduje się w module container-developer-workshop w GoogleCloudPlatform na GitHubie. Skopiuj 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
Udostępnij 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 przygotowuje dla Ciebie tę infrastrukturę. Proces obsługi administracyjnej potrwa ponad 10 minut. W trakcie przetwarzania możesz kontynuować wykonywanie kilku kolejnych czynności.
../setup.sh
3. Tworzenie nowej aplikacji startowej w języku Python
- Utwórz plik o nazwie
requirements.txt
i skopiuj do niego tę zawartość
Flask
gunicorn
google-cloud-spanner
ptvsd==4.3.2
- Utwórz plik o nazwie
app.py
i 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 plik.
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 ładowanie zmian kodu w aplikacji w Pythonie na kolbę. Ten plik Dockerfile pozwala przekazać tę wartość jako argument kompilacji.
Generuj pliki manifestu
Wykonaj w terminalu to polecenie, aby wygenerować domyślny plik skaffold.yaml i deploy.yaml.
- Zainicjuj Skaffold za pomocą tego polecenia
skaffold init --generate-manifests
Gdy pojawi się prośba, użyj strzałek, aby poruszać kursorem, a spację, aby wybrać opcje.
Wybierz:
8080
za porty
, aby zapisać konfigurację.
Aktualizowanie konfiguracji Skaffold
- Zmień domyślną nazwę aplikacji
- Otwórz:
skaffold.yaml
- Wybierz nazwę obrazu, który jest obecnie ustawiony jako
dockerfile-image
- Kliknij prawym przyciskiem myszy i wybierz Zmień wszystkie wystąpienia
- Wpisz nową nazwę jako
python-app
- Zmodyfikuj sekcję kompilacji, tak aby była
- dodaj
docker.buildArgs
, aby wjechać do firmyFLASK_DEBUG=1
- Zsynchronizuj ustawienia, aby wczytać wszelkie zmiany w plikach
*.py
z 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'
Zmodyfikuj plik konfiguracji Kubernetes
- Zmiana nazwy domyślnej
- Otwórz plik
deployment.yaml
- Wybierz nazwę obrazu, który jest obecnie ustawiony jako
dockerfile-image
- Kliknij prawym przyciskiem myszy i wybierz Zmień wszystkie wystąpienia
- Wpisz nową nazwę jako
python-app
4. Omówienie procesu programowania
Dzięki dodanej logice biznesowej możesz teraz wdrożyć i przetestować aplikację. W następnej sekcji omówiono korzystanie z wtyczki Cloud Code. Integruje się ona między innymi ze skaffold, aby usprawnić proces programowania. Gdy wdrożysz obraz kontenera w GKE w poniższych krokach, Cloud Code i Skaffold automatycznie skompilują obraz kontenera, wypchnie go do Container Registry, a następnie wdroży aplikację w GKE. Dzieje się to za kulisami, odbierając szczegóły od procesu deweloperskiego.
Wdróż 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. W razie potrzeby wybierz Tak, aby użyć bieżącego kontekstu Kubernetes.
To polecenie uruchamia kompilację kodu źródłowego, a następnie uruchamia testy. Kompilacja i testy potrwają kilka minut. Te testy obejmują testy jednostkowe oraz etap weryfikacji, który sprawdza reguły ustawione dla środowiska wdrożenia. Ten etap weryfikacji jest już skonfigurowany i dzięki temu ostrzeżemy Cię o problemach z wdrożeniem, nawet jeśli nadal pracujesz w środowisku programistycznym.
- Przy pierwszym uruchomieniu polecenia u góry ekranu pojawi się prompt z pytaniem, czy chcesz uzyskać bieżący kontekst Kubernetes. Wybierz „Tak”. aby zaakceptować i wykorzystać bieżący kontekst.
- Pojawi się pytanie, którego rejestru kontenerów użyć. Naciśnij Enter, aby zaakceptować podaną wartość domyślną
- Wybierz kartę Wyniki w dolnym panelu, aby zobaczyć postęp i powiadomienia.
- Wybierz „Kubernetes: Run/Debug - detail”. w menu kanału po prawej stronie, aby wyświetlić dodatkowe szczegóły i logi, które są przesyłane na żywo z kontenerów.
Po zakończeniu kompilacji i testów na karcie Dane wyjściowe pojawi się komunikat Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully.
i wyświetli się adres URL http://localhost:8080.
- W terminalu Cloud Code najedź kursorem na pierwszy adres URL w danych wyjściowych (http://localhost:8080), a następnie w wyświetlonej wskazówce narzędzia wybierz Otwórz podgląd w przeglądarce.
- Otworzy się nowa karta przeglądarki i wyświetli się na niej wiadomość:
Hello, World!
Ponowne załadowanie „na gorąco”
- Otwórz plik
app.py
. - Zmień wiadomość powitalną na
Hello from Python
Od razu zauważysz, że w oknie Output
, 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 przełączysz się na widok
Kubernetes: Run/Debug - Detailed
, zauważysz, że rozpoznaje zmiany w plikach, a następnie skompiluje i ponownie wdroży 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 Code
w dolnym menu i wybierzDebug on Kubernetes
, aby uruchomić aplikację w trybiedebug
.
- W widoku
Kubernetes Run/Debug - Detailed
oknaOutput
zwróć uwagę, że skaffold wdroży tę aplikację w trybie debugowania.
- Przy pierwszym uruchomieniu pojawi się pytanie, gdzie w kontenerze znajduje się źródło. Ta wartość jest powiązana z katalogami w pliku Dockerfile.
Naciśnij Enter, aby zaakceptować domyślną wartość
Skompilowanie i wdrożenie aplikacji zajmie kilka minut.
- Po zakończeniu procesu. W połączeniu pojawi się debuger.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
- Kolor dolnego paska stanu zmieni się z niebieskiego na pomarańczowy, co oznacza, że urządzenie działa w trybie debugowania.
- Zwróć uwagę na to, że w widoku
Kubernetes Run/Debug
został uruchomiony 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 ***********************************
Wykorzystuj punkty przerwania
- Otwórz plik
app.py
. - Znajdź instrukcję, która brzmi:
return message
- Dodaj do tego wiersza punkt przerwania, klikając puste miejsce po lewej stronie numeru wiersza. Pojawi się czerwony wskaźnik informujący o ustawieniu punktu przerwania
- Załaduj ponownie przeglądarkę. Pamiętaj, że debuger zatrzymuje proces w punkcie przerwania i umożliwia zbadanie zmiennych oraz stanu aplikacji uruchomionej zdalnie w GKE.
- Kliknij w dół do sekcji ZMIENNE
- Kliknij przycisk Lokalne. Znajdziesz tam zmienną
"message"
. - Kliknij dwukrotnie zmienną o nazwie „wiadomość”. i w wyskakującym okienku zmień wartość na inną, np.
"Greetings from Python"
. - Kliknij przycisk Dalej w panelu sterowania debugowania
.
- Sprawdź odpowiedź w przeglądarce, w której wyświetla się wprowadzona przed chwilą zaktualizowana wartość.
- Zatrzymaj „Debugowanie” naciśnij przycisk zatrzymania
i usuń punkt przerwania, ponownie klikając go.
5. Opracowanie usługi spoczynku CRUD
Na tym etapie Twoja aplikacja jest w pełni skonfigurowana do programowania skonteneryzowanego i masz już za sobą podstawowy przepływ pracy programistyczny w Cloud Code. W kolejnych sekcjach przećwiczysz zdobyte informacje, dodając punkty końcowe usługi spoczynkowej łączące się z zarządzaną bazą danych w Google Cloud.
Zakoduj resztę usługi
Poniższy kod tworzy prostą usługę spoczynku, która używa Spannera jako bazy danych jako kopii zapasowej aplikacji. Utwórz aplikację, kopiując do niej poniższy kod.
- Utwórz główną aplikację, zastępując fragment
app.py
następującą 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)
Dodaj konfiguracje bazy danych
Aby połączyć się z usługą Spanner w bezpieczny sposób, skonfiguruj aplikację pod kątem korzystania z tożsamości zadań. Dzięki temu aplikacja może działać jako własne konto usługi i mieć indywidualne uprawnienia podczas uzyskiwania dostępu do bazy danych.
- Zaktualizuj urządzenie
deployment.yaml
. Dodaj następujący kod na końcu pliku (pamiętaj, aby zachować wcięcia tabulacji w przykładzie poniżej)
serviceAccountName: python-ksa
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: "true"
Wdróż i zweryfikuj aplikację
- W panelu u dołu edytora Cloud Shell kliknij
Cloud Code
, a następnie wybierzDebug on Kubernetes
u góry ekranu. - Po zakończeniu kompilacji i testów na karcie Dane wyjściowe pojawi się komunikat
Resource deployment/python-app status completed successfully
i wyświetli się adres URL: „Przekierowany adres URL z usługi python-app: http://localhost:8080” - Dodaj kilka wpisów.
W terminalu Cloud Shell uruchom poniższe polecenie
curl -X POST http://localhost:8080/singer -H 'Content-Type: application/json' -d '{"first_name":"Cat","last_name":"Meow", "singer_id": 6}'
- Przetestuj metodę GET, uruchamiając poniższe polecenie w terminalu
curl -X GET http://localhost:8080/singer?singer_id=6
- Testowanie usuwania: teraz spróbuj usunąć wpis, uruchamiając następujące polecenie. W razie potrzeby zmień wartość parametru item-id.
curl -X DELETE http://localhost:8080/singer?singer_id=6
This throws an error message
500 Internal Server Error
Zidentyfikuj i rozwiąż problem
- Włącz tryb debugowania i znajdź problem. Oto kilka porad:
- Wiemy, że coś jest nie tak z funkcją DELETE, ponieważ nie zwraca ona oczekiwanych wyników. Punkt przerwania należy więc ustawić w metodzie
delete_singer
w metodzieapp.py
. - Uruchom wykonanie krok po kroku i obserwuj zmienne w każdym kroku, aby obserwować wartości zmiennych lokalnych w lewym oknie.
- Aby obserwować określone wartości, takie jak
singer_id
irequest.args
, dodaj te zmienne do okna odtwarzania filmu.
- Zwróć uwagę, że atrybut
singer_id
ma wartośćNone
. Zmień kod, aby rozwiązać problem.
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 przetestuj ją jeszcze raz, próbując ją usunąć.
- Zatrzymaj sesję debugowania, klikając czerwony kwadrat
na pasku narzędzi debugowania
6. Czyszczenie
Gratulacje! W tym module udało Ci się utworzyć od zera nową aplikację w Pythonie i skonfigurować ją tak, aby wydajnie współpracowała z kontenerami. Następnie wdrożono i debugowałeś(-aś) aplikację w zdalnym klastrze GKE, postępując zgodnie z procedurą programistyczną obowiązującą w tradycyjnych stosach aplikacji.
Aby posprzątać po ukończeniu modułu:
- Usuń pliki używane w module
cd ~ && rm -rf container-developer-workshop
- Usuń projekt, aby usunąć całą powiązaną infrastrukturę i zasoby