k8s--Ingress 介紹、ingress-nginx


Ingress 介紹

在前面我們已經知道,Service 對集群之外暴露服務的主要方式有兩種:NodePort 和 LoadBalance,但是這兩種方式,都有一定的缺點

  • NodePort 方式的缺點是會占用很多集群機器的端口,那么當集群服務變多的時候,這個缺點就更加明顯
  • LoadBalance 的缺點是每個 Service 需要一個 LoadBalance,浪費、麻煩,並且需要 kubernetes 之外設備的支持

基於這種現狀,kubernetes 提供了 ingress 資源對象,ingress 只需要一個 NodePort 或者一個 LoadBalance 就可以滿足暴露多個 Service 的需要,工作機制大致如下圖所示:

實際上,Ingress 相當於一個 7 層的負載均衡器,是 kubernetes 對反向代理的一個抽象,它的工作原理類似於 Nginx,可以理解成在 Ingress 里建立諸多映射規則,Ingress Controller 通過監聽這些配置規則並轉化成 Nginx 的反向代理配置 , 然后對外部提供服務。在這里有兩個核心概念:

  • ingress:kubernetes 中的一個對象,作用是定義請求如何轉發到 service 的規則
  • ingress controller:具體實現反向代理及負載均衡的程序,對 ingress 定義的規則進行解析,根據配置的規則來實現請求轉發,實現方式有很多,比如 Nginx, Contour, Haproxy 等等

Ingress(以Nginx為例)的工作原理如下:

  1. 用戶編寫 Ingress 規則,說明哪個域名對應 kubernetes 集群中的哪個 Service
  2. Ingress 控制器動態感知 Ingress 服務規則的變化,然后生成一段對應的 Nginx 反向代理配置
  3. Ingress 控制器會將生成的 Nginx 配置寫入到一個運行着的 Nginx 服務中,並動態更新
  4. 到此為止,其實真正在工作的就是一個 Nginx 了,內部配置了用戶定義的請求轉發規則

lngress-nginx可解決的問題

  • 動態配置服務:如果按照傳統方式, 當新增加一個服務時, 我們可能需要在流量入口加一個反向代理指向我們新的 k8s 服務. 而如果用了 Ingress-nginx, 只需要配置好這個服務, 當服務啟動時, 會自動注冊到 Ingress 的中, 不需要額外的操作
  • 減少不必要的端口映射:配置過 k8s 的都清楚, 第一步是要關閉防火牆的, 主要原因是 k8s 的很多服務會以 NodePort 方式映射出去, 這樣就相當於給宿主機打了很多孔, 既不安全也不優雅. 而 Ingress 可以避免這個問題, 除了 Ingress 自身服務可能需要映射出去, 其他服務都不要用 NodePort 方式

ingress-nginx 實戰

官網:https://kubernetes.github.io/ingress-nginx/

創建一個命名空間 zouzou

# 創建命名空間 zouzou
kubectl create ns zouzou
創建 httpd 服務、Service 資源對象

創建一個 httpd-01.yaml 的文件,內容如下

apiVersion: apps/v1
kind: Deployment  # 類型為 Deployment
metadata:
  name: web01  # Deployment 的名稱
  namespace: zouzou  # ns
spec:
  replicas: 3  # 3 個副本數
  selector:  # 標簽選擇器
    matchLabels:
      app: httpd01
  template:
    metadata:
      labels:
        app: httpd01
    spec:
      containers:
      - name: httpd
        image: httpd:2.4  # 鏡像
---
apiVersion: v1
kind: Service  # 類型為 Service
metadata:
  name: httpd-svc  # svc 的名稱
  namespace: zouzou
spec:
  selector:
    app: httpd01  # 選擇標簽為 app=httpd01 的 pod,也就是上面的
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

運行 yaml 文件

# 創建 Deployment 和 Service
[root@dce-10-6-215-215 tmp]# kubectl apply -f httpd-01.yaml
deployment.apps/web01 created
service/httpd-svc created

運行完等會查看是否正常啟動

