热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

阿里云线上案例分析:网格应用存活状态异常

-Istioisthefuture-Istio作为服务网格的典型实现,某种程度上已经成为网络技术事实上的标准。本文选自《云原生操作系统Kubernetes》一书&

 

- Istio is the future -

Istio 作为服务网格的典型实现,某种程度上已经成为网络技术事实上的标准。

本文选自《云原生操作系统Kubernetes》一书,分享一个阿里云线上Istio 的真实案例,并借此和大家讨论一下网格技术背后的逻辑。

 

1.在线一半的微服务

问题是这样的 :用户在自己的测试集群里安装了 Istio,并依照官方文档部署 bookinfo 应用。部署之后,用户执行 kubectl get pods 命令,发现所有的 Pod都只有1/2个容器是 Ready 的。

# kubectl get pods
NAME                                READY STATUSRESTARTS AGE
details-v1-68868454f5-94hzd     1/2 Running     0      1m
productpage-v1-5cb458d74f-28nlz 1/2 Running  0    1m
ratings-v1-76f4c9765f-gjjsc     1/2 Running     0      1m
reviews-v1-56f6855586-dplsf 1/2 Running 0    1m
reviews-v2-65c9df47f8-zdgbw 1/2 Running 0    1m
reviews-v3-6cf47594fd-cvrtf 1/2 Running 0    1m

如果从来都没有注意过 Ready 这一列的话,我们大概会有两个疑惑 :

“2”是什么意思?

“1/2”又意味着啥?

 

简单来讲,这里的 Ready 列,给出的是每个 Pod 内部容器的 readiness,即就绪状态。每个集群节点上的 Kubelet 会根据容器本身 readiness 规则的定义,分别以 tcp、http 或 exec 的方式,来确认对应容器的 readiness 情况。

更具体一点,Kubelet 作为运行在每个节点上的进程,以 tcp/http 的方式(从节点网络命名空间到 Pod 网络命名空间)访问容器定义的接口,或者在容器的命名空间里执行 exec 定义的命令,来确定容器是否就绪,如图1 所示。

 

图1 Kubelet 健康检查机制

这里的“2”说明这些 Pod 里都有两个容器,“1/2”则表示每个 Pod 里只有一个容器是就绪的,即通过 readiness 测试的。关于“2”这一点,我们一会儿再深入讲,这里我们先看一下,为什么所有的 Pod 里都有一个容器没有就绪。

使用 kubectl 工具拉取第一个 details pod 的编排模板,可以看到这个 Pod里的两个容器只有一个定义了 readiness probe。对于未定义 readiness probe 的容器,Kubelet 认为,只要容器里的进程开始运行,容器就进入就绪状态了。

所以 1/2 个就绪 Pod 意味着,有定义了 readiness probe 的容器没有通过 Kubelet的测试。

没有通过 readiness probe 测试的是 istio-proxy 这个容器。它的 readiness probe 规则定义如下。

readinessProbe:failureThreshold: 30httpGet:path: /healthz/readyport: 15020scheme: HTTPinitialDelaySeconds: 1periodSeconds: 2successThreshold: 1timeoutSeconds: 1

我们登录这个 Pod 所在的节点,用 curl 工具来模拟 Kubelet 访问下面的URI,测试 istio-proxy 的就绪状态。

