Mengoptimalkan penskalaan otomatis Pod berdasarkan metrik


Tutorial ini menunjukkan cara menskalakan workload Google Kubernetes Engine (GKE) secara otomatis berdasarkan metrik yang tersedia di Cloud Monitoring ini.

Dalam tutorial ini, Anda dapat menyiapkan penskalaan otomatis berdasarkan salah satu dari empat metrik yang berbeda:

CPU

Penggunaan CPU

Penskalaan berdasarkan persentase penggunaan CPU di seluruh node. Cara ini dapat menghemat biaya, sehingga Anda dapat memaksimalkan penggunaan resource CPU. Namun, karena penggunaan CPU merupakan metrik akhir, pengguna mungkin mengalami latensi saat peningkatan skala sedang berlangsung.

Pub/Sub

Backlog Pub/Sub

Skalakan berdasarkan jumlah pesan yang tidak dikonfirmasi yang tersisa dalam langganan Pub/Sub. Hal ini dapat mengurangi latensi secara efektif sebelum menjadi masalah, tetapi mungkin menggunakan lebih banyak resource daripada penskalaan otomatis berdasarkan pemakaian CPU.

Metrik kustom

Metrik Cloud Monitoring kustom

Penskalaan berdasarkan metrik kustom yang ditentukan pengguna dan diekspor oleh library klien Cloud Monitoring. Untuk mempelajari lebih lanjut, lihat artikel Membuat metrik kustom di dokumentasi Cloud Monitoring.

Prometheus Kustom

Metrik Prometheus Kustom

Skalakan berdasarkan metrik kustom yang ditentukan pengguna dan diekspor dalam format Prometheus. Metrik Prometheus Anda harus berjenis Gauge, dan tidak boleh berisi awalan custom.googleapis.com.

Pada dasarnya, penskalaan otomatis adalah menemukan keseimbangan yang dapat diterima antara biaya dan latensi. Sebaiknya Anda bereksperimen dengan kombinasi metrik ini dan lainnya untuk menemukan kebijakan yang cocok bagi Anda.

Tujuan

Tutorial ini membahas tugas-tugas berikut:

  1. Cara men-deploy Adaptor Metrik Kustom.
  2. Cara mengekspor metrik dari dalam kode aplikasi.
  3. Cara melihat metrik Anda di antarmuka Cloud Monitoring.
  4. Cara men-deploy resource HorizontalPodAutoscaler (HPA) untuk menskalakan aplikasi Anda berdasarkan metrik Cloud Monitoring.

Biaya

Dalam dokumen ini, Anda menggunakan komponen Google Cloud yang dapat ditagih berikut:

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga. Pengguna baru Google Cloud mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Setelah menyelesaikan tugas yang dijelaskan dalam dokumen ini, Anda dapat menghindari penagihan berkelanjutan dengan menghapus resource yang Anda buat. Untuk mengetahui informasi selengkapnya, lihat Pembersihan.

Sebelum memulai

Lakukan langkah-langkah berikut untuk mengaktifkan Kubernetes Engine API:
  1. Buka halaman Kubernetes Engine di Konsol Google Cloud.
  2. Buat atau pilih project.
  3. Tunggu hingga API dan layanan terkait diaktifkan. Proses ini dapat memerlukan waktu beberapa menit.
  4. Pastikan penagihan telah diaktifkan untuk project Google Cloud Anda.

Anda dapat mengikuti tutorial ini menggunakan Cloud Shell, yang telah diinstal sebelumnya dengan alat command line gcloud dan kubectl yang digunakan dalam tutorial ini. Jika menggunakan Cloud Shell, Anda tidak perlu menginstal alat command line ini di workstation.

Untuk menggunakan Cloud Shell:

  1. Buka Konsol Google Cloud.
  2. Klik tombol Activate Cloud Shell Tombol Activate Shell di bagian atas jendela Konsol Google Cloud.

    Sesi Cloud Shell akan terbuka di dalam frame baru di bagian bawah Konsol Google Cloud dan menampilkan prompt command line.

    Sesi Cloud Shell