# 查看 pod、svc、deployment
[root@dce-10-6-215-215 tmp]# kubectl get pod,svc,deploy -n zouzou
NAME                         READY   STATUS    RESTARTS   AGE
pod/web01-7445cbbd94-hrb2p   1/1     Running   0          7m9s
pod/web01-7445cbbd94-qx6np   1/1     Running   0          7m9s
pod/web01-7445cbbd94-s5z9v   1/1     Running   0          7m10s

NAME                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/httpd-svc   ClusterIP   172.31.63.225   <none>        80/TCP    7m9s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web01   3/3     3            3           7m10s
創建 tomcat 服務及 service

創建一個 tomcat-01.yaml 文件,內容如下

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web02  # deployment 的名稱
  namespace: zouzou
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat01
  template:
    metadata:
      labels:
        app: tomcat01  # label
    spec:
      containers:
      - name: tomcat
        image: tomcat:8-jdk8  # 鏡像
---
apiVersion: v1
kind: Service
metadata:
  name: tomcat-svc  # svc 名稱
  namespace: zouzou
spec:
  selector:
    app: tomcat01  # 匹配 app=tomcat01 的 pod
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080

運行 yaml 文件 

# 創建 deployment 和 svc
[root@dce-10-6-215-215 tmp]# kubectl apply -f tomcat-01.yaml
deployment.apps/web02 created
service/tomcat-svc created

在來查看 pod 和 svc 是否都正常

# 查看 pod,svc,deployment
[root@dce-10-6-215-215 tmp]# kubectl get pod,svc,deploy -n zouzou
NAME                         READY   STATUS    RESTARTS   AGE
pod/web01-7445cbbd94-hrb2p   1/1     Running   0          22m
pod/web01-7445cbbd94-qx6np   1/1     Running   0          22m
pod/web01-7445cbbd94-s5z9v   1/1     Running   0          22m
pod/web02-fff958574-9j7cl    1/1     Running   0          57s
pod/web02-fff958574-c9hz9    1/1     Running   0          57s
pod/web02-fff958574-v77cc    1/1     Running   0          57s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/httpd-svc    ClusterIP   172.31.63.225   <none>        80/TCP     22m
service/tomcat-svc   ClusterIP   172.31.116.87   <none>        8080/TCP   57s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web01   3/3     3            3           22m
deployment.apps/web02   3/3     3            3           57s

 使用 cluster-ip 訪問 pod 看能否訪問成功

# 訪問 httpd
[root@dce-10-6-215-215 tmp]# curl 172.31.63.225
<html><body><h1>It works!</h1></body></html>

# 訪問 tomcat,因為沒有頁面,所以是 404
[root@dce-10-6-215-215 tmp]# curl 172.31.116.87:8080
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/8.5.73</h3></body></html>[root@dce-10-6-215-215 tmp]#
創建 Ingress-nginx 資源對象

創建文件夾 ingress-controller 存放 ingress-nginx 的 yaml 文件

 # 創建文件夾
[root@dce-10-6-215-215 tmp]# mkdir ingress-controller

# 進入到文件夾里面
[root@dce-10-6-215-215 tmp]# cd ingress-controller/
[root@dce-10-6-215-215 ingress-controller]#

獲取 ingress-nginx,本次案例使用的是0.30版本

# 獲取 ingress-nginx,本次案例使用的是0.30版本
[root@dce-10-6-215-215 ingress-controller]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
[root@dce-10-6-215-215 ingress-controller]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml

下載完成之后查看

[root@dce-10-6-215-215 ingress-controller]# ls
mandatory.yaml  service-nodeport.yaml

修改 mandatory.yaml 文件中的代碼

關於上面 yaml 文件中寫入的 “hostNetwork: true” 具體解釋:如果使用此網絡參數,那么 pod 中運行的應用程序可以直接使用 Node 節點端口,這樣 node 節點主機所在的網絡的其他主機,都可以通過訪問到此應用程序。

修改完成之后運行 mandatory.yaml 文件

