k8s 對外服務之ingress


1.什么是 Ingress

      k8s  對外暴露服務(service)主要有兩種方式: NotePortLoadBalance, 此外 externalIPs也可以使各類service對外提供服務,但是當集群服務很多的時候,NodePort方式最大的缺點是會占用很多集群機器的端口;LB方式最大的缺點則是每個service一個LB又有點浪費和麻煩,並且需要k8s之外的支持; 而ingress則只需要一個NodePort或者一個LB就可以滿足所有 service對外服務的需求。工作機制大致可以用下圖表示:

      提示:如上圖所示,ingress就是ingress 控制器pod的代理規則;用戶請求某個后端pod所提供的服務時,首先會通過ingress controller pod把流量引入到集群內部,然后ingress controller pod根據ingress定義的規則,把對應ingress規則轉化為對應ingress controller pod實現的對應應用的配置(ingress controller 可以由任何具有七層反向代理功能的服務實現,比如nginx,haproxy等等)然后再適配用戶請求,把對應請求反代到對應service上;而對於pod的選擇上,ingress控制器可以基於對應service中的標簽選擇器,直接同pod直接通信,無須通過service對象api的再次轉發,從而省去了用戶請求到kube-proxy實現的代理開銷(本質上ingress controller 也是運行為一個pod,和其他pod在同一網段中)。     

      Ingress 可以給 Service 提供集群外部訪問的 URL、負載均衡、SSL 終止、HTTP 路由等。為了配置這些 Ingress 規則,集群管理員需要部署一個 Ingress Controller,它監聽 Ingress 和 Service 的變化,並根據規則配置負載均衡並提供訪問入口。

      Ingress 控制器和k8s上的其他控制不一樣,ingress控制器並不能直接運行為kube-controller-manager的一部分,它類似k8s集群上的coredns,需要在集群上單獨部署,本質上就是一個pod,我們可以使用k8s上的ds或deploy控制器來創建它。

2.Ingress的核心組件

要理解ingress,需要區分兩個概念,ingress和ingress-controller:

  • ingress controller:核心是一個deployment,實現方式有很多,比如nginx, Contour, Haproxy, trafik, Istio,需要編寫的yaml有:Deployment, Service, ConfigMap, ServiceAccount(Auth),其中service的類型可以是NodePort或者LoadBalancer。具體是實現反向代理及負載均衡的程序,對ingress定義的規則進行解析,根據配置的規則來實現請求轉發;簡單來說,Ingress-controller才是負責轉發的組件,通過各種方式將他暴露在集群入口,外部對集群的請求流量會先到Ingress-controller,而Ingress對象是用來告訴Ingress-controller該如何轉發請求,比如那些域名那些path要轉發到那些服務等.
  • ingress:這個就是一個類型為Ingress的k8s api對象了,一般用yaml配置,作用是定義請求如何轉發到service的規則,可以理解為配置模板。

假設已經有兩個服務部署在了k8s集群內部:
$ kubectl get svc,deploy
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
svc/coffee-svc   ClusterIP   <none>       <none>        80/TCP    1m
svc/tea-svc      ClusterIP   <none>       <none>        80/TCP    1m

NAME            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/coffee   2         2         2            2           1m
deploy/tea      1         1         1            1           1m

配置 Ingress resources,即可實現多個service對外暴露服務:

1)coffee-svc 

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: cafe-ingress
spec:
  rules:
  # 配置七層域名
  - host: foo.bar.com
    http:
      paths:
      # 配置Context Path
      - path: /tea
        backend:
          serviceName: tea-svc
          servicePort: 80
      # 配置Context Path
      - path: /coffee
        backend:
          serviceName: coffee-svc
          servicePort: 80

2)tea-svc

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: cafe-ingress
spec:
  rules:
  # 配置七層域名
  - host: tea.foo.bar.com
    http:
      paths:
      - backend:
          serviceName: tea-svc
          servicePort: 80
  - host: coffee.foo.bar.com
    http:
      paths:   
      - backend:
          serviceName: coffee-svc
          servicePort: 80

接着在hosts文件中添加一條解析規則即可在瀏覽器訪問了。

 

3.部署Nginx Ingress Controller( 基於Nginx 來處理請求)

資料信息地址:

Ingress-Nginx-github 地址:https://github.com/kubernetes/ingress-nginx

Ingress-Nginx 官方地址:https://kubernetes.github.io/ingress-nginx

注意:選擇合適的版本

 

3.1下載並修改配置文件

下載整合配置文件,獲取配置文件地址:https://github.com/kubernetes/ingress-nginx/tree/nginx-0.30.0/deploy/static

# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
# service-nodeport.yaml為ingress通過nodeport對外提供服務,注意默認nodeport暴露端口為隨機,可以編輯該文件自定義端口。
# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

應用yml文件創建ingress資源:

# kubectl apply -f  mandatory.yaml
# kubectl apply -f service-nodeport.yaml 
# kubectl get all -n ingress-nginx -o wide

 

