1. Przegląd
Microsoft .NET Core to wersja .NET typu open source, która działa na wielu platformach i może działać natywnie w kontenerach. Platforma .NET Core jest dostępna na GitHubie i jest utrzymywana przez Microsoft oraz społeczność .NET. W tym module wdrożysz skonteneryzowaną aplikację .NET Core w Google Kubernetes Engine (GKE).
W tym module przedstawiono typowy wzorzec programistyczny, w którym aplikacje są tworzone w lokalnym środowisku programisty, a następnie wdrażane w środowisku produkcyjnym. W pierwszej części modułu przykładowa aplikacja .NET Core jest sprawdzana za pomocą kontenera działającego w Cloud Shell. Po sprawdzeniu aplikacja jest wdrażana w Kubernetes za pomocą GKE. Moduł zawiera instrukcje tworzenia klastra GKE.
W drugiej części modułu wprowadzimy w aplikacji niewielką zmianę, która spowoduje wyświetlanie nazwy hosta kontenera, w którym działa instancja aplikacji. Zaktualizowana aplikacja jest następnie sprawdzana w Cloud Shell, a wdrożenie jest aktualizowane, aby używać nowej wersji. Ilustracja poniżej przedstawia sekwencję działań w tym module:

Koszty
Jeśli wykonasz ten moduł dokładnie według instrukcji, zostaną naliczone standardowe opłaty za te usługi:
2. Konfiguracja i wymagania
Wymagania wstępne
Do ukończenia tego modułu wymagane są konto i projekt Google Cloud. Szczegółowe instrukcje tworzenia nowego projektu znajdziesz w tym ćwiczeniu z programowania.
W tym module używamy Dockera działającego w Cloud Shell, który jest dostępny w konsoli Google Cloud i jest wstępnie skonfigurowany z wieloma przydatnymi narzędziami, takimi jak gcloud i Docker. Poniżej pokazano, jak uzyskać dostęp do Cloud Shell. Kliknij ikonę Cloud Shell w prawym górnym rogu, aby wyświetlić Cloud Shell w dolnym panelu okna konsoli.

