使用 Service 公开应用


本页面介绍如何在 Google Kubernetes Engine (GKE) 集群中创建 Kubernetes Service。有关 Service 概念的说明以及各种 Service 类型的讨论,请参阅 Service

简介

Service 的理念是将一组 Pod 端点划分为单一资源。您可以配置各种方式来访问该分组。默认情况下,您会获得稳定的集群 IP 地址,集群内部的客户端可以使用该 IP 地址与 Service 中的 Pod 通信。客户端向稳定 IP 地址发送请求,然后请求会被路由到 Service 的其中一个 Pod。

提供五种类型的 Service:

  • ClusterIP(默认)
  • NodePort
  • LoadBalancer
  • ExternalName
  • Headless

默认情况下,Autopilot 集群是公开的。如果选择使用专用 Autopilot 集群,则必须配置 Cloud NAT 以进行出站互联网连接,例如从 DockerHub 拉取映像。

本主题提供多个练习。在每个练习中,您将创建 Deployment 并将通过创建 Service 来公开其 Pod。然后,您将向 Service 发送 HTTP 请求。

准备工作

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

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。
* 创建 GKE 集群

创建 ClusterIP 类型的 Service

在本部分中,您将创建一项 ClusterIP 类型的 Service。

kubectl apply

以下是 Deployment 的清单:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  selector:
    matchLabels:
      app: metrics
      department: sales
  replicas: 3
  template:
    metadata:
      labels:
        app: metrics
        department: sales
    spec:
      containers:
      - name: hello
        image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"

将此清单复制到名为 my-deployment.yaml 的文件,然后创建该 Deployment:

kubectl apply -f my-deployment.yaml

确认三个 Pod 是否正在运行:

kubectl get pods

输出会显示三个正在运行的 Pod:

NAME                            READY   STATUS    RESTARTS   AGE
my-deployment-dbd86c8c4-h5wsf   1/1     Running   0          7s
my-deployment-dbd86c8c4-qfw22   1/1     Running   0          7s
my-deployment-dbd86c8c4-wt4s6   1/1     Running   0          7s

以下是 ClusterIP 类型的 Service 的清单:

apiVersion: v1
kind: Service
metadata:
  name: my-cip-service
spec:
  type: ClusterIP
  # Uncomment the below line to create a Headless Service
  # clusterIP: None
  selector:
    app: metrics
    department: sales
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

该 Service 所具有的选择器指定了两个标签:

  • app: metrics
  • department: sales

您之前创建的 Deployment 中的每个 Pod 都有这两个标签。因此,Deployment 中的 Pod 将成为此 Service 的成员。

将此清单复制到名为 my-cip-service.yaml 的文件,然后创建该 Service:

kubectl apply -f my-cip-service.yaml

等待 Kubernetes 为 Service 分配稳定的内部地址,然后查看 Service:

kubectl get service my-cip-service --output yaml

输出会显示 clusterIP 的值:

spec:
  clusterIP: 10.59.241.241

记下您的 clusterIP 值以备后续使用。

控制台

创建 Deployment

  1. 转到 Google Cloud 控制台中的工作负载页面。

    转到“工作负载”

  2. 点击 部署

  3. 指定容器下,选择现有容器映像

  4. 对于映像路径,请输入 us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0

  5. 点击完成,然后点击继续

  6. 配置下,对于应用名称,输入 my-deployment

  7. 标签下,创建以下标签:

    • appmetrics
    • departmentsales
  8. 集群下,选择要在其中创建 Deployment 的集群。

  9. 点击部署

  10. Deployment 准备就绪后,Deployment 详情页面随即打开。在托管 pod 下,您可以看到您的 Deployment 具有一个或多个正在运行的 Pod。

创建 Service 以公开您的 Deployment

  1. Deployment 详情页面上,点击 操作 > 公开
  2. 公开对话框中的端口映射下,设置以下值:

    • 端口80
    • 目标端口8080
    • 协议TCP
  3. Service 类型下拉列表中,选择集群 IP

  4. 点击公开

  5. Service 准备就绪后,Service 详情页面随即打开,您可以看到有关 Service 的详细信息。在集群 IP 下,记下 Kubernetes 分配给 Service 的 IP 地址。这是内部客户端在调用 Service 时可以使用的 IP 地址。