Ingress Contronler 通過與 Kubernetes API 交互,動態的去感知集群中 Ingress 規則變化,然后讀取它,按照自定義的規則,規則就是寫明了哪個域名對應哪個service,生成一段 Nginx 配置,再寫到 Nginx-ingress-control的 Pod 里,這個 Ingress Contronler 的pod里面運行着一個nginx服務,控制器會把生成的nginx配置寫入/etc/nginx.conf文件中,然后 reload 一下 使用配置生效。以此來達到域名分配置及動態更新的問題。
 
接下來訪問Ingress的nodeport端口測試發現是404,這是正常現象,因為沒有配置后台服務。下面我們來實際應用一下。
 

3.2實際應用舉例

3.2.1創建svc及后端deployment

# cat test-ingress-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: web-a
  name: web-a
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-a
  template:
    metadata:
      labels:
        app: web-a
    spec:
      containers:
      - image: nginx
        name: web-a

---
apiVersion: v1
kind: Service
metadata:
  name: web-a
  labels:
    app: web-a
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: web-a

應用yaml:

# kubectl apply -f test-ingress-pod.yaml 
# kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
web-a-89b89d4dd-chhhq       1/1     Running   0          38s
web-a-89b89d4dd-tjh82       1/1     Running   0          38s

查看service:

# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          15d
web-a        ClusterIP   10.96.214.85    <none>        80/TCP           64s

 

3.2.2創建Ingress規則

其實就是配置NGINX的一個過程

# ingress規則中,要指定需要綁定暴露的svc名稱
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-web-a
  annotations: 
    kubernetes.io/ingress.class: "nginx"    # 指定 Ingress Controller 的類型
    nginx.ingress.kubernetes.io/use-regex: "true"    # 指定我們的 rules 的 path 可以使用正則表達式
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"    # 連接超時時間,默認為 5s
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"      # 后端服務器回轉數據超時時間,默認為 60s
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"      # 后端服務器響應超時時間,默認為 60s
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"         # 客戶端上傳文件,最大大小,默認為 20m
spec:
  rules:         #定義路由規則
  - host: www.web-a.com      # 主機名,只能是域名,修改為你自己的
    http:
      paths:
      - path: /
        backend:
          serviceName: web-a           # 后台部署的 Service Name
          servicePort: 80              # 后台部署的 Service Port

說明:在ingress配置中,annotations很重要,前面有說ingress-controller有很多不同的實現,而不同的Ingress-controller就可以根據"kubernetes.io/ingress.class"來判斷要使用那些ingress配置,同時,不同的ingress-controller也有對應的annotations配置,用於自定義一些參數。

應用yaml文件:

# kubectl apply -f test-ingress-web-a.yaml 
kubectl get ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME            CLASS    HOSTS           ADDRESS        PORTS   AGE
ingress-web-a   <none>   www.web-a.com   10.96.148.17   80      6m26s

 

 

在win主機配置hosts域名解析 c:\windows\system32\drivers\etc\hosts:

192.168.0.25 www.web-a.com

訪問測試:域名+nodeport的模式

 
 
 

總結:

  1. 上面我們創建一個針對於nginx的deployment資源,pod為2個;
  2. 為nginx的pod暴露service服務,名稱為web-a
  3. 通過ingress把nginx暴露出去
    這里對於nginx創建的svc服務,其實在實際調度過程中,流量是直接通過ingress然后調度到后端的pod,而沒有經過svc服務,svc只是提供一個收集pod服務的作用。
 

4.Ingress的部署,架構簡談

Ingress的部署,需要考慮兩個方面:

# 1 . ingress-controller是作為Pod來運行的,以什么方式部署比較好
# 2 . ingress解決了如何請求路由到集群內部,那他自己怎么暴露給外部比較好

下面列舉一些目前常用的部署和暴露方式,具體使用哪種方式還得根據實際需要考慮來決定:

  • Deployment+LoadBalancer模式的service

如果要把ingress部署在公有雲,那用這種方式比較合適。用Deployment部署ingress-controller,創建一個type為LoadBalancer的service關聯這組pod。大部分公有雲,都會為LoadBalancer的service自動創建一個負載均衡器,通常還綁定了公網地址。只要把域名解析指向該地址,就實現了集群服務的對外暴露。

  • Deloyment+NodePort模式的service

同樣用deployment模式部署ingress-controller,並創建對應的服務,但是type為NodePort。這樣,ingress就會暴露在集群節點ip的特定端口上。由於nodeport暴露的端口是隨機端口,一般會在前面再搭建一套負載均衡器來轉發請求。該方式一般用於宿主機是相對固定的環境ip地址不變的場景。
NodePort方式暴露ingress雖然簡單方便,但是NodePort多了一層NAT,在請求量級很大時可能對性能會有一定影響。

  • DaemonSet+HostNetwork+nodeSelector

用DaemonSet結合nodeselector來部署ingress-controller到特定的node上,然后使用HostNetwork直接把該pod與宿主機node的網絡打通,直接使用宿主機的80/433端口就能訪問服務。這時,ingress-controller所在的node機器就很類似傳統架構的邊緣節點,比如機房入口的nginx服務器。該方式整個請求鏈路最簡單,性能相對NodePort模式更好。缺點是由於直接利用宿主機節點的網絡和端口,一個node只能部署一個ingress-controller pod。比較適合大並發的生產環境使用。

