本文档举例说明了如何在使用 Google Distributed Cloud for VMware(纯软件)创建的用户集群中部署应用。
准备工作
对于本文档提供的示例,您需要一个使用捆绑式 MetalLB 负载均衡的用户集群。如需了解如何创建使用 MetalLB 的最小用户集群,请参阅创建基本集群。
您可以使用 Google Cloud 控制台或在管理员工作站上使用命令行工具 kubectl 来部署应用。
控制台
- 在控制台中,进入 Google Kubernetes Engine 集群概览页面。 
- 在集群列表中,点击用户集群,并验证您已登录该集群。 - 如果您尚未登录用户集群,请按照通过 Google Cloud 控制台管理集群中的说明登录。 
容器
- 在新建容器下,选择现有容器映像。 
- 在映像路径字段中,输入 - us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0。
- 点击继续。 
配置
- 在部署名称字段中,输入 - my-deployment。
- 在命名空间字段中,输入 - default。
- 输入以下两个标签: - 键 1:app,值 1:metrics
- 键 2:department,值 2:sales
 
- 键 1:
- 在 Kubernetes 集群下拉列表中,选择您的集群。 
- 点击继续。 
公开
- 勾选将部署作为新服务公开。 
- 在端口 1 字段中,输入 - 80。
- 在目标端口 1 字段中,输入 - 8080。此值是适当的值,因为- hello-app容器默认监听 TCP 端口 8080。您可以通过查看应用的 Dockerfile 和源代码来查看此信息。
- 在协议 1 字段中,选择 - TCP。
- 在服务类型字段中,选择 - LoadBalancer。
点击页面底部的部署按钮。
查看 Deployment 和 Service 详情
- Deployment 准备就绪后,部署详情页面会在 Google Cloud 控制台的 Kubernetes 工作负载部分中打开。在此页面上,您可以查看有关 Deployment 及其三个 Pod 的详细信息。 
- 在公开服务下,点击公开 Deployment 的 Service 的名称。在本练习中,该名称为 - my-deployment-service。
- 此时会打开 Service 详情页面。在此页面上,您可以查看有关 Service 的详细信息。例如,您可以看到任何具有标签 - app: metrics和- department: sales的 Pod 都是 Service 的成员。之前提到,- my-deployment中的 Pod 具有这些标签。
您还可以查看负载均衡器 IP 的值。系统已在集群负载均衡器上自动配置负载均衡器 IP。
Service 的转发
假设集群外部的客户端在 TCP 端口 80 上向负载均衡器 IP 发送请求。请求会路由到集群负载均衡器。负载均衡器将请求转发到 TCP 端口 8080 上的成员 Pod。之前提到,my-deployment 中的每个 Pod 都有一个监听 TCP 端口 8080 的容器。
测试 Service
前往负载均衡器 IP 可路由到的机器。
如需调用 Service,请在浏览器中输入负载均衡器 IP,或者使用 curl 之类的命令。例如:
curl [LOAD_BALANCER_IP]:80
输出会显示 Hello, world! 消息。例如:
curl 203.0.113.1:80 Hello, world! Version: 2.0.0 Hostname: my-deployment-dbd86c8c4-9wpbv
删除 Deployment
进入控制台,前往 Kubernetes Engine 部分中的工作负载页面。
在 Deployment 列表中,选择 my-deployment。
点击页面顶部的删除。此操作会同时删除 Deployment 和公开的 Service。
命令行
连接到管理员工作站
与管理员工作站建立 SSH 连接。 在管理员工作站上执行以下步骤。
创建 Deployment
以下是 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 --kubeconfig USER_CLUSTER_KUBECONFIG -f my-deployment.yaml
其中,USER_CLUSTER_KUBECONFIG 是用户集群的 kubeconfig 文件的路径。
获取有关 Deployment 的基本信息:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get deployment my-deployment
输出结果显示 Deployment 有三个可用的 Pod:
NAME READY UP-TO-DATE AVAILABLE AGE my-deployment 3/3 3 3 27s
列出 Deployment 中的 Pod:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get pods
输出结果显示 Deployment 有三个正在运行的 Pod:
NAME READY STATUS RESTARTS AGE my-deployment-54944c8d55-4srm2 1/1 Running 0 6s my-deployment-54944c8d55-7z5nn 1/1 Running 0 6s my-deployment-54944c8d55-j62n9 1/1 Running 0 6s
获取有关 Deployment 的详细信息:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get deployment my-deployment --output yaml
输出结果显示有关 Deployment 规范和状态的详细信息:
kind: Deployment
metadata:
  ...
  generation: 1
  name: my-deployment
  namespace: default
  ...
