Knative serving 的跨專案多租戶架構

本指南將逐步說明如何設定 Knative Serving,允許一或多個 Google Cloud 專案執行及管理在不同 Google Cloud 專案的 GKE 叢集上執行的工作負載。

使用 Knative Serving 時,常見的運作模式是應用程式開發人員團隊使用 Google Cloud 專案,在其他團隊的Google Cloud 專案中,部署及管理在不同 GKE 叢集中執行的服務。這項功能稱為「多租戶」,可讓平台營運商只允許開發團隊存取在貴機構各種環境 (例如正式版與預先發布版) 中執行的服務。

Knative serving 專門支援企業多租戶。這類多租戶可讓叢集 Google Cloud 專案存取 GKE 叢集的特定資源。獲准存取叢集專案的專案是 Google Cloud Google Cloud 租戶 Google Cloud 專案。叢集 Google Cloud 專案的租戶可以使用 Knative serving 存取、操作及擁有獲准存取的服務和資源。

從概念上來說,使用 Knative Serving 設定企業多租戶有四個步驟:

  1. 使用 Google 群組和 Identity and Access Management,設定租戶對叢集 Google Cloud 專案的存取權。
  2. 將每個租戶 Google Cloud 專案對應至叢集 Google Cloud 專案。
  3. 使用記錄檔值區和接收器,將叢集 Google Cloud 專案記錄資料傳送至租戶 Google Cloud 專案。
  4. 使用角色型存取權控管,為租戶定義叢集權限。

事前準備

負責設定多租戶的平台營運人員必須瞭解並滿足下列需求:

定義本機環境變數

如要簡化這個程序中使用的指令,請為叢集 Google Cloud 專案和租戶 Google Cloud 專案定義本機環境變數:

  1. YOUR_CLUSTER_PROJECT_ID 替換為叢集專案的 ID,然後執行下列指令: Google Cloud

    export CLUSTER_PROJECT_ID=YOUR_CLUSTER_PROJECT_ID
    
  2. YOUR_TENANT_PROJECT_ID 替換為租戶專案的 ID,然後執行下列指令: Google Cloud

    export TENANT_PROJECT_ID=$YOUR_TENANT_PROJECT_ID
    
  3. 執行下列指令,確認本機環境變數:

    echo "cluster Google Cloud project is:" $CLUSTER_PROJECT_ID
    echo "tenant Google Cloud project is:" $TENANT_PROJECT_ID
    

現在,所有指定 $CLUSTER_PROJECT_ID$TENANT_PROJECT_ID 的下列指令都會使用叢集 Google Cloud 專案 ID 和租戶 Google Cloud 專案 ID。

驗證身分與存取權管理權限

執行下列 testIamPermissions 指令,確認您具備必要的 IAM 權限,可存取叢集 Google Cloud 專案和租戶 Google Cloud 專案中的資源。

執行下列指令,驗證叢集 Google Cloud 專案的權限:

curl -X POST \
  -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
  --header "Content-Type: application/json" \
  --data '{"permissions":["logging.sinks.create", "logging.sinks.get", "resourcemanager.projects.setIamPolicy"]}' \
  https://cloudresourcemanager.googleapis.com/v1/projects/$CLUSTER_PROJECT_ID:testIamPermissions

叢集 Google Cloud 專案的預期結果:

{
  "permissions": [
    "logging.sinks.create",
    "logging.sinks.get",
    "resourcemanager.projects.setIamPolicy"
  ]
}

執行下列指令,驗證每個房客 Google Cloud 專案的權限:

curl -X POST \
  -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
  --header "Content-Type: application/json" \
  --data '{"permissions":["logging.buckets.create", "logging.buckets.get", "resourcemanager.projects.setIamPolicy", "resourcesettings.settingvalues.create", "serviceusage.services.enable"]}' \
  https://cloudresourcemanager.googleapis.com/v1/projects/$TENANT_PROJECT_ID:testIamPermissions

