1. Présentation
Microsoft .NET Core est une version Open Source et multiplate-forme de .NET qui peut s'exécuter de manière native dans des conteneurs. .NET Core est disponible sur GitHub et géré par Microsoft et la communauté .NET. Cet atelier déploie une application .NET Core conteneurisée dans Google Kubernetes Engine (GKE).
Cet atelier suit un modèle de développement classique dans lequel les applications sont développées dans un environnement local de développeurs, puis déployées en production. Dans la première partie de l'atelier, un exemple d'application .NET Core est validé à l'aide d'un conteneur s'exécutant dans Cloud Shell. Une fois validée, l'application est déployée sur Kubernetes à l'aide de GKE. L'atelier comprend la procédure à suivre pour créer un cluster GKE.
Dans la deuxième partie de l'atelier, une modification mineure est apportée à l'application afin d'afficher le nom d'hôte du conteneur qui exécute cette instance d'application. L'application mise à jour est ensuite validée dans Cloud Shell, et le déploiement est mis à jour pour utiliser la nouvelle version. L'illustration suivante montre le déroulement des activités de cet atelier:
Coûts
Si vous exécutez cet atelier exactement comme indiqué, les coûts normaux des services suivants s'appliqueront
2. Préparation
Prérequis
Pour réaliser cet atelier, vous devez posséder un compte et un projet Google Cloud. Pour obtenir des instructions plus détaillées sur la création d'un projet, reportez-vous à cet atelier de programmation.
Cet atelier utilise Docker exécuté dans Cloud Shell, disponible dans la console Google Cloud et préconfiguré avec de nombreux outils utiles, tels que gcloud et Docker. La procédure d'accès à Cloud Shell est présentée ci-dessous. Cliquez sur l'icône Cloud Shell en haut à droite pour la révéler dans le volet inférieur de la fenêtre de la console.
Autres options de configuration pour le cluster GKE (facultatif)
Cet atelier nécessite un cluster Kubernetes. Dans la section suivante, nous allons créer un cluster GKE avec une configuration simple. Cette section présente quelques commandes gcloud
qui fournissent d'autres options de configuration à utiliser lors de la création d'un cluster Kubernetes à l'aide de GKE. Par exemple, les commandes ci-dessous permettent d'identifier différents types de machines, zones et même GPU (accélérateurs).
- Listez les types de machines à l'aide de la commande
gcloud compute machine-types list
- Lister les GPU à l'aide de la commande
gcloud compute accelerator-types list
- Listez les zones de calcul à l'aide de la commande
gcloud compute zones list
- Obtenir de l'aide sur n'importe quelle commande gcloud
gcloud container clusters --help
- Par exemple, cette section fournit des détails sur la création d'un cluster Kubernetes
gcloud container clusters create --help
.
- Par exemple, cette section fournit des détails sur la création d'un cluster Kubernetes
Pour obtenir la liste complète des options de configuration de GKE, consultez ce document.
Préparer la création du cluster Kubernetes
Dans Cloud Shell, vous devez définir certaines variables d'environnement et configurer le client gcloud. Pour ce faire, utilisez les commandes suivantes.
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}
Créer un cluster GKE
Étant donné que cet atelier déploie l'application .NET Core sur Kubernetes, vous devez créer un cluster. Utilisez la commande suivante pour créer un cluster Kubernetes dans Google Cloud à l'aide de 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
est le nombre de nœuds à ajouter par zone ; ce nombre peut faire l'objet d'un scaling ultérieur--node-locations
est une liste de zones séparées par une virgule. Dans ce cas, la zone que vous identifiez dans la variable d'environnement ci-dessus etus-central1-b
sont utilisées.- REMARQUE: Cette liste ne peut pas contenir de doublons
--workload-pool
établit l'identité de la charge de travail afin que les charges de travail GKE puissent accéder aux services Google Cloud
Pendant la création du cluster, ce qui suit s'affiche
Creating cluster dotnet-cluster in us-central1-b... Cluster is being deployed...⠼
Configurer kubectl
La CLI kubectl
est le principal moyen d'interagir avec un cluster Kubernetes. Pour que vous puissiez l'utiliser avec le cluster qui vient d'être créé, vous devez le configurer pour qu'il s'authentifie auprès du cluster. Pour ce faire, utilisez la commande suivante.
$ gcloud container clusters get-credentials dotnet-cluster --zone ${DEFAULT_ZONE}
Fetching cluster endpoint and auth data.
kubeconfig entry generated for dotnet-cluster.
Vous devriez maintenant pouvoir utiliser kubectl
pour interagir avec le cluster.
$ 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. Tester localement et confirmer le fonctionnement souhaité
Cet atelier utilise les images de conteneur suivantes, qui proviennent du dépôt .NET officiel sur Docker Hub.
Exécuter le conteneur localement pour vérifier son fonctionnement
Dans Cloud Shell, vérifiez que Docker fonctionne correctement et que le conteneur .NET fonctionne comme prévu en exécutant la commande Docker suivante:
$ 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
Confirmer le fonctionnement de l'application Web
Un exemple d'application Web peut également être validé dans Cloud Shell. La commande Docker run ci-dessous crée un conteneur qui expose le port 80
et le mappe sur le port localhost
8080
. Pour rappel, localhost
se trouve dans ce cas dans 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
Puisqu'il s'agit d'une application Web, elle doit être affichée et validée dans un navigateur Web. La section suivante explique comment effectuer cette opération dans Cloud Shell à l'aide de l'aperçu sur le Web.
4. Accéder aux services depuis Cloud Shell à l'aide de l'aperçu sur le Web
Cloud Shell propose un aperçu sur le Web, une fonctionnalité qui permet d'utiliser un navigateur pour interagir avec les processus exécutés dans l'instance Cloud Shell.
Utiliser l'option "Aperçu sur le Web" pour afficher les applications dans Cloud Shell
Dans Cloud Shell, cliquez sur le bouton "Aperçu sur le Web", puis sélectionnez Prévisualiser sur le port 8080. (ou tout autre port sur lequel l'aperçu sur le Web est configuré).
Une fenêtre de navigateur s'ouvre avec une adresse semblable à celle-ci:
https://8080-cs-754738286554-default.us-central1.cloudshell.dev/?authuser=0
Afficher l'exemple d'application .NET à l'aide de l'aperçu sur le Web
Vous pouvez maintenant afficher l'application exemple lancée à la dernière étape en démarrant l'aperçu sur le Web et en chargeant l'URL fournie. Voici un exemple :
5. Déployer sur Kubernetes
Créer le fichier YAML et appliquer
L'étape suivante nécessite un fichier YAML décrivant deux ressources Kubernetes : un déploiement et un service. Créez un fichier nommé dotnet-app.yaml
dans Cloud Shell et ajoutez-y le contenu suivant.
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
Utilisez maintenant kubectl
pour appliquer ce fichier à Kubernetes.
$ kubectl apply -f dotnet-app.yaml
deployment.apps/dotnet-deployment created
service/dotnet-service created
Notez les messages indiquant que les ressources souhaitées ont été créées.
Explorer les ressources obtenues
Nous pouvons utiliser la CLI kubectl
pour examiner les ressources créées ci-dessus. Commençons par examiner les ressources de déploiement et vérifier que le nouveau déploiement s'y trouve.
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
dotnet-deployment 3/3 3 3 80s
Intéressons-nous maintenant aux ReplicaSets. Le déploiement ci-dessus devrait créer un ReplicaSet.
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
dotnet-deployment-5c9d4cc4b9 3 3 3 111s
Enfin, jetez un œil aux pods. Le déploiement indiquait qu'il devait y avoir trois instances. La commande ci-dessous devrait indiquer qu'il y a trois instances. L'option -o wide
est ajoutée afin d'afficher les nœuds sur lesquels ces instances s'exécutent.
$ 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>
Examiner la ressource Service
Une ressource Service dans Kubernetes est un équilibreur de charge. Les points de terminaison sont déterminés par des étiquettes sur les pods. Ainsi, dès que de nouveaux pods sont ajoutés au déploiement via l'opération kubectl scale deployment
ci-dessus, les pods obtenus sont immédiatement disponibles pour les requêtes traitées par ce service.
La commande suivante doit afficher la ressource Service.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dotnet-service ClusterIP 10.20.9.124 <none> 8080/TCP 2m50s
...
Vous pouvez obtenir plus d'informations sur le service à l'aide de la commande suivante.
$ 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>
Notez que le service est de type ClusterIP
. Cela signifie que n'importe quel pod du cluster peut résoudre le nom du service dotnet-service
sur son adresse IP. Les requêtes envoyées au service font l'objet d'un équilibrage de charge sur l'ensemble des instances (pods). La valeur Endpoints
ci-dessus indique les adresses IP des pods actuellement disponibles pour ce service. Comparez-les aux adresses IP des pods renvoyés ci-dessus.
Vérifier l'application en cours d'exécution
À ce stade, l'application est opérationnelle et prête à recevoir les requêtes des utilisateurs. Pour y accéder, utilisez un proxy. La commande suivante crée un proxy local qui accepte les requêtes sur le port 8080
et les transmet au cluster Kubernetes.
$ kubectl proxy --port 8080
Starting to serve on 127.0.0.1:8080
Utilisez maintenant l'aperçu sur le Web dans Cloud Shell pour accéder à l'application Web.
Ajoutez le code suivant à l'URL générée par l'aperçu sur le Web: /api/v1/namespaces/default/services/dotnet-service:8080/proxy/
. Le résultat ressemblera à ceci:
https://8080-cs-473655782854-default.us-central1.cloudshell.dev/api/v1/namespaces/default/services/dotnet-service:8080/proxy/
Félicitations ! Vous avez déployé une application .NET Core sur Google Kubernetes Engine. Nous allons maintenant modifier l'application et la redéployer.
6. Modifier l'application
Dans cette section, l'application est modifiée pour afficher l'hôte sur lequel l'instance est en cours d'exécution. Vous pourrez ainsi vérifier que l'équilibrage de charge fonctionne et que les pods disponibles répondent comme prévu.
Obtenir le code source
git clone https://github.com/dotnet/dotnet-docker.git
cd dotnet-docker/samples/aspnetapp/
Mettre à jour l'application pour inclure le nom d'hôte
vi aspnetapp/Pages/Index.cshtml
<tr>
<td>Host</td>
<td>@Environment.MachineName</td>
</tr>
Créer une image de conteneur et la tester en local
Créez la nouvelle image de conteneur avec le code mis à jour.
docker build --pull -t aspnetapp:alpine -f Dockerfile.alpine-x64 .
Comme précédemment, testez la nouvelle application en local
$ 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
Comme auparavant, vous pouvez accéder à l'application via l'aperçu sur le Web. Cette fois, le paramètre "Host" doit être visible, comme indiqué ci-dessous:
Ouvrez un nouvel onglet dans Cloud Shell et exécutez docker ps
pour vérifier que l'ID du conteneur correspond à la valeur d'hôte indiquée ci-dessus.
$ 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
Ajouter un tag à l'image et la transférer afin qu'elle soit disponible pour Kubernetes
L'image doit être taguée et transférée pour que Kubernetes puisse l'extraire. Commencez par répertorier les images de conteneurs et identifiez l'image souhaitée.
$ docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
aspnetapp alpine 95b4267bb6d0 6 days ago 110MB
Ajoutez ensuite un tag à cette image et transférez-la vers Google Container Registry. Avec l'ID DE L'IMAGE ci-dessus, le résultat doit ressembler à ceci :
docker tag 95b4267bb6d0 gcr.io/${PROJECT_ID}/aspnetapp:alpine
docker push gcr.io/${PROJECT_ID}/aspnetapp:alpine
7. Redéployer l'application mise à jour
Modifier le fichier YAML
Revenez au répertoire dans lequel le fichier dotnet-app.yaml
est enregistré. Recherchez la ligne suivante dans le fichier YAML
image: mcr.microsoft.com/dotnet/core/samples:aspnetapp
Il doit être modifié pour référencer l'image de conteneur créée et transférée vers gcr.io ci-dessus.
image: gcr.io/PROJECT_ID/aspnetapp:alpine
N'oubliez pas de le modifier pour utiliser votre PROJECT_ID
. Une fois terminé, l'application devrait ressembler à ceci :
image: gcr.io/myproject/aspnetapp:alpine
Appliquer le fichier YAML mis à jour
$ kubectl apply -f dotnet-app.yaml
deployment.apps/dotnet-deployment configured
service/dotnet-service unchanged
Notez que la ressource Déploiement indique que l'état est mis à jour et que la ressource Service indique qu'elle n'a pas été modifiée. Les pods mis à jour peuvent être vus comme précédemment avec la commande kubectl get pod
, mais cette fois, nous allons ajouter -w
, qui surveillera toutes les modifications en temps réel.
$ 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
Le résultat ci-dessus montre la mise à jour progressive en cours. Tout d'abord, les nouveaux conteneurs sont démarrés et, lorsqu'ils s'exécutent, les anciens conteneurs sont arrêtés.
Vérifier l'application en cours d'exécution
À ce stade, l'application est mise à jour et prête à recevoir les requêtes des utilisateurs. Comme précédemment, il est accessible à l'aide d'un proxy.
$ kubectl proxy --port 8080
Starting to serve on 127.0.0.1:8080
Utilisez maintenant l'aperçu sur le Web dans Cloud Shell pour accéder à l'application Web.
Ajoutez le code suivant à l'URL générée par l'aperçu sur le Web: /api/v1/namespaces/default/services/dotnet-service:8080/proxy/
. Le résultat ressemblera à ceci:
https://8080-cs-473655782854-default.us-central1.cloudshell.dev/api/v1/namespaces/default/services/dotnet-service:8080/proxy/
Vérifier que le service Kubernetes répartit la charge
Actualisez cette URL plusieurs fois. Notez que l'hôte change lorsque le service effectue l'équilibrage de charge des requêtes entre les différents pods. Comparez les valeurs d'hôte à la liste de pods ci-dessus pour vérifier que tous les pods reçoivent du trafic.
Scaling à la hausse des instances
Le scaling d'applications dans Kubernetes est un jeu d'enfant. La commande suivante permet de faire évoluer le déploiement jusqu'à six instances de l'application.
$ kubectl scale deployment dotnet-deployment --replicas 6
deployment.apps/dotnet-deployment scaled
Vous pouvez consulter les nouveaux pods et leur état actuel à l'aide de cette commande
kubectl get pod -w
Notez que l'actualisation de la même fenêtre de navigateur indique que le trafic est désormais équilibré entre tous les nouveaux pods.
8. Félicitations !
Dans cet atelier, un exemple d'application Web .NET Core a été validé dans un environnement de développement, puis déployé sur Kubernetes à l'aide de GKE. L'application a ensuite été modifiée de façon à afficher le nom d'hôte du conteneur dans lequel elle s'exécutait. Le déploiement Kubernetes a ensuite été mis à jour vers la nouvelle version, et l'application a fait l'objet d'un scaling à la hausse pour démontrer la répartition de la charge entre les instances supplémentaires.
Pour en savoir plus sur .NET et Kubernetes, consultez ces tutoriels. Elles s'appuient sur ce que vous avez appris au cours de cet atelier en présentant Istio Service Mesh pour des modèles de routage et de résilience plus sophistiqués.
9. Effectuer un nettoyage
Afin d'éviter les coûts inattendus, exécutez les commandes suivantes pour supprimer le cluster et l'image de conteneur que vous avez créées dans cet atelier.
gcloud container clusters delete dotnet-cluster --zone ${DEFAULT_ZONE}
gcloud container images delete gcr.io/${PROJECT_ID}/aspnetapp:alpine