使用网络代理创建 GKE 专用集群以访问控制器

Last reviewed 2019-07-02 UTC

使用专用集群控制器端点创建 GKE 专用集群时,您无法通过公共互联网访问集群的控制器节点,但您必须能够访问该节点以对其进行管理。

默认情况下,集群可以通过其专用端点访问控制器,并且已获授权的网络可以在 VPC 中进行定义。

但是,如需从本地或其他 VPC 网络访问控制器,需要执行额外步骤。这是因为托管控制器的 VPC 网络由 Google 拥有,无法从通过其他 VPC 网络对等互连连接、Cloud VPN 或 Cloud Interconnect 连接的资源进行访问。

如需从本地或从通过 Cloud VPN 或 Cloud Interconnect 连接的其他 VPC 网络访问控制器,请从您的 VPC 网络到 Google 拥有的 VPC 网络之间启用路由导出

如需允许从其他 VPC 网络或从通过其他 VPC 网络对等互连(例如采用中心辐射型设计)连接的本地访问控制器,请创建在已获授权的 IP 地址空间中托管的代理,这是因为 VPC 网络对等互连不具有传递性。

本教程介绍了如何在您的 GKE 专用集群中配置代理。

目标

  • 创建没有外部访问权限的 GKE 专用集群。
  • 创建并部署 Docker 映像以运行代理。
  • 创建 Kubernetes 服务以访问代理。
  • 测试对代理的访问权限。

费用

本教程使用 Google Cloud Platform 的可计费组件,包括:

您可使用价格计算器根据您的预计用量来估算费用。

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

准备工作

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  3. 确保您的 Google Cloud 项目已启用结算功能

  4. 启用 Compute Engine and Google Kubernetes Engine API。

    启用 API

  5. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  6. 确保您的 Google Cloud 项目已启用结算功能

  7. 启用 Compute Engine and Google Kubernetes Engine API。

    启用 API

设置环境

在本教程中,您将使用 Cloud Shell 输入命令。Cloud Shell 让您能够使用 Google Cloud 控制台中的命令行,并包含在 Google Cloud 中进行开发所需的 Google Cloud CLI 和其他工具。Cloud Shell 显示为 Google Cloud 控制台底部的一个窗口。初始化可能需要几分钟,但窗口会立即显示。

为了使用 Cloud Shell 设置您的环境,请执行以下操作:

  1. 在 Google Cloud Console 中,打开 Cloud Shell。

    打开 Cloud Shell

  2. 确保正在使用您创建或选择的项目。将 [YOUR_PROJECT_ID] 替换为您的 Google Cloud 项目。

    gcloud config set project [YOUR_PROJECT_ID]
    export PROJECT_ID=`gcloud config list --format="value(core.project)"`
    
  3. 设置默认计算区域。在本教程中,计算区域为 us-central1-c。如果要部署到生产环境,请部署到您选择的区域

    gcloud config set compute/region us-central1
    gcloud config set compute/zone us-central1-c
    export REGION=us-central1
    export ZONE=us-central1-c
    
    

创建 VPC 网络和客户端虚拟机

创建用于托管资源的 VPC 网络和子网。

  1. 创建 VPC 网络:

    gcloud compute networks create k8s-proxy --subnet-mode=custom
    
  2. 在新创建的 VPC 网络中创建自定义子网:

    gcloud compute networks subnets create subnet-cluster \
        --network=k8s-proxy --range=10.50.0.0/16
    
  3. 创建将用于在 Kubernetes 集群中部署资源的客户端虚拟机:

    gcloud compute instances create --subnet=subnet-cluster \
        --scopes cloud-platform proxy-temp
    
  4. 将新创建的实例的内部 IP 地址保存在环境变量中:

    export CLIENT_IP=`gcloud compute instances describe proxy-temp \
        --format="value(networkInterfaces[0].networkIP)"`
    
  5. 创建防火墙规则以允许通过 SSH 访问 VPC 网络:

    gcloud compute firewall-rules create k8s-proxy-ssh --network k8s-proxy \
        --allow tcp:22
    

创建专用集群

现在创建一个用于本教程的专用集群。