每個用戶群專案的預期結果: Google Cloud

{
  "permissions": [
    "logging.buckets.create",
    "logging.buckets.get",
    "resourcemanager.projects.setIamPolicy",
    "resourcesettings.settingvalues.create",
    "serviceusage.services.enable",
  ]
}

使用 Google 群組和 Identity and Access Management 設定房客存取權

使用 Google 群組,允許房客存取 GKE 叢集。 IAM 權限可讓租戶取得憑證,但必須在後續步驟中設定 Kubernetes 角色式存取權控管,租戶才能在叢集中執行任何操作。

您必須建立 Google 群組,並將所有租戶 Google Cloud 專案的使用者納入其中。 如要進一步瞭解如何使用安全性群組,請參閱「使用 Google 群組管理 GKE」。

為 Google 群組建立下列本機環境變數:

export SECURITY_GROUP=gke-security-groups@company.com

Kubernetes 叢集檢視者

執行下列指令,允許租戶取得叢集的憑證,但這不會允許租戶讀取或操控 GKE 叢集上的任何資源。

IAM 參考資料

gcloud projects add-iam-policy-binding $CLUSTER_PROJECT_ID \
   --member=group:$SECURITY_GROUP \
   --role='roles/container.clusterViewer' \
   --condition=None

如要限制特定叢集的存取權,可以使用 IAM 條件

gcloud projects add-iam-policy-binding $CLUSTER_PROJECT_ID \
   --member=group:$SECURITY_GROUP \
   --role='roles/container.clusterViewer' \
   --condition="expression=resource.name == 'cluster-name',title=Restrict cluster access"

監控檢視者

執行下列指令,允許租戶讀取監控指標。

監控角色參考資料

gcloud projects add-iam-policy-binding $CLUSTER_PROJECT_ID \
   --member=group:$SECURITY_GROUP \
   --role='roles/monitoring.viewer' \
   --condition=None

將每個租戶 Google Cloud 專案對應至叢集 Google Cloud 專案

您可以使用資源設定值,將租戶 Google Cloud 專案對應至叢集 Google Cloud 專案。

您可以為每個個別租戶 Google Cloud 專案設定資源,也可以在資料夾階層的任何層級設定資源。在單一租戶資料夾層級設定較為簡單,但在每個租戶專案層級設定則更具彈性。設定完成後,房客瀏覽 Knative 服務 UI 時,也會在叢集 Google Cloud 專案中看到自己的服務。這不會變更叢集 Google Cloud 專案或 GKE 叢集的 IAM 權限,只會將租戶專案 (或資料夾) 對應至叢集 Google Cloud 專案。

  1. 在租戶 Google Cloud 專案中啟用 resourcesettings API。

    gcloud services enable resourcesettings.googleapis.com \
      --project=$TENANT_PROJECT_ID
    
  2. 執行下列指令,將機構管理員權限 (roles/resourcesettings.admin) 新增至使用者 ID:

    gcloud organizations add-iam-policy-binding YOUR_ORGANIZATION_ID \
      --member=YOUR_ADMIN_MEMBER_ID \
      --role='roles/resourcesettings.admin'
    

    YOUR_ORGANIZATION_ID 替換為機構 ID,並將 YOUR_ADMIN_MEMBER_ID 替換為使用者 ID,例如 user:my-email@my-domain.com

  3. 選擇下列其中一種方法來定義對應。

    如果所有子項 Google Cloud 專案和 Google Cloud 資料夾都使用相同的值,您可以在上層 Google Cloud 資料夾中設定資源設定值。

用戶群專案

