Men-deploy dan Mengupdate aplikasi .NET Core di Google Kubernetes Engine

1. Ringkasan

Microsoft .NET Core adalah versi .NET lintas platform dan open source yang dapat berjalan secara native di container. .NET Core tersedia di GitHub dan dikelola oleh Microsoft dan komunitas .NET. Lab ini men-deploy aplikasi .NET Core dalam container ke Google Kubernetes Engine (GKE).

Lab ini mengikuti pola pengembangan umum di mana aplikasi dikembangkan di lingkungan lokal developer, lalu di-deploy ke produksi. Di bagian pertama lab, aplikasi .NET core contoh divalidasi menggunakan container yang berjalan di Cloud Shell. Setelah divalidasi, aplikasi kemudian di-deploy di Kubernetes menggunakan GKE. Lab ini mencakup langkah-langkah untuk membuat cluster GKE.

Di bagian kedua lab, perubahan kecil dilakukan pada aplikasi yang menampilkan nama host container yang menjalankan instance aplikasi tersebut. Aplikasi yang diupdate kemudian divalidasi di Cloud Shell dan deployment diupdate untuk menggunakan versi baru. Ilustrasi berikut menunjukkan urutan aktivitas dalam lab ini:

Diagram urutan demo

Biaya

Jika Anda menjalankan lab ini persis seperti yang tertulis, biaya normal untuk layanan berikut akan berlaku

2. Penyiapan dan Persyaratan

Prasyarat

Untuk menyelesaikan lab ini, Anda memerlukan akun dan project Google Cloud. Untuk petunjuk yang lebih mendetail tentang cara membuat project baru, lihat Codelab ini.

Lab ini menggunakan Docker yang berjalan di Cloud Shell, yang tersedia melalui Konsol Google Cloud dan telah dikonfigurasi sebelumnya dengan banyak alat yang berguna, seperti gcloud dan Docker. Cara mengakses cloud shell ditunjukkan di bawah. Klik ikon Cloud Shell di kanan atas untuk menampilkannya di panel bawah jendela konsol.

Cloud Shell

Opsi konfigurasi alternatif untuk cluster GKE (opsional)

Lab ini memerlukan cluster Kubernetes. Di bagian berikutnya, cluster GKE dengan konfigurasi sederhana akan dibuat. Bagian ini menunjukkan beberapa perintah gcloud yang memberikan opsi konfigurasi alternatif untuk digunakan saat membangun cluster Kubernetes menggunakan GKE. Misalnya, menggunakan perintah di bawah, Anda dapat mengidentifikasi berbagai jenis mesin, zona, dan bahkan GPU (akselerator).

  • Mencantumkan jenis mesin dengan perintah ini gcloud compute machine-types list
  • Mencantumkan GPU dengan perintah ini gcloud compute accelerator-types list
  • Mencantumkan zona komputasi dengan perintah ini gcloud compute zones list
  • Mendapatkan bantuan untuk perintah gcloud gcloud container clusters --help
    • Misalnya, ini memberikan detail tentang cara membuat cluster kubernetes gcloud container clusters create --help

Untuk mengetahui daftar lengkap opsi konfigurasi untuk GKE, lihat dokumen ini

Bersiap untuk membuat cluster kubernetes

Di Cloud Shell, Anda perlu menetapkan beberapa variabel lingkungan dan mengonfigurasi klien gcloud. Hal ini dilakukan dengan perintah berikut.

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}

Membuat cluster GKE

Karena lab ini men-deploy aplikasi .NET Core di Kubernetes, Anda perlu membuat cluster. Gunakan perintah berikut untuk membuat cluster Kubernetes baru di Google Cloud menggunakan 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 adalah jumlah node yang akan ditambahkan per zona dan dapat diskalakan nanti
  • --node-locations adalah daftar zona yang dipisahkan koma. Dalam hal ini, zona yang Anda identifikasi dalam variabel lingkungan di atas dan us-central1-b digunakan
    • CATATAN: Daftar ini tidak boleh berisi duplikat
  • --workload-pool membuat identitas workload sehingga workload GKE dapat mengakses layanan Google Cloud

Saat cluster sedang dibuat, hal berikut akan ditampilkan

