Envoy is failing to become ready because its control plane, Istiod, is refusing to serve configuration to it, usually due to an invalid configuration object you’ve applied.

Here’s what’s happening: When an Istio-enabled pod starts, the Envoy sidecar proxy within that pod needs to connect to Istiod (the Istio control plane) to fetch its configuration. If Istiod can’t provide valid configuration for that specific Envoy instance, Envoy will remain in a "not ready" state, preventing your application from receiving traffic and often causing deployment failures.

Common Causes and Fixes:

  1. Invalid VirtualService or Gateway Configuration: This is by far the most frequent culprit. A syntax error, an incorrect host, or a conflicting route definition in your Istio networking resources will cause Istiod to reject the configuration request.

    • Diagnosis: Check the Istio proxy container logs for your application pod. Look for messages indicating issues fetching configuration from Istiod. Then, check the Istiod logs for errors related to configuration validation. You can often find these by running:
      kubectl logs -n istio-system deploy/istiod -c discovery -f
      
      Specifically, look for messages mentioning the pod’s name or namespace and errors like "failed to validate X" or "invalid field Y".
    • Fix: Carefully review your VirtualService and Gateway definitions for the affected namespace. Pay close attention to:
      • Host Mismatches: Ensure the hosts field in your VirtualService exactly matches the hostname the Envoy proxy is expecting or the hosts defined in your Gateway.
      • Syntax Errors: YAML indentation, missing commas, or incorrect field names are common. Use a YAML linter.
      • Conflicting Routes: If multiple VirtualService resources apply to the same host, they might conflict. Istio prioritizes based on the order of application or specific annotations.
      • Example Fix (VirtualService): If your Gateway defines hosts: ["my-app.example.com"] and your VirtualService has hosts: ["myapp.example.com"], correct it to:
        apiVersion: networking.istio.io/v1alpha3
        kind: VirtualService
        metadata:
          name: my-app-vs
          namespace: default # or your app's namespace
        spec:
          hosts:
          - my-app.example.com # Corrected hostname
          gateways:
          - my-gateway # Name of your Gateway resource
          http:
          - route:
            - destination:
                host: my-app-service.default.svc.cluster.local
                port:
                  number: 8080
        
      • Why it works: Istiod validates all incoming Istio configuration objects against its internal schema. If an object is malformed or logically inconsistent (e.g., a VirtualService trying to route for a host not declared in any Gateway), Istiod will reject it, preventing Envoy from receiving any configuration, thus keeping it "not ready".
  2. Incorrect ServiceEntry Configuration: If your application communicates with external services that are registered in Istio via ServiceEntry, an invalid ServiceEntry can cause issues, although this is less common for pod startup readiness.

    • Diagnosis: Similar to VirtualService issues, check Istiod logs for errors related to ServiceEntry validation.
    • Fix: Ensure the hosts, addresses, and ports in your ServiceEntry are correctly defined for the external service.
      apiVersion: networking.istio.io/v1alpha3
      kind: ServiceEntry
      metadata:
        name: external-api
        namespace: istio-system # or shared namespace
      spec:
        hosts:
        - api.example.com
        ports:
        - number: 443
          name: https
          protocol: HTTPS
        resolution: DNS
        location: MESH_EXTERNAL
      
      • Why it works: A correct ServiceEntry allows Istiod to generate the necessary configuration for Envoy to route traffic to external destinations. An incorrect one might lead Istiod to believe there’s an unresolvable configuration request.
  3. Istiod Pod Issues: If the Istiod pods themselves are unhealthy or crashing, they cannot serve configuration to any Envoy sidecars.

    • Diagnosis: Check the health of your Istiod deployment:
      kubectl get pods -n istio-system -l app=istiod
      
      If any Istiod pods are not Running or Ready, check their logs:
      kubectl logs -n istio-system <istiod-pod-name>
      
    • Fix: If Istiod is crashing, investigate the logs for specific errors (e.g., out of memory, panics). You might need to increase Istiod’s resource limits (resources.limits.cpu, resources.limits.memory in the istiod deployment) or resolve underlying Kubernetes issues.
      # Example snippet from istiod deployment YAML
      containers:
      - name: discovery
        image: istio/pilot:1.17.0 # Use your Istio version
        resources:
          limits:
            cpu: 1000m
            memory: 1024Mi # Increased memory
          requests:
            cpu: 100m
            memory: 256Mi
      
      • Why it works: Istiod is the central brain. If it’s down or struggling, it can’t fulfill the configuration requests from any Envoy proxies, leading to widespread "not ready" errors.
  4. Network Connectivity Between Envoy and Istiod: The Envoy sidecar needs to be able to reach the Istiod service within the cluster.

    • Diagnosis: From within the application pod (you might need to temporarily kubectl exec into a running pod or a debug pod in the same namespace), try to reach the Istiod service. Istiod typically listens on port 15012 for xDS (discovery service) traffic.
      # Exec into your app pod
      kubectl exec -it <your-app-pod-name> -c istio-proxy -n <your-namespace> -- curl -v istiod.istio-system.svc.cluster.local:15012
      
      Look for connection refused or timeout errors. Also, ensure your CNI (Container Network Interface) is functioning correctly and network policies are not blocking communication.
    • Fix:
      • Check istiod Service: Ensure the istiod service exists and is correctly configured:
        kubectl get svc -n istio-system istiod
        
        It should have a ClusterIP and listen on port 15012.
      • Network Policies: If you use Kubernetes NetworkPolicy, ensure it allows egress from your application pods to the istio-system namespace on port 15012.
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: allow-istiod-egress
          namespace: <your-namespace> # Namespace of your app pod
        spec:
          podSelector: {} # Apply to all pods in this namespace
          policyTypes:
          - Egress
          egress:
          - to:
            - namespaceSelector:
                matchLabels:
                  kubernetes.io/metadata.name: istio-system # Target namespace
            ports:
            - protocol: TCP
              port: 15012
        
      • CNI Issues: If you suspect CNI problems, check your CNI plugin’s logs and status.
      • Why it works: Envoy relies on a stable network connection to Istiod to fetch its configuration. If this path is blocked or unreliable, Envoy cannot initialize.
  5. Resource Starvation: The application pod might not have enough resources (CPU/memory) allocated, causing the Envoy sidecar to be OOMKilled or to fail to start its processes correctly.

    • Diagnosis: Check the pod’s events and container status:
      kubectl describe pod <your-app-pod-name> -n <your-namespace>
      
      Look for OOMKilled status or CrashLoopBackOff with messages indicating resource issues.
    • Fix: Increase the resources.requests and resources.limits for both your application container and the istio-proxy container in your pod’s deployment definition. A common starting point for the sidecar is requests: { cpu: "100m", memory: "128Mi" } and limits: { cpu: "2000m", memory: "1024Mi" }.
      # Example container spec for your app pod
      containers:
      - name: my-app
        image: my-app-image:latest
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
      - name: istio-proxy
        image: istio/proxyv2:1.17.0 # Use your Istio version
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "2000m" # Generous limit for proxy
            memory: "1024Mi" # Generous limit for proxy
      
      • Why it works: The Envoy sidecar is a separate process that consumes resources. If the pod is constrained, the sidecar might fail to start or run, preventing it from initializing and connecting to Istiod.
  6. Istio Injection/Configuration Errors: Less common, but sometimes the automatic sidecar injection or manual configuration of the proxy can be flawed.

    • Diagnosis: Verify that the istio-proxy container is actually present in the pod’s spec:
      kubectl get pod <your-app-pod-name> -n <your-namespace> -o yaml
      
      Look for the istio-proxy container definition. Also, check the pod’s annotations for sidecar.istio.io/status.
    • Fix: If injection is failing, ensure the istio-injection=enabled label is present on the namespace or the pod. If using manual injection, double-check the initContainer and proxyContainer definitions. You might need to re-apply the namespace label or redeploy the pod.
      # Example for namespace injection
      kubectl label namespace <your-namespace> istio-injection=enabled --overwrite
      
      • Why it works: The istio-proxy container is essential. If it’s not present or misconfigured due to injection issues, Envoy cannot run.

After resolving these, the next error you’ll likely encounter is related to Envoy failing to route traffic due to missing or incorrect VirtualService or DestinationRule configurations, once it’s actually ready.

Want structured learning?

Take the full Istio course →