使用 Redis 和 PHP 创建多层 Web 应用

本教程演示了如何使用 Google Kubernetes Engine (GKE) 构建多层 Web 应用。

在本教程中,您将执行以下操作:

  • 设置具有外部 IP 地址和负载均衡器的 Web 应用。
  • 创建具有单个主实例 (Leader) 和多个副本(关注者)Redis 集群。

此示例介绍了以下 Kubernetes 概念:

  • 使用 YAML 清单文件的声明式配置
  • Deployment,这是 Kubernetes 资源,用于确定一组副本 Pod 的配置
  • Service,用于为一组 Pod 创建内部和外部负载均衡器

目标

如需在 GKE 上部署和运行应用,请执行以下操作:

  1. 设置 Redis Leader
  2. 设置两个 Redis 关注者
  3. 设置 Web 前端
  4. 访问网站
  5. 纵向扩容 Web 前端

下图展示了完成上述目标后创建的集群架构概览:

GKE 集群架构

费用

在本文档中,您将使用 Google Cloud的以下收费组件:

如需根据您的预计使用情况来估算费用,请使用价格计算器

新 Google Cloud 用户可能有资格申请免费试用

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

准备工作

Cloud Shell 中预安装了本教程所需的软件,包括 kubectlgcloud CLI。如果您不使用 Cloud Shell,则必须安装 gcloud CLI。

  1. 安装 Google Cloud CLI。

  2. 配置 gcloud CLI 以使用您的联合身份。

    如需了解详情,请参阅使用联合身份登录 gcloud CLI

  3. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  4. 创建或选择 Google Cloud 项目

    选择或创建项目所需的角色

    • 选择项目:选择项目不需要特定的 IAM 角色,您可以选择已获授角色的任何项目。
    • 创建项目:如需创建项目,您需要拥有 Project Creator 角色 (roles/resourcemanager.projectCreator),该角色包含 resourcemanager.projects.create 权限。了解如何授予角色
    • 创建 Google Cloud 项目:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替换为您要创建的 Google Cloud 项目的名称。

    • 选择您创建的 Google Cloud 项目:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替换为您的 Google Cloud 项目名称。

  5. 验证是否已为您的 Google Cloud 项目启用结算功能

  6. 启用 GKE API:

    启用 API 所需的角色

    如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (roles/serviceusage.serviceUsageAdmin),该角色包含 serviceusage.services.enable 权限。了解如何授予角色

    gcloud services enable container.googleapis.com

准备环境

如需设置您的环境,请按以下步骤操作:

  1. 设置环境变量:

    export PROJECT_ID=PROJECT_ID
    export COMPUTE_LOCATION=COMPUTE_LOCATION
    

    替换以下内容:

  2. 克隆 GitHub 代码库:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  3. 切换到工作目录:

    cd kubernetes-engine-samples/quickstarts/guestbook/
    

创建 GKE 集群

创建 Autopilot 或 Standard GKE 集群:

Autopilot

gcloud container clusters create-auto guestbook \
    --location=${COMPUTE_LOCATION} \

Standard

gcloud container clusters create guestbook \
    --location=${COMPUTE_LOCATION} \
    --num-nodes=4

连接到集群

配置 kubectl 以与集群通信:

gcloud container clusters get-credentials guestbook \
    --location=${COMPUTE_LOCATION}

设置 Redis Leader

该应用使用 Redis 来存储其数据。该应用将数据写入 Redis Leader 实例,并从多个 Redis 关注者实例中读取数据。

  1. 以下清单描述了一个运行单个副本 Redis Leader Pod 的 Kubernetes Deployment:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: redis-leader
      labels:
        app: redis
        role: leader
        tier: backend
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: redis
      template:
        metadata:
          labels:
            app: redis
            role: leader
            tier: backend
        spec:
          containers:
          - name: leader
            image: "docker.io/redis:6.0.5"
            resources:
              requests:
                cpu: 100m
                memory: 100Mi
            ports:
            - containerPort: 6379

    将清单应用到您的集群:

    kubectl apply -f redis-leader-deployment.yaml
    
  2. 验证 Redis Leader Pod 是否正在运行:

    kubectl get pods
    

    输出类似于以下内容:

    NAME                           READY     STATUS    RESTARTS   AGE
    redis-leader-343230949-qfvrq   1/1       Running   0          43s
    

    STATUS 可能需要几分钟才能从 Pending 变为 Running

创建 Redis Leader 服务

该 Web 应用需要与 Redis Leader 通信才能写入其数据。您可以创建一个 Service 来代理传输到 Redis Leader Pod 的流量。

