GitHub 的 DNS 基礎設施
在 GitHub,我們最近從頭改進了 DNS。這包括了我們如何與外部 DNS 提供商交互以及我們如何在內部向我們的主機提供記錄。為此,我們必須設計和構建一個新的 DNS 基礎設施,它可以隨著 GitHub 的增長擴展並跨越多個數據中心。
以前,GitHub 的 DNS 基礎設施相當簡單直接。它包括每台伺服器上本地的、只具備轉發功能的 DNS 緩存伺服器,以及一對被所有這些主機使用的緩存伺服器和權威伺服器主機。這些主機在內部網路以及公共互聯網上都可用。我們在緩存守護程序中配置了 區域 存根 ,以在本地進行查詢,而不是在互聯網上進行遞歸。我們還在我們的 DNS 提供商處設置了 NS 記錄,它們將特定的內部 域 指向這對主機的公共 IP,以便我們網路外部的查詢。
這個配置使用了很多年,但它並非沒有缺點。許多程序對於解析 DNS 查詢非常敏感,我們遇到的任何性能或可用性問題在最好的情況下也會導致服務排隊和性能降級,而最壞情況下客戶會遭遇服務中斷。配置和代碼的更改可能會導致查詢率發生大幅度的意外變化。因此超出這兩台主機的擴展成為了一個問題。由於這些主機的網路配置,如果我們只是繼續添加 IP 和主機的話存在一些本身的問題。在試圖解決和補救這些問題的同時,由於缺乏測量指標和可見性,老舊的系統難以識別問題的原因。在許多情況下,我們使用 tcpdump
來識別有問題的流量和查詢。另一個問題是在公共 DNS 伺服器上運行,我們處於泄露內部網路信息的風險之下。因此,我們決定建立更好的東西,並開始確定我們對新系統的要求。
我們著手設計一個新的 DNS 基礎設施,以改善上述包括擴展和可見性在內的運維問題,並引入了一些額外的需求。我們希望通過外部 DNS 提供商繼續運行我們的公共 DNS 域,因此我們構建的系統需要與供應商無關。此外,我們希望該系統能夠服務於我們的內部和外部域,這意味著內部域僅在我們的內部網路上可用,除非另有特別配置,而外部域也不用離開我們的內部網路就可解析。我們希望新的 DNS 架構不但可以基於部署的工作流進行更改,並可以通過我們的倉庫和配置系統使用 API 自動更改 DNS 記錄。新系統不能有任何外部依賴,太依賴於 DNS 功能將會陷入級聯故障,這包括連接到其他數據中心和其中可能有的 DNS 服務。我們的舊系統將緩存伺服器和權威伺服器在同一台主機上混合使用。我們想轉到具有獨立角色的分層設計。最後,我們希望系統能夠支持多數據中心環境,無論是 EC2 還是裸機。
實現
為了構建這個系統,我們確定了三類主機: 緩存主機 、 邊緣主機 和 權威主機 。緩存主機作為 遞歸解析器 和 DNS 「路由器」 緩存來自邊緣層的響應。邊緣層運行 DNS 權威守護程序,用於響應緩存層對 DNS 區域 的請求,其被配置為來自權威層的 區域傳輸 。權威層作為隱藏的 DNS 主伺服器 ,作為 DNS 數據的規範來源,為來自邊緣主機的 區域傳輸 提供服務,並提供用於創建、修改或刪除記錄的 HTTP API。
在我們的新配置中,緩存主機存在於每個數據中心中,這意味著應用主機不需要穿過數據中心邊界來檢索記錄。緩存主機被配置為將 區域 映射到其 地域 內的邊緣主機,以便將我們的內部 區域 路由到我們自己的主機。未明確配置的任何 區域 將通過互聯網遞歸解析。
邊緣主機是地域性的主機,存在我們的網路邊緣 PoP( 存在點 )內。我們的 PoP 有一個或多個依賴於它們進行外部連接的數據中心,沒有 PoP 數據中心將無法訪問互聯網,互聯網也無法訪問它們。邊緣主機對所有的權威主機執行 區域傳輸 ,無論它們存在什麼 地域 或 位置 ,並將這些區域存在本地的磁碟上。
我們的權威主機也是地域性的主機,只包含適用於其所在 地域 的 區域 。我們的倉庫和配置系統決定一個 區域 存放在哪個 地域性權威主機 ,並通過 HTTP API 服務來創建和刪除記錄。 OctoDNS 將區域映射到地域性權威主機,並使用相同的 API 創建靜態記錄,以及確保動態源處於同步狀態。對於外部域 (如 github.com),我們有另外一個單獨的權威主機,以允許我們可以在連接中斷期間查詢我們的外部域。所有記錄都存儲在 MySQL 中。
可運維性
遷移到更現代的 DNS 基礎設施的巨大好處是可觀察性。我們的舊 DNS 系統幾乎沒有指標,只有有限的日誌。決定使用哪些 DNS 伺服器的一個重要因素是它們所產生的指標的廣度和深度。我們最終用 Unbound 作為緩存主機,NSD 作為邊緣主機,PowerDNS 作為權威主機,所有這些都已在比 GitHub 大得多的 DNS 基礎架構中得到了證實。
當在我們的裸機數據中心運行時,緩存通過私有的 任播 IP 訪問,從而使之可以到達最近的可用緩存主機。緩存主機已經以機架感知的方式部署,在它們之間提供了一定程度的平衡負載,並且與一些電源和網路故障模式相隔離。當緩存主機出現故障時,通常將用其進行 DNS 查詢的伺服器現在將自動路由到下一個最接近的緩存主機,以保持低延遲並提供對某些故障模式的容錯。任播允許我們擴展單個 IP 地址後面的緩存數量,這與先前的配置不同,使得我們能夠按 DNS 需求量運行儘可能多的緩存主機。
無論地域或位置如何,邊緣主機使用權威層進行區域傳輸。我們的 區域 並沒有大到在每個 地域 保留所有 區域 的副本成為問題。(LCTT 譯註:此處原文「Our zones are not large enough that keeping a copy of all of them in every region is a problem.」,根據上下文理解而翻譯。)這意味著對於每個區域,即使某個地域處於離線狀態,或者上游服務提供商存在連接問題,所有緩存伺服器都可以訪問具備所有區域的本地副本的本地邊緣伺服器。這種變化在面對連接問題方面已被證明是相當有彈性的,並且在不久前本來會導致客戶面臨停止服務的故障期間幫助保持 GitHub 可用。
那些區域傳輸包括了內部和外部域從它們相應的權威伺服器進行的傳輸。正如你可能會猜想像 github.com 這樣的區域是外部的,像 github.net 這樣的區域通常是內部的。它們之間的區別僅在於我們使用的類型和存儲在其中的數據。了解哪些區域是內部和外部的,為我們在配置中提供了一些靈活性。
$ dig +short github.com
192.30.253.112
192.30.253.113
公共 區域 被同步到外部 DNS 提供商,並且是 GitHub 用戶每天使用的 DNS 記錄。另外,公共區域在我們的網路中是完全可解析的,而不需要與我們的外部提供商進行通信。這意味著需要查詢 api.github.com
的任何服務都可以這樣做,而無需依賴外部網路連接。我們還使用了 Unbound 的 stub-first
配置選項,它給了我們第二次查詢的機會,如果我們的內部 DNS 服務由於某些原因在外部查詢失敗,則可以進行第二次查找。
$ dig +short time.github.net
10.127.6.10
大部分的 github.net
區域是完全私有的,無法從互聯網訪問,它只包含 RFC 1918 中規定的 IP 地址。每個地域和站點都劃分了私有區域。每個地域和/或站點都具有適用於該位置的一組子區域,子區域用於管理網路、服務發現、特定的服務記錄,並且還包括在我們倉庫中的配置主機。私有區域還包括 PTR 反向查找區域。
總結
用一個新系統替換可以為數百萬客戶提供服務的舊系統並不容易。使用實用的、基於需求的方法來設計和實施我們的新 DNS 系統,才能打造出一個能夠迅速有效地運行、並有望與 GitHub 一起成長的 DNS 基礎設施。
想幫助 GitHub SRE 團隊解決有趣的問題嗎?我們很樂意你加入我們。在這申請。
via: https://githubengineering.com/dns-infrastructure-at-github/
作者:Joe Williams 譯者:geekpi 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive