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 方法。

e9d9f201f696efe85f34bb46c7c78c8c.png

我们在本地 DEBUG 就是启动这个 main 方法,首先进行配置的初始化,然后定义了 3 个资源加载的方式,和官方描述的一样,可以从配置文件、命令行参数和环境变量读取配置。

之后就是添加启动命令,包括健康检测、版本检查,最后回去调用cli.Execute方法,这个方法跟进去看也挺简单的,最终其实都会调用到CommandRun方法,也就是会执行runCmd方法。

b043e612d10a087b4c817a2c9601c0c5.png

进入 Execute 方法,我们启动是没有其他参数的,只是启动命令,所以进入第一个判断,参数长度为1。

caf2f5c84781d617d6a87956332c7df5.png

然后最终跟我们上面说的一样,调用到了cmd.Run

e59786b208ecdff26ff40bad871b69fc.png

然后直接进入runCmd方法中看服务如何启动的。

这里干了几件事情,首先是初始化日志的配置、静态配置,然后解析静态配置为 json,然后就是很关键的两个步骤,一个是setupServer初始化 server,之后是 server 的启动。

145c972f407869a993bce8d60f7ee043.png

这里可以看一下静态配置到底都有些什么东西,因为我们没有配置 AcessLog、Metric 这些东西,所以都是空的,其实关键就两个东西,一个是 EntryPoints,另外一个是 Provider。

2cfd9a919a1606b18bacefb14d33af7b.png

这里我们本地启动通过 CRD 的方式,入口点只是默认的配置。

1081263f98a48b6be06e04aab467a8cc.png

Server初始化

3b95b3a17d01f361816aa817f1b0c174.png

然后我们直接看 setupServer都干了些什么,这个方法非常长,我们忽略调一些无关的细节,只看重点的部分。

首先创建 provider 的聚合器,其实就是服务发现的提供者,我们知道有很多,像是文件、Docker、K8S、ECS、Consul 等等很多,在之前我们就提到过这个,这里我们主要是 CRD。

ACME 是 HTTPS 证书相关的东西,可以忽略他。

然后是关于server.NewTCPEntryPoints,用于构建入口点的逻辑,这个很关键。

cf825008f1bf1bf9fb9f799cb25c4ace.png

接着是创建 Provider 的插件,这个X509Source又是关于证书的一些逻辑,主要是使用 SPIFFE (Secure Production Identity Framework For Everyone) 获取证书,以便与其他服务进行安全通信,这个不是重点,忽略。

4a584fd978c8a7dcc28448382e6fc0d2.png

接着往下走是几个比较关键的 Factory,一个是managerFactory,另外一个则是routerFactory,这两个工厂会构建出后续请求的流程链路,放到后面再说。

db3c65309e6b3c72bdae975e6f05f5d2.png

这里的 watcher 也是一个关键点,添加了关于 TLS、Metrics、Server Transports 和 Switch Router 的动态配置的监听。

这里的switchRouter是一个很重要的方法,待会儿再细看。

c573b9a2fd5bdee470dfb3bbd705e24e.png

最终流程走完到最终执行NewServer方法创建 Server,配置初始化 Server 的流程结束。

577790209836f203bb80bcbbb27881cf.png

配置监听

0ab33d3d2cddb124225224fca0b312cb.png

这个流程看完之后,回到最开始的地方,开始启动 Server。

01ca195a230c44a7b2401d9a0b3d6bf6.png

这里主要关注两个方法,一个是 TCP 入口点的启动,另外一个则是监听 watcher 的启动,首先看tcpEntryPoints.Start

这里可以看到入口点默认是两个,一个是 traefik 自己默认的,另外一个是处理 web 请求的入口点,之后开启协程进入 serverEntryPoint.Start(ctx)

94c3f95f34d2edd0dc17ca9d1c64143d.png

这里主要是监听连接,当有新连接到达时,创建一个新的 writeCloser 对象,并在其上设置读/写超时。接下来,使用 e.switcher.ServeTCP 处理新连接,如果出现错误,则会记录错误日志并将错误转发到 e.httpServer 和 e.httpsServer 的 channel。

83d94b893b6c5646e9e31d0c2ad8dc5c.png

之后就进入 watcher 监听的启动方法,主要实现了 3 个方法。

17d7bbf7edf5a7e2c81bafe74f4f7d8a.png
  1. 1. receiveConfigurations 是用于接收配置的变化,并且发送到消费者

  2. 2. applyConfigurations 是合并配置、应用配置

  3. 3. 启动 Provider 的聚合器,做服务发现

d4e302d1c949c56ae6be89db6f7fc955.png

receiveConfigurations主要是死循环监听配置的变更,新的配置会发送到 output 的 channel。

8bd2844cc6741c2a1086c1065c9a918c.png

applyConfigurations 则是收到新的配置之后,合并然后应用配置,具体合并的细节就不看了,忽略他。

d45cebad9f2c493e3e27460dcffcb0c1.png

