K8S--負載均衡


一、K8S雲原生服務集群問題

(一)負載均衡原理  

  在之前的文章說過,每一個Pod都是獨立的IP、HostName、存儲,同時Pod是隨時可以被動態創建和回收的,那么就有個問題,我們如何知道Pod的IP並進行訪問的呢?其實K8S是使用Service VIP技術的虛擬ip + kube-proxy來解決這個問題,其中service VIP用來轉發請求,kube-proxy用來監控pod狀態,並且會及時修改pod的ip

  service是K8S的資源對象,service資源對象運行在每一個node節點上,每一個node節點都有一個service進程,service有自己的IP地址(虛擬IP),而service VIP相當於一個網關,所有的請求都要經過service VIP,通過service VIP進行轉發,從而實現負載均衡。

  service VIP一旦被創建,是不會被修改的,除非刪除service后重新創建service;同時由於service信息存儲在高可用的etcd中,且service實例運行在多個node節點上,因此Service VIP不存在單點故障的問題;由於service VIP中使用的是虛擬IP,因此Service VIP只能在局域網內部進行訪問,不能通過外網進行訪問,如果想要進行外網訪問,則需要借助物理網卡進行端口映射轉發。

  在K8S中IP資源的分類如下:

    Node IP:Node物理節點IP

    Pod IP:物理機內部運行的一個虛擬容器pod的ip

    cluster IP:集群IP,也是個虛擬IP,是K8S抽象出來的一個service的IP。此IP只能局域網內部訪問,不能通過外網訪問,如果要使用外網訪問,就必須開辟nodeport類型的IP地址。如下圖所示,外網訪問物理IP,然后將訪問請求映射到service VIP上,service VIP從etcd上獲取endpoints中pod的IP,然后使用負載均衡策略選擇一個pod進行調用

      

(二)Pod服務發現

  Pod服務發現借助kube-proxy實現,該組件實現了三件事情:監控pod;pod如果發生了變化,及時修改映射關系;修改映射關系的同時,修改路由規則,以便在負載均衡時可以選擇到新的pod。

      

 二、負載均衡方案(四層負載)

  K8S的負載均衡方案有三種:kube-proxy(userspace)、iptables(防火牆)、ipvs。

  1、kube-proxy

    使用kube-proxy的負載方案是使用kube-proxy來監控pod的狀態,如果pod發生了變化,則需要kube-proxy去修改service和pod的映射關系(endpoints),同時修改路由規則,並且由kube-proxy轉發請求,這種方式kube-proxy的壓力比較大,性能可能會出現問題。

      

  2、IPtables

    IPtables是K8S默認采用的負載策略,這種方式中,kube-proxy同樣用來監控pod和修改映射關系以及修改路由規則,但是轉發請求是采用輪詢iptables路由規則的方式進行調用處理的。

      

    這種模式kube-proxy主要做好watching Cluster API即可,路由和請求的轉發都交給了iptables,但是kube-proxy在請求無響應時會換一個pod進行重試,而iptables則是一條條的路由規則,不會進行重試。

    在iptables中,默認的輪詢策略是隨機的輪詢策略,但是也可以將其設置為輪詢。

    (1)設置為隨機策略

# 隨機:(Random balancing)
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode random --probability 0.33  -j DNAT --to-destination 10.0.0.2:1234
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode random --probability 0.5 -j DNAT --to-destination 10.0.0.3:1234
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017  -j DNAT --to-destination 10.0.0.4:1234

    在iptables命令中,命令的執行和順序有關,在上述命令中,用--probability 設置了命中幾率,第一條設置了紀律是0.33,也就是整個請求的0.33,第二條命中率為0.5,實際是剩余請求的0.5,也就是總請求的0.335,第三條是剩余的流量全部打到該ip上,也就是0.335,基本上就是隨機分配了。

    (2)設置為輪詢策略

