通过 Ingress 配置 Cloud CDN

本指南介绍如何使用 BackendConfig 自定义资源定义 (CRD) 在 Google Kubernetes Engine (GKE) 中配置 Cloud CDN

概览

在 GKE 集群中,HTTP(S) 负载平衡Cloud Load Balancing 的一个组件)负责处理传入流量。通常 HTTP(S) 负载平衡器由 GKE Ingress 控制器配置,该控制器从 Kubernetes Ingress 对象获取配置信息。Ingress 与一个或多个 Service 对象相关联。每个 Service 对象包含用于将传入请求定向到特定 Pod 和端口的路由信息。

从 Kubernetes 1.10.5-gke.3 版本开始,您可以为外部负载平衡器提供其他配置,方法是将 Service 端口与名为 BackendConfig自定义资源相关联。

GKE Ingress 控制器会从 BackendConfig 读取配置信息并相应地设置负载平衡器。BackendConfig 包含特定于 Cloud Load Balancing 的配置信息。 Kubernetes Ingress 和 Service 资源不支持配置特定于提供方的功能(如 Cloud CDN);您可以通过 BackendConfig 来执行这项配置。

下面简要介绍如何在本练习中设置 BackendConfig:

  1. 创建一个 BackendConfig。
  2. 创建一个 Service,并将它的一个端口与 BackendConfig 关联。
  3. 创建一个 Ingress,并将该 Ingress 与(Service, 端口)对关联。

准备工作

在开始之前,请确保您已执行以下任务:

使用以下任一方法设定默认的 gcloud 设置:

  • 使用 gcloud init(如果您想要在系统引导下完成默认设置)。
  • 使用 gcloud config(如果您想单独设置项目 ID、区域和地区)。

使用 gcloud init

如果您收到 One of [--zone, --region] must be supplied: Please specify location 错误,请完成本部分。

  1. 运行 gcloud init 并按照说明操作:

    gcloud init

    如果您要在远程服务器上使用 SSH,请使用 --console-only 标志来防止命令启动浏览器:

    gcloud init --console-only
  2. 按照说明授权 gcloud 使用您的 Google Cloud 帐号。
  3. 创建新配置或选择现有配置。
  4. 选择 Google Cloud 项目。
  5. 选择默认的 Compute Engine 区域。

使用 gcloud config

  • 设置默认项目 ID
    gcloud config set project project-id
  • 如果您使用的是区域级集群,请设置默认计算区域
    gcloud config set compute/zone compute-zone
  • 如果您使用的是地区级集群,请设置默认计算地区
    gcloud config set compute/region compute-region
  • gcloud 更新到最新版本:
    gcloud components update

创建命名空间

为本指南中所用的对象创建 Kubernetes 命名空间:

kubectl create namespace cdn-how-to

创建 Deployment

  1. 根据以下 Deployment 清单创建名为 my-deployment.yaml 的文件。该清单声明您要运行 ingress-gce-echo-amd64 Web 应用的两个副本:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      namespace: cdn-how-to
      name: my-deployment
    spec:
      selector:
        matchLabels:
          purpose: demonstrate-cdn
      replicas: 2
      template:
        metadata:
          labels:
            purpose: demonstrate-cdn
        spec:
          containers:
          - name: echo-amd64
            image: gcr.io/google-samples/hello-app-cdn:1.0
    
  2. 创建 Deployment 资源:

    kubectl apply -f my-deployment.yaml
    

