基於CoreDNS Plugin擴充套件實現Istio Service Entry的DNS定址
CoreDNS 及其Plugin擴充套件
CoreDNS是一個CNCF下的孵化級專案,它的前身是SkyDNS,主要目的是構建一個快速靈活的 DNS 伺服器,讓使用者可以通過不同方式訪問和使用 DNS 內的資料。基於 Caddy 伺服器框架,CoreDNS 實現了一個外掛鏈的架構,將大量邏輯抽象成外掛Plugin的形式暴露給使用者,每個外掛都執行DNS功能,例如Kubernetes 的 DNS 服務發現、Prometheus 監控等。
除了外掛化之外,CoreDNS還有以下特性:
- 配置簡單化: 引入表達力更強的 DSL,即 Corefile 形式的配置檔案(也是基於 Caddy 框架開發);
- 一體化的解決方案:區別於 kube-dns,CoreDNS 編譯出來就是一個單獨的二進位制可執行檔案,內建了 cache,backend storage ,health check 等功能,無需第三方元件來輔助實現其他功能,從而使得部署更方便,記憶體管理更為安全;
Corefile 介紹
Corefile 是 CoreDNS 的配置檔案(源於 Caddy 框架的配置檔案 Caddyfile),定義了以下內容:
- 伺服器以什麼協議監聽在哪個埠(可以同時定義多個 server 監聽不同埠)
- 伺服器負責哪個 zone 的 authoritative DNS 解析
- 伺服器將載入哪些外掛
一個典型的 Corefile 格式如下所示:
ZONE:[PORT] {
[PLUGIN] ...
}
其中,
- ZONE:用於定義伺服器負責的 zone;
- PORT: 監聽埠,可選項,預設為 53;
- PLUGIN:定義伺服器所要載入的外掛plugin,每個 plugin 可以有多個引數;
Plugin工作機制
當 CoreDNS 啟動後,它將根據配置檔案啟動不同 server ,每臺 server 都擁有自己的外掛鏈。當有 DNS 請求時,它將依次經歷如下 3 步邏輯:
- 如果有當前請求的 server 有多個 zone,將採用貪心原則選擇最匹配的 zone;
- 一旦找到匹配的 server,按照 plugin.cfg 定義的順序執行外掛鏈上的外掛;
每個外掛將判斷當前請求是否應該處理,將有以下幾種可能:
-
- 請求被當前外掛處理
外掛將生成對應的響應並回給客戶端,此時請求結束,下一個外掛將不會被呼叫,如 whoami 外掛;
- 請求不被當前外掛處理
直接呼叫下一個外掛。如果最後一個外掛執行錯誤,伺服器返回 SERVFAIL 響應; -
請求被當前外掛以 Fallthrough 形式處理
如果請求在該外掛處理過程中有可能將跳轉至下一個外掛,該過程稱為 fallthrough,並以關鍵字 fallthrough 來決定是否允許此項操作,例如 host 外掛,當查詢域名未位於 /etc/hosts,則呼叫下一個外掛;- 請求在處理過程被攜帶 Hint
請求被外掛處理,並在其響應中添加了某些資訊(hint)後繼續交由下一個外掛處理。這些額外的資訊將組成對客戶端的最終響應,如 metric 外掛;
- 請求在處理過程被攜帶 Hint
- 請求被當前外掛處理
CoreDNS與Kubernetes
從Kubernetes 1.11開始,CoreDNS作為Kubernetes的DNS外掛進入GA狀態,Kubernetes推薦使用CoreDNS作為叢集內的DNS服務。在阿里雲容器服務Kubernetes 1.11.5及更新版本中預設安裝使用CoreDNS作為DNS服務。通過如下命令可以檢視CoreDNS配置資訊:
# kubectl -n kube-system get configmap coredns -oyaml
apiVersion: v1
data:
Corefile: |-
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
proxy . /etc/resolv.conf
cache 30
reload
}
kind: ConfigMap
metadata:
creationTimestamp: "2018-12-28T07:28:34Z"
name: coredns
namespace: kube-system
resourceVersion: "2453430"
selfLink: /api/v1/namespaces/kube-system/configmaps/coredns
uid: 2f3241d5-0a72-11e9-99f1-00163e105bdf
配置檔案各引數的含義如下:
名稱 | 含義 |
---|---|
errors | 錯誤會被記錄到標準輸出 |
health | 健康狀況,可以通過http://localhost:8080/health 檢視 |
kubernetes | 根據服務的IP響應DNS查詢請求,Cluster Domain預設為cluster.local |
prometheus | 可以通過http://localhost:9153/metrics 獲取prometheus格式的監控資料 |
proxy | 本地無法解析後,向上級地址進行查詢,預設使用宿主機的 /etc/resolv.conf 配置 |
cache | 快取時間 |
通過應用目錄簡便部署Istio CoreDNS
阿里雲容器服務Kubernetes 1.11.5目前已經上線,可以通過容器服務管理控制檯非常方便地快速建立 Kubernetes 叢集。具體過程可以參考建立Kubernetes叢集。
點選左側的應用目錄
,在右側選中ack-istio-coredns
,在開啟的頁面中點選引數
, 可以通過修改引數配置進行定製化,如下所示:
引數描述如下:
引數 | 描述 | 值 | 預設 |
---|---|---|---|
replicaCount |
指定副本數 | number | 1 |
coreDNSImage |
指定coredns映象名稱 | valid image tag | coredns/coredns:1.2.2 |
coreDNSPluginImage |
指定外掛映象名稱 | valid image name | registry.cn-hangzhou.aliyuncs.com/aliacs-app-catalog/istio-coredns-plugin:v1.0-istio-1.1 |
修改之後,在右側選擇對應的叢集、名稱空間 istio-system
以及釋出名稱 istio-coredns
,然後點選部署。幾秒鐘之後,Istio CoreDNS釋出就可以創建出來,如下圖所示:
更改叢集CoreDNS配置
可以通過執行以下命令來獲取 istiocoredns
服務的Cluster IP:
# kubectl get svc istiocoredns -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istiocoredns ClusterIP 172.19.10.196 <none> 53/UDP,53/TCP 44m
更新叢集的coredns的配置項configmap, 將此istiocoredns
服務作為 *.global
域的上游DNS服務,在此配置項configmap中新增域 *.global
,如下所示:
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |-
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
proxy . /etc/resolv.conf
cache 30
reload
}
global:53 {
errors
cache 30
proxy . {replace this with the actual cluster IP of this istiocoredns service}
}
更改此配置項後,叢集的CoreDNS容器會重新載入這些配置內容,可以通過如下命令列檢視載入日誌:
# kubectl get -n kube-system pod | grep coredns
coredns-8645f4b4c6-5frkg 1/1 Running 0 20h
coredns-8645f4b4c6-lj59t 1/1 Running 0 20h
# kubectl logs -f -n kube-system coredns-8645f4b4c6-5frkg
....
2019/01/08 05:06:47 [INFO] Reloading
2019/01/08 05:06:47 [INFO] plugin/reload: Running configuration MD5 = 05514b3e44bcf4ea805c87cc6cd56c07
2019/01/08 05:06:47 [INFO] Reloading complete
# kubectl logs -f -n kube-system coredns-8645f4b4c6-lj59t
....
2019/01/08 05:06:31 [INFO] Reloading
2019/01/08 05:06:32 [INFO] plugin/reload: Running configuration MD5 = 05514b3e44bcf4ea805c87cc6cd56c07
2019/01/08 05:06:32 [INFO] Reloading complete
建立ServiceEntry驗證DNS解析
ServiceEntry 能夠在 Istio 內部的服務登錄檔中加入額外的條目,從而讓網格中自動發現的服務能夠訪問和路由到這些手工加入的服務。ServiceEntry 描述了服務的屬性,即包括DNS 名稱、虛擬IP、埠、協議以及端點等。這類服務可能是網格外的 API,或者是處於網格內部但卻不存在於平臺的服務登錄檔中的條目,例如需要和 Kubernetes 服務溝通的一組基於虛擬機器VM提供的服務。
下面的例子中,使用了萬用字元定義 hosts,並指定了address,如下所示:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-svc-serviceentry
spec:
hosts:
- '*.test.global'
addresses:
- 127.255.0.2
ports:
- number: 8080
name: http1
protocol: HTTP
location: MESH_INTERNAL
resolution: DNS
endpoints:
- address: 47.111.38.80
ports:
http1: 15443
執行如下命令檢視容器 istiocoredns
,可以看到上述ServiceEntry的域名對映關係已經被載入:
# kubectl get po -n istio-system | grep istiocoredns
istiocoredns-cdc56b67-ngtkr 2/2 Running 0 1h
# kubectl logs --tail 2 -n istio-system istiocoredns-cdc56b67-ngtkr -c istio-coredns-plugin
2019-01-08T05:27:22.897845Z info Have 1 service entries
2019-01-08T05:27:22.897888Z info adding DNS mapping: .test.global.->[127.255.0.2]
使用映象 tutum/dnsutils 建立測試容器:
kubectl run dnsutils -it --image=tutum/dnsutils bash
進入容器命令列之後,執行dig 檢視相應的域名解析:
[email protected]:/# dig +short 172.19.0.10 A service1.test.global
127.255.0.2
[email protected]:/# dig +short 172.19.0.10 A service2.test.global
127.255.0.2
總結
Istio支援幾種不同的拓撲結構,用於在單個叢集之外分發應用程式的服務,例如在服務網格中的服務可以使用 ServiceEntry 來訪問獨立的外部服務或訪問由另一個服務網格公開的服務(這種情況通常稱之為網格聯合)。使用Istio CoreDNS為遠端叢集中的服務提供DNS解析,將允許現有的應用程式不需要修改就可以如同訪問本叢集內的服務一樣。