Service 是 Kubernetes 抽象,定义了一个逻辑 Pod 集及实现其访问权限的政策。创建 Service 时,您需要根据 Pod 标签来说明要代理哪些 Pod。

  1. 以下清单描述了 Redis Leader 的 Service:

    apiVersion: v1
    kind: Service
    metadata:
      name: redis-leader
      labels:
        app: redis
        role: leader
        tier: backend
    spec:
      ports:
      - port: 6379
        targetPort: 6379
      selector:
        app: redis
        role: leader
        tier: backend

    此清单包含一组标签选择器。这些标签与上一步中部署的标签集匹配。因此,该 Service 将网络流量路由到上一步中创建的 Redis Leader Pod。

    清单的 ports 部分声明了单个端口映射。此 Service 将 port: 6379 上的流量路由到匹配指定 selector 标签的容器的 targetPort: 6379。Deployment 中使用的 containerPort 必须与 targetPort 匹配才能将流量路由到 Deployment。

    将清单应用到您的集群:

    kubectl apply -f redis-leader-service.yaml
    
  2. 验证 GKE 是否已创建 Service:

    kubectl get service
    

    输出类似于以下内容:

    NAME           CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    kubernetes     10.51.240.1     <none>        443/TCP    42s
    redis-leader   10.51.242.233   <none>        6379/TCP   12s
    

设置 Redis 关注者

虽然 Redis Leader 属于单个 Pod,但您可以通过添加一些 Redis 关注者副本来为其实现高可用性,并满足流量需求。

  1. 以下清单描述了 Redis 关注者 Pod 的 Deployment:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: redis-follower
      labels:
        app: redis
        role: follower
        tier: backend
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: redis
      template:
        metadata:
          labels:
            app: redis
            role: follower
            tier: backend
        spec:
          containers:
          - name: follower
            image: us-docker.pkg.dev/google-samples/containers/gke/gb-redis-follower:v2
            resources:
              requests:
                cpu: 100m
                memory: 100Mi
            ports:
            - containerPort: 6379
  2. 将清单应用到您的集群:

    kubectl apply -f redis-follower-deployment.yaml
    
  3. 验证这两个 Redis 关注者副本是否正在运行:

    kubectl get pods
    

    输出类似于以下内容:

    NAME                              READY   STATUS    RESTARTS   AGE
    redis-follower-76588f55b7-bnsq6   1/1     Running   0          27s
    redis-follower-76588f55b7-qvtws   1/1     Running   0          27s
    redis-leader-dd446dc55-kl7nl      1/1     Running   0          119s
    

    STATUS 可能需要几分钟才能从 Pending 变为 Running

创建 Redis 关注者服务

该 Web 应用必须与 Redis 关注者通信才能读取数据。如需让 Redis 关注者更容易被发现,您必须设置一个 Service。

  1. 以下清单描述了 Redis 关注者的 Service:

    apiVersion: v1
    kind: Service
    metadata:
      name: redis-follower
      labels:
        app: redis
        role: follower
        tier: backend
    spec:
      ports:
        # the port that this service should serve on
      - port: 6379
      selector:
        app: redis
        role: follower
        tier: backend

    此清单指定了 Service 在端口 6379 上运行。Service 的 selector 字段与上一步中创建的 Redis 关注者 Pod 匹配。

    将清单应用到您的集群:

    kubectl apply -f redis-follower-service.yaml
    
  2. 验证 GKE 是否已创建 Service:

    kubectl get service
    

    输出类似于以下内容:

    NAME           CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    kubernetes     10.51.240.1     <none>        443/TCP    1m
    redis-leader   10.51.242.233   <none>        6379/TCP   49s
    redis-follower 10.51.247.238   <none>        6379/TCP   3s
    

设置应用 Web 前端

现在,您已经为应用设置了 Redis 存储,接下来可以启动 Web 服务器。与 Redis 关注者一样,该前端将使用 Kubernetes Deployment 进行部署。

