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

1. Ringkasan

Microsoft .NET Core adalah versi .NET open source dan lintas platform yang dapat berjalan secara native dalam container. .NET Core tersedia di GitHub serta dikelola oleh Microsoft dan komunitas .NET. Lab ini men-deploy aplikasi .NET Core dalam container ke dalam 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 ini, dilakukan perubahan kecil pada aplikasi yang menunjukkan nama host container yang menjalankan instance aplikasi tersebut. Aplikasi yang telah diupdate kemudian divalidasi di Cloud Shell dan deployment akan diupdate untuk menggunakan versi baru ini. 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 memanfaatkan Docker yang berjalan di Cloud Shell, yang tersedia melalui Konsol Google Cloud dan sudah dikonfigurasi sebelumnya dengan banyak alat berguna, seperti gcloud dan Docker. Cara mengakses Cloud Shell ditampilkan 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, dengan menggunakan perintah di bawah ini, Anda dapat mengidentifikasi berbagai jenis mesin, zona, dan bahkan GPU (akselerator).

  • Tampilkan daftar jenis mesin dengan perintah ini gcloud compute machine-types list
  • Tampilkan GPU dengan perintah ini gcloud compute accelerator-types list
  • Tampilkan daftar zona komputasi dengan perintah ini gcloud compute zones list
  • Mendapatkan bantuan terkait perintah gcloud gcloud container clusters --help
    • Misalnya, bagian ini memberikan detail tentang pembuatan 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 dapat 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 menetapkan workload identity sehingga workload GKE dapat mengakses layanan Google Cloud

Saat cluster sedang membangun, hal berikut akan ditampilkan

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

Mengonfigurasi kubectl

CLI kubectl adalah cara utama untuk berinteraksi dengan cluster Kubernetes. Agar dapat digunakan dengan cluster baru yang baru saja dibuat, cluster perlu dikonfigurasi untuk melakukan autentikasi terhadap cluster. Hal ini dilakukan dengan mengikuti perintah.

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

Sekarang seharusnya kubectl sudah dapat digunakan 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 fungsi yang diinginkan

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

Jalankan container secara lokal untuk memverifikasi fungsi

Di Cloud Shell, pastikan Docker sudah aktif dan berjalan dengan benar serta bahwa 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 di Cloud Shell juga dapat divalidasi. Perintah Docker run di bawah membuat container baru yang mengekspos port 80 dan memetakannya ke port localhost 8080. Perlu diingat bahwa localhost dalam kasus 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 perlu dilihat dan divalidasi di browser web. Bagian berikutnya menunjukkan cara melakukannya di Cloud Shell menggunakan Web Preview.

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

Cloud Shell menawarkan Pratinjau Web, yaitu fitur yang dapat digunakan 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, lalu pilih "Preview on port 8080" (atau port apa pun yang ingin digunakan untuk Pratinjau Web port).

Cloud Shell

Langkah itu 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

Membuat file YAML dan menerapkan

Langkah selanjutnya 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.

Menjelajahi resource yang dihasilkan

Kita dapat menggunakan CLI kubectl untuk memeriksa resource yang dibuat di atas. Pertama-tama, mari kita lihat resource Deployment dan konfirmasi bahwa deployment baru telah tersedia.

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

Selanjutnya, lihat ReplicaSets. Harus 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>

Meninjau resource Layanan

Resource Service di Kubernetes adalah load balancer. Endpoint ditentukan berdasarkan 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 Layanan berjenis ClusterIP. Artinya, setiap Pod dalam cluster dapat me-resolve nama Service, dotnet-service ke alamat IP-nya. Permintaan yang dikirim ke layanan akan di-load balanced di semua instance (Pod). Nilai Endpoints di atas menunjukkan IP Pod yang saat ini tersedia untuk service ini. Bandingkan ini dengan IP Pod yang output-nya di atas.

Memverifikasi aplikasi yang sedang berjalan

Pada tahap ini, aplikasi sudah aktif dan siap menerima permintaan pengguna. Untuk mengaksesnya, gunakan proxy. Perintah berikut membuat proxy lokal yang menerima permintaan pada 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 dibuat 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 men-deploy aplikasi .NET Core di Google Kubernetes Engine. Berikutnya, kita akan melakukan perubahan pada aplikasi dan men-deploy ulang.

6. Memodifikasi aplikasi

Di bagian ini, aplikasi akan diubah untuk menunjukkan host tempat instance berjalan. Dengan begitu, 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/

Update aplikasi untuk menyertakan nama host

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

Membuat image container baru dan melakukan pengujian secara lokal

Bangun image container baru dengan kode yang 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 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

Memberi tag dan mengirim image agar tersedia untuk Kubernetes

Gambar harus diberi tag dan dikirim agar Kubernetes dapat menariknya. Mulai dengan mencantumkan image container dan menentukan 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 kirim ke Google Container Registry. 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 sudah diupdate

Mengedit file YAML

Ubah kembali ke direktori tempat file dotnet-app.yaml disimpan. Cari baris berikut dalam {i>file<i} YAML

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

Hal ini perlu diubah untuk mereferensikan image container yang dibuat dan dikirimkan ke gcr.io di atas.

        image: gcr.io/PROJECT_ID/aspnetapp:alpine

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

        image: gcr.io/myproject/aspnetapp:alpine

Menerapkan file YAML yang diperbarui

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

Perhatikan bahwa resource Deployment menunjukkan bahwa resource yang diupdate dan resource Service tidak berubah. Pod yang diupdate 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 yang sedang terjadi. Pertama, container baru dimulai, dan saat container tersebut berjalan, container lama dihentikan.

Memverifikasi aplikasi yang sedang berjalan

Pada tahap ini, aplikasi akan diupdate dan siap menerima permintaan pengguna. Seperti sebelumnya, {i>page<i} dapat diakses menggunakan {i>proxy<i}.

$ 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 dibuat 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 Layanan Kubernetes mendistribusikan beban

Refresh URL ini beberapa kali dan perhatikan bahwa Host berubah saat permintaan diseimbangkan oleh beban di berbagai Pod berdasarkan Layanan. Bandingkan nilai Host dengan daftar Pod di atas untuk melihat apakah semua Pod menerima traffic.

Meningkatkan skala instance

Menskalakan aplikasi di Kubernetes itu mudah. Perintah ikuti 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 akan menunjukkan bahwa traffic kini seimbang di semua Pod baru.

8. Selamat!

Di lab ini, aplikasi web contoh .NET Core divalidasi di lingkungan developer, lalu di-deploy ke Kubernetes menggunakan GKE. Aplikasi kemudian dimodifikasi untuk menampilkan nama host penampung tempatnya dijalankan. Deployment Kubernetes kemudian diupdate ke versi baru dan aplikasi ditingkatkan skalanya untuk menunjukkan cara beban didistribusikan di seluruh instance tambahan.

Untuk mempelajari .NET dan Kubernetes lebih lanjut, pertimbangkan tutorial ini. Hal ini dikembangkan berdasarkan hal yang telah dipelajari di lab ini dengan memperkenalkan Istio Service Mesh untuk pola ketahanan dan perutean yang lebih canggih.

9. Pembersihan

Untuk mengatasi 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