#every:每n個包匹配一次規則
#packet:從第p個包開始
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode nth --every 3 --packet 0 -j DNAT --to-destination 10.0.0.2:1234
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode nth --every 2 --packet 0  -j DNAT --to-destination 10.0.0.3:1234
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -j DNAT --to-destination 10.0.0.4:1234

  3、IPVS

    ipvs (IP Virtual Server) 實現傳輸層負載均衡,通常稱為第四層LAN交換,是Linux內核的一部分。

    ipvs與iptables的區別:

      ipvs為大型集群提供了更好的可擴展性和性能

      ipvs支持比iptables更復雜的負載均衡算法

      ipvs支持服務器的健康檢查和連接重試等。

    對於上述差異做個說明:

      在linux中iptables設計是用於防火牆的,對於比較少的規則,沒有太多的性能影響,如果對於一個龐大的K8S集群,會有上千Service服務,Service服務會對應多個pod,每條都是一個iptables規則,那么對於集群來說,每個node上都有大量的規則,簡直是噩夢。而IPVS則是使用hash tables來存儲網絡轉發規則的,比iptables更有優勢,而且ipvs主要工作在kerbespace,減少了上下文的切換。

      IPVS有輪詢(rr)、最小連接數(lc)、目的地址hash(dh)、源地址hash(sh)、最短期望延遲(sed)、無須隊列等待(nq)等負載均衡算法,在node上通過 “–ipvs-scheduler”參數,指定kube-proxy的啟動算法。

    kube-proxy和IPVS合作的流程:

      (1)kube-proxy仍然是watching Cluster API,獲取新建、刪除Service或Endpoint pod指令,如果有新的Service建立,kube-proxy回調網絡接口,構建IPVS規則。

      (2)kube-proxy會定期同步Service和Pod的轉發規則,確保失效的轉發可以被及時修復

      (3)有請求轉發到后端的集群時,IPVS的負載均衡直接將其轉發到對應的Pod上

三、Ingres-nginx(七層負載均衡)

(一)為什么要使用Ingres

  1、先介紹以下部署K8S服務時使用到的配置文件:

    創建配置文件(ingres.yaml),用來部署一個nginx的deployment和service

# 創建一個service資源對象
# kubectl expose deployment xxName –port=80 –target-port=80 k8s指令模式創建一個service # k8s部署yaml方式 apiVersion: v1 kind: Service metadata: name: nginx namespace: default spec: selector: app: nginx ports: - port: 80 targetPort: 80 --- # 部署deployment對象,k8s創建3個資源對象:Deployment,ReplicaSet,POD apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: default spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.16 ports: - containerPort: 80

  對上面的配置文件做個描述:

    

   首先看Deployment:

    apiVersion標記版本,Kind標記類型,說明要創建一個Deployment,該deployment的名字叫nginx,空間為默認空間。

    spec下是rs和pod的配置,首先replicas是副本的數量,然后就是選擇器的名稱為nginx。

    template下是副本的配置,首先副本的標簽是nginx,容器的名字是nginx,鏡像為nginx1.16,這里可以配置為鏡像倉庫地址和對應的鏡像,最后ports是容器開放的端口。

    這里說明幾個比較重要的配置,就是選擇器的名稱和容器的標簽一定要一致(綠色連接線),否則容器不會被副本控制器RS所控制。

  然后說一下Service:

    apiVersion和Kind都和Deployment一樣,Kind的值表明了這是一個Service配置。

    然后就是這個service的名字,service標簽選擇器的名字,以及目標容器的端口。

    這里說幾個比較重要的配置,和Deployment一樣,選擇器的名字要和容器的名字一致(綠色連接線),目標容器端口要和容器的端口保持一致(紫色連接線)

  執行配置文件,生成deployment和service

kubectl apply -f ingres.yaml

  執行后查看deployment、service、rs、pod的情況(注意:這一步一般時間比較久,需要等一會)

      

   從上面圖片的輸出中可以看到,nginx的type為ClusterIp,這種類型的service只能在集群內部訪問,而不能在外部直接訪問,那么就需要修改類型為NodePort,修改命令:

