GKE 上的多租户日志记录

本页面介绍如何为 Google Kubernetes Engine (GKE) 集群配置多租户日志记录。

多个团队通常会共享一个 GKE 集群。共享集群具有多项优势,包括简化服务发现、简化安全性,以及减少集群管理员需要维护的集群。但是,各个应用团队通常会有单独的项目。这种结构称为多租户,具有一个主 GKE 集群,但每个应用团队都有单独的命名空间。应用团队的项目称为租户。

借助 Google Cloud,GKE 集群管理员可以创建一个系统,其中集群的日志保留在主 GKE 项目中,并且租户日志会分配到租户项目。要以这种方式配置日志,请使用 Cloud Logging 日志路由器。通过日志路由器,您可以控制 Google Cloud 项目中的日志流以及日志如何流向其他 Google Cloud 项目。

如需创建特定于租户的日志,集群管理员需要创建一个接收器,以将日志条目路由到租户项目中创建的日志存储桶。您还可以选择创建排除规则,以防止将租户日志存储在主 GKE 项目中。

下图简要介绍了使用日志存储分区的多租户日志记录架构:

GKE 多租户架构

此架构包括:

  1. 在每个租户项目中创建的日志存储分区
  2. 为每个租户命名空间创建的日志接收器
  3. 为每个日志接收器自动创建的服务帐号
  4. (可选)用于防止主 GKE 项目中的日志重复的排除规则

以下几个部分将指导您如何创建此类架构。

前提条件

配置多租户日志记录

您可以使用 gcloud 命令行工具或 Google Cloud Console 配置多租户日志记录。

gcloud

如需为 GKE 集群实现多租户日志记录,请完成以下步骤:

  1. 设置变量:

    export TENANT_NAMESPACE="TENANT_NAMESPACE"
    export MAIN_PROJECT="MAIN_PROJECT_ID"
    export TENANT_PROJECT="TENANT_PROJECT_ID"
    

    请替换以下内容:

    • TENANT_NAMESPACE:租户项目命名空间的名称
    • MAIN_PROJECT_ID:主项目的项目 ID
    • TENANT_PROJECT_ID:租户项目的项目 ID
  2. 在多租户集群中创建命名空间:

    kubectl create namespace $TENANT_NAMESPACE
    
  3. 在租户项目中创建日志存储分区

    gcloud logging buckets create gke-$TENANT_NAMESPACE-log-bucket \
        --project=$TENANT_PROJECT \
        --location=global \
        --description="Log bucket for $TENANT_NAMESPACE namespace from $MAIN_PROJECT"
    

    如需详细了解这些字段,请参阅 gcloud logging buckets create API 文档

  4. 在主 GKE 项目中创建日志接收器:

    gcloud logging sinks create gke-$TENANT_NAMESPACE-sink \
    logging.googleapis.com/projects/$TENANT_PROJECT/locations/global/buckets/gke-$TENANT_NAMESPACE-log-bucket \
        --project=$MAIN_PROJECT \
        --log-filter=resource.labels.namespace_name="$TENANT_NAMESPACE" \
        --description="Log sink to $TENANT_PROJECT for $TENANT_NAMESPACE namespace"
    

    此命令会创建一个日志接收器,将与 $TENANT_NAMESPACE 命名空间相关的所有日志发送到您在上一步中创建的日志存储分区。

    有时,您可能需要使用限制性更强的 --log-filter。例如,如果您的集群和租户具有相同的命名空间,则可以添加集群过滤条件。

    如需详细了解这些字段,请参阅 gcloud logging sinks create API 文档

  5. 从主项目的接收器获取服务帐号,并将其分配给变量。在下一步中,您需要此服务帐号来授予权限。

    export SERVICE_ACCOUNT=$(gcloud logging sinks describe gke-$TENANT_NAMESPACE-sink \
        --project=$MAIN_PROJECT \
        --format='value(writerIdentity)')
    
  6. logging.bucketWriter 角色授予接收器使用的服务帐号。主项目需要此权限才能写入租户项目中的存储分区。

     gcloud projects add-iam-policy-binding $TENANT_PROJECT \
         --member=$SERVICE_ACCOUNT --role='roles/logging.bucketWriter' \
         --condition="expression=resource.name.endsWith(\"locations/global/buckets/gke-$TENANT_NAMESPACE-log-bucket\"),title=Log bucket writer for $TENANT_NAMESPACE,description=Grants logging.bucketWriter role to service account $SERVICE_ACCOUNT used by gke-$TENANT_NAMESPACE-sink"
    

    如需详细了解这些字段,请参阅 gcloud projects add-iam-policy-binding API 文档

  7. (可选)在 _Default 存储分区中创建排除规则。此规则将阻止租户日志也写入主存储分区。如果您省略此命令,则主项目的 _Default 存储桶和租户存储桶中将会出现重复日志。

    gcloud logging sinks update _Default --project=$MAIN_PROJECT \
        --add-exclusion="name=gke-$TENANT_NAMESPACE-default-exclusion,description=\"Exclusion rule on the _Default bucket for $TENANT_NAMESPACE\",filter=resource.labels.namespace_name=\"$TENANT_NAMESPACE\""
    

    如需详细了解这些字段,请参阅 gcloud logging sinks update API 文档

