本文针对Istio 0.7及以下版本,0.8以上路由大改,文章思路适用,但是具体内容不适用。

这段时间一直在研究如何使用istio连接外部RDS服务,这里记录一下我的解决过程,以及心路历程。

首次连接失败

事情发生在1周前,当时我在尝试将之前的spring cloud服务剥离出来,并将服务移植到k8s集群上的istio中。最开始写其他测试程序的时候,出发点是集群内部服务互通,如我的这篇文章
但是,由于原项目使用了阿里的RDS服务,所以第一次移植的时候是失败的,而且这个报错很奇葩,因为使用了hibernate,报错竟然是:

Access to DialectResolutionInfo cannot be null when ‘hibernate.dialect’ not set。

这里有个插曲挺有趣的,当时机缘巧合,我的电脑网络出了问题,所以本地启动服务的时候也报这个错误了,所以我在移植服务的时候发现这个错误,就可以肯定是RDS连接出了问题。于是我提了工单,当时有个回复很有意思,我吐槽了很久,但是现在回过头来想,当时的环境是因为我的问题所以给人造成了误导。这个慢慢说,我先说一下当时的工单回复,你就知道我为什么觉得好笑,并想要吐槽;后面我会说,为什么我发现是我的问题了。

另外,关于报错记录
Access to DialectResolutionInfo cannot be null when ‘hibernate.dialect’ not set
建议使用引擎搜索相关文档
常规的解法是指定hibernate.dialec

一字不差,所以我觉得好笑,因为这是把我当纯小白啊,这个任谁可能都不会觉得很好受吧。

不过事实证明,我确实有些小白。。。

定位问题,寻找解决方案

首先我定位的问题就是,外部服务没有进入我启动的内部服务中,我的第一反应是k8s的问题,所以当时提工单的时候我一直在强调k8s导致我无法连接外部的rds服务。当时我的方法是在pod中curl -I www.baidu.com,得到的结果是

HTTP/1.1 404 Not Found

这时我仍然天真的认为是无法访问外部服务造成的,后来我才见识了什么才是真正的无法访问外部服务。

在后面的工单讨论中,其实工程师已经点出了我的问题了,但是当时我有点太固执了,有点钻牛角尖了(从前我有些反感那些钻牛角尖的人,结果还是变成了自己曾经讨厌的样子,哈哈哈)。

看一下工单中给我的几处提示:

在pod里,默认应该是能直接访问外网的吧,在pod里,访问百度域名 和 rds域名地址,是否是都通的。
域名能访问访问通,pod里的程序,就可以用这个域名进行访问。


访问显示是404,找不到页面,这种情况一般也是访问通了,只是返回了404状态码。

然后当时我总觉得他答非所问,所以索性关闭了工单,后来发现是我没有把问题的根源找到。这也是我后续用了更长的时间定位问题以及解决问题的伏笔。

寻找解决方向

Endpoints

之后一段时间我仍然将问题的解决方法放在了如何使k8s 内的pod 能够访问到外部的rds 。所以寻找方案就变成了如何使k8s访问外部服务,这是找到的第一个解决方案,但是大概看了一下,感觉不靠谱,因为这个需要用ip才行。但是rds 是一个域名,所以肯定不能用,但是后面我还是在绝望中尝试了一下,病急乱投医嘛,就更绝望了。因为用ping可以看到域名后的ip ,所以当时就尝试了这种方案。

ExternalName Service

这个是我找到的第二个解决方案,同样是因为当时的方向问题,并且在网上找到了一个和我问题基本相同的帖子,是个老外写的,他当时用的就是这个方案解决的。地址
不过这个方案我当时思考了一下,也不太可行。首先它的原理类似是通过服务名的方式做alias映射,直接走k8s-dns解析(这块只是我的粗浅理解,欢迎拍砖)。但是这样就有一个问题,我们知道项目中的db.url形式类似jdbc:mysql://test.database.example.com:3306/<databaseName>?...;如果按照ExternalName Service的解法,这块的前后缀如何解决,这个问题很难逾越,当时我纠结这个问题纠结了很久,为此还特地写了个评论想问原帖的作者有没有遇到类似问题:

Hi,i have some trouble in the ExternalName service 。The lable “externalName” must like the form of “test.database.example.com”, it’s end with “.com”; but “db.url” which in my project looks like “jdbc:mysql://test.database.example.com:3306/?…”, and it should be changed to the name of the ExternalName service, like you say. So, how can I deal with this problem? Could you give me an example?

