Crear una aplicación web multinivel con Redis y PHP

En este tutorial se muestra cómo crear una aplicación web multinivel con Google Kubernetes Engine (GKE).

En este tutorial, harás lo siguiente:

  • Configura una aplicación web con una dirección IP externa y un balanceador de carga.
  • Crea un clúster de Redis con un solo maestro (líder) y varias réplicas (seguidores).

En el ejemplo se describen los siguientes conceptos de Kubernetes:

Preparar el entorno

Para configurar tu entorno, sigue estos pasos:

  1. Define las variables de entorno:

    export PROJECT_ID=PROJECT_ID
    export COMPUTE_LOCATION=COMPUTE_LOCATION
    

    Haz los cambios siguientes:

  2. Clona el repositorio de GitHub:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  3. Cambia al directorio de trabajo:

    cd kubernetes-engine-samples/quickstarts/guestbook/
    

Crear un clúster de GKE

Crea un clúster de GKE Autopilot o Estándar:

Autopilot

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

Estándar

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

Conéctate al clúster

Configura kubectl para que se comunique con el clúster:

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

Configurar el líder de Redis

La aplicación usa Redis para almacenar sus datos. La aplicación escribe sus datos en una instancia principal de Redis y lee datos de varias instancias secundarias de Redis.

  1. El siguiente manifiesto describe un Deployment de Kubernetes que ejecuta un pod de líder de Redis de una sola réplica:

    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

    Aplica el manifiesto a tu clúster:

    kubectl apply -f redis-leader-deployment.yaml
    
  2. Comprueba que el pod del líder de Redis se está ejecutando:

    kubectl get pods
    

    El resultado debería ser similar al siguiente:

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

    STATUS puede tardar varios minutos en cambiar de Pending a Running.

Crear el servicio de líder de Redis

La aplicación web necesita comunicarse con el líder de Redis para escribir sus datos. Puedes crear un servicio para dirigir el tráfico al pod líder de Redis.

Un servicio es una abstracción de Kubernetes que define un conjunto lógico de pods y una política para habilitar el acceso a los pods. Cuando creas un servicio, describes qué pods se deben proxyizar en función de las etiquetas de los pods.

  1. El siguiente manifiesto describe un servicio para el líder de Redis:

    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

    Este manifiesto incluye un conjunto de selectores de etiquetas. que coinciden con el conjunto de etiquetas que se desplegaron en el paso anterior. Por lo tanto, este servicio dirige el tráfico de red al pod líder de Redis que has creado en un paso anterior.

    La sección ports del manifiesto declara una sola asignación de puertos. El servicio dirige el tráfico de port: 6379 a targetPort: 6379 de los contenedores que coincidan con las etiquetas selector especificadas. El containerPort usado en el Deployment debe coincidir con el targetPort para enrutar el tráfico al Deployment.

    Aplica el manifiesto a tu clúster:

    kubectl apply -f redis-leader-service.yaml
    
  2. Verifica que GKE haya creado el servicio:

    kubectl get service
    

    El resultado debería ser similar al siguiente:

    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
    

Configurar seguidores de Redis

Aunque el líder de Redis consta de un solo pod, se pueden añadir algunos seguidores o réplicas de Redis para aumentar en gran medida su disponibilidad y satisfacer las demandas de tráfico.

  1. El siguiente manifiesto describe una implementación de los pods de réplica de Redis:

    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. Aplica el manifiesto a tu clúster:

    kubectl apply -f redis-follower-deployment.yaml
    
  3. Comprueba que las dos réplicas de seguidores de Redis se están ejecutando:

    kubectl get pods
    

    El resultado debería ser similar al siguiente:

    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 puede tardar varios minutos en cambiar de Pending a Running.

Crear el servicio de seguidor de Redis

La aplicación web debe comunicarse con los seguidores de Redis para leer datos. Para que los seguidores de Redis se puedan detectar, debes configurar un servicio.

  1. El siguiente manifiesto describe un servicio para los seguidores de Redis:

    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

    Este manifiesto especifica que el servicio se ejecuta en el puerto 6379. El campo selector del servicio coincide con los pods de seguidores de Redis que has creado en el paso anterior.

    Aplica el manifiesto a tu clúster:

    kubectl apply -f redis-follower-service.yaml
    
  2. Verifica que GKE haya creado el servicio:

    kubectl get service
    

    El resultado debería ser similar al siguiente:

    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
    

