Configurar una malla de servicios de sidecar de Envoy

Esta configuración es compatible con los clientes de la versión preliminar, pero no la recomendamos para los usuarios nuevos de Cloud Service Mesh. Para obtener más información, consulta la descripción general de Cloud Service Mesh.

En esta guía, se muestra cómo configurar una malla de servicios simple en tu flota. La guía incluye los siguientes pasos:

  • Implementar el inyector de sidecar de Envoy en el clúster. El inyector inserta el contenedor del proxy de Envoy en los Pods de la aplicación.
  • Implementar recursos de la API de puerta de enlace que configuren el archivo adicional de Envoy en la malla de servicios para enrutar solicitudes a un servicio de ejemplo en el espacio de nombres store
  • Implementar un cliente simple para verificar la implementación.

En el diagrama siguiente, se muestra la malla de servicios configurada.

Una malla de servicios de sidecar de Envoy en una flota
Una malla de servicios de sidecar de Envoy en una flota (haz clic para ampliar)

Puedes configurar solo un Mesh en un clúster, porque el nombre de la malla en la configuración del inyector de sidecar y el nombre del recurso Mesh deben ser idénticos.

Implementa el inyector de sidecar de Envoy

Para implementar el inyector de sidecar, haz lo siguiente:

  1. Configura la información del proyecto

    # The project that contains your GKE cluster.
    export CLUSTER_PROJECT_ID=YOUR_CLUSTER_PROJECT_NUMBER_HERE
    # The name of your GKE cluster.
    export CLUSTER=YOUR_CLUSTER_NAME
    # The channel of your GKE cluster. Eg: rapid, regular, stable.
    export CHANNEL=YOUR_CLUSTER_CHANNEL
    # The location of your GKE cluster, Eg: us-central1 for regional GKE cluster,
    # us-central1-a for zonal GKE cluster
    export LOCATION=ZONE
    
    # The mesh name of the traffic director load balancing API.
    export MESH_NAME=YOUR_MESH_NAME
    # The project that holds the mesh resources.
    export MESH_PROJECT_NUMBER=YOUR_PROJECT_NUMBER_HERE
    
    export TARGET=projects/${MESH_PROJECT_NUMBER}/locations/global/meshes/${MESH_NAME}
    
    gcloud config set project ${CLUSTER_PROJECT_ID}
    

    Para conocer el MESH_NAME, asigna el valor de la siguiente manera, en la que MESH_NAME es el valor del campo metadata.name en la especificación de recursos Mesh:

    gketd-MESH_NAME
    

    Por ejemplo, si el valor de metadata.name en el recurso Mesh es butterfly-mesh, configura el valor de MESH_NAME de la siguiente manera:

    export MESH_NAME="gketd-butterfly-mesh"
    
  2. Aplica las configuraciones para el webhook de mutación

    En las siguientes secciones, se proporcionan instrucciones para aplicar MutatingWebhookConfiguration al clúster. Cuando se crea un pod, se invoca el controlador de admisión en el clúster. El controlador de admisión se comunica con el inyector de sidecar administrado para agregar el contenedor de Envoy al pod.

    Aplica las siguientes configuraciones de webhooks de mutación a tu clúster.

    cat <<EOF | kubectl apply -f -
    apiVersion: admissionregistration.k8s.io/v1
    kind: MutatingWebhookConfiguration
    metadata:
      labels:
        app: sidecar-injector
      name: td-mutating-webhook
    webhooks:
    - admissionReviewVersions:
      - v1beta1
      - v1
      clientConfig:
        url: https://meshconfig.googleapis.com/v1internal/projects/${CLUSTER_PROJECT_ID}/locations/${LOCATION}/clusters/${CLUSTER}/channels/${CHANNEL}/targets/${TARGET}:tdInject
      failurePolicy: Fail
      matchPolicy: Exact
      name: namespace.sidecar-injector.csm.io
      namespaceSelector:
        matchExpressions:
        - key: td-injection
          operator: Exists
      reinvocationPolicy: Never
      rules:
      - apiGroups:
        - ""
        apiVersions:
        - v1
        operations:
        - CREATE
        resources:
        - pods
        scope: '*'
      sideEffects: None
      timeoutSeconds: 30
    EOF
    

    Si necesitas personalizar el inyector de sidecar, sigue estos pasos para personalizarlo en tu clúster:

  3. Configura TLS para el inyector de sidecar.

  4. Habilita la inserción de sidecar

  5. Opciones para las inyecciones automáticas de Envoy

Implemente el servicio store

En esta sección, implementarás el servicio store en la malla.

  1. En el archivo store.yaml, guarda el siguiente manifiesto:

    kind: Namespace
    apiVersion: v1
    metadata:
      name: store
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: store
      namespace: store
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: store
          version: v1
      template:
        metadata:
          labels:
            app: store
            version: v1
        spec:
          containers:
          - name: whereami
            image: us-docker.pkg.dev/google-samples/containers/gke/whereami:v1
            ports:
            - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    
  2. Aplica el manifiesto a gke-1:

    kubectl apply -f store.yaml
    

Crea una malla de servicios

  1. En el archivo mesh.yaml, guarda el siguiente manifiesto mesh. El nombre del recurso mesh debe coincidir con el nombre de la malla especificado en el configmap del inyector. En esta configuración de ejemplo, el nombre td-mesh se usa en ambos lugares:

    apiVersion: net.gke.io/v1alpha1
    kind: TDMesh
    metadata:
      name: td-mesh
      namespace: default
    spec:
      gatewayClassName: gke-td
      allowedRoutes:
        namespaces:
          from: All
    
  2. Aplica el manifiesto mesh a gke-1, que crea una malla lógica con el nombre td-mesh:

    kubectl apply -f mesh.yaml
    
  3. En el archivo store-route.yaml, guarda el siguiente manifiesto HTTPRoute. El manifiesto define un recurso HTTPRoute que enruta el tráfico HTTP que especifica el nombre de host example.com a un servicio de Kubernetes store en el espacio de nombres store:

    apiVersion: gateway.networking.k8s.io/v1alpha2
    kind: HTTPRoute
    metadata:
      name: store-route
      namespace: store
    spec:
      parentRefs:
      - name: td-mesh
        namespace: default
        group: net.gke.io
        kind: TDMesh
      hostnames:
      - "example.com"
      rules:
      - backendRefs:
        - name: store
          namespace: store
          port: 8080
    
  4. Aplica el manifiesto de ruta a gke-1:

    kubectl apply -f store-route.yaml
    

Valida la implementación

  1. Inspecciona el estado y los eventos de Mesh para validar que los recursos de Mesh y HTTPRoute se implementen de forma correcta:

    kubectl describe tdmesh td-mesh
    

    El resultado es similar a este:

    ...
    
    Status:
      Conditions:
        Last Transition Time:  2022-04-14T22:08:39Z
        Message:
        Reason:                MeshReady
        Status:                True
        Type:                  Ready
        Last Transition Time:  2022-04-14T22:08:28Z
        Message:
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
    Events:
      Type    Reason  Age   From                Message
      ----    ------  ----  ----                -------
      Normal  ADD     36s   mc-mesh-controller  Processing mesh default/td-mesh
      Normal  UPDATE  35s   mc-mesh-controller  Processing mesh default/td-mesh
      Normal  SYNC    24s   mc-mesh-controller  SYNC on default/td-mesh was a success
    
  2. Para asegurarte de que la inserción de sidecar esté habilitada en el espacio de nombres predeterminado, ejecuta el siguiente comando:

    kubectl get namespace default --show-labels
    

    Si la inserción de sidecar está habilitada, verás lo siguiente en el resultado:

    istio-injection=enabled
    

    Si la inserción de sidecar no está habilitada, consulta Habilita la inserción de sidecar.

  3. Para verificar la implementación, implementa un Pod de cliente que actúe como cliente en el servicio store definido con anterioridad. En el archivo client.yaml, guarda lo siguiente:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        run: client
      name: client
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          run: client
      template:
        metadata:
          labels:
            run: client
        spec:
          containers:
          - name: client
            image: curlimages/curl
            command:
            - sh
            - -c
            - while true; do sleep 1; done
    
  4. Implementa la especificación:

    kubectl apply -f client.yaml
    

    El inyector de sidecar que se ejecuta en el clúster inserta de forma automática un contenedor de Envoy en el Pod del cliente.

  5. Para verificar que se inserte el contenedor de Envoy, ejecuta el siguiente comando:

    kubectl describe pods -l run=client
    

    El resultado es similar a este:

    ...
    Init Containers:
      # Istio-init sets up traffic interception for the Pod.
      istio-init:
    ...
      # td-bootstrap-writer generates the Envoy bootstrap file for the Envoy container
      td-bootstrap-writer:
    ...
    Containers:
    # client is the client container that runs application code.
      client:
    ...
    # Envoy is the container that runs the injected Envoy proxy.
      envoy:
    ...
    

Después de aprovisionar el Pod del cliente, envía una solicitud desde el Pod del cliente al servicio store.

  1. Obtén el nombre del pod cliente:

    CLIENT_POD=$(kubectl get pod -l run=client -o=jsonpath='{.items[0].metadata.name}')
    
    # The VIP where the following request will be sent. Because all requests
    # from the client container are redirected to the Envoy proxy sidecar, you
    # can use any IP address, including 10.0.0.2, 192.168.0.1, and others.
    VIP='10.0.0.1'
    
  2. Envía una solicitud para almacenar el servicio y genera los encabezados de respuesta:

    TEST_CMD="curl -v -H 'host: example.com' $VIP"
    
  3. Ejecuta el comando de prueba en el contenedor de cliente:

    kubectl exec -it $CLIENT_POD -c client -- /bin/sh -c "$TEST_CMD"
    

    El resultado es similar a este:

    < Trying 10.0.0.1:80...
    < Connected to 10.0.0.1 (10.0.0.1) port 80 (#0)
    < GET / HTTP/1.1
    < Host: example.com
    < User-Agent: curl/7.82.0-DEV
    < Accept: */*
    <
    < Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < content-type: application/json
    < content-length: 318
    < access-control-allow-origin: *
    < server: envoy
    < date: Tue, 12 Apr 2022 22:30:13 GMT
    <
    {
      "cluster_name": "gke-1",
      "zone": "us-west1-a",
      "host_header": "example.com",
      ...
    }
    

¿Qué sigue?