4.1.DaemonSet+HostNetwork+nodeSelector部署

DaemonSet簡介:

DaemonSet 是指在 Kubernetes 集群里運行一個 Daemon Pod, 它有如下特征:

  • 這個 Pod 默認運行在 Kubernetes 集群里的每一個Node節點上;
  • 每個節點上只有一個這樣的 Pod 實例;
  • 當有新的節點加入集群時,會自動創建該 Pod 。

修改mandatory.yaml,主要修改pod相關:

apiVersion: apps/v1
kind: DaemonSet     #修改為DaemonSet
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  #replicas: 1     #注銷此行,DaemonSet不需要此參數
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
    spec:
      # wait up to five minutes for the drain of connections
      terminationGracePeriodSeconds: 300
      serviceAccountName: nginx-ingress-serviceaccount
      hostNetwork: true   #添加該字段讓docker使用物理機網絡,在物理機暴露服務端口(80),注意物理機80端口提前不能被占用
      dnsPolicy: ClusterFirstWithHostNet    #使用hostNetwork后容器會使用物理機網絡包括DNS,會無法解析內部service,使用此參數讓容器使用K8S的DNS
      nodeSelector:       #添加節點標簽,在符合標簽的node上部署,所以運行此服務的node標簽要打上這個標簽
        kubernetes.io/ingress-controller-ready: "true" tolerations:         #添加對指定node節點污點的容忍度,和node節點的污點有關系,pod指定了容忍度后,就可以在對應的打了此污點的node上部署。
      - key: "node-role.kubernetes.io/master"
        operator: "Equal"
        value: ""
        effect: "NoSchedule"
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
……

修改參數如下:

  • kind: Deployment #修改為DaemonSet
  • replicas: 1 #注銷此行,DaemonSet不需要此參數
  • hostNetwork: true #添加該字段讓docker使用物理機網絡,在物理機暴露服務端口(80),注意物理機80端口提前不能被占用
  • dnsPolicy: ClusterFirstWithHostNet #使用hostNetwork后容器會使用物理機網絡包括DNS,會無法解析內部service,使用此參數讓容器使用K8S的DNS
  • nodeSelector:kubernetes.io/ingress-controller-ready: "true" #添加節點標簽,在符合標簽的node上部署,所以運行此服務的node標簽要改成這個標簽
  • tolerations: 添加對指定node節點的污點容忍度,和node節點的污點有關系,pod指定了容忍度后,就可以在對應的打了此污點的node上部署。
示例環境:
k8smaster01    k8snode01     k8snode02     k8snode03
在node01、node02部署Ingress,所以給這2台node打標簽:這一步驟限定的部署的范圍
先查看下:
# kubectl get nodes --show-labels
 
根據上面配置文件中nodeSelector中定義的給node01和node02打上標簽:
# kubectl label nodes k8snode01 kubernetes.io/ingress-controller-ready=true
# kubectl label nodes k8snode02 kubernetes.io/ingress-controller-ready=true

在查看: 



 給node02、node02打上污點,污點內容根據上述配置文件中tolerations定義的來進行:這一步主要的作用是限定了只有容忍這個污點的pod才可以在這個節點上部署,也就是只有Ingress才能在這個node上部署。
# kubectl taint nodes k8snode01 node-role.kubernetes.io/master=:NoSchedule
# kubectl taint nodes k8snode02 node-role.kubernetes.io/master=:NoSchedule

說明:因為value是空的,所以=后面直接就是:NoSchedule

查看污點:

# kubectl describe nodes k8snode01 
Name:               k8snode01
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=k8snode01
                    kubernetes.io/ingress-controller-ready=true
                    kubernetes.io/os=linux
Annotations:        flannel.alpha.coreos.com/backend-data: {"VNI":1,"VtepMAC":"3a:bc:8d:c3:5f:47"}
                    flannel.alpha.coreos.com/backend-type: vxlan
                    flannel.alpha.coreos.com/kube-subnet-manager: true
                    flannel.alpha.coreos.com/public-ip: 192.168.0.27
                    kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
                    node.alpha.kubernetes.io/ttl: 0
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Sun, 05 Sep 2021 04:26:07 -0400 Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false
……

部署Ingress:

# kubectl apply -f mandatory.yaml 
# kubectl get pod -n ingress-nginx -o wide   
NAME                             READY   STATUS    RESTARTS   AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx-ingress-controller-hpnz8   1/1     Running   0          7m36s   192.168.0.28   k8snode02   <none>           <none>
nginx-ingress-controller-pjxr8   1/1     Running   0          7m36s   192.168.0.27   k8snode01   <none>           <none>

測試:

ingress規則還是使用前面我們創建的。

在win主機上直接解析,IP地址為node01或node02任意節點ip即可,訪問的時候也無需再加端口:

 

 
 
 
 參考:
https://www.cnblogs.com/you-men/p/13225781.html
https://www.jianshu.com/p/c726ed03562a
https://blog.csdn.net/happyzwh/article/details/89204167

 


免責聲明!

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



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