Sidecar 注入问题

Sidecar 注射的结果与我的预期不符

这包括在意外情况下注入的 Sidecar 以及预期情况下缺少注入的 Sidecar。

  1. 确保您的 Pod 不在 kube-systemkube-public 命名空间中。对于这些命名空间中的 Pod,将忽略自动 Sidecar 注射。

  2. 确保您的 Pod 在其 Pod 规范中没有 hostNetwork: true。对于位于主机网络上的 Pod,将忽略自动 Sidecar 注射。

    Sidecar 模型假设 Envoy 拦截流量所需的 iptables 更改位于 Pod 内。对于主机网络上的 Pod,此假设被违反,这会导致主机级别的路由失败。

  3. 检查 Webhook 的 namespaceSelector 以确定 Webhook 是针对目标命名空间的可选加入还是可选退出。

    可选加入的 namespaceSelector 将如下所示

    $ kubectl get mutatingwebhookconfiguration istio-sidecar-injector -o yaml | grep "namespaceSelector:" -A5
      namespaceSelector:
        matchLabels:
          istio-injection: enabled
      rules:
      - apiGroups:
        - ""
    

    对于在具有 istio-injection=enabled 标签的命名空间中创建的 Pod,将调用注入 Webhook。

    $ kubectl get namespace -L istio-injection
    NAME           STATUS    AGE       ISTIO-INJECTION
    default        Active    18d       enabled
    istio-system   Active    3d
    kube-public    Active    18d
    kube-system    Active    18d
    

    可选退出的 namespaceSelector 将如下所示

    $ kubectl get mutatingwebhookconfiguration istio-sidecar-injector -o yaml | grep "namespaceSelector:" -A5
      namespaceSelector:
        matchExpressions:
        - key: istio-injection
          operator: NotIn
          values:
          - disabled
      rules:
      - apiGroups:
        - ""
    

    对于在没有 istio-injection=disabled 标签的命名空间中创建的 Pod,将调用注入 Webhook。

    $ kubectl get namespace -L istio-injection
    NAME           STATUS    AGE       ISTIO-INJECTION
    default        Active    18d
    istio-system   Active    3d        disabled
    kube-public    Active    18d       disabled
    kube-system    Active    18d       disabled
    

    验证应用程序 Pod 的命名空间是否已正确标记,并根据需要(重新)标记,例如:

    $ kubectl label namespace istio-system istio-injection=disabled --overwrite
    

    (对注入 Webhook 应该为新 Pod 调用的所有命名空间重复)

    $ kubectl label namespace default istio-injection=enabled --overwrite
    
  4. 检查默认策略

    检查 istio-sidecar-injector configmap 中的默认注入策略。

    $ kubectl -n istio-system get configmap istio-sidecar-injector -o jsonpath='{.data.config}' | grep policy:
    policy: enabled
    

    允许的策略值为 disabledenabled。默认策略仅在 Webhook 的 namespaceSelector 与目标命名空间匹配时才适用。无法识别的策略会导致完全禁用注入。

  5. 检查每个 Pod 覆盖注释

    默认策略可以通过 Pod 模板规范的元数据中的 sidecar.istio.io/inject 标签覆盖。部署的元数据将被忽略。标签值为 true 会强制注入 Sidecar,而值为 false 会强制注入 Sidecar。

    以下标签将覆盖任何默认的 policy 以强制注入 Sidecar

    $ kubectl get deployment curl -o yaml | grep "sidecar.istio.io/inject:" -B4
    template:
      metadata:
        labels:
          app: curl
          sidecar.istio.io/inject: "true"
    

无法创建 Pod

在失败的 Pod 的部署上运行 kubectl describe -n namespace deployment name。无法调用注入 Webhook 通常会在事件日志中捕获。

Warning  FailedCreate  3m (x17 over 8m)  replicaset-controller  Error creating: Internal error occurred: \
    failed calling admission webhook "sidecar-injector.istio.io": Post https://istiod.istio-system.svc:443/inject: \
    x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying \
    to verify candidate authority certificate "Kubernetes.cluster.local")

x509: certificate signed by unknown authority 错误通常是由 Webhook 配置中的空 caBundle 引起的。

验证 mutatingwebhookconfiguration 中的 caBundle 是否与 istiod Pod 中挂载的根证书匹配。

$ kubectl get mutatingwebhookconfiguration istio-sidecar-injector -o yaml -o jsonpath='{.webhooks[0].clientConfig.caBundle}' | md5sum
4b95d2ba22ce8971c7c92084da31faf0  -
$ kubectl -n istio-system get configmap istio-ca-root-cert -o jsonpath='{.data.root-cert\.pem}' | base64 -w 0 | md5sum
4b95d2ba22ce8971c7c92084da31faf0  -

CA 证书应该匹配。如果不匹配,请重新启动 istiod Pod。

