wishli 2020-06-03
作者 | 子白(阿里云开发工程师)、溪恒(阿里云技术专家)
<关注阿里巴巴云原生公众号,回复?排查?即可下载电子书>
《深入浅出 Kubernetes》一书共汇集 12 篇技术文章,帮助你一次搞懂 6 个核心原理,吃透基础理论,一次学会 6 个典型问题的华丽操作!
Kubernetes?集群中,业务通常采用?Deployment + LoadBalancer?类型?Service?的方式对外提供服务,其典型部署架构如图?1?所示。这种架构部署和运维都十分简单方便,但是在应用更新或者升级时可能会存在服务中断,引发线上问题。今天我们来详细分析下这种架构为何在更新应用时会发生服务中断以及如何避免服务中断。
图1 业务部署图
Deployment?滚动更新时会先创建新?pod,等待新?pod running?后再删除旧?pod。
图?2 服务中断示意图
中断原因:Pod running?后被加入到?Endpoint?后端,容器服务监控到?Endpoint?变更后将?Node?加入到?SLB?后端。此时请求从?SLB?转发到?Pod?中,但是?Pod?业务代码还未初始化完毕,无法处理请求,导致服务中断,如图?2?所示。
解决方法:为?pod?配置就绪检测,等待业务代码初始化完毕后后再将?node?加入到?SLB?后端。
在删除旧?pod?过程中需要对多个对象(如?Endpoint、ipvs/iptables、SLB)进行状态同步,并且这些同步操作是异步执行的,整体同步流程如图?3?所示。
图?3 Deployment?更新时序图
中断原因:上述?1、2、3、4步骤同时进行,因此有可能存在?Pod?收到?SIGTERM?信号并且停止工作后,还未从?Endpoints?中移除的情况。此时,请求从?slb?转发到?pod?中,而?Pod?已经停止工作,因此会出现服务中断,如图?4?所示。
图?4 服务中断示意图
解决方法:为?pod?配置?preStop Hook,使?Pod?收到?SIGTERM?时?sleep?一段时间而不是立刻停止工作,从而确保从?SLB?转发的流量还可以继续被?Pod?处理。
中断原因:当?pod?变为?termintaing?状态时,会从所有?service?的?endpoint?中移除该?pod。kube-proxy?会清理对应的?iptables/ipvs?条目。而容器服务?watch?到?endpoint?变化后,会调用?slb openapi?移除后端,此操作会耗费几秒。由于这两个操作是同时进行,因此有可能存在节点上的?iptables/ipvs?条目已经被清理,但是节点还未从?slb?移除的情况。此时,流量从?slb?流入,而节点上已经没有对应的?iptables/ipvs?规则导致服务中断,如图?5?所示。
图?5 服务中断示意图
解决方法:
图?6 Cluster?模式请求转发示意图
图?7 Local?模式原地升级时请求转发示意图
图 8? ENI?模式请求转发示意图
图 9??服务中断示意图
中断原因:容器服务监控到?Endpoints?变化后,会将?Node?从?slb?后端移除。当节点从?slb?后端移除后,SLB?对于继续发往该节点的长连接会直接断开,导致服务中断。
解决方法:为?SLB?设置长链接优雅中断(依赖具体云厂商)。
避免服务中断可以从?Pod?和?Service?两类资源入手,接下来将针对上述中断原因介绍相应的配置方法。
apiVersion: v1 kind: Pod metadata: name: nginx namespace: default spec: containers: - name: nginx image: nginx # 存活检测 livenessProbe: failureThreshold: 3 initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 tcpSocket: port: 5084 timeoutSeconds: 1 # 就绪检测 readinessProbe: failureThreshold: 3 initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 tcpSocket: port: 5084 timeoutSeconds: 1 # 优雅退出 lifecycle: preStop: exec: command: - sleep - 30 terminationGracePeriodSeconds: 60
注意:需要合理设置就绪检测(readinessProbe)的探测频率、延时时间、不健康阈值等数据,部分应用启动时间本身较长,如果设置的时间过短,会导致 POD 反复重启。
apiVersion: v1 kind: Service metadata: name: nginx namespace: default spec: externalTrafficPolicy: Cluster ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer
容器服务会将集群中所有节点挂载到?SLB?的后端(使用?BackendLabel?标签配置后端的除外),因此会快速消耗?SLB quota。SLB?限制了每个?ECS?上能够挂载的?SLB?的个数,默认值为?50,当?quota?消耗完后会导致无法创建新的监听及?SLB。
Cluster?模式下,如果当前节点没有业务?pod?会将请求转发给其他?Node。在跨节点转发时需要做?NAT,因此会丢失源?IP。
apiVersion: v1 kind: Service metadata: name: nginx namespace: default spec: externalTrafficPolicy: Local ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer # 需要尽可能的让每个节点在更新的过程中有至少一个的Running的Pod # 通过修改UpdateStrategy和利用nodeAffinity尽可能的保证在原地rolling update # * UpdateStrategy可以设置Max Unavailable为0,保证有新的Pod启动后才停止之前的pod # * 先对固定的几个节点打上label用来调度 # * 使用nodeAffinity+和超过相关node数量的replicas数量保证尽可能在原地建新的Pod # 例如: apiVersion: apps/v1 kind: Deployment ...... strategy: rollingUpdate: maxSurge: 50% maxUnavailable: 0% type: RollingUpdate ...... affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: deploy operator: In values: - nginx
容器服务默认会将?Service?对应的?Pod?所在的节点加入到?SLB?后端,因此?SLB quota?消耗较慢。Local?模式下请求直接转发到?pod?所在?node,不存在跨节点转发,因此可以保留源?IP?地址。Local?模式下可以通过原地升级的方式避免服务中断,yaml?文件如上。
apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/backend-type: "eni" name: nginx spec: ports: - name: http port: 30080 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer
Terway?网络模式下,通过设置?service.beta.kubernetes.io/backend-type:
"eni" annotation?可以创建?ENI?模式的?SLB。ENI?模式下,pod会直接挂载到?SLB?后端,不经过?kube-proxy,因此不存在服务中断的问题。请求直接转发到?pod,因此可以保留源?IP?地址。
三种?svc?模式对比如下表所示。
图 10 Service?对比
选用?ENI?模式的?svc + 设定?Pod?优雅终止 + 就绪检测。
为了更多开发者能够享受到 Serverless 带来的红利,这一次,我们集结了 10+ 位阿里巴巴 Serverless 领域技术专家,打造出最适合开发者入门的 Serverless 公开课,让你即学即用,轻松拥抱云计算的新范式——Serverless。
点击即可免费观看课程:https://developer.aliyun.com/learning/roadmap/serverless
“阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的公众号。”
###host字段指定授权使用该证书的etcd节点IP或子网列表,需要将etcd集群的3个节点都添加其中。cp etcd-v3.3.13-linux-amd64/etcd* /opt/k8s/bin/