在 Kubernetes 環境中,服務發現和名稱解析至關重要。本文將詳細說明如何整合外部 DNS 與 CoreDNS,以實作動態服務註冊,確保服務名稱能被正確解析。此過程涉及使用 ETCD 作為 DNS 資訊儲存函式庫,並利用 external-dns 自動更新 DNS 紀錄。我們將逐步講解安裝 Helm、佈署 ETCD、組態 CoreDNS 和 external-dns,最後透過建立 LoadBalancer 服務驗證整個流程。

整合外部 DNS 與 CoreDNS 實作動態服務註冊

在 Kubernetes 叢集中,CoreDNS 提供了叢集內部的 DNS 名稱解析服務。然而,CoreDNS 的功能不僅限於此,它還能夠提供外部名稱解析,支援任何由 CoreDNS 佈署管理的 DNS 區域。

設定 external-dns

目前我們的 CoreDNS 只解析內部叢集名稱,因此需要為新的 DNS 條目建立區域。假設 FooWidgets 希望所有應用程式都位於 foowidgets.k8s 區域,我們將使用該區域作為新的 DNS 區域。

整合 external-dns 與 CoreDNS

要提供動態服務註冊功能給叢集,最後一步是佈署並整合 external-dns 與 CoreDNS。為了組態 external-dns 和 CoreDNS 在叢集中協同工作,需要設定兩者都使用 ETCD 來管理新的 DNS 區域。由於我們的叢集使用 KinD 並預裝了 ETCD,我們將佈署一個新的 ETCD Pod,專門用於 external-dns 區域。

安裝 Helm 與佈署 ETCD

首先,需要安裝 Helm 二進位制檔案。可以使用 Helm 團隊提供的指令碼快速安裝 Helm:

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh

接著,使用 Helm 建立 ETCD 叢集:

helm install etcd-dns --set customResources.createEtcdClusterCRD=true stable/etcd-operator --namespace kube-system

這個命令將佈署 ETCD Operator 並建立一個三節點的 ETCD 叢集。

#### 內容解密:

此步驟中,我們使用了 Helm 來安裝 ETCD Operator 和建立 ETCD 叢集。Helm 是 Kubernetes 的套件管理器,可以簡化應用程式的佈署和管理。ETCD Operator 可以自動化 ETCD 叢集的管理工作。

檢視 ETCD 佈署狀態

佈署完成後,可以透過檢視 kube-system 名稱空間中的 Pod 狀態來檢查 ETCD Operator 和節點的狀態:

kubectl get pods -n kube-system

成功佈署後,將看到三個 ETCD Operator Pod 和三個 ETCD 叢集 Pod。

取得 ETCD 服務 IP

佈署完成後,檢視 kube-system 名稱空間中的服務,以取得新建立的 ETCD 服務的 IP 地址:

kubectl get svc -n kube-system

找到名為 etcd-cluster-client 的服務,並記錄其 IP 地址。

#### 內容解密:

此步驟中,我們需要找到 etcd-cluster-client 服務的 IP 地址,以便在後續步驟中組態 external-dns 和 CoreDNS。

新增 ETCD 區域至 CoreDNS

external-dns 需要 CoreDNS 將區域儲存在 ETCD 伺服器上。編輯 CoreDNS 的 ConfigMap,並新增以下組態:

apiVersion: v1
data:
  Corefile: |
    .:53 {
        errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
            ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf
        etcd foowidgets.k8s {
            stubzones
            path /skydns
            endpoint http://<ETCD_SERVICE_IP>:2379
        }
        cache 30
        loop
        reload
        loadbalance
    }
kind: ConfigMap

<ETCD_SERVICE_IP> 替換為之前取得的 ETCD 服務 IP 地址。

#### 內容解密:

此步驟中,我們在 CoreDNS 的 ConfigMap 中增加了 etcd 外掛的組態,以啟用對 foowidgets.k8s 區域的支援。endpoint 欄位需要填入 ETCD 服務的 IP 地址和埠。

佈署 external-dns

使用以下命令佈署 external-dns:

ETCD_URL=$(kubectl -n kube-system get svc etcd-cluster-client -o go-template='{{ .spec.clusterIP }}')
cat external-dns.yaml | sed -E "s/<ETCD_URL>/${ETCD_URL}/" > external-dns-deployment.yaml
kubectl apply -f external-dns-deployment.yaml

