1. 程式人生 > >kubernetes service 和 ingress

kubernetes service 和 ingress

也有 允許 雲計 def c4c 網絡請求 class 內核和 linux.

一 總述

1 service 作用

POD 中運行的容器存在動態、彈性的變化(容器的重啟IP地址會變化),因此便產生了service,其資源為此類POD對象提供一個固定、統一的訪問接口及負載均衡能力,並借助DNS系統的服務發現功能,解決客戶端發現容器難得問題

service 和POD 對象的IP地址在集群內部可達,但集群外部用戶無法接入服務,解決的思路有:
1 在POD上做端口暴露(hostPort)
2 在工作節點上公用網絡名稱空間(hostNetwork)
3 使用service 的NodePort 或 loadbalancer (service 依賴於 DNS資源服務)
4 ingress七層負載均衡和反向代理資源

2 service資源及實現模型

1 service 概述

1 service是微服務的一種實現,事實上其是一種抽象:通過關註定義出多個POD對象組合而成的邏輯集合,以及訪問這組POD的策略,service關聯POD 需要標簽選擇器完成,其基於標簽選擇器將一組POD定義成一個邏輯集合,並通過自己的IP地址和端口調度代理請求至後端POD之上。


2 service 對象的IP地址稱為cluster IP,位於K8S集群配置指定的專用IP地址範圍內,其是一種虛擬IP地址,其在service對象創建後保持不變,並且能夠被同一集群中的POD資源訪問,service端口接受客戶端的請求並將其轉發至後端POD中的相應端口,因此,其又被稱為四層代理,因其工作在TCP/IP層。


3 service 資源通過API server 持續監視標簽選擇器匹配到的後端POD對象,並實時跟蹤各對象的變動,service並不直接連接POD對象,而是通過endpoints 資源對象類型處理,其有IP地址和端口組成,默認情況下,當創建service對象時,其關聯的endpoints對象也會被自動創建。

2 虛擬IP和服務代理

1 虛擬IP

一個service對象就是工作節點上的一些iptables或ipvs,用於將到達service對象的IP地址的流量轉發到相應的endpoint對象指定的IP地址和端口上,kube-proxy組件通過api-server持續監控著各個service及其相關的POD對象,並將其創建或變動實時反映到工作節點的iptable或ipvs上。


ipvs是借助於netfilter實現的網絡請求報文調度框架,支持rr、wrr、lc、wlc、sh、sed和nq 等十余種調度算法,用戶空間的命令行工具是ipvsadm,用於管理工作於ipvs上的調度規則。


service IP 事實上是用於生成iptables 或 ipvs 規則時使用的ip地址,僅用於實現K8S集群網絡的內部通信,並能夠通過規則中定義的轉發服務請求作為目標地址予以響應,這也是其成為虛擬IP地址的原因。

2 代理模型

1 userspace 代理模型(用戶空間模型)

userspace 是Linux操作系統的用戶空間,這種模型中,kube-proxy 負責跟蹤API server 上的endpoints對象的變動,並根據其進行相關的調整策略。

對於每個service對象,其都會隨機打開一個本地端口,任何到達此端口的請求都會被代理到當前service資源的後端各個POD對象上,其默認使用RR調度策略。

其代理的過程是: 請求到達service後,其被轉發到內核,經由套接字送往用戶空間的kube-proxy,而後經由kube-proxy送回內核空間,並調度至後端POD,其傳輸方式效率太低。在1.1 版本之前,其是默認的轉發策略。

2 iptables代理模型

kube-proxy 負責跟蹤API server上 service和 endpoints對象的變動,並據此作出service資源定義的變動,對於每個service,都會創建iptabls規則直接捕獲到達clusterIP 和PORT 的流量,並將其重定向到當前的service後端,默認算法是隨機調度算法,POD 直接請求service IP 地址通過其直接訪問對應的POD服務,在1.2開始成為默認類型,其使用的是iptables的目標地址轉換至後端的POD對象,相對而言,其不用在內核和用戶空間之間切換,因此更加高效,但其不能再被挑中的POD資源無響應時進行重定向,但用戶空間(userspace)模型可以。

3 ipvs模型

此模型跟蹤API service上的service和endpoints對象的變動,據此來調用netlink接口創建IPVS規則,並確保API server中的變動保持同步,其流量調度策略在IPVS中實現,其余的在iptables中實現。
ipvs 支持眾多調度算法,如rr、lc、dh、sh、sed和nq 等。