访问 Service

列出正在运行的 Pod:

kubectl get pods

在输出中,复制以 my-deployment 开头的其中一个 Pod 名称。

NAME                            READY   STATUS    RESTARTS   AGE
my-deployment-dbd86c8c4-h5wsf   1/1     Running   0          2m51s

获取其中一个正在运行的容器的 shell:

kubectl exec -it POD_NAME -- sh

POD_NAME 替换为 my-deployment 中其中一个 Pod 的名称。

在 shell 中,安装 curl

apk add --no-cache curl

在容器中,通过使用您的集群 IP 地址和端口 80,向 Service 发出请求。请注意,80 是 Service 的 port 字段的值。这是用作 Service 客户端的端口。

curl CLUSTER_IP:80

CLUSTER_IP 替换为 Service 中 clusterIP 的值。

您的请求将转发到 TCP 端口 8080 上的其中一个成员 Pod,而 8080 是 targetPort 字段的值。请注意,Service 的每个成员 Pod 必须具有一个监听端口 8080 的容器。

响应会显示 hello-app 的输出:

Hello, world!
Version: 2.0.0
Hostname: my-deployment-dbd86c8c4-h5wsf

要退出容器的 shell,请输入 exit

创建 NodePort 类型的 Service

在本部分中,您将创建一项 NodePort 类型的 Service。

kubectl apply

以下是 Deployment 的清单:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment-50000
spec:
  selector:
    matchLabels:
      app: metrics
      department: engineering
  replicas: 3
  template:
    metadata:
      labels:
        app: metrics
        department: engineering
    spec:
      containers:
      - name: hello
        image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50000"

请注意清单中的 env 对象。env 对象指定正在运行的容器的 PORT 环境变量的值将为 50000hello-app 应用监听 PORT 环境变量所指定的端口。因此在本练习中,您指示容器监听端口 50000。

将此清单复制到名为 my-deployment-50000.yaml 的文件,然后创建该 Deployment:

kubectl apply -f my-deployment-50000.yaml

确认三个 Pod 是否正在运行:

kubectl get pods

以下是 NodePort 类型的 Service 的清单:

apiVersion: v1
kind: Service
metadata:
  name: my-np-service
spec:
  type: NodePort
  selector:
    app: metrics
    department: engineering
  ports:
  - protocol: TCP
    port: 80
    targetPort: 50000

将此清单复制到名为 my-np-service.yaml 的文件,然后创建该 Service:

kubectl apply -f my-np-service.yaml

查看 Service:

kubectl get service my-np-service --output yaml

输出会显示 nodePort 值:

...
  spec:
    ...
    ports:
    - nodePort: 30876
      port: 80
      protocol: TCP
      targetPort: 50000
    selector:
      app: metrics
      department: engineering
    sessionAffinity: None
    type: NodePort
...

创建一条防火墙规则以允许 TCP 流量进入节点端口:

gcloud compute firewall-rules create test-node-port \
    --allow tcp:NODE_PORT

NODE_PORT 替换为 Service 的 nodePort 字段的值。

控制台

创建 Deployment

  1. 转到 Google Cloud 控制台中的工作负载页面。

    转到“工作负载”

  2. 点击 部署

  3. 指定容器下,选择现有容器映像

  4. 对于映像路径,请输入 us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0

  5. 点击 添加环境变量

  6. 对于,输入 PORT;对于,输入 50000

  7. 点击完成,然后点击继续

  8. 配置下,对于应用名称,输入 my-deployment-50000

  9. 标签下,创建以下标签:

    • appmetrics
    • departmentengineering
  10. 集群下,选择要在其中创建 Deployment 的集群。

  11. 点击部署

  12. Deployment 准备就绪后,Deployment 详情页面随即打开。在托管 pod 下,您可以看到您的 Deployment 具有一个或多个正在运行的 Pod。