控制台

如需为 GKE 实现多租户日志记录,请完成以下步骤:

  1. 在租户项目中创建日志存储分区:

    1. 转到日志存储菜单:

      转到“日志存储”

    2. 点击页面顶部的项目下拉列表,然后选择租户项目。

    3. 点击创建日志存储分区

    4. 输入存储桶的名称说明

    5. 选择日志存储分区区域下拉列表中,选择一个区域。

    6. 点击创建存储分区。您的新存储桶将显示在日志存储桶列表中。

  2. 在主 GKE 项目中创建日志接收器:

    1. 点击页面顶部的项目下拉列表,然后选择主 GKE 项目。
    2. 在左侧菜单中,选择日志路由器。您将转到“日志路由器”页面。
    3. 点击创建接收器。此时将显示选择接收器窗口。
    4. 选择接收器窗口中,选择 Cloud Logging 存储桶
    5. 输入接收器的名称说明,然后点击下一步
    6. 选择接收器服务下拉列表中,选择其他项目
    7. 接收器目标位置字段中,添加以下目的地:logging.googleapis.com/projects/TENANT_PROJECT_ID/locations/LOG_BUCKET_REGION/buckets/BUCKET_NAME

      请替换以下内容:

      • TENANT_PROJECT_ID:主项目的项目 ID
      • LOG_BUCKET_REGION:您在其中创建日志存储桶的区域
      • BUCKET_NAME:您在上一部分中创建的日志存储桶的名称
    8. 点击下一步

    9. 构建包含项过滤条件中,添加以下过滤条件:resource.labels.namespace_name="TENANT_NAMESPACE"。将 TENANT_NAMESPACE 替换为租户项目命名空间的名称。

      有时,您可能需要使用更严格的包含过滤器。例如,如果您的集群和租户具有相同的命名空间,则可以添加集群过滤条件。

    10. 点击创建接收器。新接收器将显示在日志路由接收器列表中。

  3. 从主项目的接收器中获取服务帐号。在下一步中,您需要此服务帐号来授予权限。

    1. 在“日志路由器”页面中,从主项目找到日志接收器。
    2. 在该接收器旁边,点击 更多,然后选择查看接收器详情
    3. 复制“写入者身份:serviceAccount:”旁边的值。
  4. 向租户的接收器使用的服务帐号授予 Log Bucket Writer 角色。主项目需要此权限才能写入租户项目中的存储分区。

    1. 在 Cloud Console 中,转到 IAM 页面。

      转到 IAM

    2. 点击添加

    3. 新成员字段中,添加接收器的服务帐号。

    4. 选择角色下拉列表中,选择日志记录,然后选择 Log Bucket Writer

    5. 点击保存

  5. (可选)在 _Default 存储分区中创建排除规则。这将阻止租户日志也写入主存储分区。如果您省略此命令,则主项目的 _Default 存储桶和租户存储桶中将会出现重复日志。

    1. 在 Cloud Console 中,转到日志路由器页面。

      转到日志路由器

    2. _Default 存储桶旁边,点击 更多,然后选择修改接收器

    3. 选择要从接收器中过滤掉的日志部分,点击添加排除项

    4. 添加过滤条件名称。

    5. 构建排除项过滤条件框中,添加 resource.labels.namespace_name="TENANT_NAMESPACE"

    6. 点击更新接收器

验证租户日志