二 service 資源基本應用

service 本身不提供服務,其是通過後端POD提供對應的服務,因此,service資源對象通常要和deployment謝忠完成應用的創建和對外發布。

1 創建service 資源

1 使用命令行創建service資源

創建POD資源

 kubectl run   nginx  --image=nginx:1.14  --replicas=3

查看deployment資源
技術分享圖片
其名稱為nginx

創建對應的service資源

kubectl expose  deployment nginx --name=nginx --port=80 --target-port=80 --protocol=TCP

查看生成的service
技術分享圖片

查看生成的endpoints對應關系
技術分享圖片
node節點資源訪問

技術分享圖片

2 使用配置文件創建service

#[root@master1 service]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用於匹配後面POD對象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就緒性探測,用於探測服務是否正常運行,若未就緒則service不能向該POD上調度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名稱
spec:
    selector:  # 用於匹配後面POD對象
        app: service
    ports:
        - protocol: TCP  # 使用的協議
          port: 80  #service 端口號
          targetPort: 80  # 後端POD端口號

部署

kubectl apply -f demo.yaml 

查看service訪問的接口
技術分享圖片

查看service詳細信息

技術分享圖片

其默認類型是clusterIP,使用地址為自動配置,此類型的service對象只能通過集群內部訪問。若集群中的POD對象的標簽為app=service,則其會被自動關聯至service後端

創建http服務用以驗證

kubectl run http  --image=httpd  -l app=service

查看POD是否啟動成功
技術分享圖片

查看 endpoints

技術分享圖片

測試
其IP地址為service對應的IP地址

for  i in  1 2 3;do curl http://10.0.0.52 && echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ;done

查看
技術分享圖片

技術分享圖片

當kubernetes 集群的service代理模式為iptables,它默認使用的算法是隨機調度,因此service會將客戶端的請求隨機調度至關聯的某個POD資源上。

2 service 會話粘滯性

1 概述

service 會話粘滯性
service 資源支持session affinity(黏性會話或會話黏性)機制,能夠將來自同一個客戶端的請求始終轉發至同一個後端POD,其會降低負載均衡的效果,因此,當客戶端訪問POD中的應用程序時,如果有基於客戶端身份保存某些私有信息,並基於這些私有信息追蹤用戶的活動一類的需求時,就應該啟動會話保持機制。


session affinity的效果會在一定時間期限內生效,默認是10800秒,超出此時間之後,客戶端的再次訪問會被調度算法重新調度,另外service資源的session affinity 機制僅能基於客戶端IP地址識別客戶端身份,他會把經由同一個NAT 服務器進行源地址轉換的所有客戶端識別為統一客戶端,調度粒度粗糙且效果不佳,因此,實踐中不推薦使用此種方法實現粘性會話。

2 設置字段解析

kubectl explain service.spec.sessionAffinityConfig.clientIP.timeoutSeconds
用於配置配置其會話保持時長,是一個嵌套字段,使用時長是1-86400,默認是10800

kubectl explain service.spec.sessionAffinity
用於定義要使用的黏性會話的類型,其僅支持"none
和"clinetIP"兩種類型。

none :不使用sessionaffinity,默認值
clientIP:基於客戶端IP地址識別客戶端身份,把來自同一個源IP地址的請求始終調度到同一個POD對象上。

3 部署實例並驗證

1 刪除上面創建實例

kubectl delete -f demo.yaml 

修改實例

[root@master1 service]# cat demo1.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用於匹配後面POD對象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就緒性探測,用於探測服務是否正常運行,若未就緒則service不能向該POD上調度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名稱
spec:
    selector:  # 用於匹配後面POD對象
        app: service
    ports:
        - protocol: TCP  # 使用的協議
          port: 80  #service 端口號
          targetPort: 80  # 後端POD端口號
    sessionAffinity: ClientIP  #配置會話粘滯基於客戶端
    sessionAffinityConfig:  # 配置會話粘滯時間
        clientIP:
            timeoutSeconds: 86400

部署

kubectl apply -f demo1.yaml 

查看後端POD情況
技術分享圖片

查看serviceIP地址
技術分享圖片

測試
技術分享圖片

技術分享圖片

其實現了會話保持

3 服務發現

1 概述

由於各個服務之間需要能夠夠正常通信並提供統一的穩定的訪問入口,所以POD客戶端中的應用需要知道某service資源的IP地址和端口號,這邊產生了service discovery

2 服務發現實現機制

1 部署穩定的服務註冊中心
2 服務提供者(POD及其應用)提供自己的位置信息,並在變動後及時更新信息
3 消費者(serice)周期性層註冊中心獲取服務者提供的最新信息從而發現要訪問的目標服務字段

3 服務發現類型

1 客戶端發現: 由客戶端到註冊中心發現其依賴到服務的相關信息,其需要內置的發現程序和發現邏輯
2 服務端發現:需要使用中央路由器或服務均衡器的組件,服務消費者(客戶端 )將其請求發送到中央路由器或負載均衡器,由他們負責查詢服務註冊中心獲取服務提供者的位置信息,並將服務消費者的請求轉發給服務提供者(POD及其應用)

coreDNS
DNS是原始的服務發現系統之一,但其傳播速度過慢,後期常見的服務註冊中心是zookeeper 和 etcd 等分布式鍵值存儲系統,其只提供基本的數據存儲功能,距離實現完整的服務發現機制還有大量的開發任務,
Netflix 和 eureka 是目前較流行的服務發現系統之一,是專門開發用來實現服務發現的系統,以可用性目的為先,可以在多種故障期間保持服務發現和服務註冊功能的可用,

傳統DNS不適合微服務環境,但skyDNS實現了,

自K8S 1.3 開始,其服務發現的DNS 更新為了kubeDNS,而另一個較新的是 coreDNS,是基於GO語言開發,通過串接一組實現DNS功能的插件的插件連進行工作,自1.11開始coreDNS取代了kubeDNS成為默認的DNS附件。

4 服務發現

1 環境變量

創建POD資源時,kubelet會將其所屬名稱空間內的每個活動的service對象以一系列環境變量的形式註入其中,其支持使用kubernetes service環境變量以及與docker的links 兼容的環境變量


1 kubernetes service 環境變量
kubernetes 為每個service資源生成包括下面形式的環境變量,在同一名稱空間(默認名稱空間default)中創建的POD對象自動擁有這些變量

.{SVCNAME}_SERVICE_HOST
.{SVCNAME}_SERVICE_PORT
註意 : 如果SVCNAME 中使用了鏈接線,則kubernetes會在定義為環境變量時將其轉換為下劃線


2 docker link 形式的環境變量
Docker使用--link 選項實現容器鏈接時所設置的環境變量形式,在創建POD對象時,kubernetes會將與此形式兼容的一系列環境變量註入POD對象中。

查看之前創建的POD的環境變量
1 進入POD

kubectl exec -it  service-demo-7677648c64-m4nqh -- /bin/bash

查看
技術分享圖片

其中DEMO_SERVICE 是之前創建的service的名稱,其以DEMO_SERVICE_SERVICE開頭的是kubernetes service資源的環境變量


基於環境變量的服務發現其功能簡單,已用,但存在局限,僅有那些與創建POD對象在同一名稱空間中且實現存在的service對象的信息才能以環境變量的形式入駐,那些處於非同一名稱空間或者在POD資源創建之後創建的service對象的相關環境變量則不會被添加。

2 cluster DNS

kubernetes上用於名稱解析和服務發現的clusterDNS 是集群的核心附件之一,集群中創建的每個service對象,都會有其自動生成相關資源記錄,默認情況,集群中各POD對象會自動配置clusterDNS 作為其名稱解析服務器,並在其DNS搜索列表中包含其所屬的名稱空間的域名後綴。

不管是使用clusterDNS還是coreDNS,其提供的DNS的服務發現解決方案都會負責解析下面資源類型以實現服務發現。


1 擁有clusterIP的service資源,具有下面類型的資源記錄
A 記錄: <service>.<ns>.svc.<zone>.<ttl> IN A <cluster-ip>

SRV記錄: <port>.<proto>.<service>.<ns>.svc.<zone>.<ttl> IN SRV <weight> <priority><port-number><service>.<ns>.svc.<zone>
PTR記錄:<d>.<c>.<b><a>.in-addr.arpa.<ttl> IN PTR <service>.<ns>.svc.<zone>


2 headless 類型的service 資源

A 記錄 : <service>.<ns>.svc.<zone>.<ttl> IN A <endpoint-ip>