创建 Service 以公开您的 Deployment

  1. Deployment 详情页面上,点击 操作 > 公开
  2. 公开对话框中的端口映射下,设置以下值:

    • 端口80
    • 目标端口50000
    • 协议TCP
  3. Service 类型下拉列表中,选择节点端口

  4. 点击公开

  5. Service 准备就绪后,Service 详情页面随即打开,您可以看到有关 Service 的详细信息。在端口下,记下 Kubernetes 分配给 Service 的节点端口

为节点端口创建防火墙规则

  1. 转到 Google Cloud 控制台中的防火墙政策页面。

    转到“防火墙政策”

  2. 点击 创建防火墙规则

  3. 对于名称,输入 test-node-port

  4. 目标下拉列表中,选择网络中的所有实例

  5. 对于来源 IPv4 范围,输入 0.0.0.0/0

  6. 协议和端口下,选择指定的协议和端口

  7. 选中 tcp 复选框,然后输入您记下的节点端口值。

  8. 点击创建

获取节点 IP 地址

找到其中一个节点的外部 IP 地址:

kubectl get nodes --output wide

输出内容类似如下:

NAME          STATUS    ROLES     AGE    VERSION        EXTERNAL-IP
gke-svc-...   Ready     none      1h     v1.9.7-gke.6   203.0.113.1

并非所有集群的节点都有外部 IP 地址。例如,专用集群中的节点没有外部 IP 地址。

访问 Service

在浏览器的地址栏中,输入以下内容:

NODE_IP_ADDRESS:NODE_PORT

替换以下内容:

  • NODE_IP_ADDRESS:其中一个节点的外部 IP 地址,可在上一个任务中创建服务时找到。
  • NODE_PORT:您的节点端口值。

输出内容类似如下:

Hello, world!
Version: 2.0.0
Hostname: my-deployment-50000-6fb75d85c9-g8c4f

创建 LoadBalancer 类型的 Service

在本部分中,您将创建一项 LoadBalancer 类型的 Service。

kubectl apply

以下是 Deployment 的清单:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment-50001
spec:
  selector:
    matchLabels:
      app: products
      department: sales
  replicas: 3
  template:
    metadata:
      labels:
        app: products
        department: sales
    spec:
      containers:
      - name: hello
        image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50001"

请注意,此 Deployment 中的容器将监听端口 50001。

将此清单复制到名为 my-deployment-50001.yaml 的文件,然后创建该 Deployment:

kubectl apply -f my-deployment-50001.yaml

确认三个 Pod 是否正在运行:

kubectl get pods

以下是 LoadBalancer 类型的 Service 的清单:

apiVersion: v1
kind: Service
metadata:
  name: my-lb-service
spec:
  type: LoadBalancer
  selector:
    app: products
    department: sales
  ports:
  - protocol: TCP
    port: 60000
    targetPort: 50001

将此清单复制到名为 my-lb-service.yaml, 的文件,然后创建该 Service:

kubectl apply -f my-lb-service.yaml

创建 LoadBalancer 类型的 Service 时,Google Cloud 控制器会唤醒并配置外部直通网络负载均衡器。等待一分钟,让控制器配置外部直通网络负载均衡器并生成稳定 IP 地址。

查看 Service:

kubectl get service my-lb-service --output yaml

输出的 loadBalancer:ingress 下方会显示稳定的外部 IP 地址:

...
spec:
  ...
  ports:
  - ...
    port: 60000
    protocol: TCP
    targetPort: 50001
  selector:
    app: products
    department: sales
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.10

控制台

创建 Deployment

  1. 转到 Google Cloud 控制台中的工作负载页面。

    转到“工作负载”

  2. 点击 部署

  3. 指定容器下,选择现有容器映像

  4. 对于映像路径,请输入 us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0

  5. 点击 添加环境变量

  6. 对于,输入 PORT;对于,输入 50001

  7. 点击完成,然后点击继续

  8. 配置下,对于应用名称,输入 my-deployment-50001

  9. 标签下,创建以下标签:

    • appproducts
    • departmentsales
  10. 集群下,选择要在其中创建 Deployment 的集群。

  11. 点击部署

  12. Deployment 准备就绪后,Deployment 详情页面随即打开。在托管 pod 下,您可以看到您的 Deployment 具有一个或多个正在运行的 Pod。

