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

1. Ringkasan

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

Lab ini mengikuti pola pengembangan umum, yaitu aplikasi dikembangkan di lingkungan lokal developer, lalu di-deploy ke produksi. Di bagian pertama lab, contoh aplikasi .NET core 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 di 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 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 menyediakan opsi konfigurasi alternatif untuk digunakan saat membangun cluster Kubernetes menggunakan GKE. Misalnya, dengan menggunakan perintah di bawah, Anda dapat mengidentifikasi berbagai jenis mesin, zona, dan bahkan GPU (akselerator).

  • Tampilkan daftar jenis mesin dengan perintah ini gcloud compute machine-types list
  • Tampilkan daftar GPU dengan perintah ini gcloud compute accelerator-types list
  • Tampilkan daftar zona komputasi dengan perintah ini gcloud compute zones list
  • Mendapatkan bantuan tentang perintah gcloud apa pun gcloud container clusters --help
    • Misalnya, ini memberikan detail tentang cara membuat cluster Kubernetes gcloud container clusters create --help

Untuk mengetahui daftar lengkap opsi konfigurasi 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 akan digunakan
    • CATATAN: Daftar ini tidak boleh berisi duplikat
  • --workload-pool membuat workload identity sehingga workload GKE dapat mengakses layanan Google Cloud

Saat cluster sedang dibangun, 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. Agar dapat digunakan dengan cluster baru yang baru saja dibuat, kubectl 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. Menguji secara lokal dan mengonfirmasi fungsionalitas yang diinginkan

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

Menjalankan container secara lokal untuk memverifikasi fungsionalitas

Di Cloud Shell, pastikan Docker aktif dan berjalan dengan benar serta 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 8080 localhost. Ingat bahwa localhost dalam hal ini ada 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 perlu dilihat dan divalidasi di browser web. Bagian berikutnya menunjukkan cara melakukannya di Cloud Shell menggunakan Pratinjau Web.

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

Cloud Shell menawarkan Pratinjau Web, 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 ini akan membuka jendela browser dengan alamat seperti ini:

https://8080-cs-754738286554-default.us-central1.cloudshell.dev/

Melihat aplikasi contoh .NET menggunakan Web Preview

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

Screenshot aplikasi .NET V1

5. Men-deploy ke Kubernetes

Membangun file YAML dan menerapkan

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 kubectl CLI untuk memeriksa resource yang dibuat di atas. Pertama, mari kita lihat resource Deployment dan pastikan deployment baru ada di sana.

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

Meninjau 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 Service 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 Service 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 menunjukkan IP Pod yang saat ini tersedia untuk layanan ini. Bandingkan IP ini dengan IP Pod yang dihasilkan di atas.

Memverifikasi aplikasi yang 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 kode 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, Anda telah berhasil men-deploy aplikasi .NET Core di Google Kubernetes Engine. Selanjutnya, kita akan membuat perubahan pada aplikasi dan men-deploy ulang.

6. Memodifikasi aplikasi

Di bagian ini, aplikasi akan diubah untuk menampilkan host tempat instance berjalan. Tindakan ini akan memungkinkan Anda 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/

Mengupdate aplikasi untuk menyertakan nama host

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

Membangun image container baru dan menguji secara lokal

Bangun image container baru dengan kode yang telah diperbarui.

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

Memberi tag dan mengirim image agar tersedia untuk Kubernetes

Image harus diberi tag dan dikirim agar Kubernetes dapat mengambilnya. 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, hasilnya 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

Mengedit 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 dikirim ke gcr.io di atas.

        image: gcr.io/PROJECT_ID/aspnetapp:alpine

Jangan lupa untuk mengubahnya agar menggunakan PROJECT_ID Anda. Tampilannya akan terlihat seperti ini setelah Anda selesai

        image: gcr.io/myproject/aspnetapp:alpine

Menerapkan file YAML yang telah diperbarui

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

Perhatikan bahwa resource Deployment menampilkan diperbarui dan resource Service menampilkan tidak berubah. Pod yang diperbarui dapat dilihat seperti sebelumnya dengan perintah kubectl get pod, tetapi kali ini kita akan menambahkan -w, yang akan mengamati 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 container tersebut berjalan, container lama akan dihentikan.

Memverifikasi aplikasi yang berjalan

Pada tahap ini, aplikasi telah diupdate dan siap untuk permintaan pengguna. Seperti sebelumnya, model 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 kode 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/

Memastikan Service Kubernetes mendistribusikan beban

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

Meningkatkan skala 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 pengembangan, lalu di-deploy ke Kubernetes menggunakan GKE. Aplikasi kemudian dimodifikasi untuk menampilkan nama host container tempat aplikasi dijalankan. Deployment Kubernetes kemudian diupdate ke versi baru dan aplikasi diskalakan untuk menunjukkan cara beban didistribusikan di seluruh instance tambahan.

Untuk mempelajari lebih lanjut .NET dan Kubernetes, pertimbangkan tutorial ini. Lab ini akan melanjutkan apa yang telah dipelajari di lab ini dengan memperkenalkan Istio mesh layanan 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