# curl http://172.16.3.43:15020/healthz/ready -v
* About to connect() to 172.16.3.43 port 15020 (#0)
* Trying 172.16.3.43...
* Connected to 172.16.3.43 (172.16.3.43) port 15020 (#0)
> GET /healthz/ready HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 172.16.3.43:15020
> Accept: */*
>
<
* Connection #0 to host 172.16.3.43 left intact

2.认识服务网格

刚刚我们描述了问题的现象&#xff0c;但是留下一个问题&#xff0c;就是 Pod 里的容器个数为什么是 2&#xff1f;

虽然每个 Pod 本质上至少有两个容器&#xff0c;一个是占位符容器pause&#xff0c;另一个是真正的工作容器&#xff0c;但是我们在使用 kubectl 命令获取 Pod 列表的时候&#xff0c;Ready 列是不包括 pause 容器的。

这里的另外一个容器&#xff0c;其实就是服务网格的核心概念 sidecar。其实把这个容器叫作 sidecar&#xff0c;某种意义上是不能反映这个容器的本质的。从本质上来说&#xff0c;sidecar 容器是反向代理&#xff0c;它本来是一个 Pod 访问其他服务后端 Pod 的负载均衡。

 

图2 服务网格局部视角

然而&#xff0c;当我们让集群中的每一个 Pod 都“随身”携带一个反向代理的时候&#xff0c;Pod 和反向代理就变成了服务网格&#xff0c;正如图3 这张经典大图所示。

 

图3 服务网格全局视角

所以 sidecar 模式其实是“自带通信员”模式。有趣的是&#xff0c;在我们把sidecar 和 Pod 绑定在一起的时候&#xff0c;sidecar 在出流量转发时扮演着反向代理的角色&#xff0c;而在入流量接收的时候&#xff0c;可以做一些超过反向代理职责的一些事情。

Istio 在 Kubernetes 基础上实现了服务网格&#xff0c;Isito 使用的 sidecar 容器就是上面我们提到的没有就绪的容器

所以这个问题其实就是&#xff0c;服务网格内部所有的sidecar 容器都没有就绪。

3.代理与代理的生命周期管理

在上一节中我们看到&#xff0c;Istio 中的每个 Pod&#xff0c;都自带了反向代理 sidecar。我们遇到的问题是&#xff0c;所有的 sidecar 都没有就绪。我们也看到 readiness probe 定义的&#xff0c;判断 sidecar 容器就绪的方式就是访问下面这个接口。

http://:15020/healthz/ready

接下来&#xff0c;我们深入理解一下 Pod&#xff0c;以及其 sidecar 的组成和原理。

在服务网格里&#xff0c;一个 Pod 内部除了本身处理业务的容器之外&#xff0c;还有 istio-proxy 这个sidecar 容器。正常情况下&#xff0c;istio-proxy 会启动两个进程&#xff0c;pilot-agent 和 Envoy。

下图中Envoy 是实际上负责流量管理等功能的代理&#xff0c;从业务容器出、入的数据流&#xff0c;都必须经过 Envoy &#xff1b;而 pilot-agent 负责维护 Envoy 的静态配置&#xff0c;并且管理 Envoy 的生命周期。这里的动态配置部分&#xff0c;我们在下一节中会展开来讲。

 

图4 代理与代理生命周期管理

我们可以使用下面的命令进入 Pod 的 istio-proxy 容器做进一步排查。

小技巧&#xff1a;我们可以以用户 1337 身份&#xff0c;使用特权模式进入 istio-proxy容器&#xff0c;如此就可以使用 iptables 等只能在特权模式下运行的命令。

docker exec -ti -u 1337 --privileged  bash

这里的用户 1337&#xff0c;其实是 sidecar 镜像里定义的一个同名用户 istio-proxy&#xff0c;默认 sidecar 容器使用这个用户。如果我们在以上命令中不使用用户选项 u&#xff0c;则特权模式实际上是赋予 root 用户的&#xff0c;所以我们在进入容器之后&#xff0c;需切换为 root用户执行特权命令。

进入容器之后&#xff0c;我们使用 netstat 命令查看监听&#xff0c;我们会发现&#xff0c;监听readiness probe 端口 15020 的&#xff0c;其实是 pilot-agent 进程。

istio-proxy&#64;details-v1-68868454f5-94hzd:/$ netstat -lnpt
Active Internet connections (only servers)
Proto  Recv-Q Send-Q  Local Address   Foreign Address  State    PID/Program name
tcp      0     0      0.0.0.0:15090   0.0.0.0:*        LISTEN   19/envoy
tcp      0     0      127.0.0.1:15000 0.0.0.0:*       LISTEN   19/envoy
tcp      0     0      0.0.0.0:9080    0.0.0.0:*        LISTEN   -
tcp6     0     0      :::15020        :::*             LISTEN   1/pilot-agent

我们在 istio-proxy 内部访问 readiness probe 接口&#xff0c;一样会得到“503”的错误。

4.就绪检查的实现

了解了 sidecar 的代理&#xff0c;以及管理代理生命周期的 pilot-agent 进程&#xff0c;我们可以稍微思考一下 pilot-agent 应该怎么去实现 healthz/ready 这个接口。显然&#xff0c;如果这个接口返回 OK 的话&#xff0c;那不仅意味着 pilot-agent 是就绪的&#xff0c;而且必须确保代理工作正常。

实际上 pilot-agent 就绪检查接口的实现正是如此。

 

图5 代理就绪检查机制的实现

这个接口在收到请求之后&#xff0c;会去调用代理 Envoy 的 server_info 接口。调用所使用的IP 地址是 localhost。这非常好理解&#xff0c;因为这是同一个 Pod 内部进程通信。使用的端口是 Envoy 的 proxyAdminPort&#xff0c;即 15000。

有了以上的知识准备之后&#xff0c;我们来看一下 istio-proxy 这个容器的日志。

实际上&#xff0c;在容器日志里&#xff0c;一直在重复输出一个报错。

这个报错分为两部分&#xff1a;

其中 Envoy proxy is NOT ready 部分是 pilot agent 在响应 healthz/ready 接口的时候输出的信息&#xff0c;即 Envoy 代理没有就绪 &#xff1b;

而剩下的 config not received from Pilot (is Pilot running?): cds updates: 0 successful, 0 rejected; lds updates: 0 successful, 0 rejected 这部分&#xff0c;是 pilot-agent 通过 proxyAdminPort 访问 server_info 的时候带回的信息&#xff0c;看来 Envoy 没有办法从 Pilot 获取配置。

Envoy proxy is NOT ready: config not received from Pilot (is Pilot running?): cds updates: 0 successful, 0 rejected; lds updates: 0 successful, 0 rejected.

到这里&#xff0c;建议大家回头看下上文的图 4&#xff0c;之前我们选择性忽略了从 Pilot 到 Envoy 这条虚线&#xff0c;即动态配置。这里的报错&#xff0c;实际上是 Envoy 从控制面 Pilot 获取动态配置失败。

5.控制面和数据面

到目前为止&#xff0c;这个问题其实已经很清楚了。在进一步分析问题之前&#xff0c;我们简单聊一下对控制面和数据面的理解。控制面和数据面模式&#xff0c;可以说无处不在&#xff0c;我们举两个极端的例子。

● 第一个例子&#xff0c;是 DHCP 服务器。

我们都知道&#xff0c;在局域网中的电脑&#xff0c;可以通过配置 DHCP 来获取 IP 地址&#xff0c;在这个例子中&#xff0c;DHCP 服务器统一管理&#xff0c;动态分配 IP 地址给网络中的电脑&#xff0c;这里的 DHCP 服务器就是控制面&#xff0c;而每个动态获取 IP 的电脑就是数据面。

● 第二个例子&#xff0c;是电影剧本和电影的演出。

剧本可以认为是控制面&#xff0c;而电影的演出&#xff0c;包括演员的每一句对白、电影场景布置等&#xff0c;都可以看作数据面。

之所以认为这是两个极端&#xff0c;是因为在第一个例子中&#xff0c;控制面仅仅影响了电脑的一个属性&#xff0c;而在第二个例子中&#xff0c;控制面几乎是数据面的一个完整的抽象和拷贝&#xff0c;影响数据面的方方面面。Istio 服务网格的控制面是比较接近第二个例子的情况&#xff0c;如下。

 

图6 控制面和数据面

Istio 的控制面 Pilot 使用 gRPC 协议对外暴露接口 istio-pilot.istiosystem:15010&#xff0c;而 Envoy 无法从 Pilot 处获取动态配置的原因是&#xff0c;在所有的 Pod 中&#xff0c;集群 DNS 都无法使用。

6.简单的原因

这个问题的原因其实比较简单&#xff0c;在 sidecar 容器 istio-proxy 里&#xff0c;Envoy 不能访问 Pilot 的原因是集群 DNS 无法解析 istio-pilot.istio-system 这个服务名字。在容器里看到 resolv.conf 配置的 DNS 服务器地址是 172.19.0.10&#xff0c;这个是集群默认的 kube-dns 服务地址。

istio-proxy&#64;details-v1-68868454f5-94hzd:/$ cat /etc/resolv.conf
nameserver 172.19.0.10
search default.svc.cluster.local svc.cluster.local cluster.local localdomain

但是客户删除、重建了 kube-dns 服务&#xff0c;且没有指定服务 IP 地址&#xff0c;这实际上导致集群 DNS 的地址改变了&#xff0c;这也是所有的 sidecar 都无法访问 Pilot 的原因。

# kubectl get svc -n kube-system
NAME   TYPE     CLUSTER-IP EXTERNAL-IP  PORT(S)    AGE
kube-dns ClusterIP 172.19.9.54       53/UDP,53/TCP  5d

最后&#xff0c;通过修改 kube-dns 服务&#xff0c;指定 IP 地址&#xff0c;sidecar 恢复正常。

# kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-68868454f5-94hzd 2/2 Running 0 6d
nginx-647d5bf6c5-gfvkm 2/2 Running 0 2d
nginx-647d5bf6c5-wvfpd 2/2 Running 0 2d
productpage-v1-5cb458d74f-28nlz 2/2 Running 0 6d
ratings-v1-76f4c9765f-gjjsc 2/2 Running 0 6d
reviews-v1-56f6855586-dplsf 2/2 Running 0 6d
reviews-v2-65c9df47f8-zdgbw 2/2 Running 0 6d
reviews-v3-6cf47594fd-cvrtf 2/2 Running 0 6d

7.阿里云服务网格&#xff08;ASM&#xff09;介绍

从以上案例可以看出&#xff0c;Istio 在提供了强大的服务治理等功能的同时&#xff0c;对工程师的运维开发带来了一定程度的挑战。

阿里云服务网格&#xff08;Alibaba Cloud Service Mesh&#xff0c;简称 ASM&#xff09;提供了一个全托管式的服务网格平台&#xff0c;极大地减轻了开发与运维人员的工作负担。

如图 7 所示&#xff0c;在阿里云 ASM 中&#xff0c;Istio 控制平面的组件全部托管&#xff0c;降低您使用的复杂度&#xff0c;您只需要专注于业务应用的开发部署。同时&#xff0c;保持与 Istio社区的兼容&#xff0c;支持声明式的方式定义灵活的路由规则&#xff0c;支持网格内服务之间的统一流量管理。

 

图7 阿里云服务网格

从能力上来看&#xff0c;一个托管了控制平面的 ASM 实例可以支持来自多个Kubernetes 集群的应用服务或者运行于 ECI Pod 上的应用服务。也可以把一些非 Kubernetes 服务&#xff08;例如运行于虚拟机或物理裸机中的服务&#xff09;集成到同一个服务网格中。

8.总结

这个案例的结论是比较简单的。基于对 Istio 的深入理解&#xff0c;问题排查的耗时也并不是很久&#xff0c;但整理这章内容&#xff0c;却有一种看《长安十二时辰》的感觉 &#xff1a;排查过程虽短&#xff0c;写完背后的原理和前因后果却花了好几个小时。

总之&#xff0c;希望本文的案例分析对大家理解服务网格技术有所帮助&#xff0c;同时希望阿里云服务网格可以帮助大家使服务网格类产品快速落地。

&#xff08;完&#xff09;

图书推荐

 

▊《阿里云数字新基建系列&#xff1a;云原生操作系统Kubernetes》

罗建龙 刘中巍 张城 黄珂 苏夏 高相林 盛训杰 著


  • 来自阿里云核心技术团队的实践沉淀
  • 7位云原生技术专家聚力撰写K8S核心原理与诊断案例

本书是阿里云容器服务产品线上实践的技术沉淀&#xff0c;主要包括理论篇和实践篇两部分内容。理论篇注重理论介绍&#xff0c;核心是Kubernetes on Cloud&#xff0c;即着重介绍Kubernetes和阿里云产品的结合。实践篇是疑难问题的诊断案例&#xff0c;希望通过案例来和读者分享Kubernetes深度问题诊断经验。

 


推荐阅读
  • k8s之Service介绍
    1、Service是什么?​Service是一种k8s集群中访问pod的一种策略。k8s中的pod具有生命周期,且不可复活。每个pod有着自己的IP地址,pod的销毁与创建都会创新 ... [详细]
  • 基于Dubbo与Zipkin的微服务调用链路监控解决方案
    本文提出了一种基于Dubbo与Zipkin的微服务调用链路监控解决方案。通过抽象配置层,支持HTTP和Kafka两种数据上报方式,实现了灵活且高效的调用链路追踪。该方案不仅提升了系统的可维护性和扩展性,还为故障排查提供了强大的支持。 ... [详细]
  • 在 Kubernetes 中,Pod 的调度通常由集群的自动调度策略决定,这些策略主要关注资源充足性和负载均衡。然而,在某些场景下,用户可能需要更精细地控制 Pod 的调度行为,例如将特定的服务(如 GitLab)部署到特定节点上,以提高性能或满足特定需求。本文深入解析了 Kubernetes 的亲和性调度机制,并探讨了多种优化策略,帮助用户实现更高效、更灵活的资源管理。 ... [详细]
  • Ceph API微服务实现RBD块设备的高效创建与安全删除
    本文旨在实现Ceph块存储中RBD块设备的高效创建与安全删除功能。开发环境为CentOS 7,使用 IntelliJ IDEA 进行开发。首先介绍了 librbd 的基本概念及其在 Ceph 中的作用,随后详细描述了项目 Gradle 配置的优化过程,确保了开发环境的稳定性和兼容性。通过这一系列步骤,我们成功实现了 RBD 块设备的快速创建与安全删除,提升了系统的整体性能和可靠性。 ... [详细]
  • 前言: 网上搭建k8s的文章很多,但很多都无法按其说明在阿里云ecs服务器成功搭建,所以我就花了些时间基于自己成功搭建k8s的步骤写了个操作手册,希望对想搭建k8s环境的盆友有所帮 ... [详细]
  • Kubernetes(k8s)基础简介
    Kubernetes(k8s)基础简介目录一、Kubernetes概述(一)、Kubernetes是什么(二& ... [详细]
  • docker+k8s+git+jenkins
    docker+k8s+git+jenkins,Go语言社区,Golang程序员人脉社 ... [详细]
  • Istio是一个用来连接、管理和保护微服务的开放平台。Istio提供一种简单的方式来为已部署的服务建 ... [详细]
  • javascript分页类支持页码格式
    前端时间因为项目需要,要对一个产品下所有的附属图片进行分页显示,没考虑ajax一张张请求,所以干脆一次性全部把图片out,然 ... [详细]
  • 在JavaWeb项目架构中,NFS(网络文件系统)的实现与优化是关键环节。NFS允许不同主机系统通过局域网共享文件和目录,提高资源利用率和数据访问效率。本文详细探讨了NFS在JavaWeb项目中的应用,包括配置、性能优化及常见问题的解决方案,旨在为开发者提供实用的技术参考。 ... [详细]
  • 解读中台架构:微服务与分布式技术的区别及应用
    中心化与去中心化是长期讨论的话题。中心化架构的优势在于部署和维护相对简单,尤其在服务负载较为稳定的情况下,能够提供高效稳定的性能。然而,随着业务规模的扩大和技术需求的多样化,中心化架构的局限性逐渐显现,如扩展性和故障恢复能力较差。相比之下,微服务和分布式技术通过解耦系统组件,提高了系统的灵活性和可扩展性,更适合处理复杂多变的业务场景。本文将深入探讨中台架构中微服务与分布式技术的区别及其应用场景,帮助读者更好地理解和选择适合自身业务的技术方案。 ... [详细]
  • 本文详细解析了神州数码DCRS5980交换机的基础配置流程和技术要点。首先,通过进入配置模式(`enable`),设置主机名(`hostname 5980`),并创建VLAN,逐步介绍了设备的初始设置步骤。此外,还涵盖了端口配置、IP地址分配及安全设置等关键环节,为用户提供了全面的配置指导。 ... [详细]
  • 2019年后蚂蚁集团与拼多多面试经验详述与深度剖析
    2019年后蚂蚁集团与拼多多面试经验详述与深度剖析 ... [详细]
  • 黄聪:MySQL主从复制配置,实现高效读写分离
    大型网站为应对高并发访问,不仅需要在前端实现分布式负载均衡,还需在数据业务和访问层采取有效措施。采用传统的数据结构已无法满足需求,通过配置MySQL主从复制,可实现高效的读写分离,显著提升系统性能和稳定性。 ... [详细]
  • k8shelm官网:https:helm.sh点击charts:https:artifacthub.iopackagessearch?sortrelevance&page11.1h ... [详细]
author-avatar
hustjs
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有