[root@dce-10-6-215-215 ingress-controller]# kubectl apply -f mandatory.yaml
namespace/ingress-nginx created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
limitrange/ingress-nginx created

確定 Ingress-nginx 容器運行正常

# 確定 Ingress-nginx 容器運行正常,注意,namespace 是在 ingress-nginx 下
[root@dce-10-6-215-215 ingress-controller]# kubectl get pod -n ingress-nginx
NAME                                        READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-5fc65f5fd7-tcskb   1/1     Running   0          29m
定義 Ingress 規則(編寫 ingress 的 yaml 文件)

創建一個 ingress-demo.yaml 文件,代碼如下

apiVersion: extensions/v1beta1
kind: Ingress  # 類型為 Ingress
metadata:
  name: test-ingress
  namespace: zouzou  # ns 為 zouzou
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: www.test01.com  # 這里寫你的域名
    http:
      paths:
      - path: /  # 訪問 / 路徑時轉發給 httpd-svc 的 service,端口為 80
        backend:
          serviceName: httpd-svc # svc 的名稱
          servicePort: 80  # svc 的端口
      - path: /tomcat 
        backend:
          serviceName: tomcat-svc  # 訪問 /tomcat 路徑時轉發給 tomcat-svc 的 service,端口為 8080
          servicePort: 8080

執行 ingress 規則的 yaml文件

kubectl apply -f ingress-demo.yaml

查看 ingress 規則資源對象

# 查看 ingresses
[root@dce-10-6-215-215 ingress-controller]# kubectl get ingresses -n zouzou
NAME           CLASS    HOSTS            ADDRESS   PORTS   AGE
test-ingress   <none>   www.test01.com             80      31m

至此已經實現了我們想要的功能,現在就可以通過 www.test01.com 來訪問到我們后端 httpd 容器提供的服務,通過 www.test01.com/tomcat 來訪問我們后端 tomcat 提供的服務

在訪問之前,需要配置 dns 解析,修改你的 hosts 文件,將 www.test01.com 加進去

liufujia@zou ~ % sudo vim /etc/hosts
127.0.0.1	localhost
255.255.255.255	broadcasthost
::1             localhost
127.0.0.1 kubernetes.docker.internal
10.6.215.200 www.test01.com # 對應你的服務器地址

注意,上面的 10.6.215.200 為你 Ingress-nginx 容器所在的節點 IP

# 可以看到 ingress-nginx 的 pod 是在 node 為 dce-10-6-215-200 的節點上,這個節點的 ip 就是 10.6.215.200
[root@dce-10-6-215-215 ingress-controller]# kubectl get pod -n ingress-nginx -o wide
NAME                                        READY   STATUS    RESTARTS   AGE   IP             NODE               NOMINATED NODE   READINESS GATES
nginx-ingress-controller-5fc65f5fd7-tcskb   1/1     Running   0          39m   10.6.215.200   dce-10-6-215-200   <none>           <none>

然后我們去訪問兩個地址

為 Ingress 規則創建一個 service

在上面的訪問測試中,雖然訪問到了對應的服務,但是有一個弊端,就是在做 DNS 解析的時候,只能指定 Ingress-nginx 容器所在的節點 IP。而指定 k8s 集群內部的其他節點 IP(包括master)都是不可以訪問到的,如果這個節點一旦宕機,Ingress-nginx 容器被轉移到其他節點上運行(不考慮節點標簽的問題)。隨之還要我們手動去更改 DNS 解析的 IP(要更改為Ingress-nginx 容器所在節點的 IP,通過命令 “kubectl get pod -n ingress-nginx -o wide” 可以查看到其所在節點),很是麻煩。

有沒有更簡單的一種方法呢?答案是肯定的,就是我們為 Ingress-nginx 規則再創建一個類型為 nodePort 的 Service,這樣,在配置 DNS 解析時,就可以使用 www.test01.com 綁定所有node 節點,包括 master 節點的 IP了,很是靈活。

在前面我們還下載了一個 service-nodeport.yaml 的文件,還沒有用到,這里就可以用到了

