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

Ce document explique les problèmes couramment rencontrés dans Cloud Service Mesh et indique comment les résoudre. Si vous avez besoin d'une aide supplémentaire, consultez la page Assistance.

Échec du démarrage de la passerelle avec un proxy sans distribution lorsqu'un port privilégié est exposé

Par défaut, le proxy sans distribution démarre avec des autorisations non root, ce qui peut parfois entraîner des échecs de liaison sur les ports privilégiés. Si des erreurs semblables à celles ci-dessous s'affichent lors du démarrage du proxy, vous devez appliquer un securityContext supplémentaire pour un déploiement de passerelle.

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

L'exemple suivant correspond au fichier YAML d'un déploiement de passerelle de sortie :

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 

Connexion refusée lors de l'accès à un point de terminaison Cloud Service Mesh

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

Cela peut se produire lorsque la charge de travail de votre application démarre 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 pour rediriger l'intégralité du trafic sortant vers Envoy. Comme istio-proxy n'est pas encore prêt, les règles iptables redirigeront le trafic vers un proxy side-car qui n'a pas encore démarré. L'application reçoit donc l'erreur ECONNREFUSED.

Pour savoir si vous rencontrez cette erreur, procédez comme suit :

  1. Consultez les journaux Stackdriver avec le filtre suivant pour identifier les pods qui ont rencontré le problème.

    Voici un exemple de message d'erreur type :

    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, utilisez 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 le 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 le code temporel 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 d'istio-proxy pour confirmer que les erreurs se produisent lorsque Envoy n'est pas prêt.

    Si des 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 2020-03-31T10:41:15.552128897Z, mais à 2020-03-31T10:41:58Z, istio-proxy échouait toujours aux vérifications de l'aptitude.

    Même si le conteneur istio-proxy a démarré en premier, il est possible qu'il ne soit pas prêt avant que l'application ne tente déjà de se connecter au point de terminaison externe.

    Si c'est le problème que vous rencontrez, suivez les étapes de dépannage ci-dessous.

  8. Annotez la configuration au niveau du pod. Cette option est uniquement disponible au niveau du pod, et non au niveau mondial.

    annotations:
    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  9. Modifiez le code de l'application pour qu'il vérifie si Envoy est prêt avant d'essayer 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 d'état istio-proxy et ne se poursuit qu'une fois qu'un code 200 est obtenu. Le point de terminaison d'état istio-proxy est le suivant :

    http://localhost:15020/healthz/ready
    

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

Lorsque vous utilisez vault pour la gestion des secrets, vault injecte parfois un side-car avant istio, ce qui bloque les pods à l'état Init. Lorsque cela se produit, les pods créés restent bloqués à l'état "Init" après le redémarrage d'un déploiement ou 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 dû à une condition de concurrence. Istio et vault injectent le side-car, et Istio doit être le dernier à le faire. Le proxy istio ne fonctionne pas pendant l'exécution des conteneurs d'initialisation. Le conteneur d'initialisation istio configure les règles iptables pour rediriger l'intégralité du trafic vers le proxy. Comme il n'est pas encore en cours d'exécution, ces règles ne redirigent vers rien, ce qui bloque tout le trafic. C'est pourquoi le conteneur d'initialisation doit être le 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, cela ne fonctionne pas.

Pour résoudre la condition, autorisez l'adresse IP de vault afin que le trafic destiné à 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 nouvelle annotation nommée excludeOutboundIPRanges doit être ajoutée.

Pour le service Cloud Service Mesh 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 Cloud Service Mesh en cluster, vous pouvez le définir comme ressource globale avec un 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.

Identifier le type d'image de proxy utilisé dans le cluster

Pour identifier le type d'image de proxy (default ou distroless) utilisé par un pod spécifique, vous pouvez inspecter la spécification du pod.

Exécutez la commande suivante pour vérifier l'image utilisée par le conteneur istio-proxy :

kubectl get pod POD_NAME -n NAMESPACE -o jsonpath='{.spec.containers[?(@.name=="istio-proxy")].image}'
  • Si le chemin d'accès à l'image ne contient pas -distroless dans le tag ou le suffixe, il utilise l'image default.
  • Si le chemin d'accès à l'image contient -distroless dans le tag ou le suffixe, il utilise l'image distroless.

Vérifier l'intention de configuration

Le type d'image peut être configuré de deux manières (l'annotation est prioritaire par rapport à MeshConfig) :

  1. Annotation de pod : vérifiez si le pod comporte l'annotation sidecar.istio.io/proxyImageType.

    kubectl get pod POD_NAME -n NAMESPACE -o jsonpath='{.metadata.annotations["sidecar.istio.io/proxyImageType"]}'
    
  2. MeshConfig : vérifiez le paramètre defaultConfig.image.imageType dans votre ConfigMap istio-RELEASE_CHANNEL dans l'espace de noms istio-system.

Remarque : Pour les clusters avec le plan de contrôle géré TRAFFIC_DIRECTOR :

  • Pour les clusters provisionnés directement avec un plan de contrôle TRAFFIC_DIRECTOR géré, seules les images distroless sont compatibles. Les remplacements d'autres types d'images sont ignorés.
  • Pour les clusters migrés vers le plan de contrôle TRAFFIC_DIRECTOR (par exemple, ceux migrés depuis CSM-ISTIOD), le type d'image est défini par défaut sur l'image default, mais vous pouvez choisir distroless à l'aide de MeshConfig ou d'une annotation de pod. Les remplacements d'autres types d'images (tels que debug) ne sont pas compatibles.