kubectl edit svc nginx

      

   更改完畢之后,重新查看service,發現type已經變為NodePort,且port也變更了,前面的80是容器內的端口,后面的31758是對外開放的端口,也就是宿主機的端口。

      

   此時,使用宿主機的ip + 31758訪問,即可訪問nginx

      

   但是有個問題,就是如果每個服務都要對外開啟一個端口,那么就需要開啟很多的端口,這樣即麻煩又有點浪費,因此就需要Ingres來解決這個問題,Ingres只需要一個NodePort就可以解決上述的問題。因為ingress相當於一個7層的負載均衡器,是k8s對反向代理的一個抽象。大概的工作原理也確實類似於Nginx,可以理解成在 Ingress 里建立一個個映射規則 , ingress Controller 通過監聽 Ingress這個api對象里的配置規則並轉化成 Nginx 的配置(kubernetes聲明式API和控制循環) , 然后對外部提供服務。

(二)Ingres-Nginx介紹  

  Ingres是K8S對於nginx進行雲原生模式的封裝,使得nginx更適合雲原生的結構,使用Ingres可以對Service進行負載均衡,因此Ingres工作在七層,屬於七層負載均衡。

  Ingres通過http協議的方式實現Service的負載均衡:

      

   對於K8S來說,Ingres就是一個資源控制器,用來控制資源的訪問策略,

(三)部署Ingres及使用同一個域名訪問不同服務

  Ingres的配置文件如下所示:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  rules:
  - host: ingress.lcl.com
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80

   在上面文件中,配置了Ingres的規則,那么對於使用同一個域名訪問不同服務的配置,則是在paths下面增加多個path路徑,讓path指向不同的服務,並且在metadata中新增請求重寫配置annotations,去除path的路徑,保證訪問到指定服務上的路徑不帶有該path,具體配置如下所示:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: / # 請求重寫
spec: 
  rules:
  - host: ingress.lcl.com
    http:
      paths:
        - path: /nginx   # 把path追加到域名后面 ingress.lcl.com/nginx   把/nignx當成服務請求的一部分
          backend:
            serviceName: nginx
            servicePort: 80
        - path: /tomcat
          backend:
            serviceName: tomcat
            servicePort: 8080

(四)不同域名訪問不同服務

  不同域名訪問不同服務主要是在rules下面配置不同的規則即可。

# 使用多個域名,訪問不同的服務
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  rules:
  - host: ingress.lcl.com
    http:
      paths:
      - path: /
        backend:
         serviceName: nginx
         servicePort: 80
  - host: ingress.lcl.com
    http:
      paths:
      - path: /
        backend:
         serviceName: tomcat
         servicePort: 8080

(五)Ingres和https

  如果想將http請求升級為https,我們就需要制作證書

# 生成私鑰
openssl genrsa -out lcl.key 2048
# 自簽發證書
openssl req -new -x509 -key lcl.key -out lcl.crt -subj /C=CN/ST=Shanghai/L=Shanghai/O=DevOps/CN=ingres.lcl.com
# 創建K8S使用的證書
kubectl create secret tls lcl-secret --cert=lcl.crt --key=lcl.key

  創建ingres,使用證書的Ingres

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-tomcat-tls
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
  labels:
    app: tomcat
spec:
  tls:
  - hosts:
    - ingress.lcl.com
    secretName: lcl
  rules:
  - host: ingres.lcl.com
    http:
      paths:
        - backend:
            serviceName: nginx
            servicePort: 8080

  查看secret資源

kubectl describe secret lcl

  修改原來的ingres配置文件

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  tls:
  - hosts:
    - ingres.lcl.com
    secretName: lcl-secret
  rules:
  - host: ingress.lcl.com
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80

  主要就是新增了spec下面的tls配置,使用了剛才創建的secret文件,此時使用https訪問即可正常訪問。


免責聲明!

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



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