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

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

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

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

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

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

准备环境

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

  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 即可。