k8s与istio结合后遇到的那些坑

621 阅读3分钟

Istio是一款优秀的Service Mesh,很好的补齐了 k8s 在微服务治理上的这部分能力。同时,两者结合后,在生产环境可能因为错误的配置等原因遇到一些问题,本篇主要记录下踩到的一些坑。

Istio协议选择

Istio 默认支持代理所有 TCP 流量。包括 HTTP、HTTPS、gRPC 以及原始 TCP 协议。但为了提供额外的能力,比如路由和丰富的指标,必须确定协议。协议可以被自动检测或者手动声明。

协议可以在Service定义中手动指定。

可以通过以下两种方式配置:

  • 通过端口名称配置:name: [-]。
  • 在版本 1.18+ 的Kubernetes,通过 appProtocol 字段配置:appProtocol: 。

例如,Service 通过 appProtocol 、名称分别定义一个 mysql 端口和一个 http 端口:

kind: Service
metadata:
  name: myservice
spec:
  ports:
  - port: 3306
    name: database
    appProtocol: mysql
  - port: 80
    name: http-web

但是在实际生产过程中,由于错误配置,name字段未按照规范命名,同时没有appProtocal字段,导致协议被自动检查,使用Http协议,导致解析失败。案例如下:

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  ports:
    - name: kafka-gRPC-8090
      protocol: gRPC
      port: 8090
      targetPort: 8090
    - name: http-addition
      protocol: TCP
      port: 8001
      targetPort: 8001

我们可以看到在 ports 中的name字段起点不是协议名,导致被自动检查,使用了错误的协议。

官方具体的配置指导链接:istio.io/latest/zh/d…

Istio优雅终止

当项目上线新特性时,经常出现grpc断链告警,经过排查,是envoy被强杀,业务容器还未处理完,就结束了。

当使用Istio,流量会先经过sicecar。

当 Pod 开始停止时,它将从服务的 endpoints 中摘除掉,不再转发流量给它,同时 Sidecar 也会收到 SIGTERM 信号,立刻不再接受 inbound 新连接,但会保持存量 inbound 连接继续处理,outbound 方向流量仍然可以正常发起。

若 Pod 没有很快退出,istio 默认是会在停止开始的 5s 后强制杀死 envoy,当 envoy 进程不在了也就无法转发任何流量(不管是 inbound 还是 outbound 方向)。

所以如果业务容器处理时间较长,导致未处理完,就断开了,这时就会有问题。

这时,我们可以对参数 terminationDrainDuration 设置合理值。zheg

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      annotations:
        proxy.istio.io/config: |
          terminationDrainDuration: 30s # 这里自定义 Envoy 优雅终止时长
      labels:
        app: nginx

同时,增加 preStopHook,能够执行一定时间的 sleep,这个主要是影响 “新建请求” 到业务 Pod,也就是业务新特性刚发布进行灰度时。 例如:

apiVersion: apps/v1
kind: Deployment
metadata:
    labels:
        app: abc
    name: abc
spec:
    replicas: 1
    selector:
        matchLabels:
            app: abc
    template:
        metadata:
            labels:
                app: abc
        spec:
            containers:
                image: xxxx.com/abc:v1
                imagePullPolicy: IfNotPresent
                name: app
                ports:
                    - containerPort: 8086
                      name: http
                      protocol: TCP
                lifecycle:
                    preStop:
                        exec:
                            command: ["sh""-c""sleep 10"# 延迟关闭 10秒 -- T2
                terminationMessagePath: /dev/termination-log
                terminationMessagePolicy: File
            dnsPolicy: ClusterFirst
            restartPolicy: Always
            schedulerName: default-scheduler
            securityContext: {}
            terminationGracePeriodSeconds: 60 # 容忍关闭时间 60秒 -- T1, T3时间就是 60 - 10 = 50秒

主要参考的文章链接:
www.jianshu.com/p/87b5b0688… zhuanlan.zhihu.com/p/378077951

livenessProbe就绪探针崩溃,Pod重启

之前遇到了一次生产故障,流量激增,CPU骤增,就绪探针崩溃,导致Pod一直重启,使得原先的问题扩大化,临时采取的措施是,删除就绪探针配置,避免Pod重启。

实际情况与这篇文章类似:blog.csdn.net/oqqYuan1234…

同时,生产环境的istio为1.8版本,不支持TCP livenessprobe 探测,增加配置,临时使用netstat检查端口是否正常。设置类似如下:

apiVersion: v1
kind: Pod
metadata:
  name: liveness-pod
  namespace: default
spec:
    containers:
    - name: myapp
      image: xxxxx
      imagePullPolicy: IfNotPresent
      livenessProbe:
        exec:
          command: ['sh','-c','netstat -nlp|grep -w 5160']  #检测端口是否存在
        initialDelaySeconds: 10  #Pod开启后,延迟10s再进行检测

官方问题描述链接:github.com/istio/istio…
后续的版本弥补了这一缺陷,github.com/istio/istio…
参考文档:blog.fatedier.com/2021/08/24/…