# 查看內容,不需要修改
[root@dce-10-6-215-215 ingress-controller]# cat service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  type: NodePort
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---

執行 yaml 文件

[root@dce-10-6-215-215 ingress-controller]# kubectl apply -f service-nodeport.yaml
service/ingress-nginx created

查看運行的 service 

# 可以看到 service 分別將 80 和 443 端口映射到了節點的 31162 和 35493 端口(隨機映射的,也可以修改 yaml 文件指定端口)
[root@dce-10-6-215-215 ingress-controller]# kubectl get svc -n ingress-nginx
NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   172.31.195.202   <none>        80:31162/TCP,443:35493/TCP   4m16s

然后我們將我們本地的 DNS 解析成 master 的 ip

liufujia@zou ~ % sudo vim /etc/hosts
127.0.0.1	localhost
255.255.255.255	broadcasthost
::1             localhost
127.0.0.1 kubernetes.docker.internal
10.6.215.215 www.test01.com # 對應你的 master 的地址

然后使用域名+端口去訪問,這里我使用 http,端口就是 31162

基於虛擬主機的 Ingress 規則

如果現在是另一種需求,我需要將 www.test01.com 和 www.test02.com 都對應上我后端的 httpd 容器提供的服務,那么此時應該怎么配置?

修改 ingress-demo.yaml 文件規則,如下

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: zouzou
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: www.test02.com       # 增加 www.test02.com 配置
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc       # 綁定和 www.test01 相同的service名稱
          servicePort: 80
  - host: www.test01.com     # 增加 www.test01.com 配置
    http:
      paths:
      - path: /
        backend:
          serviceName: httpd-svc  # 綁定和 www.test01 相同的service名稱
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: tomcat-svc
          servicePort: 8080

從上面的 yaml 文件里我們可以得到下面信息

  • 當訪問 www.test02.com 時,只有一個根路由 /
  • 當訪問 www.test01.com 時,有兩個路由,一個是 /,還有一個是 /tomcat

改完 yaml 后重新配置 ingress-demo.yaml 文件

[root@dce-10-6-215-215 ingress-controller]# kubectl apply -f ingress-demo.yaml
ingress.extensions/test-ingress configured

在本地的 hosts 文件里添加上 www.test02.com 的映射關系

查看 svc 的地址

# 因為我刪除過,重新改了,所以這里的 端口就不一樣了
[root@dce-10-6-215-215 ingress-controller]# kubectl get svc -n ingress-nginx
NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   172.31.116.17   <none>        80:38750/TCP,443:36490/TCP   23m

然后訪問 www.test01.com

訪問 www.test02.com

可以查看 ingress 的規則

[root@dce-10-6-215-215 ingress-controller]# kubectl describe ingresses
No resources found in default namespace.
[root@dce-10-6-215-215 ingress-controller]# kubectl describe ingresses -n zouzou
Name:             test-ingress
Namespace:        zouzou
Address:          172.31.116.17
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host            Path  Backends
  ----            ----  --------
  www.test02.com  # www.test02.com 只有一個路由
                  /   httpd-svc:80 (172.29.190.191:80,172.29.34.227:80,172.29.34.40:80)  
  www.test01.com  # www.test01.com 有兩個路由
                  /         httpd-svc:80 (172.29.190.191:80,172.29.34.227:80,172.29.34.40:80)
                  /tomcat   tomcat-svc:8080 (172.29.190.172:8080,172.29.35.135:8080,172.29.38.17:8080)
Annotations:      nginx.ingress.kubernetes.io/rewrite-target: /
Events:
  Type    Reason  Age                  From                      Message
  ----    ------  ----                 ----                      -------
  Normal  UPDATE  45m                  nginx-ingress-controller  Ingress zouzou/test-ingress
  Normal  CREATE  29m                  nginx-ingress-controller  Ingress zouzou/test-ingress
  Normal  UPDATE  9m43s (x3 over 28m)  nginx-ingress-controller  Ingress zouzou/test-ingress

 


免責聲明!

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



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