- 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: */*
>
< HTTP/1.1 503 Service Unavailable
< Date: Fri, 30 Aug 2019 16:43:50 GMT
< Content-Length: 0
<
* Connection #0 to host 172.16.3.43 left intact

2.认识服务网格

刚刚我们描述了问题的现象,但是留下一个问题,就是 Pod 里的容器个数为什么是 2?

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

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

图2 服务网格局部视角

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

图3 服务网格全局视角

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

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

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

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

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

http://<pod ip>:15020/healthz/ready

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

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

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

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

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

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

docker exec -ti -u 1337 --privileged <istio-proxy container id> bash

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

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

istio-proxy@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 接口,一样会得到“503”的错误。

4.就绪检查的实现

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

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

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

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

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

实际上,在容器日志里,一直在重复输出一个报错。

这个报错分为两部分:

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

而剩下的 config not received from Pilot (is Pilot running?): cds updates: 0 successful, 0 rejected; lds updates: 0 successful, 0 rejected 这部分,是 pilot-agent 通过 proxyAdminPort 访问 server_info 的时候带回的信息,看来 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.

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

5.控制面和数据面

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

● 第一个例子,是 DHCP 服务器。

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

● 第二个例子,是电影剧本和电影的演出。

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

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

图6 控制面和数据面

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

6.简单的原因

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

istio-proxy@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 服务,且没有指定服务 IP 地址,这实际上导致集群 DNS 的地址改变了,这也是所有的 sidecar 都无法访问 Pilot 的原因。

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

最后,通过修改 kube-dns 服务,指定 IP 地址,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.阿里云服务网格(ASM)介绍

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

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

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

图7 阿里云服务网格

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

8.总结

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

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

(完)

图书推荐

▊《阿里云数字新基建系列:云原生操作系统Kubernetes》

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

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

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

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

  1. 2020年云栖大会阿里云线上直播地址

    最新消息,阿里云在官微上宣布"2020云栖大会"即将于9月17日-18日开幕,大会由阿里巴巴集团主办,是面向政府.产业.开发者的世界级.现象级科技大会. 云栖大会的前身可追溯到20 ...

  2. 阿里云线上部署自己的写的小项目

    unbuntu20.0.4线上部署自己写的项目(laravel+vue) 这周把自己写的菜鸡项目,仿小米商城部署到线上 系统unbuntu20.0.4大致流程及bug记录 一.搭建环境 1.安装Apa ...

  3. 基于Spring boot + Mybatis +Netty 实现前后端分离的聊天App,部署到阿里云线上服务器...

    前后端分离Spring boot 项目部署 了解前后端分离项目 配置云服务器 java maven tomcat nginx mysql 部署后端项目 部署前端项目 部署Java环境 1.下载JDK软 ...

  4. 阿里云线上环境操作Redis

    官网对Redis常见的数据结构定义为:   Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings ...

  5. 从Arduino IDE安装到成功控制LED灯光的开发过程|阿里云远程控制灯光案例|Arduino编译缺少python27.dll问题|玉念聿辉

    目录 初识Arduino 安装Arduino IDE ESP32 Blink(控制主板led) 安装 FireBeetle Board-ESP32 开发板核心 连接 FireBeetle Board- ...

  6. 部署在阿里云服务器上的系统也要做等保测评吗?

    系统部署在阿里云上,也必须做等保.但是对比线下推广做等保,部署在阿里云上的系统过等保要更容易也更便捷.今日本文就给各位共享一下部署在阿里云上的系统如何做等保. 部署在阿里云服务器上的系统也要做等保测评 ...

  7. 阿里云2020上云采购季,你适合买什么云产品?

    线下IDC机房成本高? 自建数据库卡.慢,延迟高? 被黑客攻击了怎么办? 今年IT预算没多少? 不知道怎么过等保2.0? 你遇到了哪些问题?来阿里云2020上云采购季!主会场请戳:https://ww ...

  8. 阿里云服务器上安装rabbitmq流程

    阿里云服务器上安装rabbitmq流程 1.一定要注意版本问题 rabbitmq+erlang+centos的版本得都得考虑 Erlang24和centos7不能一起用,el7对应centos7,el ...

  9. 10038错误,无法连接上阿里云服务器上的MySQL

    这个错误,网上说的很多,基本上说的都是服务器端口没有开放的原因,我也到阿里云服务器上设置过,发现并不是这个的原因,附上解决方法: 配置安全组规则即可 错误是:2003 can't connect to ...

  10. 阿里云centos上处理2t3ik与ddgs病毒

    阿里云centos上处理2t3ik与ddgs病毒 有段时间没有登陆阿里云了,前两天收到阿里云的短信,意思是:检测到我的linux服务器出现异常文件下载,请登陆控制台查看,我登陆控制台看到如下图显示 系 ...

最新文章

  1. B树、B+树、AVL树、红黑树
  2. 读写xml节点的数据总结
  3. R语言观察日志(part5)--利用readr和readxl包读写数据
  4. linux dd入门,Linux基础知识:Linux中DD命令详解
  5. js判断一个元素是否在数组中
  6. Python 处理gbk编码文件
  7. 通过TP-Link路由器WAN口嗅探PPPoE拨号密码-路由器拨号密码破解方法
  8. android qq输入法表情,QQ输入法如何输入表情
  9. C语言笔试经典编程题目(汇总帖)
  10. Linux c/c++开发常用头文件
  11. 2:0战胜Dota2世界冠军OG,OpenAI发起全网挑战,不服来战!
  12. cruzer php sandisk 闪迪u盘量产工具_SanDisk Cruzer CZ36闪迪U盘 怎么量产
  13. Hadoop HA架构
  14. 果然十三香!史上最强iPhone13来了:全面降价、刘海缩小,支持120HZ高刷!网友:真香!苹果:业内苦苦追赶我们的芯片性能...
  15. Genymotion安卓模拟器常见问题汇总
  16. Python数据分析入门笔记10——简单案例练习(学生信息分析)
  17. 国产接口芯片兼容替换TI MM1192,用于通信设备协议
  18. good man or bad man?
  19. 有限元三角形单元的等效节点力
  20. 西南计算机维修技术0240,0240 2016《计算机维修技术》西南大学网上作业题及答案...

热门文章

  1. C++VS2019中新建自定义模板与删除自定义模板
  2. javascript 忍者秘籍读书笔记(二)
  3. 第11章 连接查询和分组查询
  4. 利用百度OCR实现验证码自动识别
  5. Openresty 与 Tengine
  6. 【图灵学院01】Java程序员开发效率工具IntelliJ IDEA使用
  7. Windows RPC Demo实现
  8. JQUERY 使用键盘左右键切换选项卡
  9. (VBA) Get String
  10. Codeforces 1009G Allowed Letters 最大流转最小割 sosdp