k8s service(kube-proxy)


kube-proxy和service

kube-proxy 是k8s中的組件之一,是以Pod 形式真實運行的進程,而service 是它的代理功能的具體實現,service 是k8s 中一種資源類型,里面定義的是集群Pod 的訪問轉發規則。

存在的意義

1、pod 是短暫的-它們隨時會啟動或者關閉, 無論是為了給其他 pod 提供空間而從節點中被移除, 或者是減少了 pod 的數量, 又或者是因為集群中存在節點異常。
 
2、Kubernetes 在 pod 啟動前會給已經調度到節點上的pod 分配 IP 地址----因此客戶端不能提前知道提供服務的 pod 的 IP 地址。
 
3、水平仲縮意味着多個 pod 可能會提供相同的服務每個 pod 都有自己的 IP地址, 客戶端無須關心后端提供服務 pod 的數量, 以及各自對應的 IP 地址。它們無須記錄每個 pod 的 IP 地址。 相反, 所有的 pod       可以通過一個單一的IP 地址進行訪問。
 
為了解決上述問題, Kubemetes 提供了一種資源類型一服務 (service),一個service 對應一個服務,每個后端服務都有一個端口,service 通過映射內部服務端口對外提供訪問,每個服務運行一組pod 。

service 作用

服務發現(防止pod 失聯)

負載均衡(輪詢轉發請求到后端集群中的pod)

service與Pod 關聯

兩種方式

1、service 通過標簽選擇器selector 關聯pod 的標簽,找到pod 。

2、service 通過關聯deployment 等資源,通過deployment 等資源間接關聯pod。注意寫yaml文件創建service 關聯deployment 通過標簽選擇器配置成 selector: app: pay 形式關聯的是pod 的標簽不是                      deployment   的標簽,可以通過expose命令關聯dep資源創建service。

service 的三種形式

ClusterIP  

集群IP,僅供k8s內部訪問(只能在pod 或node 上訪問,無法外部訪問),相當於service 加了1個vip,通過vip 提供訪問地址,再轉發給各個Pod

NodePort  

在每個node 節點為相應Pod啟動一個對外端口(默認30000起步),映射pod 內部端口。通過任意一個Pod 所在的節點ip+port 就能訪問pod ,多個pod 需要在service 前面加一個LB(lvs/proxy)把每個節點的ip+port 加入,才能實現負載均衡,這樣每個服務都得添加一次,增加了管理維護成本。

Loadblance   

雲服務廠商提供的,自動添加service 映射對外端口到負載上面,例如阿里雲可以通過SLB為service 提供負載均衡。只有雲服務廠商的k8s 才有此形式。

相關操作

 service  的創建

方式一 expose

kubectl  expose  --help

kubectl     expose     deployment       nginx-dep1   --port=2022         --target-port=80    --type=NodePort         -n kzf

                    service代理資源類型    資源名稱   代理對外端口          pod 中內部端口      端口暴露類型(默認ClusterIp)   命名空間
View Code

方式二  創建yaml

apiVersion: v1
kind: Service
metadata:
  name: service-kzf1
  namespace: asdf
spec:
  clusterIP: NodePort            #不寫默認類型為Clusterip
  ports:
  - port: 2021                 #clusterip 集群端口
    targetPort: 80              #pod 內部端口
  selector:
    app: nginx-label             #通過標簽選擇pod 
View Code
拓展
1、創建的服務可以暴露一個端口,也可以暴露多個端口。比如,pod 監聽兩個端口,比如 HTTP 監聽 8080 端口、 HTTPS 監聽 8443 端口,可以使用 一個服務從端口 80 和 443 轉發至 pod端口 8080 和 8443 2、可以對pod 的端口號命名,然后定義service 的時候targetport 使用端口號的名字。這樣實現了解耦,即使pod 端口號變了,但是service 端無需更改spec。
3、注意 標簽選擇器應用於整個服務,不能對每個端 做單獨的配直 如果不同的pod 有不同的端 映射關系,需要創建兩個服務

service  查看

