Resolver problemas de proxy no Cloud Service Mesh

Este documento explica os problemas comuns do Cloud Service Mesh e como os resolver. Se precisar de assistência adicional, consulte a secção Receber apoio técnico.

Ligação recusada quando atinge um ponto final com o Istio

Pode ter erros de ligação recusada (ECONNREFUSED) intermitentemente com a comunicação dos seus clusters para os seus pontos finais, por exemplo, Memorystore Redis, CloudSQL ou qualquer serviço externo que a carga de trabalho da sua aplicação precise de alcançar.

Isto pode ocorrer quando a carga de trabalho da aplicação é iniciada mais rapidamente do que o contentor istio-proxy (Envoy) e tenta alcançar um ponto final externo. Uma vez que, nesta fase, o istio-init (initContainer) já foi executado, existem regras de iptables que redirecionam todo o tráfego de saída para Envoy. Uma vez que o istio-proxy ainda não está pronto, as regras de iptables vão redirecionar o tráfego para um proxy sidecar que ainda não foi iniciado e, por isso, a aplicação recebe o erro ECONNREFUSED.

Os passos seguintes detalham como verificar se este é o erro que está a ter:

  1. Verifique os registos do Stackdriver com o seguinte filtro para identificar os pods que tiveram o problema.

    O exemplo seguinte mostra uma mensagem de erro típica:

    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. Pesquise uma ocorrência do problema. Se estiver a usar o Stackdriver antigo, use resource.type="container".

    resource.type="k8s_container"
    textPayload:"$ERROR_MESSAGE$"
    
  3. Expanda a ocorrência mais recente para obter o nome do pod e, em seguida, tome nota do pod_name em resource.labels.

  4. Obtenha a primeira ocorrência do problema para esse agrupamento:

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

    Exemplo de saída:

    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. Tome nota da data/hora do primeiro erro deste pod.

  6. Use o seguinte filtro para ver os eventos de arranque do pod.

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

    Exemplo de saída:

    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. Use as datas/horas dos erros e dos eventos de arranque do istio-proxy para confirmar que os erros ocorrem quando o Envoy não está pronto.

    Se os erros ocorrerem enquanto o contentor istio-proxy ainda não estiver pronto, é normal receber erros de ligação recusada. No exemplo anterior, o pod estava a tentar estabelecer ligação ao Redis assim que 2020-03-31T10:41:15.552128897Z, mas, por 2020-03-31T10:41:58Z, o istio-proxy ainda estava a falhar as sondagens de prontidão.

    Embora o contentor istio-proxy tenha sido iniciado primeiro, é possível que não tenha ficado pronto com a rapidez suficiente antes de a app já estar a tentar ligar-se ao ponto final externo.

    Se este for o problema que está a ter, continue com os seguintes passos de resolução de problemas.

  8. Anotar a configuração ao nível do pod. Esta opção só está disponível ao nível do grupo de anúncios e não ao nível global.

    annotations:
    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  9. Modifique o código da aplicação para que verifique se Envoy está pronto antes de tentar fazer outros pedidos a serviços externos. Por exemplo, no início da aplicação, inicie um ciclo que faça pedidos ao ponto final de verificação do estado de funcionamento do istio-proxy e só continue quando for obtido um 200. O ponto final de verificação do estado de funcionamento do istio-proxy é o seguinte:

    http://localhost:15020/healthz/ready
    

Condição de corrida durante a injeção de sidecar entre o cofre e o Istio

Quando usa o vault para a gestão de segredos, por vezes, o vault injeta o sidecar antes do istio, o que faz com que os pods fiquem bloqueados no estado Init. Quando isto acontece, os pods criados ficam bloqueados no estado Init depois de reiniciar qualquer implementação ou implementar uma nova. Por exemplo:

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 é causado por uma condição de corrida. Tanto o Istio como o vault injetam o sidecar, e o Istio tem de ser o último a fazê-lo. O proxy istio não está em execução durante os contentores de inicialização. O contentor istio init configura regras de iptables para redirecionar todo o tráfego para o proxy. Uma vez que ainda não está em execução, essas regras não redirecionam para nada, bloqueando todo o tráfego. É por isso que o contentor init tem de ser o último, para que o proxy esteja em funcionamento imediatamente após a configuração das regras iptables. Infelizmente, a ordem não é determinística, por isso, se o Istio for injetado primeiro, ocorre uma falha.

Para resolver este problema, permita o endereço IP de vault para que o tráfego destinado ao IP do Vault não seja redirecionado para o proxy Envoy, que ainda não está pronto e, por isso, está a bloquear a comunicação. Para o conseguir, deve adicionar uma nova anotação com o nome excludeOutboundIPRanges.

Para a malha de serviços na nuvem gerida, isto só é possível ao nível da implementação ou do pod em spec.template.metadata.annotations, por exemplo:

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

Para a malha de serviços na nuvem no cluster, existe uma opção para a definir como global com um IstioOperator em spec.values.global.proxy.excludeIPRanges, por exemplo:

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

Depois de adicionar a anotação, reinicie as cargas de trabalho.