Localhost 迷航記

當 localhost 不再是 localhost 時

ta-ching chen

2 minute read

 文章目錄

Introduction 

故事背景稍微介紹一下,使用者反映 Fission基於 Kubernetes 之上的 FaaS (Function-as-a-Service) 框架 在週末突發性的無法正常運作。作為一個興趣使然的工程師,遇到使用者反應問題當然要 (義不容辭) 協助排解。 經過各種遠端通靈一種在不知曉確切運作環境或對於問題毫無頭緒下,仍然嘗試除錯的技術 ,發現問題發生在當要初始化使用者的 function 時出現。

function-pod

Fig. 1 Fission function pod specialization process

整個初始化流程如 Fig. 1,首先 executor 會送出 specialize 請求給 fetcher,讓它取得 function code 後放至 share volume 內。 再由 fetcher 呼叫 env runtime,讓其載入 function code 後服務 HTTP 請求。

"logger":"fetcher"
"msg":"error connecting to function environment pod for specialization request, retrying"
"error":"dial tcp 10.58.152.224:8888: i/o timeout"

從日誌上來看錯誤是 i/o timeout。奇妙的地方在於本來是呼叫 localhost,卻顯示 10.58.152.224 超時 ?!

而用戶反應問題是在公司開始導入 proxy 後發生的,到這邊可能性有兩個:

  1. Proxy 設定出現異常,導致 Pod 內部的本地端 HTTP call 被攔截送往其他地方
  2. DNS 解析出現錯誤

原本想說會不會跟 docker 的 NO_PROXY 設定相關,但該設定主要跟 pull image 相關且測試後也驗證不是這個原因。

事已至此,剩下 DNS 解析出錯的可能性,也只能開始往最瞎的方向開始思考:

是不是在 namespace 底下有個名為 localhost 的服務存在?

Kubernetes Pod DNS 

Fig.2 為 Kubernetes 內 Pod 做 DNS 解析時的流程圖

pod-dns

Fig. 2 Kubernetes Pod DNS

當遇到域名時,整個解析過程的順序如下

  1. 向 kube-dns 詢問解析結果
  2. 若 cluster 內沒有對應記錄就繼續往上游 DNS 查詢
  3. 如果都沒有任何結果的話,查看本地端的 /etc/resolv.conf

好玩的是,其實 Kubernetes 允許建立名為 localhost 的服務,因此在 Pod 內查詢時就會被 kube-dns 當成

localhost.default.svc.cluster.local

所以正常狀況下會得到 127.0.0.1 的結果

root@helloworld-v1-7c45d5f8c4-8nzb7:/# nslookup localhost
Server:        10.96.0.10
Address:    10.96.0.10#53

Non-authoritative answer:
Name:    localhost
Address: 127.0.0.1

在當 localhost 同名 kubernetes service 存在時,kube-dns 會回傳該 service 的 cluster ip。

$ kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE     SELECTOR
localhost    NodePort    10.104.136.35   <none>        5678:32116/TCP   3m42s   app=localhost

root@helloworld-v1-7c45d5f8c4-8nzb7:/opt/microservices# nslookup localhost
Server:        10.96.0.10
Address:    10.96.0.10#53

Name:    localhost.default.svc.cluster.local
Address: 10.104.136.35

End of story 

可以看到問題極有可能是因為 DNS 解析順序問題導致的,但套句歪國人常講的話

Who on earth would do something like that?

在 namespace 底下建立 localhost 服務,就像常見的工程師惡搞笑話一樣

define-true-false

還好結論不是因為有人創建 localhost 在惡搞 (雖然相差不遠),而是他們公司有人將自己電腦的 DNS 設定成 localhost.company.com, 所以 upstream DNS 在解析後回傳該電腦的 IP。(果然神的都是別人隊友)

既然知道問題點後,解決方式也相當簡單,改用 127.0.0.1 取代 localhost 即可。

此議題進一步延伸,甚至能根據企業需求達成轉發流量至其他服務做流量處理, 或企業內部被惡意攻擊植入偽造 DNS record 時產生潛在問題。 因此加掛 custom DNS 時要特別注意其安全性及解析先後順序,避免意外發生。

最後使用者表示:

some idiot in our company has named his computer “localhost” ….

但我猜他心裡想講的話,翻譯成中文最接近的意思大概是

誰幹的,給我出來! 我保證不一槍打死你

Star Trek - gun

這是近期遇到最奇耙的 issue,希望不要再有下個啊! XDD

最後附上血淋淋的 PR 給大家笑笑: https://github.com/fission/fission/pull/1227

相關文章

comments powered by Disqus