provider 的聚合器是根据不同的 provider 提供了不同的实现,这里我们是使用 K8S CRD 的方式,所以待会儿进去看这个实现即可。

a20f39f66146603bdfa9b28489d865ba.png

首先创建一个 K8S client 客户端,用于和 K8S 集群进行通信,然后使用该客户端创建一个事件通道。

接下来,使用WatchAll监听所有配置的 namespace 的变化。

e4e822832a504f0a90737b85fdb51eed.png

这里 debug 能看到现在我们只配置了一个默认的 namespace。

f908269d37f900f8397e89cecb9dc17e.png

在第一次启动的时候,默认调用loadConfigurationFromCRD方法从 CRD 加载配置,之后如果配置发生变化,走到 default 分支,变更的配置会发送到 configurationChan

b67734eecac0f0560d8da3a12a5f245d.png

这个 channel 的定义其实就是在方法入口的ConfigurationWatcher

8a690d00fdaf390a4f0a04ba20f5024a.png

查看 ConfigurationWatcher 结构体的定义,找到allProvidersConfigs,定义的就是我们发送到的 channel 了。

c565ccb1d0833df2c8e20a1d3bd88d95.png

看到这里,会有疑问,那么发送的配置在什么地方进行消费了呢?

答案就是上面我们已经讲过的receiveConfigurations,而receiveConfigurations消费到配置变更之后,又会发送消息到newConfigs,然后applyConfigurations方法进行消费,然后处理配置、进行合并、应用。

服务发现

然后让我们回到 loadConfigurationFromCRD这个方法中,找到loadIngressRouteConfiguration方法,这里就是启动的时候去做服务发现的地方。

79c490790df36f7cc2d79c5fcc788953.png

进入这个方法就能看到通过 K8S 的客户端去获取配置的 IngressRoute。

95500b0314a0c4920e95089c98ba6ba6.png

进入这个方法,发现也是确实如此。

e55d9b8440c3333fb37ad1520ca9d670.png

这里 DEBUG 可以看到我们日志的 IngressRoute 的信息。

6aef02c5ece17959b81ebfd363a5c5c0.png

往下看还有一个比较有意思的地方,如果说路由中配置的 service 数量超过 1,那么会默认会变成权重负载均衡。

16b6631b81ef647b82a578252bf6bfa6.png

接着往下看buildServicesLB的方法,其实和 service==1 的情况一样,只是循环去调用了nameAndService方法而已。

c8d9087fe99335273b79dc6bd04b314d.png

进入这个方法这里有两个判断,针对类型是 Service 和 TraefikService的,Service 类型是 K8S 的类型,所以会去直接获取 server 的信息,而如果配置的是 TraefikService,实际上只是根据 TraefikService 获取 Service 名字,最终还是会走到 Service 的判断逻辑上。

a2fca593f552ca9fa8f6605bd7eadf07.png

创建负载均衡代码的关键在于第一行loadServers

31ad8e26e67a97bb498c393cfb6b327d.png

进入这个方法可以看到其实就是通过 K8S 的客户端去调用 API 接口,获取到了 service 的信息,还有端口、后端服务的地址。

f2b1bb20b70701cc7003db81b028993e.png a88e21b02462934b9c961345069512eb.png

那么,到这里基本服务发现的逻辑就结束了。


在这里顺便说点事情,最近可能大家觉得公共号没啥更新了,其实情况并不是这样。

首先一点确实是公众号目前情况不佳,阅读下滑,这个也就那样吧。

另外一点是最近几个月的重心有工作、生活两方面吧。

工作研究性质的东西会比较多一点,比如最近在学 GO,研究 Traefik,所以就写了 Traefik 的一个专栏,这个玩意儿如果想在生产使用看我这个肯定没啥问题,你在网上几乎都搜不到像样的文章,这东西我们研究了好几个月了,所以我才能写出来。

而文章更新因为有了星球,所以内容会偏向星球居多一点。

当然你要说就想免费的也行啊,但是大家都知道免费的其实最贵。

还有一点是包括抖音等平台的视频更新,虽然不多,但是也有快2万粉丝了,这个我几乎佛系更新的情况下居然这么猛是我没想到的,也欢迎大家关注下。

SO,我欢迎大家不缺个100的话,可以加入星球,查看完整 Traefik 云原生网关系列,目前我已经更新了两个专栏,Traefik 系列也即将进入尾声,Q4还会有持续的更新计划。

其他的一些内容是我之前写的文章重新整理,还有后续的补充,都会在里面。

嗯,大概就是这样,我始终相信真正有价值的东西不需要太多的营销话术,仅仅是信任就行了,你懂我不会吹。

OK,就这样,感谢大家。

756c2441a49386412dd06cbea6349f9f.png

674b17fcbf6d2c13e8d0497dd2801bea.png

另外,大家也可以关注一下我的抖音,内容不多,粉丝到是有快2万了。

f27d090fd29655ced055ae8f9fff195c.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值