SRV 記錄 : <port>.<proto>.<service>.<ns>.svc.<zone>.<ttl> IN <weight><priority> <port-number> <hostname>.<ns>.svc.<zone>
PTR 記錄:<d>.<c>.<b>.<a>.in-addr-arpa.<ttl>IN PTR <hostname>.<service>.<ns>.svc.<zone>


3 externalName 類型資源的service資源,具有CNAME類型的資源記錄 。

CNAME 記錄: <service>.<ns>.svc.<zone>.<ttl> IN CNAME <extname>

名稱解析和服務發現是kubernetes系統需要功能得以實現的基礎服務,其通常是集群安裝完成應該部署的附加組件,使用kubeadm 初始化一個集群時,其會自動部署。

3 DNS

創建service資源對象時,clusterDNS 會自動創建資源記錄用於名稱解析和服務註冊。POD可直接使用其DNS 訪問service資源,每個service對象相關的DNS 記錄如下:

.{SVCNAME}.{NAMESPACE}.{CLUSTER_DOMAIN}

.{SVCNAME}.{NAMESPACE}.svc.{CLUSTER_DOMAIN}
--cluster-dns 指定了集群DNS服務的工作地址
--cluster-domino 定義了集群使用的本地域名。因此系統初始化默認會將"cluster.local."和主機所在的域"ilinux.io."作為DNS的本地域使用,這些信息會在POD創建時以DNS配置的相關信息註入它的/etc/resolv.conf 配置文件中

查看
技術分享圖片

{NAMESPACE}.svc.{CLUSTER_DEMAIN}: 如 default.svc.cluster.local

svc.{CLUSTER_DOMAIN}: 如 svc.luster.local

{CLUSTER_DOMAIN}: 如 cluster.local

{WORK_NODE_DOMAIN}: 如上述未定義

4 服務暴露

默認的service 的IP默認是在集群內部可達,但若需要外部訪問,則需要進行處理

1 service類型

1 clusterIP : 集群內部可達,無法被外部客戶端訪問,創建service的默認訪問類型

2 NodePort:建立在clusterIP之上(集群上的NODE節點+端口)均和訪問到。

3 loadbalancer:在NodePort之上,通過cloud provider提供的負載均衡器將服務暴露到集群外部,因此loadbalancer具有NodePort和clusterIP。一個loadbalancer類型的service會指向關聯至kubernetes集群外部的,切實存在的某個負載均衡設備,該設備通過工作節點上的NodePort 向集群內部發送請求流量,其優勢在於能夠把來自集群外部客戶端的請求調度至所有節點的NodePort 之上,而不是依賴於客戶端自動決定鏈接至那個節點,從而避免了因客戶端指定的節點故障而導致的服務不可用。

4 externalName: 通過將service映射到映射至由externalName字段的內容指定的主機名來暴露服務,此主機名需要被DNS服務解析成CNAME 類型的記錄,其無clusterIP 和 Noport,也沒有標簽選擇器,因此沒endpoints ,其是一個域名,是CNAME結構,集群內部的域名。

2 NodePort

1 概述

NodePort 及節點Port,其在安裝s集群系統時會預留一個端口範圍用於NodePort,默認是30000-32767之間的端口,ClusterIP類型可省略.spec.type,但其NodePort類型則必須指定對應的type方可。

2 刪除之前的實例 :

kubectl delete -f demo.yaml 

修改結果如下

#root@master1 service]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用於匹配後面POD對象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就緒性探測,用於探測服務是否正常運行,若未就緒則service不能向該POD上調度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名稱
spec:
    type: NodePort  #指定其類型為NodePort
    selector:  # 用於匹配後面POD對象
        app: service
    ports:
        - protocol: TCP  # 使用的協議
          port: 80  #service 端口號
          targetPort: 80  # 後端POD端口號
          nodePort: 32380  # 指定其節點端口為32380

此處可不配置nodePort,其會自動生成nodePort

3 部署

 kubectl apply -f demo.yaml 

查看
技術分享圖片

其NodePort 資源會創建ClusterIP,事實上,其會作為節點從NodePort 接入流量後轉發至目標地址,目標端口則是與service資源對應的spec.ports.port屬性中定義的端口。

NodeIP:NodePort------> SrviceIP:ServicePort------>PodIP:PodPort

4 訪問測試

技術分享圖片
技術分享圖片

其內部可通過clusterIP進行訪問

技術分享圖片

3 loadBalancer

