Resuelve problemas de inicio de cargas de trabajo en Cloud Service Mesh

En este documento, se explican los problemas comunes de Cloud Service Mesh y cómo resolverlos. Si necesitas asistencia adicional, consulta Obtén asistencia.

La puerta de enlace no se inicia con el proxy sin distribución cuando se expone un puerto con privilegios.

De forma predeterminada, el proxy sin distribución se inicia con permisos que no son de raíz, lo que, en algunos casos, puede causar fallas de vinculación en puertos con privilegios. Si ves errores similares al siguiente durante el inicio del proxy, se debe aplicar un securityContext adicional para una implementación de puerta de enlace.

  Error adding/updating listener(s) 0.0.0.0_80: cannot bind '0.0.0.0:80': Permission denied

El siguiente ejemplo es el archivo yaml de una implementación de puerta de enlace de salida:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: istio-egressgateway
spec:
  selector:
    matchLabels:
      app: istio-egressgateway
      istio: egressgateway
  template:
    metadata:
      annotations:
        # This is required to tell Anthos Service Mesh to inject the gateway with the
        # required configuration.
        inject.istio.io/templates: gateway
      labels:
        app: istio-egressgateway
        istio: egressgateway
    spec:
      containers:
      - name: istio-proxy
        image: auto # The image will automatically update each time the pod starts.
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
      # Allow binding to all ports (such as 80 and 443)
      securityContext:
        sysctls:
        - name: net.ipv4.ip_unprivileged_port_start
          value: "0"
      serviceAccountName: istio-egressgateway 

Se rechaza la conexión cuando se llega a un extremo de Cloud Service Mesh

Es posible que experimentes errores de conexión rechazada (ECONNREFUSED) de forma intermitente con la comunicación de tus clústeres a tus extremos, por ejemplo, Redis de Memorystore, Cloud SQL o cualquier servicio externo al que necesite llegar la carga de trabajo de tu aplicación.

Esto puede ocurrir cuando la carga de trabajo de tu aplicación se inicia más rápido que el contenedor istio-proxy (Envoy) y trata de llegar a un extremo externo. Debido a que, en esta etapa, istio-init (initContainer) ya se ejecutó, existen reglas de iptables que redireccionan todo el tráfico saliente a Envoy. Como istio-proxy aún no está listo, las reglas de iptables redireccionarán el tráfico a un proxy de Sidecar que aún no se inició y, por lo tanto, la aplicación recibe el error ECONNREFUSED.