或者,手動建立 external-dns-deployment.yaml 檔案,並填入正確的 ETCD 服務 IP 地址:

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: external-dns
rules:
- apiGroups: [""]
  resources: ["services","endpoints","pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions"]
  resources: ["ingresses"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
- kind: ServiceAccount
  name: external-dns
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
  namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
  namespace: kube-system
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: registry.opensource.zalan.do/teapot/external-dns:latest
        args:
        - --source=service
        - --provider=coredns
        - --log-level=info
        env:
        - name: ETCD_URLS
          value: http://<ETCD_SERVICE_IP>:2379

<ETCD_SERVICE_IP>替換為正確的 ETCD服務IP 位址。

#### 內容解密:

此步驟中,我們佈署了 external-dns,它將監控 Kubernetes 中的服務變化,並自動更新 CoreDNS 中的 DNS 紀錄。ETCD_URLS 環境變數需要填入正確的 ETCD服務 URL。

使用 external-dns 建立 LoadBalancer 服務

在 Kubernetes 中,external-dns 可以與 LoadBalancer 服務整合,實作動態 DNS 註冊。本文將介紹如何建立一個具有 external-dns 整合的 LoadBalancer 服務。

步驟 1:建立 nginx-dynamic.yaml 檔案

首先,建立一個名為 nginx-dynamic.yaml 的檔案,並新增以下內容:

apiVersion: v1
kind: Service
metadata:
  annotations:
    external-dns.alpha.kubernetes.io/hostname: nginx.foowidgets.k8s
  name: nginx-ext-dns
  namespace: default
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    run: nginx-web
  type: LoadBalancer

內容解密:

  • external-dns.alpha.kubernetes.io/hostname 註解指定了要建立的 DNS 記錄名稱,即 nginx.foowidgets.k8s
  • namenamespace 指定了服務的名稱和名稱空間。
  • spec 部分定義了服務的埠、協定和目標埠,以及選擇器和服務型別。

步驟 2:應用 nginx-dynamic.yaml 檔案

使用以下命令應用 nginx-dynamic.yaml 檔案:

kubectl apply -f nginx-dynamic.yaml

external-dns 將在約一分鐘內檢測到 DNS 更改。

步驟 3:驗證 DNS 記錄建立

使用以下命令檢查 external-dns pod 日誌:

kubectl logs -n kube-system -l app=external-dns

如果 DNS 記錄已建立,您將看到類別似以下的輸出:

time="2020-04-27T18:14:38Z" level=info msg="Add/set key /skydns/k8s/foowidgets/nginx/03ebf8d8 to Host=172.17.201.101, Text=\"heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/nginx-lb\", TTL=0"

內容解密:

  • 日誌輸出表明 external-dns 已建立了 DNS 記錄。
  • Host 欄位顯示了分配給服務的 IP 地址。

步驟 4:測試連線

執行一個 Netshoot 容器:

kubectl run --generator=run-pod/v1 tmp-shell --rm -i --tty --image nicolaka/netshoot -- /bin/bash

在 Netshoot 容器中,使用 nslookup 命令驗證 DNS 記錄:

nslookup nginx.foowidgets.k8s

輸出應顯示 DNS 記錄已成功建立。

將 CoreDNS 與企業 DNS 整合

本文將介紹如何將 CoreDNS 與企業 DNS 服務整合。

組態主 DNS 伺服器

在 Windows DNS 主機上,建立一個條件轉發器,將 foowidgets.k8s 域的請求轉發到執行 CoreDNS pod 的主機。

測試 DNS 轉發

使用一台組態為使用 Windows DNS 伺服器的工作站,執行 nslookup 命令測試 DNS 解析:

nslookup nginx.foowidgets.k8s

輸出應顯示正確的 IP 地址。

將 Kubernetes 叢集與企業驗證整合

在大多數企業環境中,確保使用者能夠安全地與 Kubernetes 叢集互動至關重要。這意味著需要對個別使用者進行驗證,並確保他們只能存取執行工作所需的資源。Kubernetes 提供了多種驗證選項,包括 OpenID Connect(OIDC)協定和 Kubernetes 偽裝功能。

Kubernetes 如何識別使用者身份

在 Kubernetes 中,使用者並不存在於系統中,除了服務帳戶外,沒有所謂的「User」或「Group」物件。每個 API 互動都必須包含足夠的資訊,以告知 API 伺服器使用者的身份以及所屬群組。這種斷言可以根據整合驗證的方式採用不同的形式。

OIDC 驗證流程

  1. 理解 OpenID Connect:OIDC 是一種建立在 OAuth 2.0 之上的驗證協定,能夠提供安全的驗證機制。Kubernetes 可以組態為使用 OIDC 進行使用者驗證。

  2. 組態 KinD 以使用 OIDC:若要將 KinD 叢集組態為使用 OIDC,需要進行一系列設定,包括設定 OIDC 發行者 URL、使用者名稱宣告等。

  3. 偽裝組態:Kubernetes 的偽裝功能允許管理員以其他使用者的身份執行操作,這對於測試和除錯非常有用。

組態 KinD 以使用 OIDC

步驟一:建立 KinD 叢集

首先,需要使用 KinD 建立一個 Kubernetes 叢集。可以使用以下命令建立叢集:

kind create cluster --config kind-config.yaml

步驟二:組態 OIDC

接下來,需要組態 Kubernetes API 伺服器以使用 OIDC。這涉及修改 API 伺服器的組態,以包含 OIDC 發行者 URL 和其他必要的設定。

apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
apiServer:
  extraArgs:
    oidc-issuer-url: "https://oidc.example.com"
    oidc-client-id: "kubernetes"
    oidc-username-claim: "email"

#### 內容解密:

此 YAML 組態片段用於定義 Kubernetes 叢集的 API 伺服器組態。其中,oidc-issuer-url 指定了 OIDC 發行者的 URL,oidc-client-id 指定了客戶端 ID,而 oidc-username-claim 指定了用於使用者名稱的宣告。

常見問題與解答

  1. 服務如何知道哪些 Pod 應該用作服務的端點?

    • 答案:D. By the selector label
  2. 哪個 kubectl 命令有助於排查可能無法正常運作的服務?

    • 答案:B. kubectl get ep <service name>
  3. 所有 Kubernetes 發行版都支援使用 LoadBalancer 型別的服務。

    • 答案:B. False
  4. 哪種型別的負載平衡器支援所有 TCP/UDP 連線埠並接受流量,而不管封包內容如何?

    • 答案:D. Layer 4
  5. 在沒有新增元件的情況下,您可以使用下列哪種服務型別來支援多種協定?

    • 答案:C. NodePort, LoadBalancer, 和 ClusterIP