kubectl get svc -n kzf
  NAME        TYPE      CLUSTER-IP    EXTERNAL-IP    PORT(S)              AGE
  nginx-dep1    NodePort    xxx.xx.x.x     <none>       2022:31992/TCP          27m
  service-kzf   NodePort    xxx.xx.x.x     <none>       2020:32341/TCP          2d1h
  service-kzf1   ClusterIP   xxx.xx.x.x     <none>       2021/TCP             52m

   nginx-ingress  LoadBalancer   xxx.xx.x.x   xx.xx.xxx.xx   80:3xxxx/TCP,443:xxxx6/TCP     29d

注解:

type     分為三種類型NodePort/ClusterIP/LoadBalancer 

CLUSTER-IP  無論哪種類型都有clusterip 因為Node port 和loadbalancer 都是在它的基礎上拓展的

EXTERNAL-IP 只有LoadBalancer 有,這是個負載均衡器的對外IP

Port     service 集群CLUSTER-IP IP 的端口:nodeport 類型節點上的端口

age      創建時間多久
View Code

 服務發現

當service 創建完成后pod 客戶端怎么發現它的連接地址和端口呢,有以下方式

通過環境變量發現服務

pod 開始運 時候 k8s 會初始化一系列的環境變量指向現在存在服務。 你創建的service 早於客戶端pod的創建, pod 上的進程可以根據環境變量獲得服務 IP 地址和端口號。如果pod 早於service 創建可以刪除pod 重新建立新pod 來獲取service 信息。可以通過如下命令獲取service 連接信息
kubectl exec kubia-2isdly env

通過DNS發現服務

在kube-system  命名空間有個dns 的pod 負載dns服務。在集群中的其他 pod 都被配置成使用其作為 dns ( Kubemetes 通過修改每 容器的/ etc/reso conf 實現)。

注:pod 是否使用內部DNS服務器是根據 pod spec dnsPolicy屬性來決定的,每個服務從內部 DNS服務器中獲得DNS條目,客戶端 pod在知道服務名稱的情況下可通過全限定域名 CFQDN來訪問,而不是訴諸於環境變量。
 
關於FQDN 
backend.database.default.svc.cluster.local 
backend database 對應於服務名稱, default 表示服務在其中定義的名稱空間,而 svc.cluster.local 是在所有集群本地服務名稱中使用的可配置集群域后綴。
 
注意:客戶端仍然必須知道服務的端 如果服務使用標准端 號(例如,HTTP 80 ),這樣是沒問題的 如果並不是標准端口,客戶端可以從環境變量中獲取端口號

Tip:

service 集群 IP個虛擬 IP ,ping 的時候無法ping通,只有在與服務端口結合時才有意義。

 

連接集群外部的服務

通過 Kubernetes 服務特性暴露外部服務(不在k8s集群中,例如是虛擬機運行的服務)的情況,不要讓service 將連接重定向到集群中的 pod ,而是讓它重定向到外部 IP 和端口這樣做可以讓你充分利用service負載平衡和服務發現。在集群中運行的客戶端
pod 可以像連接到內部服務那樣連接到外部服務

介紹服務 endpoint

service 並不是和 pod 直接相連的。相反,有一種資源介於兩者之間-它就是 Endpoint 資源。Endpoint資源就是暴露一個服務的IP 地址和端口的列表,當創建service的時候如果通過標簽選擇器關聯了pod那么就會自動創建一個同名的Endpoint 資源,里面記錄了后端的ip:port 的映射列表和其他Kubernetes資源一樣,所以可以使用kubectl describe 來獲取它的基本信息。

手動配置服務的 endpoint

service 的 endpoint 與service 解耦后,可以分別手動配置和更新它們,如果創建了不包含 pod選擇器的service,Kubemetes 將不會創建 Endpoint 資源(畢竟,缺少選擇器,將不會知道服務中包含哪些 pod)。這樣就需要創建 Endpoint 資源來指定該服務的 endpoint 列表。要使用手動配置 endpoint 的方式創建服務,需要創建服務和 Endpoint 資源。
創建沒有選擇器的服務首先為服務創建一個YAML文件,如下面所示。
apiVersion: vl
kind: Service
metadata:
  name: external-service
  spec:
    ports:
    - port:80
