服務和 Pod 的 DNS
Kubernetes 為 Services 和 Pod 建立 DNS 記錄。你可以使用一致的 DNS 名稱而不是 IP 地址來訪問 Services。
Kubernetes 釋出有關 Pods 和 Services 的資訊,這些資訊用於對 DNS 進行程式設計。kubelet 配置 Pod 的 DNS,以便執行中的容器可以透過名稱而不是 IP 查詢 Services。
在叢集中定義的 Services 會被分配 DNS 名稱。預設情況下,客戶端 Pod 的 DNS 搜尋列表包括 Pod 自己的名稱空間和叢集的預設域。
Services 的名稱空間
DNS 查詢可能會根據發出查詢的 Pod 的名稱空間返回不同的結果。未指定名稱空間的 DNS 查詢僅限於 Pod 的名稱空間。透過在 DNS 查詢中指定名稱空間來訪問其他名稱空間中的 Services。
例如,考慮一個在 `test` 名稱空間中的 Pod。一個 `data` Service 位於 `prod` 名稱空間中。
對 `data` 的查詢不返回任何結果,因為它使用了 Pod 的 `test` 名稱空間。
對 `data.prod` 的查詢返回預期結果,因為它指定了名稱空間。
DNS 查詢可以使用 Pod 的 `/etc/resolv.conf` 進行擴充套件。kubelet 為每個 Pod 配置此檔案。例如,對 `data` 的查詢可能會擴充套件為 `data.test.svc.cluster.local`。`search` 選項的值用於擴充套件查詢。要了解有關 DNS 查詢的更多資訊,請參閱`resolv.conf` 手冊頁。
nameserver 10.32.0.10
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
總而言之,位於 *test* 名稱空間中的 Pod 可以成功解析 `data.prod` 或 `data.prod.svc.cluster.local`。
DNS 記錄
哪些物件會獲得 DNS 記錄?
- 服務
- Pod
以下各節詳細介紹了支援的 DNS 記錄型別和佈局。任何其他可能有效的佈局、名稱或查詢都被視為實現細節,並可能在不通知的情況下更改。有關最新規範,請參閱基於 Kubernetes DNS 的服務發現。
服務
A/AAAA 記錄
“普通”(非 Headless)Services 會根據 Service 的 IP 族為其分配 DNS A 和/或 AAAA 記錄,名稱格式為 `my-svc.my-namespace.svc.cluster-domain.example`。這會解析為 Service 的叢集 IP。
Headless Services(沒有叢集 IP)也會被分配 DNS A 和/或 AAAA 記錄,名稱格式為 `my-svc.my-namespace.svc.cluster-domain.example`。與普通 Service 不同,它會解析為 Service 選擇的所有 Pod 的 IP 地址集。客戶端預計會使用該集合,或者從該集合中進行標準輪詢選擇。
SRV 記錄
為作為普通或 Headless Service 的一部分的命名埠建立 SRV 記錄。
- 對於每個命名埠,SRV 記錄的格式為 `_port-name._port-protocol.my-svc.my-namespace.svc.cluster-domain.example`。
- 對於常規 Service,這會解析為埠號和域名:`my-svc.my-namespace.svc.cluster-domain.example`。
- 對於 Headless Service,這會解析為多個答案,每個支援 Service 的 Pod 一個,幷包含埠號和 Pod 的域名,格式為 `hostname.my-svc.my-namespace.svc.cluster-domain.example`。
Pod
A/AAAA 記錄
在 DNS 規範 實現之前,Kube-DNS 版本具有以下 DNS 解析
<pod-IPv4-address>.<namespace>.pod.<cluster-domain>
例如,如果 `default` 名稱空間中的 Pod 的 IP 地址為 172.17.0.3,並且叢集的域名是 `cluster.local`,則該 Pod 具有 DNS 名稱
172-17-0-3.default.pod.cluster.local
一些叢集 DNS 機制,例如 CoreDNS,也為以下內容提供 `A` 記錄
<pod-ipv4-address>.<service-name>.<my-namespace>.svc.<cluster-domain.example>
例如,如果 `cafe` 名稱空間中的 Pod 的 IP 地址為 172.17.0.3,是名為 `barista` 的 Service 的端點,並且叢集的域名是 `cluster.local`,則該 Pod 將具有此服務作用域的 DNS `A` 記錄。
172-17-0-3.barista.cafe.svc.cluster.local
Pod 的主機名和子域名欄位
目前,當建立 Pod 時,其主機名(從 Pod 內部觀察)是 Pod 的 `metadata.name` 值。
Pod Spec 具有可選的 `hostname` 欄位,可用於指定不同的主機名。當指定時,它優先於 Pod 的名稱作為 Pod 的主機名(再次強調,從 Pod 內部觀察)。例如,給定一個 `spec.hostname` 設定為 `"my-host"` 的 Pod,該 Pod 的主機名將被設定為 `"my-host"`。
Pod spec 還有一個可選的 `subdomain` 欄位,用於指示 Pod 是名稱空間子組的一部分。例如,一個 `spec.hostname` 設定為 `"foo"`,`spec.subdomain` 設定為 `"bar"`,在名稱空間 `"my-namespace"` 中的 Pod,其主機名將設定為 `"foo"`,其完全限定域名 (FQDN) 將設定為 `"foo.bar.my-namespace.svc.cluster.local"`(再次強調,從 Pod 內部觀察)。
如果與 Pod 處於相同名稱空間中存在一個 Headless Service,且其名稱與子域名相同,則叢集的 DNS 伺服器還會為 Pod 的完全限定主機名返回 A 和/或 AAAA 記錄。
示例
apiVersion: v1
kind: Service
metadata:
name: busybox-subdomain
spec:
selector:
name: busybox
clusterIP: None
ports:
- name: foo # name is not required for single-port Services
port: 1234
---
apiVersion: v1
kind: Pod
metadata:
name: busybox1
labels:
name: busybox
spec:
hostname: busybox-1
subdomain: busybox-subdomain
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
name: busybox
---
apiVersion: v1
kind: Pod
metadata:
name: busybox2
labels:
name: busybox
spec:
hostname: busybox-2
subdomain: busybox-subdomain
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
name: busybox
給定上述 Service `"busybox-subdomain"` 和將 `spec.subdomain` 設定為 `"busybox-subdomain"` 的 Pods,第一個 Pod 將把其 FQDN 視為 `"busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example"`。DNS 在該名稱下提供 A 和/或 AAAA 記錄,指向 Pod 的 IP。Pod `"busybox1"` 和 `"busybox2"` 都將擁有自己的地址記錄。
一個EndpointSlice可以指定任何端點地址的 DNS 主機名及其 IP。
注意
由於 Pod 缺少 `hostname`,因此不會為 Pod 名稱建立 A 和 AAAA 記錄。一個沒有 `hostname` 但有 `subdomain` 的 Pod 只會為 Headless Service(`busybox-subdomain.my-namespace.svc.cluster-domain.example`)建立 A 或 AAAA 記錄,指向 Pod 的 IP 地址。此外,Pod 需要處於 Ready 狀態才能擁有記錄,除非在 Service 上設定了 `publishNotReadyAddresses=True`。Pod 的 setHostnameAsFQDN 欄位
當 Pod 配置為具有完全限定域名 (FQDN) 時,其主機名是短主機名。例如,如果你有一個 FQDN 為 `busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example` 的 Pod,那麼預設情況下,該 Pod 內部的 `hostname` 命令會返回 `busybox-1`,而 `hostname --fqdn` 命令會返回 FQDN。
當你在 Pod Spec 中設定 `setHostnameAsFQDN: true` 時,kubelet 將 Pod 的 FQDN 寫入該 Pod 名稱空間的主機名。在這種情況下,`hostname` 和 `hostname --fqdn` 都返回 Pod 的 FQDN。
注意
在 Linux 中,核心的主機名欄位(`struct utsname` 的 `nodename` 欄位)限制為 64 個字元。
如果 Pod 啟用此功能且其 FQDN 長度超過 64 個字元,它將無法啟動。該 Pod 將保持 `Pending` 狀態(`kubectl` 中顯示為 `ContainerCreating`),並生成錯誤事件,例如“Failed to construct FQDN from Pod hostname and cluster domain, FQDN `long-FQDN` is too long (64 characters is the max, 70 characters requested)”。改進此場景使用者體驗的一種方法是建立一個准入 Webhook 控制器,以便在使用者建立頂級物件(例如 Deployment)時控制 FQDN 大小。
Pod 的 DNS 策略
DNS 策略可以按每個 Pod 進行設定。目前 Kubernetes 支援以下 Pod 特定的 DNS 策略。這些策略在 Pod Spec 的 `dnsPolicy` 欄位中指定。
“`Default`”:Pod 從其執行節點繼承名稱解析配置。有關更多詳細資訊,請參閱相關討論。
“`ClusterFirst`”:任何不匹配已配置的叢集域字尾的 DNS 查詢,例如“`www.kubernetes.io`”,都由 DNS 伺服器轉發到上游名稱伺服器。叢集管理員可能配置了額外的 stub 域和上游 DNS 伺服器。有關在這些情況下如何處理 DNS 查詢的詳細資訊,請參閱相關討論。
“`ClusterFirstWithHostNet`”:對於使用 hostNetwork 執行的 Pod,應將其 DNS 策略明確設定為 “`ClusterFirstWithHostNet`”。否則,使用 hostNetwork 和 “`ClusterFirst`” 執行的 Pod 將回退到 “`Default`” 策略的行為。
注意
Windows 不支援此功能。有關詳細資訊,請參閱下文。“`None`”:它允許 Pod 忽略 Kubernetes 環境中的 DNS 設定。所有 DNS 設定都應使用 Pod Spec 中的 `dnsConfig` 欄位提供。請參閱下面的Pod 的 DNS 配置子節。
注意
"Default" 不是預設 DNS 策略。如果未明確指定 `dnsPolicy`,則使用 "ClusterFirst"。下面的示例顯示了一個 Pod,其 DNS 策略設定為 “`ClusterFirstWithHostNet`”,因為它的 `hostNetwork` 設定為 `true`。
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
Pod 的 DNS 配置
Pod 的 DNS 配置允許使用者對 Pod 的 DNS 設定進行更多控制。
`dnsConfig` 欄位是可選的,它可以與任何 `dnsPolicy` 設定一起使用。但是,當 Pod 的 `dnsPolicy` 設定為 “`None`” 時,`dnsConfig` 欄位必須指定。
以下是使用者可以在 `dnsConfig` 欄位中指定的屬性
- `nameservers`:將用作 Pod 的 DNS 伺服器的 IP 地址列表。最多可指定 3 個 IP 地址。當 Pod 的 `dnsPolicy` 設定為“`None`”時,列表必須至少包含一個 IP 地址,否則此屬性是可選的。列出的伺服器將與從指定的 DNS 策略生成的基名稱伺服器合併,並刪除重複地址。
- `searches`:Pod 中用於主機名查詢的 DNS 搜尋域列表。此屬性是可選的。指定時,提供的列表將合併到從選定的 DNS 策略生成的基搜尋域名中。重複域名將被刪除。Kubernetes 允許最多 32 個搜尋域。
- `options`:可選的物件列表,其中每個物件可能具有 `name` 屬性(必需)和 `value` 屬性(可選)。此屬性中的內容將合併到從指定的 DNS 策略生成的選項中。重複條目將被刪除。
以下是一個帶有自定義 DNS 設定的 Pod 示例
apiVersion: v1
kind: Pod
metadata:
namespace: default
name: dns-example
spec:
containers:
- name: test
image: nginx
dnsPolicy: "None"
dnsConfig:
nameservers:
- 192.0.2.1 # this is an example
searches:
- ns1.svc.cluster-domain.example
- my.dns.search.suffix
options:
- name: ndots
value: "2"
- name: edns0
當上述 Pod 被建立時,容器 `test` 的 `/etc/resolv.conf` 檔案中將包含以下內容
nameserver 192.0.2.1
search ns1.svc.cluster-domain.example my.dns.search.suffix
options ndots:2 edns0
對於 IPv6 設定,搜尋路徑和名稱伺服器應按如下方式設定
kubectl exec -it dns-example -- cat /etc/resolv.conf
輸出類似於:
nameserver 2001:db8:30::a
search default.svc.cluster-domain.example svc.cluster-domain.example cluster-domain.example
options ndots:5
DNS 搜尋域列表限制
Kubernetes 本身不對 DNS 配置進行限制,除非搜尋域列表的長度超過 32 或所有搜尋域的總長度超過 2048。此限制分別適用於節點的解析器配置、Pod 的 DNS 配置和合並的 DNS 配置。
注意
早期版本的某些容器執行時可能對 DNS 搜尋域的數量有自己的限制。根據容器執行時環境的不同,具有大量 DNS 搜尋域的 Pod 可能會停留在 pending 狀態。
已知 containerd v1.5.5 或更早版本以及 CRI-O v1.21 或更早版本存在此問題。
Windows 節點上的 DNS 解析
- 對於在 Windows 節點上執行的 Pod,不支援 `ClusterFirstWithHostNet`。Windows 將所有帶有 `.` 的名稱視為 FQDN,並跳過 FQDN 解析。
- 在 Windows 上,可以使用多個 DNS 解析器。由於它們的行為略有不同,建議使用 `Resolve-DNSName` powershell cmdlet 進行名稱查詢解析。
- 在 Linux 上,你有一個 DNS 字尾列表,當名稱作為完全限定名解析失敗後會使用該列表。在 Windows 上,你只能有一個 DNS 字尾,即與該 Pod 名稱空間關聯的 DNS 字尾(例如:`mydns.svc.cluster.local`)。Windows 可以解析 FQDN、Services 或可以透過此單一字尾解析的網路名稱。例如,在 `default` 名稱空間中生成的 Pod 將具有 DNS 字尾 `default.svc.cluster.local`。在 Windows Pod 內部,你可以解析 `kubernetes.default.svc.cluster.local` 和 `kubernetes`,但不能解析部分限定的名稱(`kubernetes.default` 或 `kubernetes.default.svc`)。
下一步
有關管理 DNS 配置的指導,請檢視配置 DNS 服務。