GCP-託管運算資源服務簡介

雲端運算的一般性名詞

傳統的地端機房就是把Application放在實體機或VM中運行。但是在雲端,運作Application的方式確有以下這些:

  • IaaS (Infrastructure as a Service)
  • PaaS (Platform as a Service)
  • FaaS (Function as a Service)
  • CaaS (Container as a Service)
  • Serverless

所謂的IaaS就是我們需要自行管理含OS內的所有安裝設定(如下圖的藍色部分)。

而PaaS則再更進一階,只需管理到Application(如下圖)。

通常CSP(Cloud Service Provider)會負責Auto scaling, Availability & Load balancing等等的底層基礎設施。而我們通常只需負責代碼與配置(Configuration)。其他像是CAAS (Container as a Service), FAAS (Function as a Service)還有Database也是PaaS的服務類型。

GCP App Engine

支援多種語言(Go, Java, .NET, Node.js, PHP, Python, Ruby),runtime有pre-configured與Custom兩種。只有resource provision時才需要付費。其他重要的功能有:

  • Automatic load balancing & Auto scaling
  • Managed platform updates & Application health monitoring
  • Application versioning
  • Traffic splitting

App Engine的環境

App Engine environment分為以下兩種

Standard:
應用程式在特定於語言的沙箱(sandbox)中運作,並且與OS/磁碟/其他Application完全隔離。其中又分V1/V2兩種版本

  • V1
    適用語言 — Java、Python、PHP、Go
    僅適用於 Python 和 PHP runtime:
    網路存取受限/僅允許白名單extensions和libraries。對Java 和 Go runtime沒有限制。
  • V2(支援範圍廣泛)
    支援Java、Python、PHP、Node.js、Ruby、Go。Full Network Access且沒有Language Extensions的限制

Flexible:(Application instance是運作在Docker Container裡的)
其底層是GCE組成的。支援任何的runtime(內建對 Python、Java、Node.js、Go、Ruby、PHP 或 .NET 的支援)。提供對background processes與local disks的存取。

Application Component Hierarchy

App Engine的層級可以分為三個層次(如上圖所示)。

最上層是Application — 一個Project只能有一個App。再來是Service,這可以是多個微服務或App Component。一個Application中可以有多個Servcie,而每個Service可以有不同的設定。最後是Version,每個version都可以是不一樣的code and configuration。每個Version可以有一個以上的Instance來運作。所以意味著同一個Application可以存在多個版本,這樣可以讓我們可以rollback或是split traffic。

以下是App engine standard與Flexible的功能比較。

我們可以看到Flexible的控制程度比Standard還要深。所以其資源使用方式與計價方式都有所不同。Flexible的計價方式更接近GCE。其中比較值得注意的是Scaling的方式。Standard有三種,Flexilbe只有兩種,以下是三種模式的說明。

Automatic — 根據負載自動縮放資源
這是適合持續運作的負載。其自動縮放基於以下三種模式:

  • Target CPU Utilization —CPU使用率的閥值
  • Target Throughput Utilization — throughput的使用閥值
  • Max Concurrent Requests — 每一個instance最大同時間的concurrent requests

另外也可以設定最大/最小的instance。

Basic — 當request時,instance才會被create
這適用於臨時性的工作負載。好處是沒有request時,不會有instance,也意味著不會有費用。但是也因為這樣,處理request的起始時間就很慢(因為處理冷開機的問題)。可以設定最大的Instances 與Idle Timeout。

Manual — 手動設定固定數量的instance來運行Application

GKE(Google Kubernetes Engine)

K8S應該是目前最流行的container orchestration(包含Cluster Management)。同時也提供了以下的功能:

  • Auto Scaling
  • Service Discovery
  • Load Balancer
  • Self Healing
  • Zero downtime deployments

而GKE就是GCP的K8S託管服務。GKE最小化了維運的需求,並且能進行auto-repair (替換有問題的 nodes)與auto-upgrade (可以根據我們的意願升級K8S的版本)。另外Cluster的node能自動擴展,並且直接於Cloud Logging 與Cloud Monitoring的GCP監控服務整合。在其node的OS中預設使用"Container-Optimized OS",這是GCP進行安全強化之後的OS,node的Disk支援Persistent disks與Local SSD。

以下是我們在操作GKE時經常會用到的command範例,有gcloud與kubectl

gcloud config set project <peojct ID>
#這通常可以在GKE cluster的三個點點的選項取得(connect)
gcloud container clusters get-credentials my-cluster --zone us-central1-c --project my-kubernetes-project-304910
#
kubectl create deployment <service name> --image=<image path/image name>
kubectl get deployment
kubectl expose deployment <service name> --type=LoadBalancer --port=<port number>
kubectl get services
kubectl get services --watch

