解決 Cloud Service Mesh 中的工作負載啟動問題

本文說明常見的 Cloud Service Mesh 問題,以及解決方法。如需其他協助,請參閱取得支援

公開特權通訊埠時,閘道無法透過無發行版 Proxy 啟動

根據預設,無發行版 Proxy 會以非 Root 權限啟動,在某些情況下可能會導致特殊權限通訊埠繫結失敗。如果您在 Proxy 啟動期間看到類似以下的錯誤,就需要為網關部署套用額外的 securityContext。

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

以下是外送閘道部署作業的 yaml 範例:

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 

連線至 Cloud Service Mesh 端點時遭拒

您可能會間歇性地發生連線遭拒 (ECONNREFUSED) 錯誤,導致叢集與端點 (例如 Memorystore Redis、Cloud SQL 或應用程式工作負載需要存取的任何外部服務) 之間的通訊中斷。

當應用程式工作負載的啟動速度比 istio-proxy (Envoy) 容器快,並嘗試存取外部端點時,就可能發生這種情況。由於在這個階段 istio-init (initContainer) 已執行,因此有 iptables 規則將所有外送流量重新導向至 Envoy。由於 istio-proxy 尚未就緒,iptables 規則會將流量重新導向至尚未啟動的側邊代理程式,因此應用程式會收到 ECONNREFUSED 錯誤。

請按照下列步驟檢查是否為您遇到的錯誤:

  1. 使用下列篩選器檢查 Stackdriver 記錄,找出有問題的 Pod。

    以下是常見的錯誤訊息示例:

    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. 搜尋問題發生的時間點。如果您使用的是舊版 Stackdriver,請使用 resource.type="container"

    resource.type="k8s_container"
    textPayload:"$ERROR_MESSAGE$"
    
  3. 展開最新的事件,取得 Pod 名稱,然後記下 resource.labels 底下的 pod_name

  4. 取得該 pod 中問題首次發生的時間:

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

    輸出內容範例:

    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. 請記下這個 Pod 第一次發生錯誤的時間戳記。

  6. 使用下列篩選器查看 Pod 啟動事件。

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

    輸出內容範例:

    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. 請使用錯誤和 Istio-Proxy 啟動事件的時間戳記,確認錯誤是在 Envoy 未就緒時發生。

    如果錯誤發生在 istio-proxy 容器尚未就緒時,則會正常收到連線遭拒的錯誤。在上述範例中,Pod 會在 2020-03-31T10:41:15.552128897Z 一啟動就嘗試連線至 Redis,但在 2020-03-31T10:41:58Z 時,istio-proxy 仍會失敗執行就緒性探查。

    即使 istio-proxy 容器先啟動,但在應用程式嘗試連線至外部端點之前,該容器可能無法及時就緒。

    如果您遇到這個問題,請繼續執行下列疑難排解步驟。

  8. 在 Pod 層級加上註解。這項功能可在 Pod 層級使用,無法在全球層級使用。

    annotations:
    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  9. 修改應用程式程式碼,讓程式碼在嘗試向外部服務提出任何其他要求前,先檢查 Envoy 是否已就緒。舉例來說,在應用程式啟動時,請啟動一個迴圈,向 istio-proxy 健康情況端點提出要求,並在取得 200 時才繼續執行。istio-proxy 健康狀態端點如下:

    http://localhost:15020/healthz/ready
    

Vault 和 Cloud Service Mesh 之間的 sidecar 注入作業發生競爭條件

使用 vault 管理密鑰時,vault 有時會在 istio 之前注入 sidecar,導致 Pod 卡在 Init 狀態。發生這種情況時,重新啟動任何部署作業或部署新部署作業後,建立的 Pod 就會卡在初始狀態。例如:

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

這個問題是由於競爭狀態造成,Istio 和 vault 都會注入 sidecar,而 Istio 必須是最後一個執行此操作的程式,istio 代理在初始化容器期間不會執行。istio 初始化容器會設定 iptables 規則,將所有流量重新導向至 Proxy。由於尚未執行,這些規則會重新導向至空白,進而封鎖所有流量。因此,初始化容器必須是最後一個,這樣 Proxy 才能在設定 iptables 規則後立即啟動及執行。很抱歉,順序並非確定性的,因此如果先注入 Istio,就會發生錯誤。

如要排解這個問題,請允許 vault 的 IP 位址,這樣傳送至 Vault IP 的流量就不會重新導向至尚未就緒的 Envoy Proxy,進而封鎖通訊。為此,您應新增名為 excludeOutboundIPRanges 的新註解。

對於代管的 Cloud Service Mesh,這項操作只能在 spec.template.metadata.annotations 下的部署或 Pod 層級執行,例如:

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

針對叢集內的 Cloud Service Mesh,您可以選擇將其設為全域服務網格,並在 spec.values.global.proxy.excludeIPRanges 下使用 IstioOperator,例如:

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

新增註解後,請重新啟動工作負載。