為每個租戶 Google Cloud 專案設定資源設定值:

  1. 取得租戶name專案的 Google Cloud ,並將其設為本機環境變數:
    export TENANT_PROJECT_NUMBER=$(gcloud projects describe $TENANT_PROJECT_ID --format="value(projectNumber)")
  2. 建立資源設定值檔案,定義從租戶 Google Cloud 專案到叢集 Google Cloud 專案的對應關係。您可以在這個檔案中定義多個叢集 Google Cloud 專案 ID,並新增至單一租戶 Google Cloud 專案。
    cat > value-file.json << EOF
    {
    "name": "projects/$TENANT_PROJECT_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
  3. 將資源設定部署至租戶 Google Cloud 專案:
    gcloud resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --project $TENANT_PROJECT_ID

租戶資料夾

為父項租戶資料夾設定資源設定值,將該值套用至所有子項租戶 Google Cloud 專案和資料夾:

  1. 取得租戶資料夾的 number,並將其設為本機環境變數:
    export TENANT_FOLDER_NUMBER=$TENANT_FOLDER_NUMBER
  2. 建立資源設定值檔案,定義從租戶資料夾到叢集 Google Cloud 專案的對應關係。您可以在這個檔案中定義多個叢集 Google Cloud 專案 ID,並新增至單一租戶資料夾。
    cat > value-file.json << EOF
    {
    "name": "folders/$TENANT_FOLDER_NUMBER/settings/cloudrun-multiTenancy/value",
    "value": {
      "stringSetValue": {
        "values": [ "projects/$CLUSTER_PROJECT_ID" ]
      }
    }
    }
    EOF
  3. 將資源設定部署至租戶資料夾:
    gcloud resource-settings set-value cloudrun-multiTenancy --value-file value-file.json --folder $TENANT_FOLDER_NUMBER

設定記錄檔 bucket 和接收器,以轉送記錄資料

為每個租戶建立記錄檔 bucket、接收器和權限,將叢集 Google Cloud 專案記錄檔資料傳送至租戶 Google Cloud 專案。在下列步驟中,叢集 Google Cloud 專案中命名空間的所有記錄檔都會傳送至值區。如要進一步瞭解如何限制共用的記錄,請參閱下方的設定。

建立下列本機環境變數:

  • 指定租戶可存取的 GKE 叢集命名空間。
  • 接收器的名稱。為簡化這個步驟,名稱會結合您先前建立的叢集 Google Cloud 專案和租戶 Google Cloud 專案本機環境變數。您可以修改這個值。
export NAMESPACE=$NAMESPACE
export SINK_NAME=$CLUSTER_PROJECT_ID-$TENANT_PROJECT_ID

執行下列指令,在租戶專案中建立記錄 bucket。請注意,記錄值區名稱必須是叢集 Google Cloud 專案的 ID,且無法變更或修改。

gcloud logging buckets \
   create $CLUSTER_PROJECT_ID \
   --location=global \
   --project=$TENANT_PROJECT_ID

執行下列指令,從叢集 Google Cloud 專案的指定命名空間建立接收器,傳送至租戶 Google Cloud 專案 bucket。請注意,您可以縮小記錄的範圍,例如定義其他 log-filter,只分享個別 GKE 叢集或特定 Knative 服務資源。

gcloud logging sinks \
   create $SINK_NAME \
   logging.googleapis.com/projects/$TENANT_PROJECT_ID/locations/global/buckets/$CLUSTER_PROJECT_ID \
   --log-filter=resource.labels.namespace_name=$NAMESPACE \
   --project $CLUSTER_PROJECT_ID

執行下列指令,將記錄接收器服務帳戶的權限新增至您建立的值區。

export SINK_SERVICE_ACCOUNT=$(gcloud logging sinks \
   describe $SINK_NAME \
   --project $CLUSTER_PROJECT_ID \
   --format="value(writerIdentity)")
gcloud projects add-iam-policy-binding $TENANT_PROJECT_ID \
   --member=$SINK_SERVICE_ACCOUNT \
   --role='roles/logging.bucketWriter' \
   --condition="expression=resource.name.endsWith\
   (\"locations/global/buckets/$CLUSTER_PROJECT_ID\"),\
   title=Log bucket writer from $CLUSTER_PROJECT_ID"

使用角色型存取控制 (RBAC) 設定房客權限

您先前使用 Google 群組和 IAM 設定權限,允許租戶存取 GKE 叢集的 Google Cloud 專案。如要允許租戶存取 GKE 叢集內的資源,您必須使用 Kubernetes RBAC 定義權限。

建立叢集角色

定義並建立下列叢集角色後,日後即可繼續使用這些角色,新增叢集 Google Cloud 專案的所有後續租戶。

UI 角色

這個角色可讓租戶查詢所有命名空間。這是必要步驟,因為您需要找出使用者有權建立 /sdk/gcloud/reference/logging/sinks/create 服務的命名空間。

kubectl create clusterrole \
   namespace-lister \
   --verb=list \
   --resource=namespaces

這個角色可讓房客查看 Knative serving 服務。這是列出 Knative serving UI 中服務的必要條件。

kubectl create clusterrole \
   ksvc-lister \
   --verb=list \
   --resource=services.serving.knative.dev

建立叢集角色

您只需要其中一項權限。第一個權限可讓租戶操控命名空間中的任何資源。第二個權限則只允許建立 Knative serving 服務,權限範圍較小。

kubectl create clusterrole \
   kubernetes-developer \
   --verb="*" \
   --resource="*.*"

如果 kubernetes-developer 權限過於寬鬆,租戶就能在自己的命名空間中建立 Knative 服務,並查看其他 Knative 資源。

cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: knative-developer
rules:
- apiGroups: ["serving.knative.dev"]
  resources: ["services"]
  verbs: ["*"]
- apiGroups: ["serving.knative.dev"]
  resources: ["*"]
  verbs: ["get", "list", "watch"]
EOF

建立租戶命名空間並指派權限。

請注意,這項假設的前提是您已使用 GKE 的 Google 網路論壇完成設定。每個租戶都必須執行這項操作。

export TENANT_GROUP=tenant-a@company.com

TENANT_GROUP 必須是 SECURITY_GROUP 的一部分

可查看所有命名空間

如要查詢 GKE 叢集,所有租戶都必須具備列出命名空間的能力。目前沒有 auth can-i,可傳回可執行動作的命名空間。唯一的解決方法是列出命名空間,然後個別查詢每個命名空間。

kubectl create clusterrolebinding \
   all-namespace-listers \
   --clusterrole=namespace-lister \
   --group=$TENANT_GROUP

能夠列出 Knative serving 服務

kubectl create clusterrolebinding \
   all-ksvc-listers \
   --clusterrole=ksvc-lister \
   --group=$TENANT_GROUP

可操控命名空間中的資源

請先建立命名空間:

kubectl create namespace $NAMESPACE

如果使用 kubernetes-developer 角色:

kubectl create rolebinding \
   kubernetes-developer \
   --namespace=$NAMESPACE \
   --clusterrole=kubernetes-developer \
   --group=$TENANT_GROUP

如果使用 knative-developer 角色:

kubectl create rolebinding \
   kubernetes-developer \
   --namespace=$NAMESPACE \
   --clusterrole=knative-developer \
   --group=$TENANT_GROUP

新增租戶存取外部 IP 位址的功能

cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ingress-reader
rules:
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get"]
EOF
kubectl create rolebinding \
   ingress-reader-$TENANT_GROUP \
   --namespace=istio-system \
   --clusterrole=ingress-reader \
   --group=$TENANT_GROUP

驗證

如要確認是否已成功設定企業多租戶,請在 Knative Serving 中開啟租戶 Google Cloud 專案,並將服務部署至 GKE 叢集。

前往 Knative serving

恭喜!現在租戶可以與 GKE 叢集命名空間中的服務和資源互動,前提是他們已獲得存取權。

多用戶群參考資料