Alternatywne opcje konfiguracji klastra GKE (opcjonalnie)
To laboratorium wymaga klastra Kubernetes. W następnej sekcji utworzysz klaster GKE o prostej konfiguracji. W tej sekcji przedstawiono niektóre polecenia gcloud, które udostępniają alternatywne opcje konfiguracji do użycia podczas tworzenia klastra Kubernetes za pomocą GKE. Na przykład za pomocą poniższych poleceń można zidentyfikować różne typy maszyn, strefy, a nawet GPU (akceleratory).
- Wyświetl listę typów maszyn za pomocą tego polecenia:
gcloud compute machine-types list - Wyświetl listę GPU za pomocą tego polecenia:
gcloud compute accelerator-types list - Wyświetl listę stref obliczeniowych za pomocą tego polecenia:
gcloud compute zones list - Uzyskiwanie pomocy dotyczącej dowolnego polecenia gcloud
gcloud container clusters --help- Na przykład ten artykuł zawiera szczegółowe informacje o tworzeniu klastra Kubernetes:
gcloud container clusters create --help
- Na przykład ten artykuł zawiera szczegółowe informacje o tworzeniu klastra Kubernetes:
Pełną listę opcji konfiguracji GKE znajdziesz w tym dokumencie.
Przygotowanie do utworzenia klastra Kubernetes
W Cloud Shell musisz ustawić pewne zmienne środowiskowe i skonfigurować klienta gcloud. Możesz to zrobić za pomocą tych poleceń.
export PROJECT_ID=YOUR_PROJECT_ID
export DEFAULT_ZONE=us-central1-c
gcloud config set project ${PROJECT_ID}
gcloud config set compute/zone ${DEFAULT_ZONE}
Tworzenie klastra GKE
Ponieważ w tym module aplikacja .NET Core jest wdrażana w Kubernetes, musisz utworzyć klaster. Użyj tego polecenia, aby utworzyć nowy klaster Kubernetes w Google Cloud za pomocą GKE.
gcloud container clusters create dotnet-cluster \
--zone ${DEFAULT_ZONE} \
--num-nodes=1 \
--node-locations=${DEFAULT_ZONE},us-central1-b \
--enable-stackdriver-kubernetes \
--machine-type=n1-standard-1 \
--workload-pool=${PROJECT_ID}.svc.id.goog \
--enable-ip-alias
--num-nodesto liczba węzłów do dodania na strefę, którą można później skalować.--node-locationsto lista stref rozdzielona przecinkami. W tym przypadku używana jest strefa określona w zmiennej środowiskowej powyżej orazus-central1-b.- UWAGA: ta lista nie może zawierać duplikatów.
--workload-poolustanawia Workload Identity, dzięki czemu zadania GKE mogą uzyskiwać dostęp do usług Google Cloud
Podczas tworzenia klastra wyświetlany jest ten komunikat:
Creating cluster dotnet-cluster in us-central1-b... Cluster is being deployed...⠼
Konfigurowanie kubectl
Interfejs wiersza poleceń kubectl to podstawowy sposób interakcji z klastrem Kubernetes. Aby używać go z nowo utworzonym klastrem, musisz skonfigurować uwierzytelnianie w klastrze. Możesz to zrobić za pomocą tego polecenia.
$ gcloud container clusters get-credentials dotnet-cluster --zone ${DEFAULT_ZONE}
Fetching cluster endpoint and auth data.
kubeconfig entry generated for dotnet-cluster.
Teraz powinno być możliwe używanie kubectl do interakcji z klastrem.
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
gke-dotnet-cluster-default-pool-02c9dcb9-fgxj Ready <none> 2m15s v1.16.13-gke.401
gke-dotnet-cluster-default-pool-ed09d7b7-xdx9 Ready <none> 2m24s v1.16.13-gke.401
3. Przetestuj lokalnie i potwierdź oczekiwane działanie.
W tym module używane są te obrazy kontenerów z oficjalnego repozytorium .NET w Docker Hub.
Uruchamianie kontenera lokalnie w celu sprawdzenia funkcjonalności
W Cloud Shell sprawdź, czy Docker działa prawidłowo i czy kontener .NET działa zgodnie z oczekiwaniami, uruchamiając to polecenie Dockera:
$ docker run --rm mcr.microsoft.com/dotnet/samples
Hello from .NET!
__________________
\
\
....
....'
....
..........
.............'..'..
................'..'.....
.......'..........'..'..'....
........'..........'..'..'.....
.'....'..'..........'..'.......'.
.'..................'... ......
. ......'......... .....
. ......
.. . .. ......
.... . .......
...... ....... ............
................ ......................
........................'................
......................'..'...... .......
.........................'..'..... .......
........ ..'.............'..'.... ..........
..'..'... ...............'....... ..........
...'...... ...... .......... ...... .......
........... ....... ........ ......
....... '...'.'. '.'.'.' ....
....... .....'.. ..'.....
.. .......... ..'........
............ ..............
............. '..............
...........'.. .'.'............
............... .'.'.............
.............'.. ..'..'...........
............... .'..............
......... ..............
.....
Environment:
.NET 5.0.1-servicing.20575.16
Linux 5.4.58-07649-ge120df5deade #1 SMP PREEMPT Wed Aug 26 04:56:33 PDT 2020
Potwierdzanie funkcji aplikacji internetowej
Przykładową aplikację internetową można też sprawdzić w Cloud Shell. Poniższe polecenie Docker run tworzy nowy kontener, który udostępnia port 80 i mapuje go na port 8080 localhost. Pamiętaj, że w tym przypadku localhost znajduje się w Cloud Shell.
$ docker run -it --rm -p 8080:80 --name aspnetcore_sample mcr.microsoft.com/dotnet/samples:aspnetapp
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
No XML encryptor configured. Key {64a3ed06-35f7-4d95-9554-8efd38f8b5d3} may be persisted to storage in unencrypted form.
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://[::]:80
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
Content root path: /app
Ponieważ jest to aplikacja internetowa, należy ją wyświetlić i zweryfikować w przeglądarce. W następnej sekcji dowiesz się, jak to zrobić w Cloud Shell za pomocą podglądu w przeglądarce.
4. Uzyskiwanie dostępu do usług z Cloud Shell za pomocą „Podglądu w przeglądarce”
Cloud Shell oferuje podgląd w przeglądarce, czyli funkcję, która umożliwia korzystanie z przeglądarki do interakcji z procesami uruchomionymi w instancji Cloud Shell.
Wyświetlanie aplikacji w Cloud Shell za pomocą funkcji „Podgląd w przeglądarce”
W Cloud Shell kliknij przycisk podglądu w przeglądarce i wybierz „Podejrzyj na porcie 8080” (lub na porcie, który jest ustawiony dla podglądu w przeglądarce).

