【Kubernetes系列七】Ingress資源物件
k8s提供了兩種內建的雲端負載均衡機制用於釋出公共應用,一種是工作於傳輸層的service資源,它實現的是TCP負載均衡器,另一種是Ingress資源,它實現的是HTTP(S)負載均衡器。
TCP負載均衡器
無論是iptables還是ipvs模型的service資源都配置於Linux核心中的netfilter之上進行四層排程,是一種型別更為通用的排程器,支援排程HTTP、MYSQL等應用層服務。不過,也正是由於工作於傳輸層從而使得它無法做到類似解除安裝https種的ssl會話等一類操作,也不支援基於url的請求排程機制,而且,k8s也不支援為此類負載均衡器配置任何型別的健康檢查機制
HTTP(S)負載均衡器
HTTP(S)負載均衡器是應用層負載均衡機制的一種,支援根據環境做出更好的排程決策。與傳輸層排程器相比,它提供了諸如可自定義url對映和tls解除安裝等功能,並支援多種型別的後端伺服器監控狀態檢測機制。
1. Ingress和Ingress Controller
service資源和pod資源的IP地址僅能用於叢集網路內部的通訊,所有的網路流量都無法穿透邊界路由器以實現叢集內外通訊。儘管可以為service使用NodePort或LoadBalancer型別通過節點引入外部流量,但它依然是4層流量轉發,可用的負載均衡器也為傳輸層負載均衡機制。
Ingress是k8s的標準資源型別之一,它其實就是一組基於DNS名稱或URL路徑把請求轉發至指定的service資源的規則,用於將叢集外部的請求流量轉發至叢集內部完成服務釋出。然而,Ingress資源自身並不能進行流量穿透,它僅是規則的集合,這些規則要想真正發揮作用還需要其他功能的輔助,如監聽某套接字,然後根據這些規則的匹配機制路由請求流量。這種能夠為Ingress資源監聽套接字並轉發流量的元件稱為Ingress控制器。
Ingress控制器可以由任何具有反向代理功能的服務程式實現,如Nginx、Envoy和Traefik等。Ingress控制器自身也是運行於叢集中的pod資源物件,它與被代理的執行為pod資源的應用運行於同一網路中。使用Ingress資源進行流量分發時,Ingress控制器可基於某Ingress資源定義的規則將客戶端的請求流量直接轉發至與service對應的後端pod資源之上,這種轉發機制會繞過service資源,從而省去了由kube-proxy實現的埠代理開銷。Ingress規則需要由一個service資源物件輔助識別相關的所有pod物件,但Ingress-nginx控制器可經由api.ilinux.io規則的定義直接將請求流量排程至後端pod上,而無須經由service物件api的再次轉發。
2. 建立Ingress資源
Ingress資源是基於http虛擬主機或url的轉發規則,它在資源配置清單的spec欄位中嵌套了rules、backend和tls等欄位的定義:
示例: 把發往www.ilinux.io的請求代理給名為myapp-svc的service資源
~]# cat my-ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: www.libux.io
http:
paths:
- backend:
serviceName: myapp-svc
servicePort: 80
資源清單中annotation用於識別其所屬的Ingress控制器的型別,這一點在叢集中部署有多個Ingress控制器時尤為重要。
Ingress spec中的欄位是定義Ingress資源的核心組成部分:
rules:用於定義當前Ingress資源的轉發規則列表;未由rules定義規則,或者沒有匹配到任何規則時,所有流量都會轉發到由backend定義的預設後端。
backend:預設的後端用於服務那些沒有匹配到任何規則的請求;定義Ingress資源時,至少應該定義backend或rules兩者之一;此欄位用於讓負載均衡器指定一個全域性預設的後端。
tls:TLS配置,目前僅支援通過預設埠443提供服務,如果要配置指定的列表成員指向了不同的主機,則須通過SNI TLS擴充套件機制來支援此功能。
backend物件的定義由兩個必選的內嵌欄位組成:serviceName和servicePort,分別用於指定流量轉發的後端目標service資源的名稱和埠。
rules物件由一系列配置Ingress資源的host規則組成,這些host規則用於將一個主機上的某個url路徑對映至相關的後端service物件。
spec:
rules:
- host: <String>
http:
paths:
- backend:
serviceName: <String>
servicePort: <String>
path: <String>
注意:spec.rules.host屬性值目前不支援使用IP地址,也不支援後跟埠號,且欄位值留空表示通配所有的主機名。
tls物件由兩個內嵌欄位組成,僅在定義tls主機的轉發規則時才需要定義此類物件:
hosts:包含於使用的tls證書之內的主機名稱字串列表,因此,此處使用的主機名必須匹配tlsSecret中的名稱
secretName:用於引用SSL會話的secret物件名稱,在基於SNI實現多主機路由的場景中,此欄位可選。
3. Ingress資源型別
基於http暴露的每個service資源均可釋出於一個獨立的FQDN主機名之上,如www.ik8s.io;也可釋出於某主機的URL路徑之上,從而將它們整合到同一個web站點,如www.ik8s.io/frafana。至於是否需要釋出為https型別的應用則取決於使用者的業務需求。
(1) 單service資源型Ingress
暴露單個服務的方法有很多種,如服務型別中的NodePort、LoadBalancer等,不過一樣可以考慮Ingress來暴露服務,此時只需要為Ingress指定default.backend即可
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
backend:
serviceName: my-svc
servicePort: 80
Ingress控制器會為其分配一個IP地址接入請求流量,並將它們轉至後端。
(2) 基於url路徑進行流量分發
垂直拆分或微服務架構中,每個小的應用都有其專用的service資源暴露服務,但在對外開放的站點上,它們可能時財經、新聞、電商即可等一類的獨立應用,可通過主域名的url路徑分別接入,用於釋出叢集內名稱為API和WAP的service資源。於是,可對應地建立一個如下的Ingress資源:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
anotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: www.ilinux.io
http:
paths:
- path: /wap
backend:
serviceName: wap
servicePort: 80
- path: /api
backend:
serviceName: api
servicePort: 80
(3) 基於主機名稱的虛擬主機
將多個FQDN解析至同一IP地址
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: api.ik8s.io
http:
paths:
- backend:
serviceName: api
servicePort: 80
- host: wap.ik8s.io
http:
paths:
- backend:
serviceName: wap
servicePort: 80
(4) TLS型別的Ingress資源
這種型別用於以https釋出service資源,基於一個含有私鑰和證書的secret物件即可配置TLS協議的Ingress資源,目前來說,Ingress資源僅支援單TLS埠,並且還會解除安裝TLS會話,在Ingress資源中引用此secret即可讓Ingress控制器載入並配置為https服務
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: no-rules-map
spec:
tls:
- secretName: ikubernetesSecret
backend:
serviceName: homesite
servicePort: 80
4.部署Ingress控制器(使用Nginx)
執行為pod資源的Ingress控制器程序接入外部的請求流量常用的有兩種解決方案:
第一種:以deployment控制器管理Ingress控制器的pod資源,並通過NodePort或LoadBalancer型別的service物件為其接入叢集外部的請求流量,這就意味著,定義一個Ingress控制器時,必須在其前端定義一個專用的service資源
第二種:藉助於DaemonSet控制器,將Ingress控制器的pod資源各自以單一例項的方式運行於叢集的所有或部分工作節點之上,並配置這類pod物件以hostPort或hostNetwork的方式在當前節點接入外部流量。
例子:釋出tomcat應用實踐
(1) 建立Ingress控制器
Ingress控制器把ingress規則轉換為nginx配置檔案,然後建立一個service,為ingress控制器提供入口,採用nodeport
~]# wget https://github.com/kubernetes/ingress-nginx/tree/master/deploy/static/mandatory.yaml
~]# kubectl get nodes --show-labels #檢視node的標籤
NAME STATUS ROLES AGE VERSION LABELS
master.ilinux.io Ready master 98d v1.12.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master.ilinux.io,node-role.kubernetes.io/master=
node01.ilinux.io Ready <none> 98d v1.12.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=node01.ilinux.io
node02.ilinux.io NotReady <none> 98d v1.12.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node02.ilinux.io
node03.ilinux.io NotReady <none> 97d v1.12.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node03.ilinux.io
需要修改mandatory.yaml檔案中的nodeSelector符合上述節點標籤對應
~]# vi mandatory.yaml
spec --> spec --> nodeSelector --> beta.kubernetes.io/os: linux
~]# kubectl apply -f mandatory.yaml
上述操作建立ingress-nginx名稱空間及ingress-nginx控制器
(2) 定義一個service,作為Ingress控制器的service資源入口,此處為NodePort 型別
~]# cat nginx-ingress-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
spec:
type: NodePort
clusterIP: 10.99.99.99
ports:
- port: 80
name: http
nodePort: 30080
- port: 443
name: https
nodePort: 30443
selector:
app.kubernetes.io/name: ingress-nginx
此時,可以通過node節點IP的30080埠測試,結果為404即為成功
(3) 建立testing名稱空間,部署tomcat應用
~]# kubectl create namespace testing
~]# cat tomcat-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deploy
namespace: testing
spec:
replicas: 2
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: tomcat
image: tomcat:8.0.50-jre8-alpine
ports:
- containerPort: 8080
name: httpport
- containerPort: 8009
name: ajpport
~]# kubectl get pods -n testing
NAME READY STATUS RESTARTS AGE
tomcat-deploy-5b9cfbdcb4-7hd4c 1/1 Running 0 10m
tomcat-deploy-5b9cfbdcb4-ph459 1/1 Running 0 10m
(4) 為tomcat例項提供service資源
~]# cat tomcat-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
namespace: testing
labels:
app: tomcat-svc
spec:
selector:
app: tomcat
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
(5) 為service提供ingress資源,編寫規則
~]# cat tomcat-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: tomcat
namespace: testing
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: tomcat.ilinux.io
http:
paths:
- path:
backend:
serviceName: tomcat-svc
servicePort: 80
~]# kubectl get ingress -n testing
NAME HOSTS ADDRESS PORTS AGE
tomcat tomcat.ilinux.io 80 24h
此時,本地繫結hosts(ingress域名,node節點IP),可以訪問域名的30080埠即可訪問