En los siguientes pasos, se detalla cómo verificar si este es el error que tienes:

  1. Verifica los registros de Stackdriver con el siguiente filtro para identificar qué pods tuvieron el problema.

    En el siguiente ejemplo, se muestra un mensaje de error típico:

    Error: failed to create connection to feature-store redis, err=dial tcp   192.168.9.16:19209: connect: connection refused
    [ioredis] Unhandled error event: Error: connect ECONNREFUSED
    
  2. Busca una ocurrencia del problema. Si usas Stackdriver heredado, usa resource.type="container".

    resource.type="k8s_container"
    textPayload:"$ERROR_MESSAGE$"
    
  3. Expande la ocurrencia más reciente para obtener el nombre del pod y, luego, toma nota de pod_name en resource.labels.

  4. Obtén la primera ocurrencia del problema para ese pod:

    resource.type="k8s_container"
    resource.labels.pod_name="$POD_NAME$"
    

    Salida de ejemplo:

    E 2020-03-31T10:41:15.552128897Z
    post-feature-service post-feature-service-v1-67d56cdd-g7fvb failed to create
    connection to feature-store redis, err=dial tcp 192.168.9.16:19209: connect:
    connection refused post-feature-service post-feature-service-v1-67d56cdd-g7fvb
    
  5. Anota la marca de tiempo del primer error de este pod.

  6. Usa el siguiente filtro para ver los eventos de inicio del pod.

    resource.type="k8s_container"
    resource.labels.pod_name="$POD_NAME$"
    

    Salida de ejemplo:

    I 2020-03-31T10:41:15Z spec.containers{istio-proxy} Container image "docker.io/istio/proxyv2:1.3.3" already present on machine  spec.containers{istio-proxy}
    I 2020-03-31T10:41:15Z spec.containers{istio-proxy} Created container  spec.containers{istio-proxy}
    I 2020-03-31T10:41:15Z spec.containers{istio-proxy} Started container  spec.containers{istio-proxy}
    I 2020-03-31T10:41:15Z spec.containers{APP-CONTAINER-NAME} Created container  spec.containers{APP-CONTAINER-NAME}
    W 2020-03-31T10:41:17Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503  spec.containers{istio-proxy}
    W 2020-03-31T10:41:26Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503  spec.containers{istio-proxy}
    W 2020-03-31T10:41:28Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503  spec.containers{istio-proxy}
    W 2020-03-31T10:41:31Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503  spec.containers{istio-proxy}
    W 2020-03-31T10:41:58Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503  spec.containers{istio-proxy}
    
  7. Usa las marcas de tiempo de los errores y los eventos de inicio de istio-proxy para confirmar que los errores ocurren cuando Envoy no está listo.

    Si los errores ocurren mientras el contenedor istio-proxy aún no está listo, es normal obtener errores de conexión rechazada. En el ejemplo anterior, el pod intentaba conectarse a Redis en cuanto se iniciaba 2020-03-31T10:41:15.552128897Z, pero a 2020-03-31T10:41:58Z, istio-proxy aún fallaba en las pruebas de preparación.

    Aunque el contenedor istio-proxy se inició primero, es posible que no se haya preparado lo suficientemente rápido antes de que la app ya estuviera intentando conectarse al extremo externo.

    Si este es el problema que tienes, continúa con los siguientes pasos para solucionarlo.

  8. Anota la configuración a nivel del pod. Esta opción solo está disponible a nivel del grupo, no a nivel global.

    annotations:
    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  9. Modifica el código de la aplicación para que verifique si Envoy está listo antes de intentar realizar otras solicitudes a servicios externos. Por ejemplo, cuando se inicia la aplicación, inicia un bucle que realiza solicitudes al extremo de estado de istio-proxy y solo continúa una vez que se obtiene un código 200. El extremo de estado de istio-proxy es el siguiente:

    http://localhost:15020/healthz/ready
    

Condición de carrera durante la inserción de sidecar entre Vault y Cloud Service Mesh

Cuando se usa vault para la administración de secretos, a veces vault inyecta el contenedor secundario antes que istio, lo que hace que los Pods se bloqueen en el estado Init. Cuando esto sucede, los Pods creados se bloquean en el estado de inicialización después de reiniciar cualquier implementación o implementar una nueva. Por ejemplo:

E 2020-03-31T10:41:15.552128897Z
post-feature-service post-feature-service-v1-67d56cdd-g7fvb failed to create
connection to feature-store redis, err=dial tcp 192.168.9.16:19209: connect:
connection refused post-feature-service post-feature-service-v1-67d56cdd-g7fvb

Este problema se debe a una condición de carrera. Istio y vault insertan el contenedor lateral, y Istio debe ser el último en hacerlo. El proxy de istio no se ejecuta durante los contenedores de inicio. El contenedor de init istio configura reglas de iptables para redireccionar todo el tráfico al proxy. Como aún no se está ejecutando, esas reglas no redireccionan a nada y bloquean todo el tráfico. Por este motivo, el contenedor init debe ser el último, de modo que el proxy esté en funcionamiento inmediatamente después de que se configuren las reglas de iptables. Lamentablemente, el orden no es determinista, por lo que, si se inyecta Istio primero, se produce un error.

Para solucionar este problema, permite la dirección IP de vault para que el tráfico que se dirige a la IP de Vault no se redireccione al proxy de Envoy, que aún no está listo y, por lo tanto, bloquea la comunicación. Para lograrlo, se debe agregar una nueva anotación llamada excludeOutboundIPRanges.

En el caso de Cloud Service Mesh administrado, esto solo es posible a nivel de la Deployment o del pod en spec.template.metadata.annotations, por ejemplo:

apiVersion: apps/v1
kind: Deployment
...
...
...
spec:
  template:
    metadata:
      annotations:
        traffic.sidecar.istio.io/excludeOutboundIPRanges:

En el caso de Cloud Service Mesh en el clúster, existe la opción de configurarlo como uno global con un IstioOperator en spec.values.global.proxy.excludeIPRanges, por ejemplo:

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  values:
    global:
      proxy:
        excludeIPRanges: ""

Después de agregar la anotación, reinicia tus cargas de trabajo.