开始使用那些使用 TENANT_NAMESPACE 的工作负载后,您可以验证租户项目是否接收特定于租户的日志:

  1. 从租户项目中,转到 Cloud Console 中的日志查看器页面。

    转到“日志查看器”

  2. 点击优化范围

  3. 选择按存储确定范围,然后选择租户的存储分区:

    gke-TENANT_NAMESPACE-log-bucket
    

清理

您可以使用 gcloud 或 Cloud Console 移除为多租户日志记录创建的对象。

gcloud

如需移除为多租户日志记录创建的对象,请完成以下步骤:

  1. 设置变量以简化以下命令:

    export TENANT_NAMESPACE="TENANT_NAMESPACE"
    export MAIN_PROJECT="MAIN_PROJECT_ID"
    export TENANT_PROJECT="TENANT_PROJECT_ID"
    

    请替换以下内容:

    • TENANT_NAMESPACE:租户项目命名空间的名称
    • MAIN-PROJECT-ID:主项目的项目 ID
    • TENANT-PROJECT-ID:租户项目的项目 ID
  2. 如果您在主项目中创建了排除规则,请将其移除:

    gcloud logging sinks update _Default \
       --project=$MAIN_PROJECT \
       --remove-exclusions=gke-$TENANT_NAMESPACE-default-exclusion
    
  3. 从服务帐号中移除 bucketWriter 角色:

    export SERVICE_ACCOUNT=$(gcloud logging sinks describe gke-$TENANT_NAMESPACE-sink \
        --project=$MAIN_PROJECT | \
        --format='value(writerIdentity)'
    
    gcloud projects remove-iam-policy-binding $TENANT_PROJECT \
        --member=$SERVICE_ACCOUNT \
        --role='roles/logging.bucketWriter' \
        --all
    
  4. 删除日志接收器:

    gcloud logging sinks delete gke-$TENANT_NAMESPACE-sink \
        --project=$MAIN_PROJECT
    
  5. 删除日志存储分区:

    gcloud logging buckets delete gke-$TENANT_NAMESPACE-log-bucket \
        --project=$TENANT_PROJECT \
        --location=global
    
  6. 删除命名空间:

    kubectl delete namespace $TENANT_NAMESPACE
    

控制台

  1. 如果您在主项目中创建了排除规则,请将其移除:

    1. 在 Cloud Console 中,转到日志路由器页面。

      转到日志路由器

    2. _Default 存储分区旁边,点击更多

    3. 选择修改接收器

    4. 在您创建的排除规则旁边,点击删除

    5. 点击更新接收器

  2. 在主项目中,移除服务帐号:

    1. 在 Cloud Console 中,转到 IAM 页面。

      转到 IAM

    2. 选择接收器的服务帐号。

    3. 点击移除

    4. 在确认窗口中,点击确认

  3. 在租户项目中,删除日志接收器:

    1. 点击页面顶部的项目下拉列表,然后选择租户 GKE 项目。
    2. 从“日志记录”菜单中选择日志路由器

      转到日志路由器

    3. 对于要删除的接收器,点击更多

    4. 选择删除接收器

    5. 在确认面板中,点击删除

  4. 在主项目中,删除日志存储分区:

    1. 点击页面顶部的项目下拉列表,然后选择主 GKE 项目。
    2. 从“日志记录”菜单中选择日志存储

      转到“日志存储”

    3. 对于要删除的存储分区,点击更多

    4. 选择删除存储分区

    5. 在确认面板上,点击删除

限制

多租户日志记录具有以下限制:

  • 每个项目的日志接收器数量配额为 200。如果您需要超过 200 个租户,请打开支持案例来申请增加配额。
  • 每个日志存储分区最多只能包含 50 条排除规则。如果您希望拥有超过 50 个租户,则需要修改 _Default 存储分区的排除规则方法。或者,您也可以执行以下操作:

    • 创建一条排除规则,以使用以下命令过滤掉所有非系统或非默认命名空间:

      gcloud logging sinks update _Default \
      --project=$MAIN_PROJECT \
      --add-exclusion="name=gke-all-tenant-default-exclusion,description=\"Exclusion rule on the _Default bucket for all tenants\",filter=resource.labels.namespace_name !~ \"kube\" AND resource.labels.namespace_name !~ \"system\ AND resource.labels.namespace_name != \"Default\""
      
    • 通过不创建排除规则,在租户项目和主项目之间复制日志。

后续步骤