Otworzy się okno przeglądarki z adresem podobnym do tego:
https://8080-cs-754738286554-default.us-central1.cloudshell.dev/
Wyświetlanie przykładowej aplikacji .NET za pomocą podglądu w przeglądarce
Przykładową aplikację, która została uruchomiona w ostatnim kroku, można teraz wyświetlić, uruchamiając podgląd w przeglądarce i wczytując podany adres URL. Powinna wyglądać mniej więcej tak:

5. Wdrażanie w Kubernetes
Utwórz plik YAML i zastosuj go
Następny krok wymaga pliku YAML opisującego 2 zasoby Kubernetes: wdrożenie i usługę. Utwórz w Cloud Shell plik o nazwie dotnet-app.yaml i dodaj do niego tę treść.
apiVersion: apps/v1
kind: Deployment
metadata:
name: dotnet-deployment
labels:
app: dotnetapp
spec:
replicas: 3
selector:
matchLabels:
app: dotnetapp
template:
metadata:
labels:
app: dotnetapp
spec:
containers:
- name: dotnet
image: mcr.microsoft.com/dotnet/samples:aspnetapp
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: dotnet-service
spec:
selector:
app: dotnetapp
ports:
- protocol: TCP
port: 8080
targetPort: 80
Teraz użyj kubectl, aby zastosować ten plik do Kubernetes.
$ kubectl apply -f dotnet-app.yaml
deployment.apps/dotnet-deployment created
service/dotnet-service created
Zwróć uwagę na komunikaty informujące o utworzeniu odpowiednich zasobów.
Przeglądanie utworzonych zasobów
Możemy użyć interfejsu wiersza poleceń kubectl, aby sprawdzić zasoby utworzone powyżej. Najpierw przyjrzyjmy się zasobom wdrożenia i sprawdźmy, czy nowe wdrożenie jest widoczne.
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
dotnet-deployment 3/3 3 3 80s
Następnie przyjrzyj się zbiorom ReplicaSet. Wdrożenie powinno utworzyć obiekt ReplicaSet.
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
dotnet-deployment-5c9d4cc4b9 3 3 3 111s
Na koniec przyjrzyj się podom. Wdrożenie wskazywało, że powinny być 3 instancje. Polecenie poniżej powinno pokazać, że istnieją 3 instancje. Dodano opcję -o wide, aby wyświetlić węzły, na których działają te instancje.
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dotnet-deployment-5c9d4cc4b9-cspqd 1/1 Running 0 2m25s 10.16.0.8 gke-dotnet-cluster-default-pool-ed09d7b7-xdx9 <none> <none>
dotnet-deployment-5c9d4cc4b9-httw6 1/1 Running 0 2m25s 10.16.1.7 gke-dotnet-cluster-default-pool-02c9dcb9-fgxj <none> <none>
dotnet-deployment-5c9d4cc4b9-vvdln 1/1 Running 0 2m25s 10.16.0.7 gke-dotnet-cluster-default-pool-ed09d7b7-xdx9 <none> <none>
Sprawdzanie zasobu usługi
Zasób Service w Kubernetes to system równoważenia obciążenia. Punkty końcowe są określane przez etykiety podów. Dzięki temu, gdy tylko nowe pody zostaną dodane do wdrożenia za pomocą powyższej operacji kubectl scale deployment, będą one natychmiast dostępne dla żądań obsługiwanych przez tę usługę.
To polecenie powinno wyświetlić zasób usługi.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dotnet-service ClusterIP 10.20.9.124 <none> 8080/TCP 2m50s
...
Możesz wyświetlić więcej szczegółów na temat usługi za pomocą tego polecenia.
$ kubectl describe svc dotnet-service
Name: dotnet-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=dotnetapp
Type: ClusterIP
IP: 10.20.9.124
Port: <unset> 8080/TCP
TargetPort: 80/TCP
Endpoints: 10.16.0.7:80,10.16.0.8:80,10.16.1.7:80
Session Affinity: None
Events: <none>
Zwróć uwagę, że usługa jest typu ClusterIP. Oznacza to, że dowolny pod w klastrze może rozpoznać nazwę usługi dotnet-service na jej adres IP. Żądania wysyłane do usługi będą równoważone pod względem obciążenia we wszystkich instancjach (podach). Wartość Endpoints powyżej pokazuje adresy IP podów obecnie dostępnych dla tej usługi. Porównaj je z adresami IP podów, które zostały wyświetlone powyżej.
Sprawdzanie działającej aplikacji
W tym momencie aplikacja jest aktywna i gotowa do obsługi żądań użytkowników. Aby uzyskać do niego dostęp, użyj serwera proxy. To polecenie tworzy lokalny serwer proxy, który akceptuje żądania na porcie 8080 i przekazuje je do klastra Kubernetes.
$ kubectl proxy --port 8080
Starting to serve on 127.0.0.1:8080
Teraz użyj podglądu w przeglądarce w Cloud Shell, aby uzyskać dostęp do aplikacji internetowej.
Dodaj do adresu URL wygenerowanego przez podgląd w przeglądarce: /api/v1/namespaces/default/services/dotnet-service:8080/proxy/. Będzie to wyglądać mniej więcej tak:
https://8080-cs-473655782854-default.us-central1.cloudshell.dev/api/v1/namespaces/default/services/dotnet-service:8080/proxy/
Gratulujemy wdrożenia aplikacji .NET Core w Google Kubernetes Engine. Teraz wprowadzimy zmianę w aplikacji i wdrożymy ją ponownie.
6. Modyfikowanie aplikacji
W tej sekcji zmodyfikujemy aplikację, aby wyświetlała hosta, na którym działa instancja. Dzięki temu będzie można potwierdzić, że równoważenie obciążenia działa, a dostępne pody odpowiadają zgodnie z oczekiwaniami.
Pobieranie kodu źródłowego
git clone https://github.com/dotnet/dotnet-docker.git
cd dotnet-docker/samples/aspnetapp/
Zaktualizuj aplikację, aby zawierała nazwę hosta
vi aspnetapp/Pages/Index.cshtml
<tr>
<td>Host</td>
<td>@Environment.MachineName</td>
</tr>
Tworzenie nowego obrazu kontenera i testowanie lokalne
Utwórz nowy obraz kontenera ze zaktualizowanym kodem.
docker build --pull -t aspnetapp:alpine -f Dockerfile.alpine-x64 .
Tak jak wcześniej, przetestuj nową aplikację lokalnie.
$ docker run --rm -it -p 8080:80 aspnetapp:alpine
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
No XML encryptor configured. Key {f71feb13-8eae-4552-b4f2-654435fff7f8} may be persisted to storage in unencrypted form.
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://[::]:80
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
Content root path: /app
Tak jak wcześniej, dostęp do aplikacji można uzyskać za pomocą podglądu w przeglądarce. Tym razem parametr Host powinien być widoczny, jak pokazano tutaj:

Otwórz nową kartę w Cloud Shell i uruchom docker ps, aby sprawdzić, czy identyfikator kontenera jest zgodny z wartością hosta wyświetlaną powyżej.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ab85ce11aecd aspnetapp:alpine "./aspnetapp" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp relaxed_northcutt
Dodawanie tagu do obrazu i przesyłanie go, aby był dostępny dla Kubernetes
Aby Kubernetes mógł pobrać obraz, musi on zostać otagowany i przesłany. Zacznij od wyświetlenia listy obrazów kontenerów i znajdź odpowiedni obraz.
$ docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
aspnetapp alpine 95b4267bb6d0 6 days ago 110MB
Następnie dodaj tag do tego obrazu i prześlij go do Google Container Registry. Jeśli użyjesz identyfikatora obrazu podanego powyżej, będzie to wyglądać tak:
docker tag 95b4267bb6d0 gcr.io/${PROJECT_ID}/aspnetapp:alpine
docker push gcr.io/${PROJECT_ID}/aspnetapp:alpine
7. Ponowne wdrażanie zaktualizowanej aplikacji
Edytowanie pliku YAML
Wróć do katalogu, w którym zapisany jest plik dotnet-app.yaml. Znajdź w pliku YAML ten wiersz:
image: mcr.microsoft.com/dotnet/core/samples:aspnetapp
Należy to zmienić, aby odwoływać się do obrazu kontenera, który został utworzony i przesłany do gcr.io powyżej.
image: gcr.io/PROJECT_ID/aspnetapp:alpine
Pamiętaj, aby zmodyfikować go tak, aby używał Twojego PROJECT_ID. Po zakończeniu powinno to wyglądać mniej więcej tak:
image: gcr.io/myproject/aspnetapp:alpine
Zastosowanie zaktualizowanego pliku YAML
$ kubectl apply -f dotnet-app.yaml
deployment.apps/dotnet-deployment configured
service/dotnet-service unchanged
Zwróć uwagę, że zasób Deployment jest zaktualizowany, a zasób Service nie został zmieniony. Zaktualizowane pody można wyświetlić tak jak wcześniej za pomocą polecenia kubectl get pod, ale tym razem dodamy -w, co pozwoli na obserwowanie wszystkich zmian w miarę ich wprowadzania.
$ kubectl get pod -w
NAME READY STATUS RESTARTS AGE
dotnet-deployment-5c9d4cc4b9-cspqd 1/1 Running 0 34m
dotnet-deployment-5c9d4cc4b9-httw6 1/1 Running 0 34m
dotnet-deployment-5c9d4cc4b9-vvdln 1/1 Running 0 34m
dotnet-deployment-85f6446977-tmbdq 0/1 ContainerCreating 0 4s
dotnet-deployment-85f6446977-tmbdq 1/1 Running 0 5s
dotnet-deployment-5c9d4cc4b9-vvdln 1/1 Terminating 0 34m
dotnet-deployment-85f6446977-lcc58 0/1 Pending 0 0s
dotnet-deployment-85f6446977-lcc58 0/1 Pending 0 0s
dotnet-deployment-85f6446977-lcc58 0/1 ContainerCreating 0 0s
dotnet-deployment-5c9d4cc4b9-vvdln 0/1 Terminating 0 34m
dotnet-deployment-85f6446977-lcc58 1/1 Running 0 6s
dotnet-deployment-5c9d4cc4b9-cspqd 1/1 Terminating 0 34m
dotnet-deployment-85f6446977-hw24v 0/1 Pending 0 0s
dotnet-deployment-85f6446977-hw24v 0/1 Pending 0 0s
dotnet-deployment-5c9d4cc4b9-cspqd 0/1 Terminating 0 34m
dotnet-deployment-5c9d4cc4b9-vvdln 0/1 Terminating 0 34m
dotnet-deployment-5c9d4cc4b9-vvdln 0/1 Terminating 0 34m
dotnet-deployment-85f6446977-hw24v 0/1 Pending 0 2s
dotnet-deployment-85f6446977-hw24v 0/1 ContainerCreating 0 2s
dotnet-deployment-5c9d4cc4b9-cspqd 0/1 Terminating 0 34m
dotnet-deployment-5c9d4cc4b9-cspqd 0/1 Terminating 0 34m
dotnet-deployment-85f6446977-hw24v 1/1 Running 0 3s
dotnet-deployment-5c9d4cc4b9-httw6 1/1 Terminating 0 34m
dotnet-deployment-5c9d4cc4b9-httw6 0/1 Terminating 0 34m
Powyższe dane wyjściowe pokazują aktualizację kroczącą w trakcie jej wykonywania. Najpierw uruchamiane są nowe kontenery, a gdy już działają, stare kontenery są wyłączane.
Sprawdzanie działającej aplikacji
W tym momencie aplikacja jest zaktualizowana i gotowa do obsługi żądań użytkowników. Tak jak wcześniej, można uzyskać do niego dostęp za pomocą serwera proxy.
$ kubectl proxy --port 8080
Starting to serve on 127.0.0.1:8080
Teraz użyj podglądu w przeglądarce w Cloud Shell, aby uzyskać dostęp do aplikacji internetowej.
Dodaj do adresu URL wygenerowanego przez podgląd w przeglądarce: /api/v1/namespaces/default/services/dotnet-service:8080/proxy/. Będzie to wyglądać mniej więcej tak:
https://8080-cs-473655782854-default.us-central1.cloudshell.dev/api/v1/namespaces/default/services/dotnet-service:8080/proxy/
Potwierdzanie, że usługa Kubernetes rozdziela obciążenie
Odśwież ten adres URL kilka razy i zwróć uwagę, że host zmienia się, gdy usługa równoważy obciążenie żądaniami między różnymi podami. Porównaj wartości hosta z listą podów powyżej, aby sprawdzić, czy wszystkie pody otrzymują ruch.
Skalowanie instancji w górę
Skalowanie aplikacji w Kubernetes jest łatwe. To polecenie przeskaluje wdrożenie do 6 instancji aplikacji.
$ kubectl scale deployment dotnet-deployment --replicas 6
deployment.apps/dotnet-deployment scaled
Nowe pody i ich bieżący stan można wyświetlić za pomocą tego polecenia:
kubectl get pod -w
Zauważ, że odświeżenie tego samego okna przeglądarki pokazuje, że ruch jest teraz równoważony we wszystkich nowych podach.
8. Gratulacje!
W tym module przykładowa aplikacja internetowa .NET Core została zweryfikowana w środowisku programistycznym, a następnie wdrożona w Kubernetes przy użyciu GKE. Następnie aplikacja została zmodyfikowana tak, aby wyświetlała nazwę hosta kontenera, w którym była uruchomiona. Następnie wdrożenie Kubernetes zostało zaktualizowane do nowej wersji, a aplikacja została przeskalowana w górę, aby pokazać, jak obciążenie jest rozdzielane między dodatkowe instancje.
Więcej informacji o .NET i Kubernetes znajdziesz w tych samouczkach. Wykorzystują one wiedzę zdobytą w tym module, wprowadzając siatkę usług Istio, która umożliwia bardziej zaawansowane wzorce routingu i odporności.
9. Czyszczenie danych
Aby uniknąć niezamierzonych kosztów, użyj poniższych poleceń, aby usunąć klaster i obraz kontenera utworzone w tym module.
gcloud container clusters delete dotnet-cluster --zone ${DEFAULT_ZONE}
gcloud container images delete gcr.io/${PROJECT_ID}/aspnetapp:alpine