k8s loadbalancer與ingress實踐

iqsing發表於2022-01-04

k8s可以通過三種方式將叢集內服務暴露到外網,分別是NodePort、LoadBalancer、Ingress,其中NodePort作為基礎通訊形式我們在《k8s網路模型與叢集通訊》中進行了介紹,這裡我們主要關注LoadBalancer和Ingress

LoadBalancer


loadbalancer是服務暴露到因特網的標準形式,和nodeport一樣我們只需在建立service是指定type為loadbalancer即可,接著Service 的通過status.loadBalancer欄位將需要建立的負載均衡器資訊釋出供負載均衡服務建立。不過loadbalancer是雲服務商”專屬“,像騰訊雲CLB、阿里雲SLB,這樣在建立service時會自動幫我們建立一個負載均衡器。

大多數雲上負載均衡也是基於nodeport,他們的結構如下:

image-20220104155502920

如果要在本地建立一個負載均衡器如何實現呢?

MetalLB,一個CNCF沙箱專案,使用標準路由協議(ARP/BGP),實現裸機K8s叢集的負載均衡器。

安裝方式可參考官方文件:installation

L2(子網)模式的結構,圖源

image-20220104163613950

安裝後我們獲得如下兩個元件:

  • metallb-system/controller deployment。用於處理IP分配的控制器。
  • metallb-system/speakerdaemonset。叢集中每個節點啟動一個協議服務守護程式。

接著新增一個configmap配置metallb IP池。

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.1.240-192.168.1.250

這樣當我們建立一個loadbalancer型別的service時,EXTERNAL-IP將會從地址池中獲取一個用於外部訪問的IP 192.168.1.243 當外部流量進入時,ARP將我們的請求地址廣播獲取所屬的service,接著k8s內部 通過iptables 規則和 kube-proxy,將流量從服務端點引導到後端。

#nginx_deployment_service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: metallb-system
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - name: http
          containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  namespace: metallb-system
  name: nginx
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer

檢視service kubectl get svc

NAME     TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
nginx    LoadBalancer   10.96.243.159   192.168.1.243   80:31052/TCP   40h

測試訪問:curl 192.168.1.243

# curl 192.168.1.243
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>

負載均衡可以建立在 OSI 網路模型的不同級別上,主要是在 L4(傳輸層,例如 TCP/UDP)和 L7(應用層,例如 HTTP)上。在 Kubernetes 中,Services是 L4 的抽象,LoadBalancer型別負載均衡依然有侷限性,同時我們看到每建立一個service對應的負載均衡器都會消耗一個靜態IP,這並不合理。當然k8s中的另一種資源物件ingress可工作在 L7 層實現應用程式協議(HTTP/HTTPS)的負載均衡。

Ingress


Ingress 公開了從叢集外部到叢集內服務的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 資源上定義的規則控制。我們可以將 Ingress 配置為服務提供外部可訪問的 URL、負載均衡流量、終止 SSL/TLS,以及提供基於名稱的虛擬主機等能力。

我們所說的Ingress包含兩個部分:

  • ingress k8s資源物件:流量路由規則的控制
  • ingress-controller控制器:控制器的實現有非常多,可參考官方文件中列表Ingress 控制器,這裡我們使用k8s官方維護的控制器NGINX Ingress Controller

外部流量進入叢集時先經過ingress-controller,然後根據ingress配置的路由規則將請求轉發到後端service。

image-20220104174923429

ingress-controller

ingress-controller其實就是守護程式加一個反向代理的應用,守護程式不斷監聽叢集中資源的變化,將ingress中的配置資訊生成反向代理配置。在nginx-ingress controller中即生成nginx.conf的配置檔案。

在本文中因為我們上面已經配置好了loadbalancer的服務,這樣我們建立一個type為LoadBalancer的service關聯這組pod,再把域名解析指向該地址,就實現了叢集服務的對外暴露。當然你也可以使用NodePortHostnetwork的方式,感興趣的小夥伴可以進行測試。

ingress-controller不是k8s內部元件,可以通過helm或資源清單方式安裝,可檢視ingress-nginx deploy

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.0/deploy/static/provider/cloud/deploy.yaml

然後我們編輯service

kubectl edit service/ingress-nginx-controller -n ingress-nginx

修改spec.type為LoadBalancer即可。

這樣我們建立好了nginx-ingress controller,下一步就要配置ingress路由規則。

ingress規則

host:k8s.com

基於url的路由:

  • /api/v1
  • /api/v2

這兩個url分別路由到不同的service中

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  namespace: training
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: k8s.com
    http:
      paths:
      - path: /api/v1
        backend:
          serviceName: service-apiv1
          servicePort: 80
      - path: /api/v2
        backend:
          serviceName: service-apiv2
          servicePort: 80

ingress.kubernetes.io/rewrite-target是nginx-ingress controller的一個註解,當後端服務中暴露的 URL 與 Ingress 規則中指定的路徑不同時可以通過此重定向。

檢視svc可以看到此時控制器已經獲得了一個EXTERNAL-IP

#kubectl get svc -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.96.87.23    192.168.1.245   80:32603/TCP,443:31906/TCP   621d
ingress-nginx-controller-admission   ClusterIP      10.96.109.70   <none>          443/TCP                      621d

現在nginx-ingress controller和ingress路由規則都有了。

我們可以進入到nginx-ingress controller pod中檢視nginx.conf可以看到此時我們的ingress配置已經被生成為路由規則。

image-20220104211938284接下來就是指定我們的backend,即上面的server-apiv1/2

我們新增兩個用於暴露的service和deployment,和loadbalancer中測試清單一樣,我們稍稍修改一下名稱即可。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-apiv1
  namespace: training
spec:
  selector:
    matchLabels:
      app: nginx-apiv1
  template:
    metadata:
      labels:
        app: nginx-apiv1
    spec:
      containers:
      - name: nginx-apiv1
        image: nginx:latest
        ports:
        - name: http
          containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  namespace: training
  name: service-apiv1
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-apiv1
  type: NodePort

將nginx-apiv1換成nginx-apiv2建立出另一個service和deployment。

最後修改hosts解析k8s.com

192.168.1.245 k8s.com

使用curl命令測試url路由(記得在pod中新增測試檔案,否則雖然url進行了路由但會出現404)。

# curl k8s.com/api/v1/index.html
api v1
# curl k8s.com/api/v2/index.html
api v2

這樣我們對ingress有了初步瞭解,ingress的路由規則可自定項較多也比較繁雜,可通過官方文件進一步學習。


希望小作文對你有些許幫助,如果內容有誤請指正。

您可以隨意轉載、修改、釋出本文,無需經過本人同意。

相關文章