Résoudre les problèmes de démarrage des charges de travail dans Cloud Service Mesh

Ce document explique les problèmes courants liés à Cloud Service Mesh et comment les résoudre. Si vous avez besoin d'une aide supplémentaire, consultez la page Obtenir de l'aide.

Connexion refusée lors d'un point de terminaison de maillage de services Cloud

Vous pouvez rencontrer par intermittence des erreurs de connexion refusée (ECONNREFUSED) lors de la communication entre vos clusters et vos points de terminaison (par exemple, pour Redis Memorystore, Cloud SQL ou tout autre service externe que la charge de travail de votre application doit atteindre).

Cela peut se produire lorsque la charge de travail de votre application se lance plus rapidement que le conteneur Istio-proxy (Envoy) et tente d'atteindre un point de terminaison externe. Étant donné qu'à ce stade, Istio-init (initContainer) a déjà été exécuté, des règles iptables sont en place et permettent de rediriger tout le trafic sortant vers Envoy. Étant donné que le proxy Istio n'est pas encore prêt, les règles iptables redirigent le trafic vers un proxy side-car qui n'est pas encore démarré. L'application reçoit donc l'erreur ECONNREFUSED.

Les étapes suivantes expliquent comment vérifier s'il s'agit de l'erreur que vous rencontrez:

  1. Vérifiez les journaux Stackdriver avec le filtre suivant pour identifier les pods présentant le problème.

    L'exemple suivant présente un message d'erreur typique:

    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. Recherchez une occurrence du problème. Si vous utilisez l'ancien Stackdriver, choisissez resource.type="container".

    resource.type="k8s_container"
    textPayload:"$ERROR_MESSAGE$"
    
  3. Développez la dernière occurrence pour obtenir le nom du pod, puis notez la valeur pod_name sous resource.labels.

  4. Obtenez la première occurrence du problème pour ce pod:

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

    Exemple de résultat :

    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. Notez l'horodatage de la première erreur pour ce pod.

  6. Utilisez le filtre suivant pour afficher les événements de démarrage du pod.

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

    Exemple de résultat :

    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. Utilisez les codes temporels des erreurs et des événements de démarrage Istio-proxy pour vérifier que les erreurs se produisent lorsque Envoy n'est pas prêt.

    Si les erreurs se produisent alors que le conteneur Istio-proxy n'est pas encore prêt, il est normal d'obtenir des erreurs de connexion refusée. Dans l'exemple précédent, le pod tentait de se connecter à Redis dès le 2020-03-31T10:41:15.552128897Z, mais par 2020-03-31T10:41:58Z, Istio-proxy échouait toujours lors des vérifications d'aptitude.

    Bien que le conteneur Istio-proxy ait été lancé en premier, il est possible qu'il ne soit pas prêt assez rapidement avant que l'application ne tente déjà de se connecter au point de terminaison externe.

    S'il s'agit du problème que vous rencontrez, suivez les étapes de dépannage ci-dessous.

  8. Annotez la configuration au niveau du pod. Cette option n'est disponible qu'au niveau du pod, et non au niveau global.

    annotations:
    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  9. Modifiez le code de l'application afin qu'il vérifie si Envoy est prêt avant de tenter d'envoyer d'autres requêtes à des services externes. Par exemple, au démarrage de l'application, lancez une boucle qui envoie des requêtes au point de terminaison de santé Istio-proxy et ne se poursuit qu'une fois le code 200 obtenu. Le point de terminaison de santé Istio-proxy se présente comme suit:

    http://localhost:15020/healthz/ready
    

Condition de concurrence lors de l'injection side-car entre Vault et Cloud Service Mesh

Lorsque vous utilisez vault pour gérer les secrets, vault injecte parfois un side-car avant istio, ce qui bloque les pods à l'état Init. Dans ce cas, les pods créés restent bloqués à l'état "Init" après le redémarrage d'un déploiement ou le déploiement d'un nouveau déploiement. Exemple :

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

Ce problème est causé par une condition de concurrence. Istio et vault injectent le side-car et Istio doit être le dernier à effectuer cette opération. Le proxy istio ne s'exécute pas pendant les conteneurs d'initialisation. Le conteneur d'initialisation istio configure des règles iptables pour rediriger tout le trafic vers le proxy. Comme il n'est pas encore exécuté, ces règles ne redirigent vers rien, bloquant tout le trafic. C'est pourquoi le conteneur "init" doit être placé en dernier, afin que le proxy soit opérationnel immédiatement après la configuration des règles iptables. Malheureusement, l'ordre n'est pas déterministe. Par conséquent, si Istio est injecté en premier, il est interrompu.

Pour résoudre cette condition, autorisez l'adresse IP de vault afin que le trafic dirigé vers l'adresse IP de Vault ne soit pas redirigé vers le proxy Envoy, qui n'est pas encore prêt et bloque donc la communication. Pour ce faire, une annotation nommée excludeOutboundIPRanges doit être ajoutée.

Pour le maillage de services Cloud géré, cela n'est possible qu'au niveau du déploiement ou du pod sous spec.template.metadata.annotations, par exemple:

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

Pour le maillage de services Cloud dans le cluster, il est possible de le définir en tant que maillage de services global avec IstioOperator sous spec.values.global.proxy.excludeIPRanges, par exemple:

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

Après avoir ajouté l'annotation, redémarrez vos charges de travail.