iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
0

前面章節講過的 Service,提供了一個穩定可讓客戶端取得想要的服務接口,這之間 POD 如何知道某特定服務的 IPPort 呢?這就需要服務發現(Service Discovery) 的幫助。我們也知道在 K8s 環境中,POD 不能依靠網路,當服務重新部署時,會導致 IP 不同,因此需要借助服務發現。服務發現簡單來說就是是弄清楚如何連接到服務的實際過程。

環境變數的服務發現

Service 環境變數

只要創建 Service 都會使用以下的環境變數,當在同一 namespacePOD 會自動擁有這些資訊。可參考官網 container-environment

  • {SVCNAME}_SERVICE_HOST
  • {SVCNAME}_SERVICE_PORT
$ kubectl exec httpd-7765f5994-97hq5 -- printenv
PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=httpd-7765f5994-97hq5
MYAPP_SVC_PORT_80_TCP_ADDR=10.8.2.52
MYAPP_SVC_SERVICE_HOST=10.8.2.52 # this
KUBERNETES_PORT_443_TCP_ADDR=10.8.0.1
MYAPP_SVC_PORT_80_TCP_PORT=80
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
MYAPP_SVC_PORT_80_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.8.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.8.0.1:443
MYAPP_SVC_SERVICE_PORT=80 # this
MYAPP_SVC_PORT=tcp://10.8.2.52:80
MYAPP_SVC_PORT_80_TCP=tcp://10.8.2.52:80
...

Docker Link 方式環境變數

這邊我在 GCP 上的 Compute Engine 拿一個節點的容器用 docker inspect 觀察。

$ docker inspect 203e907bf5ba
"Env": [
                "MYAPP_SVC_PORT=tcp://10.8.2.52:80",
                "MYAPP_SVC_PORT_80_TCP_PROTO=tcp",
                "KUBERNETES_SERVICE_PORT=443",
                "KUBERNETES_SERVICE_PORT_HTTPS=443",
                "KUBERNETES_PORT=tcp://10.8.0.1:443",
                "KUBERNETES_PORT_443_TCP=tcp://10.8.0.1:443",
                "KUBERNETES_SERVICE_HOST=10.8.0.1",
                "KUBERNETES_PORT_443_TCP_PROTO=tcp",
                "MYAPP_SVC_SERVICE_PORT=80",
                "MYAPP_SVC_PORT_80_TCP=tcp://10.8.2.52:80",
                "MYAPP_SVC_PORT_80_TCP_PORT=80",
                "KUBERNETES_PORT_443_TCP_PORT=443",
                "KUBERNETES_PORT_443_TCP_ADDR=10.8.0.1",
                "MYAPP_SVC_SERVICE_HOST=10.8.2.52",
                "MYAPP_SVC_PORT_80_TCP_ADDR=10.8.2.52",
                "PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "HTTPD_PREFIX=/usr/local/apache2",
                "HTTPD_VERSION=2.4.46",
                "HTTPD_SHA256=740eddf6e1c641992b22359cabc66e6325868c3c5e2e3f98faf349b61ecf41ea",
                "HTTPD_PATCHES="
            ],

但是,在不同 namespace、或是 PODService 部署順序不同時,環境變數方式將是一個缺點,然而 DNS 可以解決這個問題。

DNS 服務發現

Kubernetes 上在安裝環境時,有一個 CoreDNS,是一個非常重要的元件之一,它會負責將 Service 資源等轉成資源紀錄(Resource Record)。在預設下 POD 的資源紀錄也會被自動的配置,當中資源紀錄會包含 namespace 等資訊。下面是從官方Kubernetes DNS 規格定義,所節錄。

  • Service 類型為 ClusterIP 的資源紀錄
    • A Record
      • <service>.<ns>.svc.<zone>. <ttl> IN A <cluster-ip>
    • SRV Record
      • _<port>._<proto>.<service>.<ns>.svc.<zone>. <ttl> IN SRV <weight> <priority> <port-number> <service>.<ns>.svc.<zone>
    • PTR Record
      • <d>.<c>.<b>.<a>.in-addr.arpa. <ttl> IN PTR <service>.<ns>.svc.<zone>
  • Service 類型為 Headless 的資源紀錄
    • A Record
      • <service>.<ns>.svc.<zone>. <ttl> IN A <endpoint-ip>
    • SRV Record
      • _<port>._<proto>.<service>.<ns>.svc.<zone>. <ttl> IN SRV <weight> <priority> <port-number> <hostname>.<service>.<ns>.svc.<zone>
    • PTR Record
      • <d>.<c>.<b>.<a>.in-addr.arpa. <ttl> IN PTR <hostname>.<service>.<ns>.svc.<zone>
  • Service 類型為 ExternalName 的資源紀錄
    • CNAME Record
      • <service>.<ns>.svc.<zone>. <ttl> IN CNAME <extname>