1 概述

NodePort 如果外部客戶端無法得知其IP地址和對應映射的端口,則其訪問不成功,其次,若對應IP地址的Node節點故障,則其訪問也將失敗,因此,一般還應在集群外部創建一個具有公網IP地址的負載均衡器。由其接入外部客戶端請求並調度至集群節點相應的NodePort之上。

相關實例如下:

2 刪除之前配置

kubectl delete -f demo.yaml 

3 修改配置結果如下

[root@master1 service]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用於匹配後面POD對象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就緒性探測,用於探測服務是否正常運行,若未就緒則service不能向該POD上調度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名稱
spec:
    type: LoadBalancer  #指定其類型為LoadBalancer
    selector:  # 用於匹配後面POD對象
        app: service
    ports:
        - protocol: TCP  # 使用的協議
          port: 80  #service 端口號
          targetPort: 80  # 後端POD端口號
          nodePort: 32380  # 指定其節點端口為32380

4 部署

kubectl apply -f demo.yaml 

查看
技術分享圖片

5 訪問測試

其可以使用NodePort的方式進行訪問
技術分享圖片

技術分享圖片

IaaS 雲計算環境提供了LBaaS服務,它允許租戶動態的在自己的網絡中創建一個負載均衡器,那些部署在此類環境上的kubernetes集群在創建service資源時可以直接調用此接口按需創建一個軟負載均衡器,而具有這種功能的service資源及為loadBalancer類型,其目前環境不支持此種配置。

4 externalName

1 概述

externalName 類型的service資源用於將集群外部的服務發布到集群中以供Pod中的應用程序訪問,因此,其不需要使用任何標簽選擇器關聯至任何POD對象,但必須要使用spec.externalName屬性定義一個CNAME記錄用於返回外部真正提供服務的主機別名,而後通過CNAME 記錄值獲取到相關主機的IP地址。

2 配置實例

實例如下:

#[root@master1 service]# cat ex.yaml 
apiVersion: v1
kind: Pod
metadata:
    name: tomcat
    namespace: default
    labels:
        app: tomcat
spec:
    containers:
        - name: tomcat
          image: tomcat:8.5.35
          ports:
            - name: tomcat
              containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
    name: external-tomcat-svc
    namespace: default
spec:
    type: ExternalName
    externalName: www.baidu.com
    ports:
        - protocol: TCP
          port: 80
          targetPort: 80
          nodePort: 0
    selector: {}

3 部署服務

kubectl apply -f ex.yaml 

查看
技術分享圖片

等到此service資源 external-tomcat-svc 創建完成後,各POD對象即可通過external-tomcat-svc 或其FQDN格式的名稱 external-tomcat-svc.default.svc.cluster 訪問相應的資源,ClusterDNS 會將此名稱以CNAME 格式解析為.spec.externalName字段中的名稱,而後通過DNS服務將其解析為相應的主機的IP地址.

4 測試 :

需要安裝nslookup 如下

#鏈接其中一個POD
kubectl exec  -it nginx-7bc476d88b-p5sv2  -- /bin/bash
安裝nslookup
apt-get  update 
apt-get install dnsutils

查看解析

技術分享圖片

解析到其name 為www.baidu.com
由於 externalName 類型的service資源實現於DNS級別,客戶端將其直接接入外部服務而完全不需要服務代理,因此,其無序配置clusterIP,此種類型也可稱為headless Service

5 headless

1 概述

service 對象隱藏了個POD資源,並負責將客戶端請求流量調度至POD上,但也有可能存在客戶端需要直接訪問service資源後端的所有POD資源,這時就應該向客戶端暴露每個POD資源的IP地址,而不是中間層service對象的ClusterIP,這種類型便是無頭服務。


headless service 對象沒有ClusterIP,因此便無相關負載均衡或代理問題,其如何為此類service配置IP地址,其取決於標簽選擇器的定義。

1 具有標簽選擇器
端點控制器(endpoints controller)會在API中為其創建endpoints記錄,並將clusterDNS服務中的A記錄直接解析到service後端的各個POD對象的IP地址上。
2 沒有標簽選擇器: 端點控制器(endpoints controller)不會在API中為其創建endpoints記錄,clusterDNS的配置分為兩種類型,對externalName的服務創建CNAME 記錄,對其他三種類型來說,為那些與當前service共享的名稱空間的所有endpoints對象創建一條記錄。

