iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 21
0
DevOps

Docker獸 究極進化 ~~ Kubernetes獸系列 第 21

Day-21 尋覓 Service、kube-dns 與 kube-proxy

前言

Day-19中我們提到了Pod, ReplicaSet與Deployment,也知道了如何將我們的containers轉換成Pod,利用並共享同個Pod的資源。但截至目前為止的我們所學都只局限在Pod的自身,我們尚未知道Pod與Pod之間如何溝通,也不清楚外界如何將request送至我們叢集內部的Pod當中。
這些問題都會在未來兩章節中解答!

What is Service in Kubernetes?

簡單來說Service就是通往Pod的通道,在撰寫Service時需要透過labels指定Service所Mapping的對象,當Service收到requests時,會將request redirect到有這個labels的Pod當中。

因為Pods的數量是不固定的,而且每有Pod被新建或刪除,它們的IP都會改變。但有了Service的存在,我們只要把requests送至Service,他就會自動幫我們做負載平衡並將requests送至Pod當中。

所以

  1. Client可以透過ingress / loadbalaner 找到特定Service(下個篇章會介紹ingress & loadbalancer)。
  2. Service在透過配對標籤找到相對應的Pod,負載平衡並將requests送給Pod。
  3. 不同Pod間也可以彼此透過Service來互相溝通。

https://ithelp.ithome.com.tw/upload/images/20201006/20129737iugRqP9HqD.png

How the Service Works?

  • 創建Service並Mapping到Pod。
  • Kube-proxy會紀錄該Service與其配對標籤的Pod的address。
  • 每當我們透過api server(無論是endpoint 或是 kubectl)對Pod或Service進行修改時,只要ip address有變化,都會紀錄在kube-proxy。
  • 每當有requests進來時(無論從外部或內部),會依據需求先到service,之後透過kube-proxy的mapping與service的負載平衡,找出request要去的pod。

https://ithelp.ithome.com.tw/upload/images/20201006/20129737RucbvL8eCd.png

Types of Service port

在Service中有著三個不同的port對應著不同的接口,分別是NodePort、Port以及TargetPort。並對接著不同的IP,External IP、Cluster IP與Pod IP

Service IP

會透過service進行其他pod服務存取的使用者有兩者,分別為k8s集群外部使用者與集群內部的其他pod,儘管兩者想存取的路徑都相同,但仍然存在著一個關鍵差異在於: 存取ip不同。

https://ithelp.ithome.com.tw/upload/images/20201006/201297376GmtM3Trtr.png

External IP

裸露的網路位址,供外部使用者存取。對應到service上的nodePort。

<EXTERNAL-IP>:<nodePort>

Cluster IP

叢集內部的網路位址,供內部使用者存取。對應到service上的port。Cluster IP為虛擬靜態IP,當物件被產生時,會一併產生Cluster IP並且在物件被刪除前不在改變。

<CLUSTER-IP>:<port>

Pod IP

每個pod獨有的網路位址,只有叢集內可以連線。對應到service上的targetPort。

<targetPort>

https://ithelp.ithome.com.tw/upload/images/20201006/20129737wJWd0Y443C.jpg

Parse service yaml

那這邊我們一樣,寫一個對接ClusterIP的Service,後面在來解析這個yaml。

kind: Service
apiVersion: v1
metadata:
  name: ironman
  labels:
    app: ironman
spec:
  type: ClusterIP
  ports:
    - name: ironman
      protocol: TCP
      port: 80
      targetPort: 80
  selector:
    app: ironman

Deploy

$ kubectl apply -f service.yaml
service/ironman created
$ kubectl get service ironman
NAME      TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
ironman   ClusterIP   10.4.10.250   <none>        80/TCP    45s

apiVersion

apiVersion 是代表目前 Kubernetes 中該元件的版本號。以上述的例子 Pod 是 v1,而 v1也是目前Kubernetes中核心的版本號。在日後也會陸續看到 betav1, v1alpha1 等版本號,更多 Kubernetes API 的版本號,可至 官網 API versioning查看。

kind

描述該物件的屬性,常見屬性有Pod、Node、Service、Namespace、ReplicationController....etc

metadata

在 metadata 中,有三個重要的 Key,分別是 name, labels, annotations。

metadata.name

我們可以在 metadata.name 的欄位指定這個 Pod 的名稱,這裡 Pod 的名稱就是 my-pod

metadata.labels

metadata.labels 是 Kubernetes 的是核心的元件之一,Kubernetes 會透過 Label Selector 將Pod分群管理。

metadata.annotations

