速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

深入浅出 Kubernetes 实践篇 (五):二分之一活的微服务

  • 2020-03-30
  • 本文字数:4961 字

    阅读完需:约 16 分钟

深入浅出Kubernetes 实践篇 (五):二分之一活的微服务

简介:Istio is the future!基本上,我相信对云原生技术趋势有些微判断的同学,都会有这个觉悟。其背后的逻辑其实是比较简单的:当容器集群,特别是 Kubernetes 成为事实上的标准之后,应用必然会不断的复杂化,服务治理肯定会成为强需求。


Istio is the future!基本上,我相信对云原生技术趋势有些微判断的同学,都会有这个觉悟。其背后的逻辑其实是比较简单的:当容器集群,特别是 Kubernetes 成为事实上的标准之后,应用必然会不断的复杂化,服务治理肯定会成为强需求。


Istio 的现状是,聊的人很多,用的人其实很少。所以导致我们能看到的文章,讲道理的很多,讲实际踩坑经验的极少。


阿里云售后团队作为一线踩坑团队,分享问题排查经验,我们责无旁贷。这篇文章,我就跟大家聊一个简单 Istio 问题的排查过程,权当抛砖。

二分之一活的微服务

问题是这样的,用户在自己的测试集群里安装了 Istio,并依照官方文档部署 bookinfo 应用来上手 Istio。部署之后,用户执行 kubectl get pods 命令,发现所有的 pods 都只有二分之一个容器是 READY 的。


# kubectl get podsNAME READY STATUS RESTARTS AGEdetails-v1-68868454f5-94hzd 1/2 Running 0 1mproductpage-v1-5cb458d74f-28nlz 1/2 Running 0 1mratings-v1-76f4c9765f-gjjsc 1/2 Running 0 1mreviews-v1-56f6855586-dplsf 1/2 Running 0 1mreviews-v2-65c9df47f8-zdgbw 1/2 Running 0 1mreviews-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 网络命名空间)访问容器定义的接口,或者在容器的 namespace 里执行 exec 定义的命令,来确定容器是否就绪。



这里的 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: 30  httpGet:    path: /healthz/ready    port: 15020    scheme: HTTP  initialDelaySeconds: 1  periodSeconds: 2  successThreshold: 1  timeoutSeconds: 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
复制代码

绕不过去的大图

上一节我们描述了问题现象,但是留下一个问题,就是 pod 里的容器个数为什么是 2。虽然每个 pod 本质上至少有两个容器,一个是占位符容器 pause,另一个是真正的工作容器,但是我们在使用 kubectl 命令获取 pod 列表的时候,READY 列是不包括 pause 容器的。


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



然而,当我们为集群中的每一个 pod,都“随身”携带一个反向代理的时候,pod 和反向代理就变成了服务网格。正如下边这张经典大图所示。这张图实在有点难画,所以只能借用,绕不过去。



所以 sidecar 模式,其实是“自带通信员”模式。这里比较有趣的是,在我们把 sidecar 和 pod 绑定在一块的时候,sidecar 在出流量转发时扮演着反向代理的角色,而在入流量接收的时候,可以做超过反向代理职责的一些事情。这点我们会在其他文章里讨论。


Istio 在 Kubernetes 基础上实现了服务网格,Isito 使用的 sidecar 容器就是第一节提到的,没有就绪的容器。所以这个问题,其实就是服务网格内部,所有的 sidecar 容器都没有就绪。

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

上一节我们看到,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 的生命周期。这里的动态配置部分,我们在下一节会展开来讲。



我们可以使用下边的命令进入 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 -lnptActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program nametcp        0      0 0.0.0.0:15090           0.0.0.0:*               LISTEN      19/envoytcp        0      0 127.0.0.1:15000         0.0.0.0:*               LISTEN      19/envoytcp        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 的错误。

就绪检查的实现

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


实际上 pilot-agent 就绪检查接口的实现正是如此。这个接口在收到请求之后,会去调用代理 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.
复制代码


到这里,建议大家回退看下上一节的插图,在上一节我们选择性的忽略是 Pilot 到 envoy 这条虚线,即动态配置。这里的报错,实际上是 envoy 从控制面 Pilot 获取动态配置失败。

控制面和数据面

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


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


第二个例子,是电影剧本,和电影的演出。剧本可以认为是控制面,而电影的演出,包括演员的每一句对白,电影场景布置等,都可以看做是数据面。


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



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

简单的原因

这个问题的原因其实比较简单,在 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.confnameserver 172.19.0.10search default.svc.cluster.local svc.cluster.local cluster.local localdomain
复制代码


但是客户删除重建了 kube-dns 服务,且没有指定服务 IP,这导致,实际上集群 dns 的地址改变了,这也是为什么所有的 sidecar 都无法访问 Pilot。