Menyiapkan lingkungan Anda

  1. Tetapkan zona default untuk Google Cloud CLI:

    gcloud config set compute/zone zone
    

    Ganti kode berikut:

    • zone: Pilih zona yang paling dekat dengan Anda. Untuk mengetahui informasi selengkapnya, lihat Region dan Zona.
  2. Tetapkan variabel lingkungan PROJECT_ID ke project ID Google Cloud Anda (project-id):

    export PROJECT_ID=project-id
    
  3. Tetapkan zona default untuk Google Cloud CLI:

    gcloud config set project $PROJECT_ID
    
  4. Membuat cluster GKE

    gcloud container clusters create metrics-autoscaling
    

Men-deploy Adaptor Metrik Kustom

Dengan Adaptor Metrik Kustom, cluster Anda dapat mengirim dan menerima metrik dengan Cloud Monitoring.

CPU

Tidak berlaku: Autoscaler Pod Horizontal dapat diskalakan berdasarkan penggunaan CPU secara native, sehingga Adaptor Metrik Kustom tidak diperlukan.

Pub/Sub

Beri pengguna Anda kemampuan untuk membuat peran otorisasi yang diperlukan:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

Deploy adaptor model resource baru di cluster Anda:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

Metrik Kustom

Beri pengguna Anda kemampuan untuk membuat peran otorisasi yang diperlukan:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

Deploy adaptor model resource pada cluster Anda:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

Prometheus Kustom

Beri pengguna Anda kemampuan untuk membuat peran otorisasi yang diperlukan:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

Deploy adaptor model resource lama di cluster Anda:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter.yaml

Men-deploy aplikasi dengan metrik

Download repo yang berisi kode aplikasi untuk tutorial ini:

CPU

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/quickstarts/hello-app

Pub/Sub

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/databases/cloud-pubsub

Metrik Kustom

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/observability/custom-metrics-autoscaling/direct-to-sd

Prometheus Kustom

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/observability/custom-metrics-autoscaling/prometheus-to-sd

Repositori berisi kode yang mengekspor metrik ke Cloud Monitoring:

CPU

Aplikasi ini merespons "Halo dunia!" ke permintaan web apa pun pada port 8080. Metrik CPU Compute Engine dikumpulkan secara otomatis oleh Cloud Monitoring.

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

func main() {
	// register hello function to handle all requests
	mux := http.NewServeMux()
	mux.HandleFunc("/", hello)

	// use PORT environment variable, or default to 8080
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	// start the web server on port and accept requests
	log.Printf("Server listening on port %s", port)
	log.Fatal(http.ListenAndServe(":"+port, mux))
}

// hello responds to the request with a plain-text "Hello, world" message.
func hello(w http.ResponseWriter, r *http.Request) {
	log.Printf("Serving request: %s", r.URL.Path)
	host, _ := os.Hostname()
	fmt.Fprintf(w, "Hello, world!\n")
	fmt.Fprintf(w, "Version: 1.0.0\n")
	fmt.Fprintf(w, "Hostname: %s\n", host)
}

Pub/Sub

Aplikasi ini melakukan polling langganan Pub/Sub untuk menemukan pesan baru, yang mengonfirmasi saat pesan tersebut masuk. Metrik langganan Pub/Sub dikumpulkan secara otomatis oleh Cloud Monitoring.

from google import auth
from google.cloud import pubsub_v1

def main():
    """Continuously pull messages from subsciption"""

    # read default project ID
    _, project_id = auth.default()
    subscription_id = 'echo-read'

    subscriber = pubsub_v1.SubscriberClient()
    subscription_path = subscriber.subscription_path(
        project_id, subscription_id)

    def callback(message: pubsub_v1.subscriber.message.Message) -> None:
        """Process received message"""
        print(f"Received message: ID={message.message_id} Data={message.data}")
        print(f"[{datetime.datetime.now()}] Processing: {message.message_id}")
        time.sleep(3)
        print(f"[{datetime.datetime.now()}] Processed: {message.message_id}")
        message.ack()

    streaming_pull_future = subscriber.subscribe(
        subscription_path, callback=callback)
    print(f"Pulling messages from {subscription_path}...")

    with subscriber:
        try:
            streaming_pull_future.result()
        except Exception as e:
            print(e)

Metrik Kustom