创建 BackendConfig

  1. 根据以下 BackendConfig 清单创建名为 my-backend-config.yaml 的文件。该清单指定 Cloud CDN 缓存政策并声明应启用 Cloud CDN:

      apiVersion: cloud.google.com/v1
      kind: BackendConfig
      metadata:
        namespace: cdn-how-to
        name: my-backend-config
      spec:
        cdn:
          enabled: true
          cachePolicy:
            includeHost: true
            includeProtocol: true
            includeQueryString: false
    
  2. 创建 BackendConfig 资源:

    kubectl apply -f my-backend-config.yaml
    
  3. 查看 BackendConfig:

    kubectl get backendconfig my-backend-config --output yaml --namespace cdn-how-to
    

    您可以在输出中看到 Cloud CDN 缓存政策:

      apiVersion: cloud.google.com/v1
      kind: BackendConfig
      metadata:
        name: my-backend-config
        namespace: cdn-how-to
        ...
      spec:
        cdn:
          cachePolicy:
            includeHost: true
            includeProtocol: true
            includeQueryString: false
          enabled: true
    

创建 Service

  1. 根据以下 Service 清单创建名为 my-service.yaml 的文件:

    apiVersion: v1
    kind: Service
    metadata:
      namespace: cdn-how-to
      name: my-service
      labels:
        purpose: demonstrate-cdn
      annotations:
        cloud.google.com/backend-config: '{"ports": {"80":"my-backend-config"}}'
    spec:
      type: NodePort
      selector:
        purpose: demonstrate-cdn
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
    
  2. 创建 Service 资源:

    kubectl apply -f my-service.yaml
    
  3. 查看 Service:

    kubectl get service my-service --namespace cdn-how-to --output yaml
    

    输出类似于以下内容:

    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        cloud.google.com/backend-config: '{"ports": {"80":"my-backend-config"}}'
        ...
      labels:
        purpose: demonstrate-cdn
      name: my-service
      namespace: cdn-how-to
      ...
    spec:
      clusterIP: 10.51.255.39
      externalTrafficPolicy: Cluster
      ports:
      - nodePort: 31484
        port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        purpose: demonstrate-cdn
      sessionAffinity: None
      type: NodePort
    status:
      loadBalancer: {}
    

    在本练习中,您需要注意有关 Service 的以下重要事项:

    • Service 的端口 80 与名为 my-backend-config 的 BackendConfig 相关联。 这是由 cloud.google.com/backend-config 注释指定的。

    • Service 类型为 NodePort。对于要与 Ingress 关联的 Service,这是一种典型类型。

    • 具有 purpose: demonstrate-cdn 标签的任何 Pod 都是 Service 的成员。这是由 selector 字段指定的。

    • 定向至 TCP 端口 80 上的服务的流量被路由到 TCP 端口 8080 上的其中一个成员 Pod。这是由 porttargetPort 字段指定的。

保留静态外部 IP 地址

  1. 保留静态外部 IP 地址:

    gcloud compute addresses create cdn-how-to-address --global
    
  2. 查看静态外部 IP 地址:

    gcloud compute addresses list --filter "name=cdn-how-to-address"
    

    输出会显示地址的名称和值:

    NAME                ...     ADDRESS        STATUS
    cdn-how-to-address          203.0.113.1    RESERVED
    