2 創建服務資源

實例

[root@master1 service]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用於匹配後面POD對象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就緒性探測,用於探測服務是否正常運行,若未就緒則service不能向該POD上調度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名稱
spec:
    clusterIP: None  #指定其類型為Headless Service資源
    selector:  # 用於匹配後面POD對象
        app: service
    ports:
        - protocol: TCP  # 使用的協議
          port: 80  #定義暴露的端口
          targetPort: 80  # 後端POD端口號
          name: httpport  # 定義名字

部署服務

kubectl apply -f demo.yaml 

查看服務
技術分享圖片

其資源信息中沒有ClusterIP,但其存在endpoints,


查看其解析,其後端是POD的IP地址。其通過標簽選擇器選擇到此IP地址。於是客戶端向此service對象發起的請求將直接接入到POD資源中,而不再由service進行代理轉發。

技術分享圖片

查看訪問資源
技術分享圖片

3 ingress資源應用

1 概述

kubernetes 提供了兩種內建的負載均衡機制,一種是位於傳輸層的TCP/IP service資源,其實現的是TCP負載均衡器,另一種是ingress資源,其實現的是HTTP(S)負載均衡器。

TCP負載均衡器
iptables 和 ipvs均實現的是四層調度,其不能基於URL 的請求調度機制,其也不支持為此類負載均衡配置任何類型的健康檢查機制。

2 ingress 和 ingress controller

ingress 是kubernetes API 的標準資源類型之一,其其實是一組基於DNS名稱或URL路徑把請求轉發至service資源的規則,用於將集群外部的請求流量轉發至集群內部完成服務發布,ingress 資源自身並不能進行"流量穿透" ,其僅僅是一組路由規則的集合,這些規則要發揮相應的作用,則需要ingress controller,其可監聽套接字,然後給據這些規則的匹配機制路由請求流量。


註意 :ingress 不同於deployment,其不是直接運行與kube-controller-manager的一部分,其是kubernetes集群的一個重要附件,需要單獨安裝才能使用。

ingress 控制器可以由任何具有反向代理(http/https)功能的服務器程序實現,如nginx、envoy、haproxy、vulcand和traefik等,ingress控制器自身也是運行與集群中的POD資源對象,其與北代理的運行的POD資源的應用運行於同一網絡中。

另外: ingress控制器可基於ingress資源定義的規則將客戶端請求流量直接轉發到service對應的後端POD資源上,其會繞過service資源,省去了kube-proxy實現的端口代理開銷。

3 創建ingress資源

註:在此之前,需要先配置ingress資源控制器正常運行

如下
技術分享圖片

集體配置可參考 :https://blog.51cto.com/11233559/2364393 中的安裝和配置ingress服務

創建ingress資源

[root@master1 ingress]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: deploy-ingress
    namespace: default
spec:
    selector:
        matchLabels:
            app: ingress
    template:
        metadata:
            namespace: default
            labels:
                app: ingress
        spec:
            containers:
                - name: pod-ingress
                  image: nginx:1.14
                  ports:
                    - name: http
                      containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress
    namespace: default
spec:
    selector:
        app: ingress
    ports:
        - protocol: TCP
          targetPort: 80
          port: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: demo-ingress
    annotations:
        kubernetes.io/ingress.class: "nginx"  
spec:
    rules:
        - host: www.inginx.com  #指定訪問使用的URL
          http:  
            paths:
                - backend:
                    serviceName: service-ingress  #指定service的名稱
                    servicePort: 80  #指定service的端口號

部署服務

kubectl apply -f demo.yaml

查看服務
技術分享圖片
訪問查看

技術分享圖片

相關字段解析:

[root@master1 ingress]# kubectl explain   ingress.spec
KIND:     Ingress
VERSION:  extensions/v1beta1

RESOURCE: spec <Object>

DESCRIPTION:
     Spec is the desired state of the Ingress. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

     IngressSpec describes the Ingress the user wishes to exist.