Creating cluster dotnet-cluster in us-central1-b... Cluster is being deployed...⠼

Mengonfigurasi kubectl

kubectl CLI adalah cara utama untuk berinteraksi dengan cluster Kubernetes. Untuk menggunakannya dengan cluster baru yang baru saja dibuat, cluster tersebut harus dikonfigurasi untuk melakukan autentikasi terhadap cluster. Hal ini dilakukan dengan perintah berikut.

$ gcloud container clusters get-credentials dotnet-cluster --zone ${DEFAULT_ZONE}
Fetching cluster endpoint and auth data.
kubeconfig entry generated for dotnet-cluster.

Sekarang Anda dapat menggunakan kubectl untuk berinteraksi dengan 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. Uji secara lokal dan konfirmasi fungsionalitas yang diinginkan

Lab ini menggunakan image container berikut dari repositori .NET resmi di Docker Hub.

Menjalankan container secara lokal untuk memverifikasi fungsi

Di Cloud Shell, pastikan Docker sudah berjalan dengan benar dan container .NET berfungsi seperti yang diharapkan dengan menjalankan perintah Docker berikut:

$ 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

Mengonfirmasi fungsi aplikasi web

Contoh aplikasi web juga dapat divalidasi di Cloud Shell. Perintah Docker run di bawah membuat container baru yang mengekspos port 80 dan memetakannya ke port localhost 8080. Ingatlah bahwa localhost dalam hal ini berada di 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

Karena ini adalah aplikasi web, aplikasi ini harus dilihat dan divalidasi di browser web. Bagian berikutnya menunjukkan cara melakukannya di cloud shell menggunakan Web Preview.

4. Mengakses layanan dari Cloud Shell menggunakan "Pratinjau Web"

Cloud Shell menawarkan Pratinjau Web, sebuah fitur yang memungkinkan penggunaan browser untuk berinteraksi dengan proses yang berjalan di instance Cloud Shell.

Menggunakan "Pratinjau Web" untuk melihat aplikasi di Cloud Shell

Di Cloud Shell, klik tombol pratinjau web dan pilih "Preview on port 8080" (atau port apa pun yang ditetapkan untuk digunakan oleh Pratinjau Web).

Cloud Shell

Tindakan tersebut akan membuka jendela browser dengan alamat seperti ini:

https://8080-cs-754738286554-default.us-central1.cloudshell.dev/?authuser=0

Melihat aplikasi contoh .NET menggunakan Pratinjau Web

Aplikasi contoh yang dimulai pada langkah terakhir kini dapat dilihat dengan memulai Pratinjau Web dan memuat URL yang diberikan. Ini akan terlihat seperti berikut:

Screenshot aplikasi .NET V1

5. Men-deploy ke Kubernetes

Bangun file YAML dan terapkan

Langkah berikutnya memerlukan file YAML yang menjelaskan dua resource Kubernetes, yaitu Deployment dan Service. Buat file bernama dotnet-app.yaml di cloud shell dan tambahkan konten berikut ke dalamnya.

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

Sekarang gunakan kubectl untuk menerapkan file ini ke kubernetes.

$ kubectl apply -f dotnet-app.yaml
deployment.apps/dotnet-deployment created
service/dotnet-service created

Perhatikan pesan yang menunjukkan bahwa resource yang diinginkan telah dibuat.

Mempelajari resource yang dihasilkan

Kita dapat menggunakan CLI kubectl untuk memeriksa resource yang dibuat di atas. Pertama, mari kita lihat resource Deployment dan pastikan bahwa deployment baru ada.

$ kubectl get deployment
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
dotnet-deployment   3/3     3            3           80s

Selanjutnya, lihat ReplicaSet. Seharusnya ada ReplicaSet yang dibuat oleh deployment di atas.

$ kubectl get replicaset
NAME                           DESIRED   CURRENT   READY   AGE
dotnet-deployment-5c9d4cc4b9   3         3         3       111s

Terakhir, lihat Pod. Deployment menunjukkan bahwa harus ada tiga instance. Perintah di bawah akan menunjukkan bahwa ada tiga instance. Opsi -o wide ditambahkan sehingga node tempat instance tersebut berjalan akan ditampilkan.

$ 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>

Tinjau resource Service

Resource Service di Kubernetes adalah load balancer. Endpoint ditentukan oleh label pada Pod. Dengan cara ini, segera setelah Pod baru ditambahkan ke deployment melalui operasi kubectl scale deployment di atas, Pod yang dihasilkan akan langsung tersedia untuk permintaan yang ditangani oleh Layanan tersebut.

Perintah berikut akan menampilkan resource Service.

$ kubectl get svc
NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
dotnet-service   ClusterIP   10.20.9.124   <none>        8080/TCP   2m50s
...

Anda dapat melihat detail selengkapnya tentang Layanan dengan perintah berikut.

$ 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>

Perhatikan bahwa Service berjenis ClusterIP. Artinya, Pod mana pun dalam cluster dapat me-resolve nama Service, dotnet-service ke alamat IP-nya. Permintaan yang dikirim ke layanan akan di-load balance di semua instance (Pod). Nilai Endpoints di atas menampilkan IP Pod yang saat ini tersedia untuk layanan ini. Bandingkan IP ini dengan IP Pod yang ditampilkan di atas.

Memverifikasi aplikasi yang sedang berjalan

Pada tahap ini, aplikasi sudah aktif dan siap menerima permintaan pengguna. Untuk mengaksesnya, gunakan proxy. Perintah berikut akan membuat proxy lokal yang menerima permintaan di port 8080 dan meneruskannya ke cluster kubernetes.

$ kubectl proxy --port 8080
Starting to serve on 127.0.0.1:8080

Sekarang gunakan Pratinjau Web di Cloud Shell untuk mengakses aplikasi web.

Tambahkan berikut ke URL yang dihasilkan oleh Pratinjau Web: /api/v1/namespaces/default/services/dotnet-service:8080/proxy/. Hasilnya akan terlihat seperti ini:

https://8080-cs-473655782854-default.us-central1.cloudshell.dev/api/v1/namespaces/default/services/dotnet-service:8080/proxy/

Selamat telah men-deploy aplikasi .NET Core di Google Kubernetes Engine. Selanjutnya, kita akan membuat perubahan pada aplikasi dan men-deploy ulang.

6. Mengubah aplikasi

Di bagian ini, aplikasi akan diubah untuk menampilkan host tempat instance berjalan. Dengan demikian, Anda dapat mengonfirmasi bahwa load balancing berfungsi dan Pod yang tersedia merespons seperti yang diharapkan.

Mendapatkan kode sumber

git clone https://github.com/dotnet/dotnet-docker.git
cd dotnet-docker/samples/aspnetapp/

Perbarui aplikasi untuk menyertakan nama host

vi aspnetapp/Pages/Index.cshtml
    <tr>
        <td>Host</td>
        <td>@Environment.MachineName</td>
    </tr>

Buat image container baru dan uji secara lokal

Bangun image container baru dengan kode yang telah diupdate.

docker build --pull -t aspnetapp:alpine -f Dockerfile.alpine-x64 .

Seperti sebelumnya, uji aplikasi baru secara lokal

$ 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

Seperti sebelumnya, aplikasi dapat diakses menggunakan Pratinjau Web. Kali ini, parameter Host akan terlihat, seperti yang ditunjukkan di sini:

Cloud Shell

Buka tab baru di cloud shell dan jalankan docker ps untuk melihat bahwa ID penampung cocok dengan nilai Host yang ditampilkan di atas.

$ 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

Beri tag dan kirim image agar tersedia untuk Kubernetes

Image harus diberi tag dan dikirim agar Kubernetes dapat menariknya. Mulailah dengan mencantumkan image container dan mengidentifikasi image yang diinginkan.

$ docker image list
REPOSITORY                                         TAG                 IMAGE ID            CREATED             SIZE
aspnetapp                                          alpine              95b4267bb6d0        6 days ago          110MB

Selanjutnya, beri tag pada image tersebut dan kirimkan ke Google Container Registry. Dengan menggunakan ID GAMBAR di atas, akan terlihat seperti ini

docker tag 95b4267bb6d0 gcr.io/${PROJECT_ID}/aspnetapp:alpine
docker push gcr.io/${PROJECT_ID}/aspnetapp:alpine

7. Men-deploy ulang aplikasi yang telah diupdate

Edit file YAML

Ubah kembali ke direktori tempat file dotnet-app.yaml disimpan. Temukan baris berikut dalam file YAML

        image: mcr.microsoft.com/dotnet/core/samples:aspnetapp

Ini perlu diubah untuk mereferensikan image container yang dibuat dan di-push ke gcr.io di atas.

        image: gcr.io/PROJECT_ID/aspnetapp:alpine

Jangan lupa untuk mengubahnya agar menggunakan PROJECT_ID Anda. Setelah selesai, tampilannya akan terlihat seperti ini

        image: gcr.io/myproject/aspnetapp:alpine

Terapkan file YAML yang diperbarui

$ kubectl apply -f dotnet-app.yaml
deployment.apps/dotnet-deployment configured
service/dotnet-service unchanged

Perhatikan bahwa resource Deployment menampilkan pembaruan dan resource Service tidak berubah. Pod yang diperbarui dapat dilihat seperti sebelumnya dengan perintah kubectl get pod, tetapi kali ini kita akan menambahkan -w, yang akan memantau semua perubahan saat terjadi.

$ 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

Output di atas menunjukkan update berkelanjutan saat terjadi. Pertama, container baru dimulai, dan saat berjalan, container lama dihentikan.

Memverifikasi aplikasi yang sedang berjalan

Pada tahap ini, aplikasi telah diupdate dan siap menerima permintaan pengguna. Seperti sebelumnya, situs ini dapat diakses menggunakan proxy.

$ kubectl proxy --port 8080
Starting to serve on 127.0.0.1:8080

Sekarang gunakan Pratinjau Web di Cloud Shell untuk mengakses aplikasi web.

Tambahkan berikut ke URL yang dihasilkan oleh Pratinjau Web: /api/v1/namespaces/default/services/dotnet-service:8080/proxy/. Hasilnya akan terlihat seperti ini:

https://8080-cs-473655782854-default.us-central1.cloudshell.dev/api/v1/namespaces/default/services/dotnet-service:8080/proxy/

Mengonfirmasi bahwa Layanan Kubernetes mendistribusikan beban

Muat ulang URL ini beberapa kali dan perhatikan bahwa Host berubah saat permintaan di-load balance di berbagai Pod oleh Layanan. Bandingkan nilai Host dengan daftar Pod dari atas untuk melihat bahwa semua Pod menerima traffic.

Menskalakan instance

Menskalakan aplikasi di Kubernetes sangatlah mudah. Perintah berikut akan menskalakan deployment hingga 6 instance aplikasi.

$ kubectl scale deployment dotnet-deployment --replicas 6
deployment.apps/dotnet-deployment scaled

Pod baru dan statusnya saat ini dapat dilihat dengan perintah ini

kubectl get pod -w

Perhatikan bahwa memuat ulang jendela browser yang sama menunjukkan bahwa traffic kini diseimbangkan di semua Pod baru.

8. Selamat!

Di lab ini, aplikasi web contoh .NET Core divalidasi di lingkungan developer dan selanjutnya di-deploy ke Kubernetes menggunakan GKE. Aplikasi kemudian dimodifikasi untuk menampilkan nama host penampung tempat aplikasi berjalan. Deployment Kubernetes kemudian diupdate ke versi baru dan aplikasi diskalakan untuk mendemonstrasikan cara mendistribusikan beban di seluruh instance tambahan.

Untuk mempelajari lebih lanjut .NET dan Kubernetes, lihat tutorial berikut. Lab ini dibangun berdasarkan apa yang telah dipelajari di lab ini dengan memperkenalkan Istio Service Mesh untuk pola pemilihan rute dan ketahanan yang lebih canggih.

9. Pembersihan

Untuk menghindari biaya yang tidak diinginkan, gunakan perintah berikut untuk menghapus cluster dan image container yang dibuat di lab ini.

gcloud container clusters delete dotnet-cluster --zone ${DEFAULT_ZONE}
gcloud container images delete gcr.io/${PROJECT_ID}/aspnetapp:alpine