创建 Ingress

  1. 根据以下 Ingress 清单创建名为 my-ingress.yaml 的文件:

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      namespace: cdn-how-to
      name: my-ingress
      annotations:
        kubernetes.io/ingress.global-static-ip-name: "cdn-how-to-address"
    spec:
      rules:
      - http:
          paths:
          - path: /*
            backend:
              serviceName: my-service
              servicePort: 80
    
  2. 创建 Ingress 资源:

    kubectl apply -f my-ingress.yaml
    
  3. 请等待十分钟,让 Kubernetes Ingress 控制器配置 Cloud Load Balancing 负载平衡器,然后查看 Ingress:

    kubectl get ingress my-ingress --output yaml --namespace cdn-how-to
    

    输出类似于以下内容:

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      ...
      name: my-ingress
      namespace: cdn-how-to
      ...
    spec:
      rules:
      - http:
          paths:
          - backend:
              serviceName: my-service
              servicePort: 80
            path: /*
    status:
      loadBalancer:
        ingress:
        - ip: 201.0.113.1
    

    在本练习中,您需要注意有关 Ingress 的以下重要事项:

    • 传入流量的 IP 地址列在 loadBalancer:ingress: 下。

    • Ingress 具有一条规则,该规则适用于来自任何主机的传入 HTTP 请求。这是因为该规则中没有 host 字段。因此,在默认情况下,该规则适用于所有主机。

    • 无论网址路径为何,所有传入请求都被视为相同。 这是由 path/* 指定的。

    • 传入请求被路由到 my-service 的一个成员 Pod。 在本练习中,该成员 Pod 具有 purpose: demonstrate-cdn 标签。

    • 请求被路由到 my-service 中指定的目标端口上的 Pod。在此练习中,Pod 目标端口为 8080。

查看 Web 应用

输入此 curl 命令两次:

curl -v static-address/?cache=true

其中,static-address 是您的静态外部 IP 地址。

输出显示响应标头和正文。在响应标头中,您可以看到内容已缓存。Age 标头指示内容缓存的秒数:

...
< HTTP/1.1 200 OK
< Date: Fri, 25 Jan 2019 02:34:08 GMT
< Content-Length: 70
< Content-Type: text/plain; charset=utf-8
< Via: 1.1 google
< Cache-Control: max-age=86400,public
< Age: 2716
<
Hello, world!
Version: 1.0.0
Hostname: my-deployment-7f589cc5bc-l8kr8

查看负载平衡日志

您可以通过查看 HTTP 负载平衡的 Stackdriver 日志来验证内容是否已缓存。在检查日志之前,请确保您已至少两次从应用请求响应。

控制台

  1. 在 Cloud Console 中,转到日志记录菜单中的日志页面。

    转到“日志”页面

  2. 在第一个下拉菜单中,选择云端 HTTP 负载平衡器

  3. 展开最近的日志条目,然后展开该条目的 httpRequest 字段。

  4. httpRequest 字段中,您可以看到 cacheHittrue

    httpRequest: {
    cacheHit:  true
    cacheLookup:  true
    ...
    

gcloud

运行以下命令,其中 project-id 是您的项目 ID:

gcloud logging read \
    'logName="projects/project-id/logs/requests"' \
    --limit 2

输出显示存在缓存命中:

httpRequest:
cacheHit: true
cacheLookup: true

清理

完成本指南中的练习后,请按照以下步骤移除资源,以防止您的帐号产生不必要的费用:

  1. 删除您针对此练习创建的 Kubernetes 对象:

    kubectl delete ingress my-ingress --namespace cdn-how-to
    kubectl delete service my-service --namespace cdn-how-to
    kubectl delete backendconfig my-backend-config --namespace cdn-how-to
    kubectl delete deployment my-deployment --namespace cdn-how-to
    kubectl delete namespace cdn-how-to
    
  2. 删除静态外部 IP 地址:

    gcloud compute addresses delete cdn-how-to-address --global
    

限制

无法为同一 HTTP(S) 负载平衡后端服务启用 Cloud CDN 和 Identity-Aware Proxy。

问题排查

找不到 BackendConfig

如果在 Service 注释中指定了 Service 端口的 BackendConfig,但找不到实际 BackendConfig 资源,那么就会发生这种错误。 如果您根本没有创建 BackendConfig 资源,或在错误的命名空间中创建了该资源,或在 Service 注释中拼错了引用,则会发生这种情况。

kubectl get event
KIND    ... SOURCE
Ingress ... loadbalancer-controller

MESSAGE
Error during sync: error getting BackendConfig for port 80 on service “default/my-service”:
no BackendConfig for service port exists

Cloud CDN 和 IAP 均已启用

在 BackendConfig 中同时启用了 IAP 和 Cloud CDN 时,会发生此错误。

kubectl get event
KIND    ... SOURCE
Ingress ... loadbalancer-controller

MESSAGE
Error during sync: BackendConfig default/config-default is not valid:
iap and cdn cannot be enabled at the same time.

内容未被缓存

如果您发现内容未被缓存,请确保您的应用已正确配置为启用内容缓存。如需了解详情,请参阅可缓存性

后续步骤