1. Обзор
Microsoft .NET Core — это кроссплатформенная версия .NET с открытым исходным кодом, которая может работать в контейнерах. .NET Core доступен на GitHub и поддерживается Microsoft и сообществом .NET. В ходе этой лабораторной работы контейнерное приложение .NET Core развертывается в Google Kubernetes Engine (GKE).
Эта лабораторная работа соответствует типичному шаблону разработки, при котором приложения разрабатываются в локальной среде разработчика, а затем развертываются в рабочей среде. В первой части лабораторной работы пример основного приложения .NET проверяется с использованием контейнера, работающего в Cloud Shell . После проверки приложение развертывается в Kubernetes с помощью GKE. Лабораторная работа включает в себя шаги по созданию кластера GKE.
Во второй части лабораторной работы в приложение вносится небольшое изменение, в котором отображается имя хоста контейнера, на котором запущен этот экземпляр приложения. Обновленное приложение затем проверяется в облачной оболочке, и развертывание обновляется для использования новой версии. На следующем рисунке показана последовательность действий в этой лабораторной работе:
Затраты
Если вы проведете эту лабораторную работу в точности так, как написано, будут взиматься обычные расходы на следующие услуги.
2. Настройка и требования
Предварительные условия
Для выполнения этой лабораторной работы требуется учетная запись Google Cloud и проект. Более подробные инструкции о том, как создать новый проект, можно найти в этой Codelab .
В этой лабораторной работе используется Docker, работающий в Cloud Shell , который доступен через Google Cloud Console и поставляется с предварительно настроенным множеством полезных инструментов, таких как gcloud и Docker. Как получить доступ к облачной оболочке показано ниже. Щелкните значок Cloud Shell в правом верхнем углу, чтобы отобразить его на нижней панели окна консоли.
Альтернативные варианты конфигурации для кластера GKE (необязательно)
Для этой лабораторной работы требуется кластер Kubernetes. В следующем разделе создается кластер GKE с простой конфигурацией. В этом разделе показаны некоторые команды gcloud
, которые предоставляют альтернативные параметры конфигурации, которые можно использовать при создании кластера Kubernetes с использованием GKE. Например, используя приведенные ниже команды, можно идентифицировать различные типы машин, зоны и даже графические процессоры (ускорители).
- Список
gcloud compute machine-types list
машин с помощью этой команды - Выведите список графических процессоров с помощью этой команды
gcloud compute accelerator-types list
- Выведите список вычислительных зон с помощью этой команды
gcloud compute zones list
- Получите справку по любой команде gcloud
gcloud container clusters --help
- Например, здесь приведены подробные сведения о создании кластера Kubernetes
gcloud container clusters create --help
- Например, здесь приведены подробные сведения о создании кластера Kubernetes
Полный список параметров конфигурации GKE см. в этом документе.
Подготовьтесь к созданию кластера Kubernetes.
В Cloud Shell необходимо установить некоторые переменные среды и настроить клиент gcloud. Это достигается с помощью следующих команд.
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}
Создать кластер GKE
Поскольку в ходе этой лабораторной работы приложение .NET Core развертывается в Kubernetes, необходимо создать кластер. Используйте следующую команду, чтобы создать новый кластер Kubernetes в Google Cloud с помощью 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-nodes
— количество узлов, добавляемых в каждую зону , которое можно масштабировать позже. -
--node-locations
— это список зон, разделенных запятыми. В этом случае используется зона, которую вы указали в переменной среды выше, иus-central1-b
- ПРИМЕЧАНИЕ. Этот список не может содержать дубликатов.
-
--workload-pool
устанавливает идентификатор рабочей нагрузки, чтобы рабочие нагрузки GKE могли получить доступ к сервисам Google Cloud.
Во время сборки кластера отображается следующее
Creating cluster dotnet-cluster in us-central1-b... Cluster is being deployed...⠼
Настроить кубектл
Интерфейс командной строки kubectl
— это основной способ взаимодействия с кластером Kubernetes. Чтобы использовать его с только что созданным новым кластером, его необходимо настроить для аутентификации в кластере. Это делается с помощью следующей команды.
$ gcloud container clusters get-credentials dotnet-cluster --zone ${DEFAULT_ZONE}
Fetching cluster endpoint and auth data.
kubeconfig entry generated for dotnet-cluster.
Теперь должно быть возможно использовать kubectl
для взаимодействия с кластером.
$ 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. Протестируйте локально и подтвердите желаемую функциональность.
В этой лабораторной работе используются следующие образы контейнеров из официального репозитория .NET в центре Docker.
Запустите контейнер локально, чтобы проверить функциональность.
В облачной оболочке убедитесь, что Docker запущен и работает правильно, а контейнер .NET работает должным образом, выполнив следующую команду Docker:
$ 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
Подтвердите функциональность веб-приложения
Пример веб-приложения также можно проверить в облачной оболочке. Команда запуска Docker, приведенная ниже, создает новый контейнер, который предоставляет порт 80
и сопоставляет его с портом 8080
localhost
. Помните, что localhost
в данном случае находится в облачной оболочке.
$ 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
Поскольку это веб-приложение, его необходимо просматривать и проверять в веб-браузере. В следующем разделе показано, как это сделать в облачной оболочке с помощью Web Preview.
4. Доступ к сервисам из облачной оболочки с помощью «Предварительного просмотра в Интернете».
Cloud Shell предлагает веб-предварительный просмотр — функцию, которая позволяет использовать браузер для взаимодействия с процессами, выполняющимися в экземпляре облачной оболочки.
Используйте «Предварительный просмотр в Интернете» для просмотра приложений в Cloud Shell.
В Cloud Shell нажмите кнопку веб-предварительного просмотра и выберите « Просмотр на порту 8080 » (или любой другой порт, который настроен для веб-просмотра).
Откроется окно браузера с таким адресом:
https://8080-cs-754738286554-default.us-central1.cloudshell.dev/?authuser=0
Просмотрите пример приложения .NET с помощью Web Preview.
Пример приложения, запущенный на последнем шаге, теперь можно просмотреть, запустив веб-просмотр и загрузив предоставленный URL-адрес. Это должно выглядеть примерно так:
5. Развертывание в Kubernetes
Создайте файл YAML и примените его.
Для следующего шага потребуется файл YAML, описывающий два ресурса Kubernetes: развертывание и службу. Создайте файл с именем dotnet-app.yaml
в облачной оболочке и добавьте в него следующее содержимое.
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
Теперь используйте kubectl
, чтобы применить этот файл к kubernetes.
$ kubectl apply -f dotnet-app.yaml
deployment.apps/dotnet-deployment created
service/dotnet-service created
Обратите внимание на сообщения, указывающие на то, что нужные ресурсы созданы.
Изучите полученные ресурсы
Мы можем использовать CLI kubectl
для проверки ресурсов, созданных выше. Сначала давайте посмотрим на ресурсы развертывания и подтвердим наличие нового развертывания.
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
dotnet-deployment 3/3 3 3 80s
Далее взгляните на наборы реплик. Должен быть ReplicaSet, созданный указанным выше развертыванием.
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
dotnet-deployment-5c9d4cc4b9 3 3 3 111s
Наконец, взгляните на Pods . В развертывании указано, что таких экземпляров должно быть три. Команда ниже должна показать, что существует три экземпляра. Добавлена опция -o wide
, чтобы отображались узлы, на которых работают эти экземпляры.
$ 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>
Просмотрите ресурс службы
Ресурс службы в Kubernetes — это балансировщик нагрузки. Конечные точки определяются метками на модулях. Таким образом, как только в развертывание добавляются новые модули с помощью описанной выше операции kubectl scale deployment
, полученные модули немедленно становятся доступными для запросов, обрабатываемых этой службой.
Следующая команда должна показать ресурс службы.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dotnet-service ClusterIP 10.20.9.124 <none> 8080/TCP 2m50s
...
Более подробную информацию о Сервисе можно просмотреть с помощью следующей команды.
$ 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>
Обратите внимание, что Служба имеет тип ClusterIP
. Это означает, что любой модуль в кластере может преобразовать имя службы dotnet-service
в свой IP-адрес. Запросы, отправленные в службу, будут распределяться по всем экземплярам (подам). Значение Endpoints
выше показывает IP-адреса модулей, доступных в настоящее время для этой службы. Сравните их с IP-адресами модулей, которые были выведены выше.
Проверьте работающее приложение
На данный момент приложение работает и готово к запросам пользователей. Для доступа к нему используйте прокси. Следующая команда создает локальный прокси-сервер, который принимает запросы на порт 8080
и передает их в кластер Kubernetes.
$ kubectl proxy --port 8080
Starting to serve on 127.0.0.1:8080
Теперь используйте веб-просмотр в Cloud Shell для доступа к веб-приложению.
Добавьте следующее к URL-адресу, созданному с помощью Web Preview: /api/v1/namespaces/default/services/dotnet-service:8080/proxy/
. В конечном итоге это будет выглядеть примерно так:
https://8080-cs-473655782854-default.us-central1.cloudshell.dev/api/v1/namespaces/default/services/dotnet-service:8080/proxy/
Поздравляем с развертыванием приложения .NET Core в Google Kubernetes Engine. Далее мы внесем изменения в приложение и повторно развернем его.
6. Измените приложение
В этом разделе приложение будет изменено, чтобы показать хост, на котором работает экземпляр. Это позволит убедиться, что балансировка нагрузки работает и что доступные модули работают должным образом.
Получить исходный код
git clone https://github.com/dotnet/dotnet-docker.git
cd dotnet-docker/samples/aspnetapp/
Обновите приложение, включив в него имя хоста.
vi aspnetapp/Pages/Index.cshtml
<tr>
<td>Host</td>
<td>@Environment.MachineName</td>
</tr>
Создайте новый образ контейнера и протестируйте его локально.
Создайте новый образ контейнера с обновленным кодом.
docker build --pull -t aspnetapp:alpine -f Dockerfile.alpine-x64 .
Как и прежде, протестируйте новое приложение локально.
$ 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
Как и раньше, доступ к приложению можно получить с помощью веб-просмотра. На этот раз параметр Host должен быть виден, как показано здесь:
Откройте новую вкладку в облачной оболочке и запустите docker ps
чтобы убедиться, что идентификатор контейнера соответствует значению хоста, показанному выше.
$ 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
Пометьте и отправьте изображение, чтобы оно было доступно Kubernetes.
Образ необходимо пометить и отправить, чтобы Kubernetes мог его получить. Начните с перечисления образов контейнеров и определите желаемый образ.
$ docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
aspnetapp alpine 95b4267bb6d0 6 days ago 110MB
Затем пометьте это изображение и отправьте его в реестр контейнеров Google . Используя указанный выше идентификатор IMAGE, это будет выглядеть так
docker tag 95b4267bb6d0 gcr.io/${PROJECT_ID}/aspnetapp:alpine
docker push gcr.io/${PROJECT_ID}/aspnetapp:alpine
7. Повторно разверните обновленное приложение.
Отредактируйте файл YAML
Вернитесь в каталог, в котором сохранен файл dotnet-app.yaml
. Найдите следующую строку в файле YAML.
image: mcr.microsoft.com/dotnet/core/samples:aspnetapp
Это необходимо изменить, чтобы он ссылался на образ контейнера, который был создан и помещен в gcr.io выше.
image: gcr.io/PROJECT_ID/aspnetapp:alpine
Не забудьте изменить его, чтобы использовать ваш PROJECT_ID
. Когда вы закончите, это должно выглядеть примерно так
image: gcr.io/myproject/aspnetapp:alpine
Примените обновленный файл YAML
$ kubectl apply -f dotnet-app.yaml
deployment.apps/dotnet-deployment configured
service/dotnet-service unchanged
Обратите внимание, что ресурс «Развертывание» отображается обновленным, а ресурс «Сервис» — без изменений. Обновленные поды можно увидеть, как и раньше, с помощью команды kubectl get pod
, но на этот раз мы добавим ключ -w
, который будет отслеживать все изменения по мере их возникновения.
$ 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
Вывод выше показывает скользящее обновление по мере его возникновения. Сначала запускаются новые контейнеры, а когда они запускаются, старые контейнеры завершаются.
Проверьте работающее приложение
На этом этапе приложение обновлено и готово к запросам пользователей. Как и раньше, доступ к нему можно получить с помощью прокси.
$ kubectl proxy --port 8080
Starting to serve on 127.0.0.1:8080
Теперь используйте веб-просмотр в Cloud Shell для доступа к веб-приложению.
Добавьте следующее к URL-адресу, созданному с помощью Web Preview: /api/v1/namespaces/default/services/dotnet-service:8080/proxy/
. В конечном итоге это будет выглядеть примерно так:
https://8080-cs-473655782854-default.us-central1.cloudshell.dev/api/v1/namespaces/default/services/dotnet-service:8080/proxy/
Убедитесь, что служба Kubernetes распределяет нагрузку.
Обновите этот URL-адрес несколько раз и обратите внимание, что хост меняется, поскольку запросы балансируются службой между разными модулями. Сравните значения хоста со списком модулей сверху, чтобы убедиться, что все модули получают трафик.
Масштабируйте экземпляры
Масштабировать приложения в Kubernetes легко. Следующая команда масштабирует развертывание до 6 экземпляров приложения.
$ kubectl scale deployment dotnet-deployment --replicas 6
deployment.apps/dotnet-deployment scaled
Новые поды и их текущее состояние можно просмотреть с помощью этой команды
kubectl get pod -w
Обратите внимание, что обновление того же окна браузера показывает, что трафик теперь сбалансирован между всеми новыми модулями.
8. Поздравляем!
В ходе этой лабораторной работы пример веб-приложения .NET Core был проверен в среде разработки и впоследствии развернут в Kubernetes с помощью GKE. Затем приложение было изменено для отображения имени хоста контейнера, в котором оно работало. Затем развертывание Kubernetes было обновлено до новой версии, а приложение было масштабировано, чтобы продемонстрировать, как нагрузка распределяется между дополнительными экземплярами.
Чтобы узнать больше о .NET и Kubernetes, ознакомьтесь с этими руководствами. Они основаны на знаниях, полученных в ходе этой лабораторной работы, путем внедрения Istio Service Mesh для более сложных шаблонов маршрутизации и устойчивости.
9. Очистка
Чтобы избежать непредвиденных затрат, используйте следующие команды для удаления кластера и образа контейнера, созданных в ходе этой лабораторной работы.
gcloud container clusters delete dotnet-cluster --zone ${DEFAULT_ZONE}
gcloud container images delete gcr.io/${PROJECT_ID}/aspnetapp:alpine