Aplikasi ini mengekspor metrik nilai konstanta menggunakan library klien Cloud Monitoring.

func exportMetric(stackdriverService *monitoring.Service, metricName string,
	metricValue int64, metricLabels map[string]string, monitoredResource string, resourceLabels map[string]string) error {
	dataPoint := &monitoring.Point{
		Interval: &monitoring.TimeInterval{
			EndTime: time.Now().Format(time.RFC3339),
		},
		Value: &monitoring.TypedValue{
			Int64Value: &metricValue,
		},
	}
	// Write time series data.
	request := &monitoring.CreateTimeSeriesRequest{
		TimeSeries: []*monitoring.TimeSeries{
			{
				Metric: &monitoring.Metric{
					Type:   "custom.googleapis.com/" + metricName,
					Labels: metricLabels,
				},
				Resource: &monitoring.MonitoredResource{
					Type:   monitoredResource,
					Labels: resourceLabels,
				},
				Points: []*monitoring.Point{
					dataPoint,
				},
			},
		},
	}
	projectName := fmt.Sprintf("projects/%s", resourceLabels["project_id"])
	_, err := stackdriverService.Projects.TimeSeries.Create(projectName, request).Do()
	return err
}

Prometheus Kustom

Aplikasi ini mengekspor metrik nilai konstanta menggunakan format Prometheus.

metric := prometheus.NewGauge(
	prometheus.GaugeOpts{
		Name: *metricName,
		Help: "Custom metric",
	},
)
prometheus.MustRegister(metric)
metric.Set(float64(*metricValue))

http.Handle("/metrics", promhttp.Handler())
log.Printf("Starting to listen on :%d", *port)
err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)

Repo ini juga berisi manifes Kubernetes untuk men-deploy aplikasi ke cluster Anda:

CPU

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloweb
  labels:
    app: hello
spec:
  selector:
    matchLabels:
      app: hello
      tier: web
  template:
    metadata:
      labels:
        app: hello
        tier: web
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 200m

Pub/Sub

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      volumes:
      - name: google-cloud-key
        secret:
          secretName: pubsub-key
      containers:
      - name: subscriber
        image: us-docker.pkg.dev/google-samples/containers/gke/pubsub-sample:v2
        volumeMounts:
        - name: google-cloud-key
          mountPath: /var/secrets/google
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: /var/secrets/google/key.json

Metrik Kustom

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: custom-metric-sd
  name: custom-metric-sd
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: custom-metric-sd
  template:
    metadata:
      labels:
        run: custom-metric-sd
    spec:
      containers:
      - command: ["./sd-dummy-exporter"]
        args:
        - --use-new-resource-model=true
        - --use-old-resource-model=false
        - --metric-name=custom-metric
        - --metric-value=40
        - --pod-name=$(POD_NAME)
        - --namespace=$(NAMESPACE)
        image: us-docker.pkg.dev/google-samples/containers/gke/sd-dummy-exporter:v0.3.0
        name: sd-dummy-exporter
        resources:
          requests:
            cpu: 100m
        env:
        # save Kubernetes metadata as environment variables for use in metrics
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace

Prometheus Kustom

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: custom-metric-prometheus-sd
  name: custom-metric-prometheus-sd
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: custom-metric-prometheus-sd
  template:
    metadata:
      labels:
        run: custom-metric-prometheus-sd
    spec:
      containers:
      # sample container generating custom metrics
      - name: prometheus-dummy-exporter
        image: us-docker.pkg.dev/google-samples/containers/gke/prometheus-dummy-exporter:v0.2.0
        command: ["./prometheus-dummy-exporter"]
        args:
        - --metric-name=custom_prometheus
        - --metric-value=40
        - --port=8080
      # pre-built 'prometheus-to-sd' sidecar container to export prometheus
      # metrics to Stackdriver
      - name: prometheus-to-sd
        image: gcr.io/google-containers/prometheus-to-sd:v0.5.0
        command: ["/monitor"]
        args:
        - --source=:http://localhost:8080
        - --stackdriver-prefix=custom.googleapis.com
        - --pod-id=$(POD_ID)
        - --namespace-id=$(POD_NAMESPACE)
        env:
        # save Kubernetes metadata as environment variables for use in metrics
        - name: POD_ID
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.uid
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace

Deploy aplikasi ke cluster Anda:

CPU

kubectl apply -f manifests/helloweb-deployment.yaml

Pub/Sub

Aktifkan Pub/Sub API di project Anda:

gcloud services enable cloudresourcemanager.googleapis.com pubsub.googleapis.com

Buat topik dan langganan Pub/Sub:

gcloud pubsub topics create echo
gcloud pubsub subscriptions create echo-read --topic=echo

Buat akun layanan dengan akses ke Pub/Sub:

gcloud iam service-accounts create autoscaling-pubsub-sa
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member "serviceAccount:autoscaling-pubsub-sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --role "roles/pubsub.subscriber"
ini

Download file kunci akun layanan:

gcloud iam service-accounts keys create key.json \
  --iam-account autoscaling-pubsub-sa@$PROJECT_ID.iam.gserviceaccount.com

Impor kunci akun layanan ke cluster Anda sebagai Secret:

kubectl create secret generic pubsub-key --from-file=key.json=./key.json

Deploy aplikasi ke cluster Anda:

kubectl apply -f deployment/pubsub-with-secret.yaml

Metrik Kustom

kubectl apply -f custom-metrics-sd.yaml

Prometheus Kustom

kubectl apply -f custom-metrics-prometheus-sd.yaml

Setelah menunggu beberapa saat hingga aplikasi di-deploy, semua Pod mencapai status Ready:

CPU

kubectl get pods

Output:

NAME                        READY   STATUS    RESTARTS   AGE
helloweb-7f7f7474fc-hzcdq   1/1     Running   0          10s

Pub/Sub

kubectl get pods

Output:

NAME                     READY   STATUS    RESTARTS   AGE
pubsub-8cd995d7c-bdhqz   1/1     Running   0          58s

Metrik Kustom

kubectl get pods

Output:

NAME                                READY   STATUS    RESTARTS   AGE
custom-metric-sd-58dbf4ffc5-tm62v   1/1     Running   0          33s

Prometheus Kustom

kubectl get pods

Output:

NAME                                           READY   STATUS    RESTARTS   AGE
custom-metric-prometheus-sd-697bf7c7d7-ns76p   2/2     Running   0          49s

Melihat metrik di Cloud Monitoring

Saat berjalan, aplikasi Anda akan menulis metrik ke Cloud Monitoring.

Agar dapat menampilkan metrik untuk resource yang dipantau dengan menggunakan Metrics Explorer, lakukan hal berikut:

  1. Di panel navigasi Konsol Google Cloud, pilih Monitoring, lalu pilih  Metrics Explorer:

    Buka Metrics Explorer

  2. Di elemen Metric, luaskan menu Select a metric, lalu pilih jenis resource dan jenis metrik. Misalnya, untuk membuat diagram penggunaan CPU virtual machine, lakukan tindakan berikut:
    1. (Opsional) Untuk mengurangi opsi menu, masukkan bagian nama metrik dalam Panel filter. Untuk contoh ini, masukkan utilization.
    2. Di menu Active resources, pilih VM instance.
    3. Di menu Active metric category, pilih Instance.
    4. Di menu Active metrics, pilih CPU utilization, lalu klik Apply.
  3. Untuk memfilter deret waktu yang ditampilkan, gunakan elemen Filter.

  4. Untuk menggabungkan deret waktu, gunakan menu pada elemen Aggregation. Misalnya, untuk menampilkan pemakaian CPU untuk VM Anda, berdasarkan zonanya, tetapkan menu pertama ke Mean dan menu kedua ke zone.

    Semua deret waktu ditampilkan saat menu pertama elemen Aggregation disetel ke Unaggregated. Setelan default untuk elemen Aggregation ditentukan oleh jenis metrik yang Anda pilih.

Jenis dan metrik resource adalah sebagai berikut:

CPU

Metrics Explorer

Jenis resource: gce_instance

Metrik: compute.googleapis.com/instance/cpu/utilization

Pub/Sub

Metrics Explorer

Jenis resource: pubsub_subscription

Metrik: pubsub.googleapis.com/subscription/num_undelivered_messages