kubectl scale deployment <service name> --replicas=<number>
gcloud container clusters resize <cluster name> --node-pool default-pool --num-nodes=2 --zone=us-central1-c
kubectl autoscale deployment hello-world-rest-api --max=4 --cpu-percent=70
kubectl get hpa
kubectl create configmap hello-world-config --from-literal=RDS_DB_NAME=todos
kubectl get configmap
kubectl describe configmap hello-world-config
kubectl create secret generic hello-world-secrets-1 --from-literal=RDS_PASSWORD=dummytodos
kubectl get secret
kubectl describe secret hello-world-secrets-1
kubectl apply -f deployment.yaml
gcloud container node-pools list --zone=us-central1-c --cluster=my-cluster
kubectl get pods -o wide

kubectl set image deployment hello-world-rest-api hello-world-rest-api=in28min/hello-world-rest-api:0.0.2.RELEASE
kubectl get services
kubectl get replicasets
kubectl get pods
kubectl delete pod hello-world-rest-api-58dc9d7fcc-8pv7r

kubectl scale deployment hello-world-rest-api --replicas=1
kubectl get replicasets
gcloud projects list

kubectl delete service hello-world-rest-api
kubectl delete deployment hello-world-rest-api
gcloud container clusters delete my-cluster --zone us-central1-c

GKE的組件

Cluster : 一群GCE的集合,分為:

  • Master Node(s) —管理整個cluster
  • Worker Node(s) — 運行我們的Application(也就是pods)

Master Node (Control plane) 組件中又細分:

  • API Server —處理所有 K8S cluster的通訊 (從nodes內部到cluster外部)
  • Scheduler — 資源配置,決定Pod要放在哪裡
  • Control Manager — 管理deployments & replicasets
  • etcd — 分散式資料庫,儲存cluster state

Worker Node的組件有:

  • Pod(s)
  • Kubelet — 與master node之間的通訊

GKE Cluster Types

分為以下四種

  1. Zonal Cluster
    又分為Single zone與multi-zonal。都是Single Control plane但node運行在一個(Single)或多個(multi) zone中。
  2. Regional cluster
    control plane的replica在一個region中的多個zone中運作。 node也在control plane運作的同一zone中運作
  3. Private Cluster
    VPC-native cluster。node只有internal IP。
  4. Alpha cluster
    具有 alpha API 的cluster — 早期功能 API。 用於測試新的 K8S 功能

K8S Pods

Pod就是一個在K8S中最小的可佈署單元。每一個Pod可以有含一個以上的container,並且Pod的IP都是短暫的(ephemeral)。在同一個Pod中的container共享以下幾種資源:

  • Network
  • Storage
  • IP Address
  • Ports
  • Volumes (Shared persistent disks)

Pod的狀態有:Running /Pending /Succeeded /Failed /Unknown/Waiting。其中的Unknown是指control plane無法探知目前的狀態。如果是Pending狀態,有可能是資源不夠scheduler決定要放哪一個node。如果是waiting的話,通常是pull image失敗。

Deployment vs Replica Set

每一個Deployment都代表一個微服務。並且在我們更換新版本的Application時,Deployment的機制確保在更版時不會有downtime。

而Replica set是指有一個我們所規定數量的Pod要能運行。不論發生何事,Replica set都確保規定數量的PoD都能運作。Replica set也可以有新版本的設定,例如:

kubectl set image deployment j1 j1=j1:v2

這時就會產生同一個deployment name,卻有不同版號的Replica Set。

Service

我們上面提到,每一個Pod都有自己的IP。但是同一群Pod卻跑相同的Application,哪我們要怎麼把它們集合起來呢?這時我們就會create一個對外的service(就是一個Load Balancer):

kubectl expose deployment <name> --type=LoadBalancer --port=<port number>

這個做法跟我們在GCE(MIG)前面加上一個LB是一樣的。不論後面的instance發生何事,最前端都會有一個固定的IP讓user可以存取。而service的種類有以下三種:

  • ClusterIP:這只存在於Cluster的內部使用,所以該service只有內部IP。
  • LoadBalancer: 這是讓Applicaion可以對cluster外部服務。通常是一個微服務對應一個LB。
  • NodePort:這是把Node(該台VM)的port直接拿來用。通常我們不想微服務建立外部的LB。直接用某台node的port,但有其問題所在。通常應該使用Ingress的方式。我們可以用一個Ingress來對應多個微服務。