该 Web 应用使用 PHP 前端,该前端配置为根据请求属于读取请求还是写入请求,与 Redis 关注者 Service 或 Redis Leader Service 进行通信。该前端公开了一个 JSON 接口,并提供基于 jQuery Ajax 的界面。

  1. 以下清单描述了 Web 服务器的 Deployment:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: frontend
    spec:
      replicas: 3
      selector:
        matchLabels:
            app: guestbook
            tier: frontend
      template:
        metadata:
          labels:
            app: guestbook
            tier: frontend
        spec:
          containers:
          - name: php-redis
            image: us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5
            env:
            - name: GET_HOSTS_FROM
              value: "dns"
            resources:
              requests:
                cpu: 100m
                memory: 100Mi
            ports:
            - containerPort: 80

    清单文件指定了环境变量 GET_HOSTS_FROM=dns。当您将配置提供给该 Web 前端应用时,前端应用会使用主机名 redis-followerredis-leader 来执行 DNS 查找。DNS 查找将查找您在先前步骤中创建的 Service 的 IP 地址。此概念称为 DNS 服务发现。

    将清单应用到您的集群:

    kubectl apply -f frontend-deployment.yaml
    
  2. 验证副本是否正在运行:

    kubectl get pods -l app=guestbook -l tier=frontend
    

    输出类似于以下内容:

    NAME                        READY   STATUS    RESTARTS   AGE
    frontend-7b78458576-8kp8s   1/1     Running   0          37s
    frontend-7b78458576-gg86q   1/1     Running   0          37s
    frontend-7b78458576-hz87g   1/1     Running   0          37s
    

在外部 IP 地址公开前端

在当前配置下,您在先前步骤中创建的 redis-followerredis-leader Service 只能在 GKE 集群中访问,因为 Service 的默认类型是 ClusterIP

ClusterIP Service 为自己指向的 Pod 集提供单个 IP 地址。此 IP 地址只能在集群内访问。

如需使该 Web 前端 Service 可从外部访问,您可以根据需求在 Service 配置中指定 type: LoadBalancertype: NodePort

以下清单描述了 LoadBalancer 类型的 Service:

apiVersion: v1
kind: Service
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  type: LoadBalancer
  ports:
    # the port that this service should serve on
  - port: 80
  selector:
    app: guestbook
    tier: frontend

ports 部分下方的端口声明指定了 port: 80,未指定 targetPort。如果忽略 targetPort 属性,则默认为 port 字段的值。在本例中,此 Service 将端口 80 上的外部流量路由到 frontend Deployment 中容器的端口 80。

将清单应用到您的集群:

kubectl apply -f frontend-service.yaml

创建 frontend Service 时,GKE 会创建一个负载均衡器和一个外部 IP 地址。这些资源需要付费

访问应用网站

如需访问应用网站,请获取 frontend Service 的外部 IP 地址:

kubectl get service frontend

输出类似于以下内容:

NAME       CLUSTER-IP      EXTERNAL-IP        PORT(S)        AGE
frontend   10.51.242.136   109.197.92.229     80:32372/TCP   1m

创建负载均衡器时,EXTERNAL-IP 列可能会显示 <pending>。这可能需要几分钟。 如果您看到 Does not have minimum availability 等错误,请等待几分钟。此临时错误是因为 GKE 重新创建节点以进行更改而发生的。

复制该 IP 地址,然后在浏览器中打开相应网页:

在 GKE 上运行的 Web 应用

如需尝试添加一些条目,请尝试输入一则消息,然后点击提交。您输入的消息会显示在前端。此消息表示数据已通过您创建的 Service 成功添加到 Redis。

纵向扩容 Web 前端

假设您的应用已经运行了一段时间,公共宣传突然激增。您决定为前端添加更多 Web 服务器。您可以通过增加 Pod 数量来实现此目的。

  1. 增加 frontend Pod 的数量:

    kubectl scale deployment frontend --replicas=5
    

    输出类似于以下内容:

    deployment.extensions/frontend scaled
    
  2. 验证正在运行的副本数:

    kubectl get pods
    

    输出类似于以下内容:

    NAME                             READY     STATUS    RESTARTS   AGE
    frontend-88237173-3s3sc          1/1       Running   0          1s
    frontend-88237173-twgvn          1/1       Running   0          1s
    frontend-88237173-5p257          1/1       Running   0          23m
    frontend-88237173-84036          1/1       Running   0          23m
    frontend-88237173-j3rvr          1/1       Running   0          23m
    redis-leader-343230949-qfvrq     1/1       Running   0          54m
    redis-follower-132015689-dp23k   1/1       Running   0          37m
    redis-follower-132015689-xq9v0   1/1       Running   0          37m
    

    您可以使用同一命令缩减 frontend Pod 的数量,只需将 5 替换为 1 即可。

清理

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

删除项目

    删除 Google Cloud 项目:

    gcloud projects delete PROJECT_ID

逐个删除资源

如果您使用的是现有项目,并且不想将其删除,请逐个删除资源。

  1. 删除 frontend Service:

    kubectl delete service frontend
    
  2. 删除 GKE 集群:

    gcloud container clusters delete guestbook
    

后续步骤