$ kubectl -n istio-system patch deployment istiod \
    -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"`date +'%s'`\"}}}}}"
deployment.extensions "istiod" patched

部署状态错误

当为 Pod 启用自动 Sidecar 注射时,如果注入因任何原因失败,Pod 创建也会失败。在这种情况下,您可以检查 Pod 的部署状态以识别错误。错误也会出现在与部署相关的命名空间的事件中。

例如,如果您尝试部署 Pod 时 istiod 控制平面 Pod 未运行,则事件将显示以下错误

$ kubectl get events -n curl
...
23m Normal   SuccessfulCreate replicaset/curl-9454cc476   Created pod: curl-9454cc476-khp45
22m Warning  FailedCreate     replicaset/curl-9454cc476   Error creating: Internal error occurred: failed calling webhook "namespace.sidecar-injector.istio.io": failed to call webhook: Post "https://istiod.istio-system.svc:443/inject?timeout=10s": dial tcp 10.96.44.51:443: connect: connection refused
$ kubectl -n istio-system get pod -lapp=istiod
NAME                            READY     STATUS    RESTARTS   AGE
istiod-7d46d8d9db-jz2mh         1/1       Running     0         2d
$ kubectl -n istio-system get endpoints istiod
NAME           ENDPOINTS                                                  AGE
istiod   10.244.2.8:15012,10.244.2.8:15010,10.244.2.8:15017 + 1 more...   3h18m

如果 istiod Pod 或端点未准备好,请检查 Pod 日志和状态,以了解有关 Webhook Pod 无法启动和提供流量的原因的任何指示。

$ for pod in $(kubectl -n istio-system get pod -lapp=istiod -o jsonpath='{.items[*].metadata.name}'); do \
    kubectl -n istio-system logs ${pod} \
done


$ for pod in $(kubectl -n istio-system get pod -l app=istiod -o name); do \
kubectl -n istio-system describe ${pod}; \
done
$

如果 Kubernetes API 服务器具有代理设置,则自动 Sidecar 注射将失败

当 Kubernetes API 服务器包含代理设置时,例如

env:
  - name: http_proxy
    value: http://proxy-wsa.esl.foo.com:80
  - name: https_proxy
    value: http://proxy-wsa.esl.foo.com:80
  - name: no_proxy
    value: 127.0.0.1,localhost,dockerhub.foo.com,devhub-docker.foo.com,10.84.100.125,10.84.100.126,10.84.100.127

使用这些设置,Sidecar 注射将失败。唯一相关的失败日志可以在 kube-apiserver 日志中找到

W0227 21:51:03.156818       1 admission.go:257] Failed calling webhook, failing open sidecar-injector.istio.io: failed calling admission webhook "sidecar-injector.istio.io": Post https://istio-sidecar-injector.istio-system.svc:443/inject: Service Unavailable

确保 Pod 和服务 CIDR 都不根据 *_proxy 变量进行代理。检查 kube-apiserver 文件和日志以验证配置以及是否正在代理任何请求。

一个解决方法是从 kube-apiserver 清单中删除代理设置,另一个解决方法是在 no_proxy 值中包含 istio-sidecar-injector.istio-system.svc.svc。确保在每次解决方法后重新启动 kube-apiserver

已向 Kubernetes 提交了一个关于此问题的问题,该问题现已关闭。https://github.com/kubernetes/kubernetes/pull/58698#discussion_r163879443

在 Pod 中使用 Tcpdump 的限制

Tcpdump 在 Sidecar Pod 中不起作用 - 容器不以 root 身份运行。但是,同一个 Pod 中的任何其他容器都会看到所有数据包,因为网络命名空间是共享的。iptables 也会看到 Pod 范围的配置。

Envoy 和应用程序之间的通信发生在 127.0.0.1 上,并且未加密。

集群不会自动缩减

由于 Sidecar 容器挂载了本地存储卷,因此节点自动缩放器无法驱逐具有注入 Pod 的节点。这是一个已知问题。解决方法是为注入的 Pod 添加一个 Pod 注释 "cluster-autoscaler.kubernetes.io/safe-to-evict": "true"

如果 istio-proxy 未准备好,Pod 或容器将以网络问题启动

许多应用程序在启动期间执行命令或检查,这些命令或检查需要网络连接。如果 istio-proxy Sidecar 容器未准备好,这会导致应用程序容器挂起或重新启动。

为了避免这种情况,请将 holdApplicationUntilProxyStarts 设置为 true。这会导致 Sidecar 注射器在 Pod 容器列表的开头注入 Sidecar,并将其配置为阻止所有其他容器启动,直到代理准备就绪。

这可以作为全局配置选项添加

values.global.proxy.holdApplicationUntilProxyStarts: true

或者作为 Pod 注释添加

proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
这些信息有用吗?
您有什么改进建议吗?

感谢您的反馈!