View Code

為沒有選擇器的service創建endpoints。Endpoint是一個單獨的資源並不是service的一個屬性。由於創建的資源中並不包含選擇器,相關的Endpoints資源並沒有自動創建,所以必須手動創建。如下所示

apiVersion: vl
kind: Endpoints
metadata:
  name: external-service      # Endpoint的名稱必須和服務的名稱相匹配
subsets:
- addresses:
- ip: 11.11.11.11
- ip: 22.22.22.22
  ports:
  - port: 80
View Code
Endpoint對象需要與服務具有相同的名稱,並包含該服務的目標IP地址和端口列表。服務和Endpoint資源都發布到服務器后,這樣服務就可以像具有pod選擇器那樣的服務正常使用。在服務創建后創建的容器
將包含服務的環境變量,並且與其IP : port對應的所有連接都將在服務端點之間進行負載均衡。
 
Tip: 如果以后決定將外部服務遷移到Kubemetes中運行的pod,可以為服務添加選擇器,從而對Endpoint進行自動管理。反過來也是一樣的——將選擇器從服務中移除,Kubemetes將停止更新Endpoints。這意味着服務的IP地址可以保持不變,同時服務的實際實現卻發生了改變。

為外部服務創建別名

除了手動配置服務的Endpoint來代替公開外部服務方法,有一種更簡單的方法,就是通過其完全限定域名(FQDN)訪問外部服務
 
創建ExtemalName類型的服務
要創建一個具有別名的外部服務的服務時,要將創建服務資源的一個type字段設置為ExternalName。例如,設想一 下在api.somecompany.com上有公共可用的APL可以定義一個指向它的服務,如下所示
apiVersion: vl 
kind: Service 
metadata: 
  name: external-service 
spec: 
  type: ExternalName 
  externalName: someapi.asdf.com 
  ports: 
  - port: 80
View Code
service 創建完成后,pod可以 通 過external-service.default . SVC .cluster.local域名(甚至是external-service)連接到外部服務,而不是使用服務的實際FQDN。這隱藏了實際的服務名稱及其使用該服務的pod 的位置,允許修改服務定義,並且在以后如果將其指向不同的服務,只需簡單地修改 externalName屬性,或者將類型重新變回Cluster IP並為服務創建Endpoint­無論是手動創建,還是對服務上指定標簽選擇器使其自動創建。ExternalName服務僅在DNS級別實施一為服務創建了簡單的CNAME DNS記錄。 因此, 連接到服務的客戶端將直接連接到外部服務, 完全繞過服務代理。 出於這個原因, 這些類型的服務甚至不會獲得集群 IP。 注意 CNAME記錄指向完全限定的域名而不是數字 IP地址。

將服務暴漏給內部客戶端

ClusterIp 類型即可,Clusterip 就是一個虛擬vip ,代理后端的一組pod,只能在集群內部訪問(pod 里面訪問/集群節點訪問)

將服務暴露給外部客戶端

方式一:NodePort

將服務的類型設置成NodePort每個集群節點都會在節點上打開 一個端口, 對於NodePort服務, 每個集群節點在節點本身(因此得名叫NodePort)上打開一個端口,並將在該端口上接收到的流量重定向到基礎服務。該服務僅在內部集群 IP 和端口上才可訪間, 但也可通過任意一個節點上的專用端口訪問。因為nodeport 是clusterip 的拓展,所以此類型既可以通過clusterip 在集群內部訪問也可以通過node-IP:port 在外部訪問
$ kubectl get svc kubia-nodeport 
  NAME               CLUSTER-IP                 EXTERNAL-IP     PORT(S)         AGE 
  kubia-nodeport     10.111.254.223             <nodes>         80:30123/TCP     2m

