istio 配置生效流程及源码简介

461 阅读7分钟
原文链接: zhuanlan.zhihu.com

前言

我们在使用 istio 的时候,因为我们需要配置一些规则来使 istio 知道配置的改变并使配置生效,而我们在这个过程中最长使用到的工具就是 istioctl ,我们使用它来配置我们的相关业务规则;我在试用 istio 的时候也使用 istioctl 来进行规则的配置,但是有时候莫名其妙有些配置就没有生效,但是我都不知该如何入手去查找原因,而且 istio 的文档并没有太多的介绍这方面的原理(2018-04-21),所以我决定能够根据阅读 (istio.io) 的源码来理解他,对于你将会应用的开源软件来说,你越多的了解他肯定是约好的,因为出了问题你只能靠自己去解决(虽然你也可以请教别人)。

内容

下面将要介绍从我们使用 istioctl 执行一条命令之后,istio 导致做了些什么使我们的配置在我们的集群中生效;这部分理解知识自己个人的理解,且可能会涉及到其他相关的知识点,如果我有什么没理解对和有错误的地方,还希望大家能帮我一起完善;

istioctl

当我们想要在 istio 中创建并生效一个配置规则的时候,我们往往会使用 istioctl create -f xxx.yaml;但是我们现在不知道这条命令发生了到底发生了什么导致我们我们的配置就生效了?不过我们打印日志的方式来指导它导致做了什么,比如我们可以使用 istioctl create --log_output_level debug -f xxx.yaml--log_output_level debug 参数告诉 istioctl 在运行是打印 debug 即 debug 级别以上的日志(这将几乎打印所有的日志);当我们运行这条命令的时候,我们将会看到日志中包含类似

2018-04-19T09:56:06.702691Z info    curl -k -v -XPOST  -H "Accept: application/json, */*" -H "Content-Type: application/json" https://10.80.81.58:6443/apis/config.istio.io/v1alpha2/namespaces/default/egressrules/name-server-internet
2018-04-19T09:56:06.706318Z info    POST https://10.80.81.58:6443/apis/config.istio.io/v1alpha2/namespaces/default/egressrules/name-server-internet 200 OK in 3 milliseconds

注: 10.80.81.58:6443 是我的 k8s api server 的地址,istioctl 将会去读取本地的 k8s 配置信息获取 spi server 的地址和 授权信息;代码在 istio.io/istio/istioctl/cmd/istioctl/main.go#newClient

这样的日志,我们根据可以看出我们在使用 istioctl 执行 create 相关的命令时,它向我们的 api server 进行了请求并上传了数据;
看到这里我是疑惑的,因为最开始我以为它应该是想 istio-system 中某个服务发送了一条请求,并由该服务去处理使配置生效,但是这里她却向 api server 发送了请求,请求的 apiGroupVersion 还不是 k8s 自带的;其实这应该是 istio 的相关服务在启动调用了 k8s 的 CRD api 生成了 config.istio.io 相关的资源接口(目前我还没有找到具体的入口,实在有些难找,目前这一块的代码变化比较快;而且这一块的注册的逻辑并不影响我们理解配置生效的流程)

pilot-discovery

上面我们讲了 istioctl 执行命令将会把我们的配置文件更新到 k8s 的资源对象中,我们知道 k8s 中的资源对象是支持 REST 的,同时他还提供了一个 watch 接口,说到这里大家应该能够想到 istio 是怎么样来进行配置的生效了吧;
我们都知道 pilot 是专门用来对我们的数据平面进行控制的,但是是怎么控制的可能最开始还是回去看看源码才能知道(因为我最开始不怎么了解envoy,只知道他是用来转发的);
因为这个原因,我在查看实际的配置生效的代码的时候也走了好多的弯路,我感觉这个也可以说出来跟大家分享一下也挺有意思的:

  • 最开始,因为 envoy 提供了 go-control-plane 这个项目,我以为 istio 是根据监控 k8s resource 的变化然后去调用 envoy 的 api 然后对配置进行更新然后在 envoy 生效;但是我找了半天始终在 pilot 中没有找到相关的代码,我基本感到有些绝望,有点不知道该怎么下手了;
  • 后来,我在 /pilot/proxy/envoy/agent.go 找到了配置文件生成的相关代码,因为之前看文档知道 envoy 是支持监听某个文件夹文件的变化而热重启的;我想,这个方案还是不错,这样子就可以直接在 pilot-agent 中 watch resource 的变化,然后直接转话成配置文件然后再写入 envoy 的配置文件夹;这样子就免去了 istio 还要在中间做一次的转发了,觉得还是挺不错的一个实现,不过感觉这样子会不会让 k8s 跟 envoy 耦合的有些紧,因为 istio 毕竟是要做兼容两端的平台(服务治理端和数据平面端),这样子做会不会让这两端耦合的太紧,最后不好抽离实现啊。事实证明我就是在哪里自己意淫[捂脸],因为我后面看了半天也没有看到会调用 k8s 相关 api 的地方;我觉得我又找错方向了,这段代码所在的应用是 pilot-agent (/pilot/cmd/pilot-agent/main.go)的,他的作用是在 sidecar 启动的时候生成 envoy 的相关 static 配置文件并启动 envoy;
  • 我感到有点绝望,这几乎消耗了我一个周末的时间,同时也在抱怨 istio 现在的文档真的是不太好,我甚至去翻了他们维护在 google drive 的设计文档也没有里看到相关的文档,这对于我这种初学者真的是有点不太友好;虽然是要抱怨,但是活还是要继续干;我终于在 /pilot/pkg/serviceregistry 目录下找到了会调用 k8s watch 相关 api 的代码逻辑,逻辑还是有点复杂(大致就是有一个 ConfigStoreCache 接口, 定义在 pilot/pkg/model/config.go#ConfigStoreCache 中,然后有很多 controller 实现了该接口,并定义了一些自己的 handle 来处理 watch 数据的变更然后清除缓存并进行一些处理;),我树藤摸瓜一直找到了 pilot/pkg/proxy/v1/discovery.go#Register,它在这里注册的 http 的相关路由和处理方法相关信息,因为我找到的是 /v1/listeners/{%s}/{%s}" 的相关方法,然后看注释才看到这是 LDS 服务实现方法,然后再去找文档看看 LDS 到底是个啥,然后才恍然大悟,原来配置是这样子传递到 envoy 的;

就这样我大致理解了 istio 的配置从我们的编写配置文件并运行命令到配置文件到 envoy 的流程;

总结

虽然过程的不咋顺利的,但是我感觉我整个配置生效的大致逻辑逻辑理的差不多了,而且误打误撞的了解了 pilot-agent 相关的一些逻辑,感觉收获还是挺多的;因为我之前基本对 pilot 基本一无所知,经过这次之后我感觉我能够如果我的配置出错或者是没有生效,我能够知道可能是什么地方出了问题并去查看相关的日志,而不用只能等 issue 有人来帮忙解决;自己动手才能丰衣足食,当我们对源码有了足够的掌握我们才能够真正的掌控住这项技术,才能更好和更放心的使用它。不过在源代码里面找过去照过来还是有点费劲。不过我感觉是值得的,等着我的下一篇文章吧😁

哦,最后的最后发个小招聘信息,我司(成都23魔方)招 平台研发java 后端开发;有兴趣的可以直接投简历或者联系我(我可以内推哦😊);期待大家的简历哦;