FIELDS:
   backend  <Object>#默認的後端服務,用於哪些沒有匹配到任何規則的請求,定義ingress時,必須選擇backend或rules其中的一個。
     A default backend capable of servicing requests that don‘t match any rule.
     At least one of ‘backend‘ or ‘rules‘ must be specified. This field is
     optional to allow the loadbalancer controller or defaulting logic to
     specify a global default.

   rules    <[]Object>  # 用於定義當前ingress字段的轉發規則列表,未定義rules規則,或者沒有匹配到任何規則,所有流量都會轉發到由backend定義的默認後端。
     A list of host rules used to configure the Ingress. If unspecified, or no
     rule matches, all traffic is sent to the default backend.

   tls  <[]Object>#TLS 配置,目前僅支持通過默認端口443提供服務,如果要配置指定的列表成員指向了不同的主機,必須通過SBI TLS擴展機制來支持此功能。
     TLS configuration. Currently the Ingress only supports a single TLS port,
     443. If multiple members of this list specify different hosts, they will be
     multiplexed on the same port according to the hostname specified through
     the SNI TLS extension, if the ingress controller fulfilling the ingress
     supports SNI.
[root@master1 ingress]# kubectl explain   ingress.spec.backend
KIND:     Ingress
VERSION:  extensions/v1beta1

RESOURCE: backend <Object>

DESCRIPTION:
     A default backend capable of servicing requests that don‘t match any rule.
     At least one of ‘backend‘ or ‘rules‘ must be specified. This field is
     optional to allow the loadbalancer controller or defaulting logic to
     specify a global default.

     IngressBackend describes all endpoints for a given service and port.

FIELDS:
   serviceName  <string> -required-  #用於指定service名稱
     Specifies the name of the referenced service.

   servicePort  <string> -required-  # 用於指定service端口
     Specifies the port of the referenced service.
rules對象相關

spec:
    rules:
        - host:  #指定訪問URL名稱
          http: 
                paths:
                    - backend:  #用於指定後端service信息
                                serviceName:
                                servicePort:
                        path: #用於指定後綴 

註意 :ingress.spec.rules.host 屬性值目前不支持使用IP地址,也不支持後跟":PORT"格式的端口號,且此字段值留空表示通配所有的主機名。

[root@master1 ingress]# kubectl explain   ingress.spec.tls
KIND:     Ingress
VERSION:  extensions/v1beta1

RESOURCE: tls <[]Object>

DESCRIPTION:
     TLS configuration. Currently the Ingress only supports a single TLS port,
     443. If multiple members of this list specify different hosts, they will be
     multiplexed on the same port according to the hostname specified through
     the SNI TLS extension, if the ingress controller fulfilling the ingress
     supports SNI.

     IngressTLS describes the transport layer security associated with an
     Ingress.

FIELDS:
   hosts    <[]string>  # 包含與使用的TLS證書值內的主機名稱字符串列表,因此,使用的主機名必須匹配tlsSecret 中的名稱
     Hosts are a list of hosts included in the TLS certificate. The values in
     this list must match the name/s used in the tlsSecret. Defaults to the
     wildcard host setting for the loadbalancer controller fulfilling this
     Ingress, if left unspecified.

   secretName   <string> # 用於引用SSL會話的secret對象名稱,在基於SNI實現多主機路由的場景中,此字段為可選。
     SecretName is the name of the secret used to terminate SSL traffic on 443.
     Field is left optional to allow SSL routing based on SNI hostname alone. If
     the SNI host in a listener conflicts with the "Host" header field used by
     an Ingre***ule, the SNI host is used for termination and value of the Host
     header is used for routing.

4 ingress資源類型

1 單個service資源類型

暴露單個服務的方法很多,如服務類型中的NodePort,loadBalancer等,方式旨在指定默認後端服務

#[root@master1 ingress]# cat nginx.yaml 
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: default-backend-nginx
    namespace: default
spec:
    backend:
        serviceName: nginx # 指定service名稱
        servicePort: 80  #指定service端口

查看服務
技術分享圖片

2 基於URL路徑進行流量分發

[root@master1 ingress]# cat demo.yaml 
apiVersion: v1
kind: Pod
metadata:
    name: nginx
    namespace: default
    labels:
        app: ingress
spec:
    containers:
        - name: pod-ingress
          image: nginx:1.12
          ports:
            - name: http
              containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
    name: tomcat
    namespace: default
    labels:
        app: ingress1
spec:
    containers:
        - name: pod-ingress1
          image: tomcat:8.5.35
          ports:
            - name: tomcat
              containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress
    namespace: default
spec:
    selector:
        app: ingress
    ports:
        - protocol: TCP
          targetPort: 80
          port: 80
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress1
    namespace: default