EXTERNAL-IP列。 它顯示nodes 表明服務可通過任何集群節點的IP地址訪問。 PORT(S)列顯示集群IP (8 0) 的內部端口和節點端口(30123), 可
以通過以下地址訪問該服務:
• 10.11.254.223:80<ls七node'sIP>:30123
• <2ndnode'sIP>:30123, 等等
View Code
在第一個節點的端口30123收到的連接, 可以被重定向到第一節點個上運行的pod, 也可能是第二個節點上運行的pod。注意:更改防火牆規則, 讓外部客戶端訪問我們的 NodePort 服務
訪問示意圖

 

 

 

 

方式二:LoadBalance

將服務的類型設置成LoadBalance, NodePort類型的一 種擴展一這使得服務可以通過一個專用的負載均衡器來訪問, 這是由Kubernetes中正在運行的雲基礎設施提供的。 負載均衡器將流量重定向到跨所有節點的節點端口。客戶端通過負載均衡器的 IP 連接到服務。
kubect1 get svc kubia-loadbalancer
  NAME            CLUSTER-IP      EXTERNAL-IP      PORT(S)      AGE
  kubia-loadbalancer   10.111.241.153    130.211.53.173    80:32143/TCP  lm

 在這種情況下, 負載均衡器的IP地址為130.211.53.173, 因此現在可以通過該 IP 地址訪問該服務: 
 $ curl h七七p://130.211.53.173
View Code

訪問流程圖

 

 

 

方式三:Ingress

創建一 個Ingress資源, 這是一 個完全不同的機制, 通過一 個IP地址公開多個服務——它運行在 HTTP 層(網絡協議第7 層)上, 因此可以提供比工作在第4層的服務更多的功能。詳情間ingress 博文。
 

使用 headless服務來發現獨立的pod 

到服務的每個連接都被轉發到一個隨機選擇的 pod 上。但是如果客戶端需要鏈接到所有的 pod 呢?如果后端的 pod 都需要連接到所有其他pod 呢?
通常, 當執行服務的 DNS 查找時, DNS 服務器會返回單個 IP一服務的集群 IP。 但是, 如果告訴Kubemetes, 不需要為服務提供集群 IP (通過在服務 spec 中將 clusterIP 字段設置為 None 來完成此操作), 則 DNS 服務器將返回 podIP 而不是單個服務 IP。
DNS 服務器不會返回單個 DNSA記錄, 而是會為該服務返回多個A記錄, 每個記錄指向當時支持該服務的單個 pod的 IP。 客戶端因此可以做一個簡單的 DNS A記錄查找並獲取屬於該服務一部分的所有 pod的 IP。 客戶端可以使用該信息連接到其中的一個、 多個或全部。

創建headless服務 

apiVersion: vl 
kind: Service 
metadata:
  name: kubia-headless 
spec: 
  clusterIP: None      #這使得服務成為headless
  ports: 
  - port: 80
  targetPort: 8080
selector: 
  app: kubia

 service 與就緒探針

啟動容器時,可以為 bernetes 配置 等待時間,經過等待時間后才可以執行第一次准備就緒檢查 之后,它會周期性地調用探針,並根據就緒探針的結果采取行動。如果某個 po 報告它尚未准備就緒,則會從該服務中刪除該 pod 。如果再次准備就緒,則重新添加 pod
 
與存活探針不同,如果容器未通過准備檢 ,則不會被終止或重新啟動 這是存活探針與就緒探針之間的重要區別 存活探針通過殺死異常的容器並用新的正常容器替代它們來保持 pod 正常工作,而就緒探針確保只有准備好處理請求的 pod 才可以接收它們(請求)。 這在容器啟動時最為必要, 當然在容器運行一段時間后也是有用的。

service 負載功能實現原理

service 負載均衡實現主要有兩種方式

iptables(早期)

iptables  是一個工具它通過linux 的netfilter 來進行ip 包的過濾處理。主要通過維護一張規則表,從上到下匹配表中規則,每次變動都不是增量而是全表變動。隨着表的增大效率降低。

ipvs(k8s version:1.11以后)

ipvs實際上就是lvs 的原理。采用它的輪詢策略(w,rr/wrr.lc,wlc),內核級別的,效率高。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM