使用istio連線外部服務(如RDS)
本文針對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的掌握尚淺,所以導致前期定位問題就出現了失誤。同時也體現了正確定位問題的重要性。方向不對的時候,需要及時轉換思維,不要鑽牛角尖。
最後,不要隨意質疑專業人士,因為可能你和他根本沒有在同一角度看問題,所以才會導致有答非所問的感覺。畢竟現在行業細化,就連工單系統都有那麼多分支,所以定位是哪部分的問題,才能更快的幫助你解決問題。畢竟每個人專精的領域不同,雞同鴨講,永遠也碰撞不出什麼思維火花。