spec:
  ...
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: metrics
      department: sales
  ...
    spec:
      containers:
      - image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0
        imagePullPolicy: IfNotPresent
        name: hello
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
status:
  availableReplicas: 3
  conditions:
  ‑ lastTransitionTime: "2019-11-11T18:44:02Z"
    lastUpdateTime: "2019-11-11T18:44:02Z"
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: "True"
    type: Available
  ‑ lastTransitionTime: "2019-11-11T18:43:58Z"
    lastUpdateTime: "2019-11-11T18:44:02Z"
    message: ReplicaSet "my-deployment-54944c8d55" has successfully progressed.
    reason: NewReplicaSetAvailable
    status: "True"
    type: Progressing
  observedGeneration: 1
  readyReplicas: 3
  replicas: 3
  updatedReplicas: 3
描述您的 Deployment:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG describe deployment my-deployment
输出结果显示有关 Deployment 的精确格式详细信息,包括关联的 ReplicaSet:
Name: my-deployment Namespace: default CreationTimestamp: Mon, 11 Nov 2019 10:43:58 -0800 Labels:... Selector: app=metrics,department=sales Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=metrics department=sales Containers: hello: Image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0 Port: Host Port: Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: my-deployment-54944c8d55 (3/3 replicas created) 
创建 LoadBalancer 类型的 Service
将 Deployment 公开给集群外部客户端的一种方法是创建类型为 LoadBalancer 的 Kubernetes Service。
以下是 LoadBalancer 类型的 Service 的清单:
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: metrics
    department: sales
  type: LoadBalancer
  ports:
  ‑ port: 80
    targetPort: 8080
基于本练习的目的,了解以下重要事项有助于理解 Service:
- 任何具有标签 - app: metrics和标签- department: sales的 Pod 都是 Service 的成员。请注意,- my-deployment中的 Pod 具有这些标签。
- 当客户端向 TCP 端口 80 上的 Service 发送请求时,请求将被转发到 TCP 端口 8080 上的成员 Pod。 
- 每个成员 Pod 必须有一个侦听 TCP 端口 8080 的容器。 
碰巧的是,默认情况下,hello-app 容器侦听 TCP 端口 8080。您可以通过查看应用的 Dockerfile 和源代码来查看此信息。
将此清单保存到名为 my-service.yaml 的文件,然后创建该 Service:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG apply -f my-service.yaml
其中,USER_CLUSTER_KUBECONFIG 是用户集群的 kubeconfig 文件的路径。
当您创建 Service 时,Google Distributed Cloud 会自动在集群负载均衡器上配置 loadBalancerIP 地址。
查看您的 Service:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get service my-service --output yaml
输出类似于以下内容:
kind: Service
metadata:
  ...
  name: my-service
  namespace: default
  ...
spec:
  allocateLoadBalancerNodePorts: true
  clusterIP: 10.96.1.39
  clusterIPs:
  - 10.96.1.39
  externalTrafficPolicy: Cluster
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - nodePort: 31184
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: metrics
    department: sales
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.1
在上面的输出结果中,您可以看到您的 Service 有一个 clusterIP 和一个 loadBalancerIP。它还具有 port 和 targetPort。
clusterIP 与此练习无关。loadBalancerIP 是集群外部的客户端可用于调用 Service 的 IP 地址。
以上面的输出结果中显示的值为例。也就是说,假设 Service 的 loadBalancerIP = 203.0.113.1,port = 80,targetPort = 8080。
客户端将请求发送到 TCP 端口 80 上的 203.0.113.1。请求会路由到集群负载均衡器。负载均衡器将请求转发到 TCP 端口 8080 上的成员 Pod。
调用您的 Service:
curl LOAD_BALANCER_IP
输出结果会显示 Hello, world! 消息:
curl 203.0.113.1 Hello, world! Version: 2.0.0 Hostname: my-deployment-dbd86c8c4-9wpbv
删除 Service
删除 Service:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete service my-service
验证您的 Service 是否已删除:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get services
输出结果不再显示 my-service。
删除 Deployment
删除 Deployment:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete deployment my-deployment
验证您的 Deployment 是否已删除:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG get deployments
输出结果不再显示 my-deployment。