SRV 相較於其它資源類型它記錄了 Port

只要我們創建 Service 資源,DNS 會做服務解析和服務註冊的動作,這樣可讓 POD 使用 DNS 方式去請求 Service。每個 Service 會包含以下兩個資源紀錄。在安裝 K8s 環境時可設定 DNS 相關資訊,否則默認把 cluster.local. 和主機所在的域名做為本地用。

  • {SVCNAME}.{NAMESPACE}.{CLUSTER_DOMAIN}
  • {SVCNAME}.{NAMESPACE}.svc.{CLUSTER_DOMAIN}

這邊觀察 GKE 上部署的一個 POD 它的 DNS 相關設置。也就是說服務的查詢都會導向該 CoreDNSService 上。

$ kubectl exec hello-kubernetes-5b89dbbc4b-t7bvr -- cat /etc/resolv.conf
nameserver 10.8.0.10 
search default.svc.cluster.local svc.cluster.local cluster.local us-central1-c.c.sunny-catwalk-286908.internal c.sunny-catwalk-286908.internal google.internal
options ndots:5
$ kubectl get svc -n kube-system # 系統上的 DNS 系統 
NAME                   TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)         AGE
...
kube-dns               ClusterIP   10.8.0.10     <none>        53/UDP,53/TCP   18d
...
  • nameserver
    • kube-dnsService 資源
  • default.svc.cluster.local
    • {NAMESPACE}.svc.{CLUSTER_DOMAIN}
  • svc.cluster.local
    • svc.{CLUSTER_DOMAIN}

我們進到一個可交互的 POD 並使用 nslookup 查詢 myapp-svc 的域名 myapp-svc.default.svc.cluster.local,發現解析出來的就是該 ServiceIP

$ kubectl exec -it hello-kubernetes-5b89dbbc4b-t7bvr /bin/sh
~ $ nslookup myapp-svc.default.svc.cluster.local
Server:         10.8.0.10
Address:        10.8.0.10:53

Name:   myapp-svc.default.svc.cluster.local
Address: 10.8.2.52
$ kubectl get svc myapp-svc
NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
myapp-svc   ClusterIP   10.8.2.52    <none>        80/TCP    2d1h

這是基於 SRV 做查詢格式為 _PORT-NAME._PROTOCOL.SERVICE-NAME.NAMESPACE.svc.cluster.local

$ nslookup _http._tcp.myapp-svc.default.svc.cluster.local
Server:         10.8.0.10
Address:        10.8.0.10:53

_http._tcp.myapp-svc.default.svc.cluster.local  canonical name = myapp-svc.default.svc.cluster.local
Name:   myapp-svc.default.svc.cluster.local
Address: 10.8.2.52

對於 POD 解析格式為 POD-IP-ADDRESS.NAMESPACE.pod.cluster.loscal,這邊是看官網一些用法都在裡面

$ nslookup 10-4-2-53.default.pod.cluster.local
Server:         10.8.0.10
Address:        10.8.0.10:53


Name:   10-4-2-53.default.pod.cluster.local
Address: 10.4.2.53

POD DNS

因為 POD 對於 DNS 可能有不同的需求,因此也提供設定方式,這邊可直接參考官方

  • Default
    • 不需設定,同步於節點的 nameserver
  • ClusterFirst
    • 預設值
    • 使用 cluster DNS 做為設定,資訊如下
$ kubectl exec hello-kubernetes-5b89dbbc4b-t7bvr -- cat /etc/resolv.conf
nameserver 10.8.0.10 
search default.svc.cluster.local svc.cluster.local cluster.local us-central1-c.c.sunny-catwalk-286908.internal c.sunny-catwalk-286908.internal google.internal
options ndots:5
  • ClusterFirstWithHostNet
    • hostNetwork 為與主機的網路 namespace 共享時,又想使用 cluster DNS 做為設定
  • None
    • 不設定 DNS 相關資訊
    • 需使用 dnsConfig 字段來設定 DNS 相關資訊

參考資源


上一篇
Service 資源應用 part02
下一篇
K8s 8s 的儲存
系列文
我真的覺得認為 K8s 到底在火什麼30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言