创建 Service 以公开您的 Deployment

  1. Deployment 详情页面上,点击 操作 > 公开
  2. 公开对话框中的端口映射下,设置以下值:

    • 端口60000
    • 目标端口50001
    • 协议TCP
  3. Service 类型下拉列表中,选择负载均衡器

  4. 点击公开

  5. Service 准备就绪后,Service 详情页面随即打开,您可以看到有关 Service 的详细信息。在负载均衡器下,记下负载均衡器的外部 IP 地址。

访问 Service

等待几分钟,让 GKE 配置负载均衡器。

在浏览器的地址栏中,输入以下内容:

LOAD_BALANCER_ADDRESS:60000

LOAD_BALANCER_ADDRESS 替换为负载均衡器的外部 IP 地址。

响应会显示 hello-app 的输出:

Hello, world!
Version: 2.0.0
Hostname: my-deployment-50001-68bb7dfb4b-prvct

请注意,Service 中 port 的值是任意的。在上述示例中,使用的 port 值为 60000。

创建 ExternalName 类型的 Service

在本部分中,您将创建一项 ExternalName 类型的 Service。

ExternalName 类型的 Service 为外部 DNS 名称提供内部别名。内部客户端使用内部 DNS 名称发出请求,然后请求会被重定向到外部名称。

以下是 ExternalName 类型的 Service 的清单:

apiVersion: v1
kind: Service
metadata:
  name: my-xn-service
spec:
  type: ExternalName
  externalName: example.com

在上述示例中,DNS 名称是 my-xn-service.default.svc.cluster.local。当内部客户端向 my-xn-service.default.svc.cluster.local 发出请求时,请求会被重定向到 example.com。

使用 kubectl expose 创建 Service

作为编写 Service 清单的替代方法,您可以使用 kubectl expose 公开 Deployment,以创建 Service。

如需公开本主题前面展示的 my-deployment,您可以输入以下命令:

kubectl expose deployment my-deployment --name my-cip-service \
    --type ClusterIP --protocol TCP --port 80 --target-port 8080

如需公开本主题前面展示的 my-deployment-50000,您可以输入以下命令:

kubectl expose deployment my-deployment-50000 --name my-np-service \
    --type NodePort --protocol TCP --port 80 --target-port 50000

如需公开本主题前面展示的 my-deployment-50001,您可以输入以下命令:

kubectl expose deployment my-deployment-50001 --name my-lb-service \
    --type LoadBalancer --port 60000 --target-port 50001

清理

完成本页面上的练习后,请按照以下步骤移除资源,防止您的账号产生不必要的费用:

kubectl apply

删除 Service

kubectl delete services my-cip-service my-np-service my-lb-service

删除 Deployment

kubectl delete deployments my-deployment my-deployment-50000 my-deployment-50001

删除防火墙规则

gcloud compute firewall-rules delete test-node-port

控制台

删除 Service

  1. 转到 Google Cloud 控制台中的服务页面。

    进入 Service

  2. 选择您在本练习中创建的 Service,然后点击 删除

  3. 当系统提示您确认时,点击删除

删除 Deployment

  1. 转到 Google Cloud 控制台中的工作负载页面。

    转到“工作负载”

  2. 选择您在本练习中创建的 Deployment,然后点击 删除

  3. 当系统提示确认时,选中删除与所选 Deployment 关联的横向 Pod 自动扩缩器复选框,然后点击删除

删除防火墙规则

  1. 转到 Google Cloud 控制台中的防火墙政策页面。

    转到“防火墙政策”

  2. 选中 test-node-port 复选框,然后点击 删除

  3. 当系统提示您确认时,点击删除

后续步骤