1. 程式人生 > 其它 >【Kubernetes系列七】Ingress資源物件

【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埠即可訪問