annotations 的功能與 labels 相似。相較於labels,annotations 通常是使用者任意自定義的附加資訊,提供外部進行查詢使用,像是版本號,發布日期等等。

spec

spec.type

可以指定Service的型別,可以是ClusterIP type(default)、NodePort與LoadBalancer。

  1. ClusterIP: 通過集群內部IP的方式來曝露服務,只有集群內能訪問。
  2. NodePort: kube-proxy 中的 --nodeport-addresses標誌設為特定IP,若無指定的話則隨機從30000-32767找一尚未使用端口,並導向該端口流量至指定Pod。
  3. LoadBalancer:會異步地創建負載平衡器,並透過負載平衡器所綁定的外部IP來導流外部訪問的流量。

spec.ports.port

可以指定,創建的Service的Cluster IP(for 內部使用者),是哪個port number去對應到targetPort

spec.ports.nodePort

可以指定,創建的Service的External IP(for 外部使用者),是哪個port number去對應到nodePort。

另外,Service可以指定的nodePort只有30000~32767

spec.ports.targetPort

targetPort很好理解,targetPort是pod上的端口,從port與nodePort進來的requests,最終會經由kube-proxy流入後端pod的targetPort上進入容器。

spec.ports.protocol

目前service僅支援TCP與UDP兩種protocol,預設為TCP

spec.selector

selector會幫我們將特定port number收到的流量去導向標籤app為該標籤的pod。

Kube-Proxy

  • Kube-Proxy在每個Node上運行著,並且執行TCP、UDP、SCTP流量的轉發。

Iptables

  • Kube-Proxy在Node上會藉由Iptables撰寫規則,並進行轉發。相對的Service越多,Iptables規則也會越多。
  • Kube-Proxy使用Iptables進行轉發時,Performance為O(n),所以當service越多時,Performance會越差
  • Kubernetes預設為使用iptables進行轉發。

Ipvs

Ipvs是一個用於負載平衡的Linux kernal features。

  • IPvS是藉由一套優化過的API,藉由大量的負載平衡演算法來進行轉發。
  • IPvS的Performance為O(1),所以大部分時間下,它的Performance與Cluster的規模無關。
  • 但由於IPvS與IpTables的Routing rules不同,所以在並用時必須謹慎小心。

Kube-DNS

每個在kubernetes的pod或是service在創建時,都會在一個名為kube-dns的pod當中記錄每個pod/service所mapping到的dns,而該dns的name是自動創建的。因此在內部kubernetes cluster當中,pod與pod之間的溝通可以透過該dns連到所需溝通之pod的service dns。

DNS組成

<service_name>..svc.cluster.local

我們先藉由commnad來看一下dns

$ **kubectl exec -it ironman-6d655d444d-jwf4b -c ironman bash                                                                                            3010  14:33:48
$ cat /etc/resolv.conf
nameserver 10.4.0.10
search default.svc.cluster.local svc.cluster.local cluster.local asia-east1-a.c.oval-compass-290412.internal c.oval-compass-290412.internal google.internal
options ndots:5**

這邊的default.svc.cluster.local就是dns的postfix

測試DNS

我們先建立一個臨時的curl pod。

$ kubectl run --rm --generator=run-pod/v1 curl --image=radial/busyboxplus:curl -i --tty

那我們再來就GET看看上面所建立的service ironman吧

$ curl -X GET http://ironman.default.svc.cluster.local:80/v1/hc
{"message": "This endpoint for web service health check"}

那到這邊我們就確定kube-dns確實能work了,之後cluster內部的轉發也能全部透過kube-dns來實現。

Github Repo

本篇章所有程式碼將放在下面的github project當中的branch day-21

https://github.com/Neskem/ironman_2020/tree/day-21

後記

這邊我們學習了如何撰寫cluster IP的service,並且也學習了kube-proxy的原理與kube-dns的運用,這也讓我們在叢集內部的流量遞送更如虎添翼。那在下個章節我們會學習如何透過loadbalancer與ingress從外部與Pod進行溝通。
https://ithelp.ithome.com.tw/upload/images/20201006/201297376VtVTs7QWw.png

https://ithelp.ithome.com.tw/upload/images/20201006/20129737uKHHEweDaP.png

Reference

https://kubernetes.io/docs/concepts/services-networking/service/


上一篇
Day-20 使用ConfigMap 與 Secret
下一篇
Day-22 活用LoadBalancer and Ingress
系列文
Docker獸 究極進化 ~~ Kubernetes獸30

尚未有邦友留言

立即登入留言