如果您已经拥有要使用的集群,则可以跳过创建集群的步骤,但必须在客户端计算机上配置一些初始访问形式。

  • 在 Cloud Shell 中,创建一个集群:

    gcloud container clusters create frobnitz  \
        --master-ipv4-cidr=172.16.0.64/28 \
        --network k8s-proxy \
        --subnetwork=subnet-cluster \
        --enable-ip-alias \
        --enable-private-nodes \
        --enable-private-endpoint \
        --master-authorized-networks $CLIENT_IP/32 \
        --enable-master-authorized-networks
    

    该命令会创建一个名为 frobnitz 的 GKE 专用集群,并将 master-authorized-networks 设置为仅允许客户端机器访问。

创建 Docker 映像

按照以下步骤构建一个名为 k8s-api-proxy, 的 Kubernetes API 代理映像,该映像充当 Kubernetes API 服务器的转发代理。

  1. 在 Cloud Shell 中,创建一个目录并切换到该目录:

    mkdir k8s-api-proxy && cd k8s-api-proxy
  2. 创建 Dockerfile。以下配置会在 Alpine 中创建容器,它是一个具有 Privoxy 代理的轻量级分发容器。Dockerfile 还会安装 curljq 以进行容器初始化,添加必要的配置文件,在内部向 GKE 公开端口 8118,并添加启动脚本。

    FROM alpine
    RUN apk add -U curl privoxy jq && \ mv /etc/privoxy/templates /etc/privoxy-templates && \ rm -rf /var/cache/apk/* /etc/privoxy/* && \ mv /etc/privoxy-templates /etc/privoxy/templates ADD --chown=privoxy:privoxy config \ /etc/privoxy/ ADD --chown=privoxy:privoxy k8s-only.action \ /etc/privoxy/ ADD --chown=privoxy:privoxy k8s-rewrite-internal.filter \ /etc/privoxy/ ADD k8s-api-proxy.sh /
    EXPOSE 8118/tcp
    ENTRYPOINT ["./k8s-api-proxy.sh"]
  3. k8s-api-proxy 目录中,创建 config 文件并向其中添加以下内容。

    #config directory
    confdir /etc/privoxy
    # Allow Kubernetes API access only
    actionsfile /etc/privoxy/k8s-only.action
    # Rewrite https://CLUSTER_IP to https://kubernetes.default
    filterfile /etc/privoxy/k8s-rewrite-internal.filter
    # Don't show the pod name in errors
    hostname k8s-privoxy
    # Bind to all interfaces, port :8118
    listen-address  :8118
    # User cannot click-through a block
    enforce-blocks 1
    # Allow more than one outbound connection
    tolerate-pipelining 1
    
  4. 在同一目录中,创建 k8s-only.action 文件并向其中添加以下内容。请注意,k8s-api-proxy.sh 运行时将替换 CLUSTER_IP

    # Block everything...
    {+block{Not Kubernetes}}
    /
    # ... except the internal k8s endpoint, which you rewrite (see # k8s-rewrite-internal.filter). {+client-header-filter{k8s-rewrite-internal} -block{Kubernetes}} CLUSTER_IP/
  5. 创建 k8s-rewrite-internal.filter 文件并向其中添加以下内容。请注意,k8s-api-proxy.sh 运行时将替换 CLUSTER_IP

    CLIENT-HEADER-FILTER: k8s-rewrite-internal\
     Rewrite https://CLUSTER_IP/ to https://kubernetes.default/
    s@(CONNECT) CLUSTER_IP:443\
     (HTTP/\d\.\d)@$1 kubernetes.default:443 $2@ig
    
  6. 创建 k8s-api-proxy.sh 文件并向其中添加以下内容。

    #!/bin/sh
    
    set -o errexit
    set -o pipefail
    set -o nounset
    
    # Get the internal cluster IP
    export TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
    INTERNAL_IP=$(curl -H "Authorization: Bearer $TOKEN" -k -SsL https://kubernetes.default/api |
    jq -r '.serverAddressByClientCIDRs[0].serverAddress')
    
    # Replace CLUSTER_IP in the rewrite filter and action file
    sed -i "s/CLUSTER_IP/${INTERNAL_IP}/g"\
     /etc/privoxy/k8s-rewrite-internal.filter
    sed -i "s/CLUSTER_IP/${INTERNAL_IP}/g"\
     /etc/privoxy/k8s-only.action
    
    # Start Privoxy un-daemonized
    privoxy --no-daemon /etc/privoxy/config
    
  7. k8s-api-proxy.sh 设为可执行文件:

    chmod +x k8s-api-proxy.sh
  8. 构建容器并将其推送到项目中。

    docker build -t gcr.io/$PROJECT_ID/k8s-api-proxy:0.1 .
    docker push gcr.io/$PROJECT_ID/k8s-api-proxy:0.1
    

部署映像和服务

  1. 在 Cloud Shell 中,登录您之前创建的客户端虚拟机:

    gcloud compute ssh proxy-temp
    
  2. 安装 kubectl 工具。

    sudo apt-get install kubectl
    
  3. 将项目 ID 保存为环境变量:

    export PROJECT_ID=`gcloud config list --format="value(core.project)"`
    
  4. 获取集群凭据:

    gcloud container clusters get-credentials frobnitz \
    --zone us-central1-c --internal-ip
    
  5. 创建一个 Kubernetes 部署,以公开您刚刚创建的容器:

    kubectl run k8s-api-proxy \
        --image=gcr.io/$PROJECT_ID/k8s-api-proxy:0.1 \
        --port=8118
    
  6. 为内部负载平衡器创建 ilb.yaml 文件,并将以下内容复制到其中:

    apiVersion: v1
    kind: Service
    metadata:
      labels:
        run: k8s-api-proxy
      name: k8s-api-proxy
      namespace: default
      annotations:
        cloud.google.com/load-balancer-type: "Internal"
    spec:
      ports:
      - port: 8118
        protocol: TCP
        targetPort: 8118
      selector:
        run: k8s-api-proxy
      type: LoadBalancer
    
  7. 部署内部负载平衡器:

    kubectl create -f ilb.yaml
  8. 检查服务并等待为其分配 IP 地址:

    kubectl get service/k8s-api-proxy

    输出将如下所示。当您看到分配了一个外部 IP 时,代理已准备就绪。

    NAME            TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
    k8s-api-proxy   LoadBalancer   10.24.13.129   10.24.24.3    8118:30282/TCP   2m
    

    此步骤中的外部 IP 地址即是您的代理地址。

  9. 将 ILB 的 IP 地址保存为环境变量:

    export LB_IP=`kubectl get  service/k8s-api-proxy \
    -o jsonpath='{.status.loadBalancer.ingress[].ip}'`
    
  10. 将集群的控制器 IP 地址保存在环境变量中:

    export CONTROLLER_IP=`gcloud container clusters describe frobnitz \
    --zone=us-central1-c \
    --format="get(privateClusterConfig.privateEndpoint)"`
    
  11. 通过代理访问 Kubernetes API,以验证该代理是否可用:

    curl -k -x $LB_IP:8118 https://$CONTROLLER_IP/version
    
    输出将如下所示(您的输出可能会有所不同):
    {
      "major": "1",
      "minor": "15+",
      "gitVersion": "v1.15.11-gke.5",
      "gitCommit": "a5bf731ea129336a3cf32c3375317b3a626919d7",
      "gitTreeState": "clean",
      "buildDate": "2020-03-31T02:49:49Z",
      "goVersion": "go1.12.17b4",
      "compiler": "gc",
      "platform": "linux/amd64"
    }
    
  12. https_proxy 环境变量设置为 HTTP(S) 代理,以便 kubectl 命令可以从任何位置到达内部负载平衡器:

    export https_proxy=$LB_IP:8118
  13. 通过运行 kubectl 命令测试您的代理和 https_proxy 变量:

    kubectl get pods

    您将获得如下所示的输出,这表示您已通过代理成功连接到 Kubernetes API:

    NAME                             READY   STATUS    RESTARTS   AGE
    k8s-api-proxy-766c69dd45-mfqf4   1/1     Running   0          6m15s
    
  14. 退出客户端虚拟机:

    exit

清除数据

为避免因本教程中使用的资源导致您的 Google Cloud 帐号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

  1. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

删除 GKE 集群

如果您不想删除项目,请删除 GKE 集群:

gcloud container clusters delete frobnitz

后续步骤