Configurar el frontend web de la aplicación

Ahora que tienes el almacenamiento de Redis para tu aplicación, inicia los servidores web. Al igual que los seguidores de Redis, el frontend se despliega mediante un Deployment de Kubernetes.

La aplicación web usa un frontend PHP, que está configurado para comunicarse con los servicios de seguidor o líder de Redis, en función de si la solicitud es de lectura o de escritura. El frontend expone una interfaz JSON y ofrece una interfaz de usuario basada en jQuery Ajax.

  1. El siguiente manifiesto describe un Deployment para el servidor web:

    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

    El archivo de manifiesto especifica la variable de entorno GET_HOSTS_FROM=dns. Cuando proporcionas la configuración a la aplicación web frontend, esta usa los nombres de host redis-follower y redis-leader para realizar una búsqueda de DNS. La petición de DNS busca las direcciones IP de los servicios que has creado en los pasos anteriores. Este concepto se denomina descubrimiento de servicios DNS.

    Aplica el manifiesto a tu clúster:

    kubectl apply -f frontend-deployment.yaml
    
  2. Comprueba que las réplicas se estén ejecutando:

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

    El resultado debería ser similar al siguiente:

    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
    

Muestra el frontend en una dirección IP externa

Con la configuración actual, solo se puede acceder a los servicios redis-follower y redis-leader que has creado en los pasos anteriores desde dentro del clúster de GKE, ya que el tipo predeterminado de un servicio es ClusterIP.

Un ClusterIP servicio proporciona una única dirección IP para el conjunto de pods al que apunta el servicio. A esta dirección IP solo se puede acceder desde dentro del clúster.

Para que se pueda acceder al servicio del frontend web desde el exterior, puedes especificar type: LoadBalancer o type: NodePort en la configuración del servicio, en función de tus requisitos.

El siguiente manifiesto describe un servicio de tipo LoadBalancer:

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

La declaración de puerto de la sección ports especifica port: 80 y no se especifica targetPort. Si omite la propiedad targetPort, se usará el valor predeterminado del campo port. En este caso, este servicio dirige el tráfico externo del puerto 80 al puerto 80 de los contenedores de la implementación frontend.

Aplica el manifiesto a tu clúster:

kubectl apply -f frontend-service.yaml

Cuando se crea el frontend Service, GKE crea un balanceador de carga y una dirección IP externa. Estos recursos están sujetos a facturación.

Visitar el sitio web de la aplicación

Para acceder al sitio web de la aplicación, obtén la dirección IP externa del servicio frontend:

kubectl get service frontend

El resultado debería ser similar al siguiente:

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

La columna EXTERNAL-IP puede mostrar <pending> mientras se crea el balanceador de carga. Este proceso puede tardar varios minutos. Si ves errores como Does not have minimum availability, espera unos minutos. Este error temporal se produce porque GKE vuelve a crear los nodos para aplicar los cambios.

Copia la dirección IP y abre la página en el navegador:

Aplicación web que se ejecuta en GKE

Prueba a añadir algunas entradas escribiendo un mensaje y haciendo clic en Enviar. El mensaje que has escrito aparece en el frontend. Este mensaje indica que los datos se han añadido correctamente a Redis a través de los servicios que has creado.

Escalar el frontend web

Supongamos que tu aplicación lleva un tiempo en funcionamiento y, de repente, recibe una gran publicidad. Crees que sería una buena idea añadir más servidores web a la interfaz. Para ello, aumenta el número de pods.

  1. Aumenta el número de pods frontend:

    kubectl scale deployment frontend --replicas=5
    

    El resultado debería ser similar al siguiente:

    deployment.extensions/frontend scaled
    
  2. Verifica el número de réplicas que se están ejecutando:

    kubectl get pods
    

    El resultado debería ser similar al siguiente:

    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
    

    Puedes reducir el número de frontend pods con el mismo comando, pero sustituyendo 5 por 1.