可惜我没搭梯子,摔下来了,就给你们看看我浅薄的英语水平吧。。。

这无形中又堵死了一条路。

service broker

这是我找到的第三个解决方案,当时无意中在网上查k8s和rds 连接的问题,结果就搜到这个了,然后跟着官方文档做了一下,发现这是新生成一个rds啊,不过能解决问题也行啊,大不了以后迁库嘛。我还是天真,在使用的过程中,出现了几个报错,而且我感觉这个还是不太对劲,不应该要再生成rds啊,怎么会无法使用已有的rds呢?

这不科学!

上面的这些解决方案都没能解决我的问题,究其原因,是我定位问题的根源有问题。问题的根源在哪里呢?我们接着往下看。

新情况!

屋漏偏逢连夜雨,这面的负载均衡出现问题了。这下导致我之前原本能从外部通过ingress访问的服务也跪了。这个时候开始了漫长的解决负载均衡问题。第一次工单,答非所问,草草关闭。

后面我在容器服务里出了个工单,果然解决问题的方式就不一样了,所以这里再次体现了定位问题的重要性,往往定位准确,问题可以很快的解决,专业人士也能给你你最需要的帮助。

第二个工单的交流非常顺畅,并且也学到了,明白了很多东西,最后也直接导致我对最开始定位的问题产生了怀疑,并及时修改了方向,最后得以解决。

首先确定的就是:k8s集群内部pod 本来就可以访问外部服务,之前的种种迹象也能够表明,但是为什么我会出现之前的错误观念呢?
是因为,istio中的pod无法访问外部服务!因为sidecar会进行流量管理,所以导致外部服务无法访问。
后来经过种种测试也验证了这个观点。而我由于之前创建的istio服务都是落实到k8s 集群上,命令也是使用的kubectl,自然也就产生了错觉。

那么现在问题的层面就从k8s转移到istio了。

第二个学到的内容就是:k8s的ingress和istio的ingress使用的并不是同一个,所以k8s ingress使用的负载均衡ip和istio的ingress使用的负载均衡ip不同。
发现这个问题的起因是,我删除了一个负载均衡实例,但是后续新建的ingress的ip始终是删掉的这个,我觉得不太对啊。之后按照工单的指导,重建了k8s的nginx-ingress-lb服务。但是结果依旧。最后问题的根源是:istio ingress对负载均衡的ip会进行缓存,如果更换的话,需要进行更新。
这个也是多次验证,新建k8s 的ingress出现的ip是由nginx-ingress-lb服务生成的。但是当后续的istio ingress创建,又会新建一个负载均衡实例。而且以后k8s的服务也会使用istio ingress创建的那个负载均衡实例。也就是说,原nginx-ingress-lb服务创建的那个失效了。
之前理解有误,创建istio的ingress使用的是istio生成的SLB实例;创建k8s的ingress使用的是k8s的nginx-ingress-lb服务生成的SLB实例。

解决方案诞生

总之,经过这一系列的问题出现,我已经将问题定位修改为,istio如何访问外部服务。恰巧之前我已经已经找到过这个问题的解决方案,可以说和我的问题一毛一样,不过当时并没有尝试,因为一直在解决负载均衡的问题。
StackOverflow上的问题1.
StackOverflow上的问题2.

最后终于在我之前翻译的官方文档中,看到了同样的操作:Calling external services directly那部分。
只需在istioctl kube-inject时加上一个标志--includeIPRanges=10.0.0.1/24。后面这个ip范围,目前不太清楚有什么限制,不过目前来看,我使用的这个没有问题。还有尽量不要和之前分配的k8s 集群的服务和pod 的范围有重叠。如果有比较清楚的大佬,欢迎评论指正。

至此,我终于通过该方法解决了连接外部rds 的问题。

回顾及总结

此次问题的解决共计耗时一周。从结果上看,只是加一个标志符就能解决的问题,足足耗时一周,挺亏的。但从过程上看,我这一周收获的东西,挺赚的。

这次问题的爆发还是源于对k8s 及istio的掌握尚浅,所以导致前期定位问题就出现了失误。同时也体现了正确定位问题的重要性。方向不对的时候,需要及时转换思维,不要钻牛角尖。

最后,不要随意质疑专业人士,因为可能你和他根本没有在同一角度看问题,所以才会导致有答非所问的感觉。毕竟现在行业细化,就连工单系统都有那么多分支,所以定位是哪部分的问题,才能更快的帮助你解决问题。毕竟每个人专精的领域不同,鸡同鸭讲,永远也碰撞不出什么思维火花。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