GO 学了一个月,代码不会写,先看个源码解析(文末说点事儿)
本地启动
在第三篇自定义中间件的前提下,已经说了很多关于本地通过 CRD 或者 File 作为 provider 的启动方式,这里想要补充一下关于本地 DEBUG 3.0.0 版本代码的问题,后续的源码分析也都会基于目前最新的 3.0 版本。
在写文章的时候,目前 3.0 版本还是 beta 版本。
按照上述文章的方式安装之后其实会发现本地启动会报一个关于*v1alpha1.ServersTransportTCP
相关的错误,这是因为之前我们安装的 CRD 资源定义和 RBAC 都是 2.10 版本的,需要重新安装一下 3.0.0 版本的资源定义。
# Install Traefik Resource Definitions:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.0/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
# Install RBAC for Traefik:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.0/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.yml
启动流程
Traefik 启动的源码在cmd/traefik/traefik.go
中,进入到 main 方法。
我们在本地 DEBUG 就是启动这个 main 方法,首先进行配置的初始化,然后定义了 3 个资源加载的方式,和官方描述的一样,可以从配置文件、命令行参数和环境变量读取配置。
之后就是添加启动命令,包括健康检测、版本检查,最后回去调用cli.Execute
方法,这个方法跟进去看也挺简单的,最终其实都会调用到Command
的Run
方法,也就是会执行runCmd
方法。
进入 Execute 方法,我们启动是没有其他参数的,只是启动命令,所以进入第一个判断,参数长度为1。
然后最终跟我们上面说的一样,调用到了cmd.Run
。
然后直接进入runCmd
方法中看服务如何启动的。
这里干了几件事情,首先是初始化日志的配置、静态配置,然后解析静态配置为 json,然后就是很关键的两个步骤,一个是setupServer
初始化 server,之后是 server 的启动。
这里可以看一下静态配置到底都有些什么东西,因为我们没有配置 AcessLog、Metric 这些东西,所以都是空的,其实关键就两个东西,一个是 EntryPoints,另外一个是 Provider。
这里我们本地启动通过 CRD 的方式,入口点只是默认的配置。
Server初始化
然后我们直接看 setupServer
都干了些什么,这个方法非常长,我们忽略调一些无关的细节,只看重点的部分。
首先创建 provider 的聚合器,其实就是服务发现的提供者,我们知道有很多,像是文件、Docker、K8S、ECS、Consul 等等很多,在之前我们就提到过这个,这里我们主要是 CRD。
ACME 是 HTTPS 证书相关的东西,可以忽略他。
然后是关于server.NewTCPEntryPoints
,用于构建入口点的逻辑,这个很关键。
接着是创建 Provider 的插件,这个X509Source
又是关于证书的一些逻辑,主要是使用 SPIFFE (Secure Production Identity Framework For Everyone) 获取证书,以便与其他服务进行安全通信,这个不是重点,忽略。
接着往下走是几个比较关键的 Factory,一个是managerFactory
,另外一个则是routerFactory
,这两个工厂会构建出后续请求的流程链路,放到后面再说。
这里的 watcher 也是一个关键点,添加了关于 TLS、Metrics、Server Transports 和 Switch Router 的动态配置的监听。
这里的switchRouter
是一个很重要的方法,待会儿再细看。
最终流程走完到最终执行NewServer
方法创建 Server,配置初始化 Server 的流程结束。
配置监听
这个流程看完之后,回到最开始的地方,开始启动 Server。
这里主要关注两个方法,一个是 TCP 入口点的启动,另外一个则是监听 watcher 的启动,首先看tcpEntryPoints.Start
。
这里可以看到入口点默认是两个,一个是 traefik 自己默认的,另外一个是处理 web 请求的入口点,之后开启协程进入 serverEntryPoint.Start(ctx)
。
这里主要是监听连接,当有新连接到达时,创建一个新的 writeCloser
对象,并在其上设置读/写超时。接下来,使用 e.switcher.ServeTCP
处理新连接,如果出现错误,则会记录错误日志并将错误转发到 e.httpServer
和 e.httpsServer
的 channel。
之后就进入 watcher 监听的启动方法,主要实现了 3 个方法。
1. receiveConfigurations 是用于接收配置的变化,并且发送到消费者
2. applyConfigurations 是合并配置、应用配置
3. 启动 Provider 的聚合器,做服务发现
receiveConfigurations
主要是死循环监听配置的变更,新的配置会发送到 output 的 channel。
applyConfigurations
则是收到新的配置之后,合并然后应用配置,具体合并的细节就不看了,忽略他。
provider 的聚合器是根据不同的 provider 提供了不同的实现,这里我们是使用 K8S CRD 的方式,所以待会儿进去看这个实现即可。
首先创建一个 K8S client 客户端,用于和 K8S 集群进行通信,然后使用该客户端创建一个事件通道。
接下来,使用WatchAll
监听所有配置的 namespace 的变化。
这里 debug 能看到现在我们只配置了一个默认的 namespace。
在第一次启动的时候,默认调用loadConfigurationFromCRD
方法从 CRD 加载配置,之后如果配置发生变化,走到 default 分支,变更的配置会发送到 configurationChan
。
这个 channel 的定义其实就是在方法入口的ConfigurationWatcher
。
查看 ConfigurationWatcher 结构体的定义,找到allProvidersConfigs
,定义的就是我们发送到的 channel 了。
看到这里,会有疑问,那么发送的配置在什么地方进行消费了呢?
答案就是上面我们已经讲过的receiveConfigurations
,而receiveConfigurations
消费到配置变更之后,又会发送消息到newConfigs
,然后applyConfigurations
方法进行消费,然后处理配置、进行合并、应用。
服务发现
然后让我们回到 loadConfigurationFromCRD
这个方法中,找到loadIngressRouteConfiguration
方法,这里就是启动的时候去做服务发现的地方。
进入这个方法就能看到通过 K8S 的客户端去获取配置的 IngressRoute。
进入这个方法,发现也是确实如此。
这里 DEBUG 可以看到我们日志的 IngressRoute 的信息。
往下看还有一个比较有意思的地方,如果说路由中配置的 service 数量超过 1,那么会默认会变成权重负载均衡。
接着往下看buildServicesLB
的方法,其实和 service==1 的情况一样,只是循环去调用了nameAndService
方法而已。
进入这个方法这里有两个判断,针对类型是 Service 和 TraefikService的,Service 类型是 K8S 的类型,所以会去直接获取 server 的信息,而如果配置的是 TraefikService,实际上只是根据 TraefikService 获取 Service 名字,最终还是会走到 Service 的判断逻辑上。
创建负载均衡代码的关键在于第一行loadServers
。
进入这个方法可以看到其实就是通过 K8S 的客户端去调用 API 接口,获取到了 service 的信息,还有端口、后端服务的地址。
进入这个方法可以看到其实就是通过 K8S 的客户端去调用 API 接口,获取到了 service 的信息,还有端口、后端服务的地址。
那么,到这里基本服务发现的逻辑就结束了。
在这里顺便说点事情,最近可能大家觉得公共号没啥更新了,其实情况并不是这样。
首先一点确实是公众号目前情况不佳,阅读下滑,这个也就那样吧。
另外一点是最近几个月的重心有工作、生活两方面吧。
工作研究性质的东西会比较多一点,比如最近在学 GO,研究 Traefik,所以就写了 Traefik 的一个专栏,这个玩意儿如果想在生产使用看我这个肯定没啥问题,你在网上几乎都搜不到像样的文章,这东西我们研究了好几个月了,所以我才能写出来。
而文章更新因为有了星球,所以内容会偏向星球居多一点。
当然你要说就想免费的也行啊,但是大家都知道免费的其实最贵。
还有一点是包括抖音等平台的视频更新,虽然不多,但是也有快2万粉丝了,这个我几乎佛系更新的情况下居然这么猛是我没想到的,也欢迎大家关注下。
SO,我欢迎大家不缺个100的话,可以加入星球,查看完整 Traefik 云原生网关系列,目前我已经更新了两个专栏,Traefik 系列也即将进入尾声,Q4还会有持续的更新计划。
其他的一些内容是我之前写的文章重新整理,还有后续的补充,都会在里面。
嗯,大概就是这样,我始终相信真正有价值的东西不需要太多的营销话术,仅仅是信任就行了,你懂我不会吹。
OK,就这样,感谢大家。
文章转载自公众号:艾小仙