Configurar una malla de servicios de sidecar de Envoy

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, debes proporcionar dos valores.

  • TRAFFICDIRECTOR_GCP_PROJECT_NUMBER. Reemplaza PROJECT_NUMBER por el número del proyecto para tu clúster de configuración. El número de proyecto es el identificador numérico de tu proyecto.

  • TRAFFICDIRECTOR_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 TRAFFICDIRECTOR_MESH_NAME de la siguiente manera:

    TRAFFICDIRECTOR_MESH_NAME: "gketd-butterfly-mesh"
    
  • TRAFFICDIRECTOR_NETWORK_NAME Asegúrate de que el valor de TRAFFICDIRECTOR_NETWORK_NAME esté vacío:

    TRAFFICDIRECTOR_NETWORK_NAME=""
    
  1. Descarga el paquete de inyector de sidecar:

    wget https://storage.googleapis.com/traffic-director/td-sidecar-injector-xdsv3.tgz
    tar -xzvf td-sidecar-injector-xdsv3.tgz
    cd td-sidecar-injector-xdsv3
    
  2. En el archivo specs/01-configmap.yaml, propaga los campos TRAFFICDIRECTOR_GCP_PROJECT_NUMBER y TRAFFICDIRECTOR_MESH_NAME, y establece TRAFFICDIRECTOR_NETWORK_NAME como vacío.

       apiVersion: v1
       kind: ConfigMap
       metadata:
         name: injector-mesh
         namespace: istio-control
       data:
         mesh: |-
           defaultConfig:
             discoveryAddress: trafficdirector.googleapis.com:443
    
             # Envoy proxy port to listen on for the admin interface.
             # This port is bound to 127.0.0.1.
             proxyAdminPort: 15000
    
             proxyMetadata:
               # Google Cloud Project number that your Fleet belongs to.
               # This is the numeric identifier of your project
               TRAFFICDIRECTOR_GCP_PROJECT_NUMBER: "PROJECT_NUMBER"
    
               # TRAFFICDIRECTOR_NETWORK_NAME must be empty when
               # TRAFFICDIRECTOR_MESH_NAME is set.
               TRAFFICDIRECTOR_NETWORK_NAME=""
    
               # The value of `metadata.name` in the `Mesh` resource. When a
               # sidecar requests configurations from Traffic Director,
               # Traffic Director will only return configurations for the
               # specified mesh.
               TRAFFICDIRECTOR_MESH_NAME: "gketd-td-mesh"
    

Después de completar las instrucciones anteriores, sigue estos pasos para implementar el inyector de sidecar en tu clúster:

  1. Configura TLS para el inyector de sidecar.
  2. Instala el inyector de sidecar a tu clúster de GKE.
  3. Abre el puerto requerido en un clúster privado (opcional).
  4. Habilita la inserción de sidecar

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: gcr.io/google-samples/whereami:v1.2.20
            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 al siguiente:

    ...
    
    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 al siguiente:

    ...
    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 al siguiente:

    < 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?