spec:
    selector:
        app: ingress1
    ports:
        - protocol: TCP
          targetPort: 8080
          port: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: demo-ingress
    annotations:
        ingress.kubernetes.io/rewrite-target: / 
spec:
    rules:
        - host: www.inginx.com  #指定訪問使用的URL
          http:  
            paths: 
                - path: /nginx
                  backend:
                    serviceName: service-ingress  #指定service的名稱
                    servicePort: 80  #指定service的端口號
                - path: /tomcat
                  backend:
                    serviceName: service-ingress1
                    servicePort: 80

部署並查看

kubectl apply -f demo.yaml 

查看
技術分享圖片

目前: ingress-nginx尚不能很好的支持此項功能,因此其目前不能使用

測試結果如下

技術分享圖片
技術分享圖片

可看到其配置文件中版本號和測試結果版本號一致。

3 基於主機名稱的虛擬主機

1 去除上述配置

kubectl delete -f demo.yaml 

配置相關服務

#[root@master1 ingress]# cat demo.yaml 
apiVersion: v1
kind: Pod
metadata:
    name: nginx
    namespace: default
    labels:
        app: ingress
spec:
    containers:
        - name: pod-ingress
          image: nginx:1.12
          ports:
            - name: http
              containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
    name: tomcat
    namespace: default
    labels:
        app: ingress1
spec:
    containers:
        - name: pod-ingress1
          image: tomcat:8.5.35
          ports:
            - name: tomcat
              containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress
    namespace: default
spec:
    selector:
        app: ingress
    ports:
        - protocol: TCP
          targetPort: 80
          port: 80
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress1
    namespace: default
spec:
    selector:
        app: ingress1
    ports:
        - protocol: TCP
          targetPort: 8080
          port: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: demo-ingress
    annotations:
        ingress.kubernetes.io/rewrite-target: / 
spec:
    rules:
        - host: www.inginx.com  #指定訪問使用的URL
          http:  
            paths: 
                - path: 
                  backend:
                    serviceName: service-ingress  #指定service的名稱
                    servicePort: 80  #指定service的端口號
        - host: www.ttomcat.com
          http:
            paths:
                - path:
                  backend:
                    serviceName: service-ingress1
                    servicePort: 80

部署

kubectl apply -f demo.yaml 

配置相關域名解析

技術分享圖片

測試
技術分享圖片
技術分享圖片

4 基於TLS 類型的ingress資源

這種類型用於以HTTPD發布service資源,基於一個含有私鑰和證書的secret對象即可配置TLS協議的ingress資源,目前,ingress資源僅支持單TLS端口,並且還會卸載TLS會話,在ingress資源中引用此secret即可讓ingress控制器加載並配置HTTPS服務。

1 生成證書

 openssl genrsa -out tls.key 2048
 openssl req -new -x509 -key tls.key -out tls.crt -subj  /C=CN/ST=shaanxi/L=xi\‘an/O=linux/CN=www.inginx.io -days 3650

註: TLS secret中包含的證書必須以tls.crt作為其鍵名,私鑰文件必須以tls.key作為鍵名。其CN=www.inginx.io 必須與後面對應的host相同

2 生成secret資源對象

kubectl create secret tls nginx-secret --cert=tls.crt --key=tls.key  

查看

技術分享圖片

3 部署配置

#[root@master1 ingress]# cat demo1.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: nginx-https-deploy
    namespace: default
spec:
    selector:
        matchLabels:
            app: nginx-https
    template:
        metadata:
            namespace: default
            labels:
                app: nginx-https
        spec:
            containers:
                - name: nginx-https
                  image: nginx:1.14
                  ports:
                    - name: http
                      containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
    name: https-demo
spec:
    selector:
        app: nginx-https
    ports:
        - port: 80
          targetPort: 80
          protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: https-ingress
    namespace: default
    annotations:
        kubernetes.io/ingress.class: "nginx"
spec:
    tls: 
        - hosts:
            - www.inginx.io   #指定其訪問使用的域名
          secretName: nginx-secret  #指定其訪問時使用的證書
    rules:
        - host: www.inginx.io
          http:
            paths:
                - path: /
                  backend:
                    serviceName: https-demo
                    servicePort: 80

部署

kubectl apply -f demo1.yaml

配置相關解析

技術分享圖片

4 訪問查看

技術分享圖片
證書信息查看
技術分享圖片

kubernetes service 和 ingress