iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 15
0

K8s提供兩種內建的雲端負載均衡機制(cloud load balacing), 一個是工作在傳輸層的TCP負載均衡器:Service; 另一個是HTTP(S)負載均衡器:Ingress。這邊會分為兩天來介紹!

Service

在K8s中負責處理實際邏輯的是Pod, 每個Pod都有自已的Pod IP, 透過Deployment部署擴縮容或是任何原因造成Pod變動時會異動Pod IP, 此時client端如果不重新綁定IP將無法有效利用新的Pod, Service就是為了解決這個狀況而設計的; Service是K8s核心之一, 主要用於為同一組Pod集合提供統一的代理接口, 讓所有請求Pod服務的連線可以透過Service分別打到不同的Pod上面, 做到LoadBalance, Service透過LabelSelector來關聯Pod, 一個label對應一組Pod集合, client端對Service 發起請求時, Service 會調度請求到關聯的Pod集合中的其中一個Pod, client端看起來只有對Service操作請求, Service 代理Pod並調度流量的部分以及Pod上面的處理細節並不會暴露出去。實際觀察, Service 本身是不提供服務的, 提供服務的是Pod, Service需要和Pod Controller 合作才能完成請求的任務。

https://ithelp.ithome.com.tw/upload/images/20200921/20129656QSdP3f8u93.png

  • ClusterIP
    Service 的 IP也稱為 ClusterIP, 是Sevice創建時由K8s cluster 配置在專用區段的虛擬IP, 且創建後就不會再改變。ClusterIP能夠被同一cluster的Pod訪問。

  • Port Proxy
    Service 端口用於接收client請求再轉發至Pod上面對應的端口, 這種代理機制稱為Port Proxy或四層代理, 它運作在TCP/IP protocal 的傳輸層。

  • Service-Endpoints-Pod
    Service與Pod之間透過LabelSelector以鬆耦合的方式建立關係, Service可以比Pod早建立, 也可以由不同的client建立, 每個Node上的kube-proxy會透過API Server watch 隨時監控Service或LabelSelector匹配的Pod對象是否有變動, 例如: IP 改變, Pod 增加或減少, 然後再將這些異動隨時更新Endpoints。
    在Service創建時, 預設也會建立一份Endpoints, Endpoints是由LabelSelector匹配出來的Pod的IP和端口組成的列表, 實際上Service是透過Endpoints連結到Pod, 它是Service和Pod的中間層。

可以把Service視為Node上的iptables或ipvs規則的定義, client端的請求送到Service之後會透過Endpoints 中的IP和端口轉發到對應的Pod上面, 在工作節點上的kube-proxy對隨時透過API Server watch Service跟Pod的異動, 再把異動反映到iptables或ipvs規則。

服務代理

kube-proxy 將請求代理到對應端口的代理模式有三種:

  • userspace:
    https://ithelp.ithome.com.tw/upload/images/20200922/20129656GOKywBpf4k.png

    由於這個模式中用戶的請求會在內核空間和用戶空間之間來回轉發, 使得效率變得很差, 所以已經不建議使用了!
    userspace指的是Linux用戶空間的意思, userspace代理的方式是透過 kube-proxy 監控API Server上的Service和Endpoints的變化後, 再去調整Service的定義。 它會隨機打開一個Service本地端口, 把接到的請求代理轉接到後面的Pod,而Service預設是使用輪詢(round-robin)的方式調度Pod, 這類的Service會創建iptables規則來捕捉ClusterIP和Port的流量。

  • iptables:
    https://ithelp.ithome.com.tw/upload/images/20200922/20129656uj6z2luwDn.png

    iptables代理方式是透過 kube-proxy 監控API Server上的Service和Endpoints的變化後, 再去調整Service的定義(和userspace一樣)。
    它在每一個Service創建時都會把iptables資訊送到kube-proxy做為Service的定義, 每個Service上都有一份iptables , 所以可以直接捕捉ClusterIP 和Port的流量, 再把請求代理轉接到後面的Pod, 採用的調度方式是隨機(random), 由於不需要在內核空間和用戶空間之間轉發, 所以效率比userspace好很多, 但缺點是當後面的Pod無回應的時候他不會重新定向, userspace可以重新定向!

  • ipvs:
    https://ithelp.ithome.com.tw/upload/images/20200922/20129656n2792s6DDB.png

    ipvs代理方式是透過 kube-proxy 監控API Server上的Service和Endpoints的異動後, 再根據異動調用netlink接口創建ipvs規則並確保與API Server的異動保持同步。和iptables不同的地方在於調度流量是透過ipvs, ipvs建構在netlink的鉤子函數上, 他使用hash table做為底層數據結構, 並支援多種調度算法,且是在內核空間運作的, 所以她轉發流量的速度快, 規則同步也快。

創建 Service