# kubectl get svc -n kube-systemNAME                      TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                      AGEkube-dns                  ClusterIP      172.19.9.54     <none>          53/UDP,53/TCP                5d
复制代码


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


# kubectl get podsNAME READY STATUS RESTARTS AGEdetails-v1-68868454f5-94hzd 2/2 Running 0 6dnginx-647d5bf6c5-gfvkm 2/2 Running 0 2dnginx-647d5bf6c5-wvfpd 2/2 Running 0 2dproductpage-v1-5cb458d74f-28nlz 2/2 Running 0 6dratings-v1-76f4c9765f-gjjsc 2/2 Running 0 6dreviews-v1-56f6855586-dplsf 2/2 Running 0 6dreviews-v2-65c9df47f8-zdgbw 2/2 Running 0 6dreviews-v3-6cf47594fd-cvrtf 2/2 Running 0 6d
复制代码

结论

这其实是一个比较简单的问题,排查过程其实也就几分钟。但是写这篇文章,有点感觉是在看长安十二时辰,短短几分钟的排查过程,写完整背后的原理,前因后果,却花了几个小时。这是 Istio 文章的第一篇,希望在大家排查问题的时候,有所帮助。


作者简介


罗建龙(花名声东),阿里云技术专家。多年操作系统和图形显卡驱动调试和开发经验。目前专注云原生领域,容器集群和服务网格。


相关阅读


深入浅出Kubernetes 实践篇 (一):节点就绪问题之一


深入浅出Kubernetes 实践篇 (二):节点就绪问题之二


深入浅出Kubernetes 实践篇 (三):命名空间删除问题


深入浅出Kubernetes 实践篇 (四):集群安全组配置管理


2020-03-30 17:141320

评论

发布
暂无评论
发现更多内容

青海正规等保测评服务公司是4家吗?分别在哪里?

行云管家

等保 青岛 等级保护 等保测评

SaaS 出海:Databend Cloud 的定位与实践

Databend

以“好运”潮饰 “牵”情绪共鸣 老庙一串好运系列与消费者展开情绪对话

科技大数据

接口测试:Mock 技术体系

测试人

软件测试

手把手教你用Charles抓包

AntDream

网络 charles Android; 网络抓包 抓包工具

零成本搭建个人图床服务器

北桥苏

GitHub Pages 免费图床 图床搭建

pd17虚拟机安装包:Parallels Desktop 17 激活版

你的猪会飞吗

mac软件下载 Mac虚拟机下载 PD17虚拟机

时延降低 50%,小红书图数据库如何实现多跳查询性能大幅提升

小红书技术REDtech

分布式 查询 图数据库 图数据库实战 并行查询

如何在前端项目中制定代码注释规范

伤感汤姆布利柏

VMware ESXi 8.0U3 发布下载 - 领先的裸机 Hypervisor

sysin

vSphere esxi

一文带你了解Mock 技术体系

霍格沃兹测试开发学社

VMware ESXi 8.0U3 macOS Unlocker & OEM BIOS 标准版和厂商定制版

sysin

macos esxi OEM unlocker dell

云端部署mes/万界星空科技云mes系统

万界星空科技

mes 云mes 万界星空科技

IPQ4028 vs. IPQ4019: Performance, Application, and Technical Analysis

wifi6-yiyi

wifi5 WiFi5G

性能测试公开课来啦!从性能测试方案到性能调优,从负载均衡到中间件测试,全方位讲解性能测试核心内容

测吧(北京)科技有限公司

测试

小窗口大魔力,实况窗服务实时掌控重要信息变化

HarmonyOS SDK

HarmonyOS

引领产业创新,河套国际性产业与标准组织聚集区亮相2024MWC上海

最新动态

白熊AI推出两款大模型应用产品:一站式智能体开发,十万节点0.9秒响应;0门槛、低代码,全流程自动化大模型训练平台

白熊AI

白熊AI 大模型训练平台 RAG知识库 Agent智能体 Workflow工作流

VMware vCenter Server 8.0U3 发布下载 - 集中式管理 vSphere 环境

sysin

vSphere vcenter esxi

VMware vSphere 8.0 Update 3 发布下载 - 企业级工作负载平台

sysin

vSphere vcenter esxi

科普:什么是 BC-404 ?全方位解读最新通缩型 NFT 标准

NFT Research

NFT ERC404

亚马逊秘密研发 AI 对标 ChatGPT;语音 AI 未来五年或将释放 100 亿美元市场 丨 RTE 开发者日报

声网

VMware ESXi 8.0U3 macOS Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版)

sysin

macos esxi 驱动 OEM BIOS

GitLab 使用 Docker Compose 部署

极狐GitLab

制造业采购堡垒机的四大必要性看这里!

行云管家

网络安全 数据安全 堡垒机 制造

深入浅出Kubernetes 实践篇 (五):二分之一活的微服务_文化 & 方法_罗建龙(声东)_InfoQ精选文章