Risoluzione dei problemi del proxy in Anthos Service Mesh

Questo documento illustra i problemi comuni di Anthos Service Mesh e come risolverli. Se hai bisogno di ulteriore assistenza, consulta Assistenza.

Connessione rifiutata quando si raggiunge un endpoint con Istio

A intermittenza, potresti riscontrare errori di connessione rifiutata (ECONNREFUSED) nella comunicazione dai cluster ai tuoi endpoint, ad esempio Memorystore Redis, Cloud SQL o qualsiasi servizio esterno che il tuo carico di lavoro delle applicazioni deve raggiungere.

Questo può verificarsi quando il carico di lavoro dell'applicazione viene avviato più velocemente del container Istio-proxy (Envoy) e tenta di raggiungere un endpoint esterno. Poiché in questa fase istio-init (initContainer) è già stato eseguito, sono presenti regole itables che reindirizzano tutto il traffico in uscita a Envoy. Dal momento che istio-proxy non è ancora pronto, le regole iptables reindirizzano il traffico a un proxy sidecar non ancora avviato e, di conseguenza, l'applicazione riceve l'errore ECONNREFUSED.

I passaggi seguenti spiegano come verificare se si tratta dell'errore che stai riscontrando:

  1. Controlla i log di Google Cloud Observability con il filtro seguente per identificare quali pod hanno riscontrato il problema.

    Nell'esempio seguente è riportato un messaggio di errore tipico:

    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. Controlla i log di Google Cloud Observability con il filtro seguente per verificare che il container Istio-proxy (Envoy) non sia pronto.

     resource.labels.pod_name="$POD_FROM_STEP_1$"
     resource.type="k8s_container"
     resource.labels.container_name="istio-proxy"
     textPayload:"Envoy proxy is NOT ready"
    
  3. Cerca un'occorrenza del problema. Se utilizzi la versione legacy di Stackdriver, utilizza resource.type="container".

    resource.type="k8s_container"
    textPayload:"$ERROR_MESSAGE$"
    
  4. Espandi l'ultima occorrenza per ottenere il nome del pod, quindi prendi nota di pod_name in resource.labels.

  5. Ottieni la prima occorrenza del problema per quel pod:

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

    Output di esempio:

    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
    
  6. Prendi nota del timestamp del primo errore di questo pod.

  7. Utilizza il filtro seguente per visualizzare gli eventi di avvio dei pod.

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

    Output di esempio:

    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}
    
  8. Utilizza i timestamp degli errori e degli eventi di avvio istio-proxy per confermare che gli errori si verificano quando Envoy non è pronto.

    Se gli errori si verificano mentre il container istio-proxy non è ancora pronto, è normale che vengano visualizzati errori di connessione rifiutata. Nell'esempio precedente, il pod stava cercando di connettersi a Redis non appena 2020-03-31T10:41:15.552128897Z, ma istio-proxy da parte di 2020-03-31T10:41:58Z continuava a non riuscire a risolvere i probe di idoneità.

    Anche se il container istio-proxy è stato avviato prima, è possibile che non sia stato pronto abbastanza velocemente prima che l'app stesse già tentando di connettersi all'endpoint esterno.

    In questo caso, continua a svolgere la procedura per la risoluzione dei problemi che segue.

  9. Annota la configurazione a livello di pod. Questa opzione è disponibile solo a livello di pod e non a livello globale.

    annotations:
    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  10. Modifica il codice dell'applicazione in modo che verifichi se Envoy è pronto prima di provare a effettuare altre richieste ai servizi esterni. Ad esempio, all'avvio dell'applicazione, avvia un loop che invia richieste all'endpoint di integrità istio-proxy e continua solo una volta ottenuto un valore 200. L'endpoint di integrità istio-proxy è il seguente:

    http://localhost:15020/healthz/ready
    

Condizione di gara durante l'inserimento di sidecar tra vault e istio

Quando utilizzi vault per la gestione dei secret, a volte vault inserisce un file collaterale prima di istio, causando il blocco dei pod nello stato Init. In questo caso, i pod creati rimangono bloccati nello stato Init dopo il riavvio di un deployment o il deployment di un nuovo deployment. Ad esempio:

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

Questo problema è causato da una race condition. Sia Istio sia vault iniettano il file collaterale e Istio devono essere l'ultimo a farlo. Il proxy istio non è in esecuzione durante i container di inizializzazione. Il container init istio configura le regole iptables per reindirizzare tutto il traffico al proxy. Poiché non è ancora in esecuzione, queste regole non reindirizzano a nulla, bloccando tutto il traffico. Questo è il motivo per cui il container init deve essere l'ultimo, in modo che il proxy sia attivo e in esecuzione subito dopo l'impostazione delle regole iptables. Sfortunatamente, l'ordine non è deterministico, quindi se Istio viene inserito prima, non funziona.

Per risolvere questo problema, consenti l'indirizzo IP di vault in modo che il traffico verso l'IP di Vault non venga reindirizzato al proxy Envoy che non è ancora pronto e blocca quindi la comunicazione. A questo scopo, è necessario aggiungere una nuova annotazione denominata excludeOutboundIPRanges.

Per Anthos Service Mesh gestito, ciò è possibile solo a livello di deployment o di pod in spec.template.metadata.annotations, ad esempio:

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

Per Anthos Service Mesh nel cluster, esiste un'opzione per impostarlo come globale con un IstioOperator in spec.values.global.proxy.excludeIPRanges, ad esempio:

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

Dopo aver aggiunto l'annotazione, riavvia i carichi di lavoro.