Service spec 常用字段為selectorports , 分別定義使用的LabelSelector和要暴露的Port。

  • 創建YAML

    apiVersion: v1
    kind: Service
    metadata:
      name: svc-demo
    spec:
      selector:
        app: svc-demo
      ports:
      - protocol: TCP
        port: 80
        targetPort: 80
    

    Service 會透過標籤選擇器關聯到標籤為 svc-demo 的對象,並會自動創建名稱爲 svc-demo 的Endpoint。

  • 查看Service

      -> % kubectl get svc svc-demo
      NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
      svc-demo     ClusterIP   10.103.226.230   <none>        80/TCP    10m
    

Service 類型

K8s Service 有四種類型:ClusterIP,NodePort,LoadBalancer,ExternalName

ClusterIP

透過內部IP地址暴露服務, 此IP只有內部可以使用, 無法被cluster外部的client訪問。

NodePort

在工作節點的IP地址上選擇一個端口來將外部請求轉發到目標Service的clusterIP 和Port, 所以這個類型的Service可以向ClusterIP一樣收到內部Pod訪問, 也可以收到外部Client :的請求。

https://ithelp.ithome.com.tw/upload/images/20200922/20129656e8l6ZfCFTj.png

  • NodePort 就是節點Port, 是K8s部署時預留的端口範圍, 預設是 30000~32767

LoadBalancer

LoadBalancer 類型的Service會指向k8s cluster外部的一個實際存在的負載均衡設備, 該設備會透過工作節點上面的NodePort向K8s內部發送請求

https://ithelp.ithome.com.tw/upload/images/20200922/20129656SkTaiw56Le.png

  • NodePort類型的Service雖然能在cluster外部被訪問, 但是client還是需要事先知道至少一個Node的IP地址, 且選定的Node故障時, client端也需要同時更換對應的IP地址, 或者NodeIP可能是雲端讓使用的私有IP, 這類型的IP無法在網路上訪問到, 因為上述兩種原因, 所以雲端商的IaaS環境通常都會提供一個LBaaS(Load Balancer as a Service)服務, 允許用戶可以動態的在自己的網路中創建一個負載均衡的設備。

  • 在IaaS環境手動指定IP地址時, 可以使用spec.loadBalancerIP 指定負載均衡設備的IP地址, 也可使用spec.oadBalancerSourceRanges 指定負載均衡設備允許的client IP地址範圍。

ExternalName

ExternalName 不是K8s cluster提供的服務, 而是把cluster外部的服務以DNS CNAME的方式映射到cluster中, 讓cluster內部的Pod能夠訪問到外部Service的實現方式。

https://ithelp.ithome.com.tw/upload/images/20200922/20129656GNnqrZTrNr.png

  • ExternalName 不需要使用LabelSelector關聯任何Pod對象, 但必須使用spec.externalName 屬性定義一個CNAME用於返回外部真正提供服務的主機別名, 然後再透過CNAME 的紀錄取得相關主機的IP地址

  • ExternalName 實現於 DNS級別, client直接接入外部的服務而不需要服務代理, 所以也不需要配置ClusterIP, 此類型的服務也稱為Headless Service

Headless Service

client有需求需要直接訪問Service後面的額Pod時, 就需要暴露每個Pod的IP地址,Client不會使用Service的ClusterIP, 這種類型的Service稱為Headless Service
如果要為這類型的Service配置IP地址, 要看有沒有定義LabelSelector:

  • 有標籤選擇器:
    Endpoints Controller 會在API中建立Endpoints紀錄, 再把ClusterDNS服務中的紀錄解析到Pod的IP地址上

  • 沒有標籤選擇器:
    Endpoints Controller 不會在API中建立Endpoints紀錄, ClusterDNS的配置會分成兩種:

    1. 對ExternalName Service 創建CNAME紀錄
    2. 其餘的會針對共享名稱的Endpoints創建一筆紀錄

創建 Headless Service

  • 創建YAML

    -> % cat headless-svc.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: headless-demo
    spec:
      clusterIP: None
      selector:
        app: deploy-demo
      ports:
      - port: 80
        targetPort: 80
        name: httpport
    
  • 查看結果

    -> % kubectl get service
    NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    headless-demo   ClusterIP   None         <none>        80/TCP    3s
    
  • 查看Endpoints 狀況
    https://ithelp.ithome.com.tw/upload/images/20200923/201296561vAT5zsgWv.png

補充 Kubernetes IP

  • Pod IP:
    • Private IP
    • Pod 在cluster的專屬地址,在同叢集內、不同節點皆可連線
  • ClusterIP:
    • Private IP
    • Service 在叢集內的專屬地址,僅可在叢集內使用
  • Node IP:
    • 根據不同狀況可為 Public or Private IP
    • 節點 IP
  • LoadBalancer IP:
    • Public IP
    • 雲端商給該服務的對外IP

今日小結

明天來讀Ingress。


上一篇
day 14 Pod Controller(4) - Job , CronJob & PodDisruptionBudget
下一篇
day 16 Service and Ingress(2)- Ingress
系列文
K8S - 30天從擦槍到提槍上陣學習筆記。30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言