Metrik Kustom

Metrics Explorer

Jenis resource: k8s_pod

Metrik: custom.googleapis.com/custom-metric

Prometheus Kustom

Metrics Explorer

Jenis resource: gke_container

Metrik: custom.googleapis.com/custom_prometheus

Membuat objek HorizontalPodAutoscaler

Saat melihat metrik di Cloud Monitoring, Anda dapat men-deploy HorizontalPodAutoscaler untuk mengubah ukuran Deployment berdasarkan metrik.

CPU

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: cpu
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: helloweb
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 30

Pub/Sub

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: pubsub
spec:
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - external:
      metric:
       name: pubsub.googleapis.com|subscription|num_undelivered_messages
       selector:
         matchLabels:
           resource.labels.subscription_id: echo-read
      target:
        type: AverageValue
        averageValue: 2
    type: External
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: pubsub

Metrik Kustom

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: custom-metric-sd
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: custom-metric-sd
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - type: Pods
    pods:
      metric:
        name: custom-metric
      target:
        type: AverageValue
        averageValue: 20

Prometheus Kustom

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: custom-prometheus-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: custom-metric-prometheus-sd
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - type: Pods
    pods:
      metric:
        name: custom_prometheus
      target:
        type: AverageValue
        averageValue: 20

Deploy HorizontalPodAutoscaler ke cluster Anda:

CPU

kubectl apply -f manifests/helloweb-hpa.yaml

Pub/Sub

kubectl apply -f deployment/pubsub-hpa.yaml

Metrik Kustom

kubectl apply -f custom-metrics-sd-hpa.yaml

Prometheus Kustom

kubectl apply -f custom-metrics-prometheus-sd-hpa.yaml

Membuat beban

Untuk beberapa metrik, Anda mungkin perlu menghasilkan beban agar dapat melihat penskalaan otomatis:

CPU

Simulasikan 10.000 permintaan ke server helloweb:

 kubectl exec -it deployments/helloweb -- /bin/sh -c \
     "for i in $(seq -s' ' 1 10000); do wget -q -O- localhost:8080; done"

Pub/Sub

Publikasikan 200 pesan ke topik Pub/Sub:

for i in {1..200}; do gcloud pubsub topics publish echo --message="Autoscaling #${i}"; done

Metrik Kustom

Tidak Berlaku: Kode yang digunakan dalam contoh ini mengekspor nilai konstanta 40 untuk metrik kustom. HorizontalPodAutoscaler disetel dengan nilai target 20 sehingga akan mencoba meningkatkan skala Deployment secara otomatis.

Prometheus Kustom

Tidak Berlaku: Kode yang digunakan dalam contoh ini mengekspor nilai konstanta 40 untuk metrik kustom. HorizontalPodAutoscaler disetel dengan nilai target 20 sehingga akan mencoba meningkatkan skala Deployment secara otomatis.

Mengamati peningkatan skala HorizontalPodAutoscaler

Anda dapat memeriksa jumlah replika Deployment saat ini dengan menjalankan:

kubectl get deployments

Setelah memberikan beberapa waktu agar metrik menyebar, Deployment akan membuat lima Pod untuk menangani backlog.

Anda juga dapat memeriksa status dan aktivitas terbaru HorizontalPodAutoscaler dengan menjalankan:

kubectl describe hpa

Pembersihan

Agar tidak menimbulkan biaya pada akun Google Cloud Anda untuk resource yang digunakan dalam tutorial ini, hapus project yang berisi resource tersebut, atau simpan project dan hapus masing-masing resource.

CPU

Hapus cluster GKE Anda:

 gcloud container clusters delete metrics-autoscaling

Pub/Sub

  1. Bersihkan langganan Pub/Sub dan topik:

    gcloud pubsub subscriptions delete echo-read
    gcloud pubsub topics delete echo
    
  2. Hapus cluster GKE Anda:

    gcloud container clusters delete metrics-autoscaling
    

Metrik Kustom

Hapus cluster GKE Anda:

 gcloud container clusters delete metrics-autoscaling

Prometheus Kustom

Hapus cluster GKE Anda:

 gcloud container clusters delete metrics-autoscaling

Langkah selanjutnya