以下為一個Ingress範例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gateway-ingress
spec:
rules:
- http:
paths:
- path: /jason-exchange/*
backend:
serviceName: jason-exchange
servicePort: 8000
- path: /jason-conversion/*
backend:
serviceName: jason-conversion
servicePort: 8100

如果我們的Cluster有很多個微服務,哪麼應該要用一個Ingress來取代一堆LB。Ingress提供以下功能

  • load balancing與SSL termination
  • 可以用規則來控制流量

Container Registry — Image Repository

這是一個GCP提供類似Docker Hub的功能的託管服務。可以整合在GCP的CI/CD tools中。我們可以在這個服務中進行一些弱點分析與執行一些deployment policies。Image的命名方式如下:

HostName/ProjectID/Image:Tag — gcr.io/projectname/helloworld:1

GKE的使用場景

  1. 希望保持較低的成本並優化 GKE
    方法:考慮Spot VM、較便宜的region、使用CUD。用E2 機器類型(最便宜的)。另外選擇適合工作負載類型的正確環境(如果需要,請使用多個node pool)
  2. 要高效、完全的Auto scaling
    方法:可以使用GKE解決方案,如配置 Horizo​​ntal Pod Autoscaler 以進行部署和針對node pool的Cluster Autoscaler
  3. 想要在 K8s Cluster中執行不受信任的第三方代碼
    方法:使用 GKE Sandbox 建立新的node pool。 將不受信任的代碼部署到Sandbox node pool
  4. 只想在K8S cluster中的微服務部署之間啟用內部通訊
    方法:建立 Cluster IP 類型的服務

Cloud Function(GCP的serverless/even based)

當我們想要單純的運行某些小量代碼(簡單的事情)而不想管理其底層的所有基礎設施。就可以選用Cloud Function。例如將檔案upload到Cloud Storage或把error log寫到Cloud logging或接受 Http request等這一類event based的行為。

因為不用管理其底層基礎架構,所以其擴充性(scaling)與可用性(availability)就由GCP來承擔並且進行管理。我們只要專注於我們的代碼就可以了。

而其計費的方式需要考慮以下三種維度:

  1. 被呼叫的次數
  2. 每次被呼叫後的運算時間(最短一分鐘,最長60分鐘)
  3. 啟動的CPU/Memory

Cloud Function有兩個世代,第二代的支援較多。它是建立在Cloud Run與Eventarc之上的。

由於Cloud Function是event based的服務。所以在其整個概念中會分為:

  • Trigger — 當事件發生時,哪一個function會被觸發?
  • Functions — 取得事件的資料並進行某些動作

事件的觸發來源可以來自:

  • Cloud Storage
  • Cloud Pub/Sub
  • HTTP POST/GET/DELETE/PUT/OPTIONS
  • Firebase Cloud Firestore
  • Cloud logging

Http類型的Node.js代碼範例

const escapeHtml = require('escape-html');

exports.helloHttp = (req, res) => {
res.send(`Hello ${escapeHtml(req.query.name || req.body.name || 'World')}!`);
};

Pub/Sub的Node.Js代碼範例

/**
* Background Cloud Function to be triggered by Pub/Sub.
* This function is exported by index.js, and executed when
* the trigger topic receives a message.
*
* @param {object} message The Pub/Sub message.
* @param {object} context The event metadata.
*/
exports.helloPubSub = (message, context) => {
const name = message.data
? Buffer.from(message.data, 'base64').toString()
: 'World';
console.log(`Hello, ${name}!`);
};

Cloud Run for Anthos

Cloud Run也是一個Container的服務,只是它不用像GKE哪樣需要設計與管理整個K8S Cluster。它是建立在Knative之上的,也就是K8s+Serverless。一種針對containerized applications的全託管式serverless平台。號稱:

  • ZERO infrastructure management
  • Pay-per-use (For used CPU, Memory, Requests and Networking)

可以高度的與整個軟體開發流程進行整合,如Cloud Code, Cloud Build, Cloud Monitoring & Cloud Logging Integrations。而Anthos就是將我們的container運行在任何地方(雲端/地端/多雲),不過Control plane還是在GCP身上。

Cloud Run for anthos就是將工作負載部署到 Anthos cluster上,不論是在地端或GCP上。並利用我們現有的資產來運作Container的serverless platform。

第二代Cloud Function

第二代的加強功能如下:

  • 針對HTTP-triggered functions,timeout時間可以設定到60分鐘
  • 更大的instance size — 16GiB RAM/4 vCPU (一代只能到 8GB RAM/2 vCPU)
  • 每個Function instance可以有1000 Concurrency requests
  • 同一個Function有多個版本,所以可以做到Traffic splitting
  • 可以90以上的 event types

Scaling and Concurrency

一般serverless function的架構是:

  • Autoscaling — 當負載/流量變大時,系統會自行增加/縮減 instance
  • 一個instance function,同一時間只能接收一個request(第二代沒有這種限制)

而serverless通常會有cold start(冷開機)的問題。也就是當有request進來時,instance才會被create。通常會設定最小數量的instance,但是會有成本增加的問題。

最佳實踐

  1. 不設定最大的instance上限,以防大流量的需求
  2. 使用Cloud Endpoints(或Apigee)來進行版本導流
  3. 使用 Cloud Run(和 Cloud Functions gen 2)
    配置哪些不同的版本應接收流量以及接收流量的數量
    如果需要,我們可以rollback到先前的版本
  4. 使用Secret Manager來儲存我們的Secrets,例如API keys.
  5. 每一個Cloud function使用不同的Service Accounts(給予roles/cloudfunctions.invoker)。

--

--

運用"雲端服務"加速企業的數位轉型願景
運用"雲端服務"加速企業的數位轉型願景

Written by 運用"雲端服務"加速企業的數位轉型願景

我們協助您駕馭名為"雲端運算"的怪獸,馴服它為您所用。諮詢請來信jason.kao@suros.com.tw. https://facebook.com/jason.kao.for.cloud

No responses yet