注:本文使用的Traefik爲1.x的版本
在生產環境中,咱們經常須要控制來自互聯網的外部進入集羣中,而這恰巧是Ingress的職責。前端
Ingress的主要目的是將HTTP和HTTPS從集羣外部暴露給該集羣中運行的服務。這與Ingress控制如何將外部流量路由到集羣有殊途同歸之妙。接下來,咱們舉一個實際的例子來更清楚的說明Ingress的概念。nginx
首先,想象一下在你的Kubernetes集羣中有若干個微服務(小型應用程序之間彼此通訊)。這些服務可以在集羣內部被訪問,但咱們想讓咱們的用戶從集羣外部也可以訪問它們。所以,咱們須要作的是使用反向代理將每一個HTTP(S)(例如,service.yourdomain.com
)路由與相應的後端關聯,並在該服務的不一樣實例之間(如,pod)進行負載均衡。與此同時,因爲Kubernetes的性質會不斷髮生變化,所以咱們但願跟蹤服務後端的更改,以便可以在添加或刪除新Pod時將這些HTTP路由從新關聯到新Pod實例。web
使用Ingress資源和關聯的Ingress Controller,你能夠實現如下目標:算法
app.domain.com
指向你的私有網絡中的微服務應用程序domain.com/web
指向你的私有網絡中的微服務webbackend.domain.com
指向你的私有網絡中的微服務後端,並在該微服務的多個實例之間(Pod)進行負載均衡如今,你理解了Ingress的重要性。它可以幫助將HTTP路由指向在Kubernetes集羣中特定的微服務。後端
可是,流量路由並非Ingress在Kubernetes中的惟一功能。例如,還能夠將Ingress配置爲負載均衡流量到你的應用程序、終止SSL、執行基於名稱的虛擬主機、在不一樣服務之間分配流量、設置服務訪問規則等。api
Kubernetes有一個特別的Ingress API資源,它可以支持上述全部功能。可是,簡單地建立一個Ingress API資源是沒有做用的。你還須要一個Ingress Controller。目前,Kubernetes支持許多Ingress controller,如Contour、HAProxy、NGINX以及Traefik。瀏覽器
在本文中,我將使用Traefik Ingress Controller建立Ingress。它可以實現現代HTTP反向代理和負載均衡器的功能,從而簡化了微服務的部署。此外,Traefik對Docker、Marathon、Consul、Kubernetes、Amazon ECS等系統和環境都提供了強大的支持。服務器
Traefik對於諸如Kubernetes之類的靈活性較強的系統十分有用。在Kubernetes中,天天須要屢次添加、刪除或升級服務,而Traefik能夠監聽服務鏡像倉庫/編排器 API並當即生成或更新路由,所以你的微服務無需手動配置便可與外界鏈接。網絡
除此以外,Traefik支持多個負載均衡算法、Let’s Encrypt的HTTPS(支持通配證書)、斷路器、WebSoket、GRPC和多個監控程序(Rest、Prometheus、Statsd、Datadog、InfluxDB等)。有關Traefik中可用功能的更多信息,請參考其官方文檔:app
在教程開始以前,咱們先來簡單地討論一下Ingress資源是如何工做的。如下是隱式使用Nginx Ingress Controller的Ingress示例。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-example annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - http: paths: - path: /microservice1 backend: serviceName: test servicePort: 80
以上Ingress manifest 包含了一系列HTTP規則,它們用於規定controller如何路由流量。
可選主機。若是未指定主機(如上所示),則該規則適用於經過指定IP地址的全部入站HTTP流量。若是提供了主機(如yourhost.com
),則該規則僅適用於該主機。
一個路徑列表(如,/microservice1
),它指向由serviceName
和servicePort
定義的關聯後端。
一個後端。向Ingress發出的HTTP(和HTTPS)請求將與給定規則的主機和路徑匹配,而後將其路由到該規則中指定的後端服務。
在以上例子中,咱們配置了一個名爲」test「的後端,它將接收全部來自/microservice
路徑的流量。然而,咱們也能夠配置一個默認後端,它將將爲任何不符合規範中路徑的用戶請求提供服務。同時,若是不定義任何規則,Ingress將路由全部流量到默認後端。例如:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress spec: backend: serviceName: defaultbackend servicePort: 80
在本例中,全部流量都被轉發到默認後端中defaultbackend
。如今,咱們理解了Ingress 資源的基本概念,接下來咱們來看看一些具體的例子。
如上文咱們所說的,定義一個Ingress資源沒有任何做用,除非你使用了Ingress Controller。在本教程中,咱們在Kubernetes集羣中將Traefik設置爲Ingress Controller。
要完成教程,你須要進行如下準備:
請注意:如下示例均假設你在本地計算上使用Minikube運行Kubernetes集羣。
首先,咱們須要向Traefik授予一些權限,以訪問集羣中運行的Pod、endpoint和服務。爲此,咱們將使用ClusterRole
和ClusterRoleBinding
資源。可是,你也能夠對命名空間範圍內的RoleBindings
使用最小特權方法。一般,若是集羣的命名空間不會動態更改,而且Traefik沒法監視全部集羣的命名空間,那麼這是首選的方法。
讓咱們建立一個新的ServiceAccount
,爲Traefik提供集羣中的身份。
apiVersion: v1 kind: ServiceAccount metadata: name: traefik-ingress namespace: kube-system
要建立一個ServiceAccount
,須要在traefik-service-acc.yaml
中保存以上manifest並運行:
kubectl create -f traefik-service-acc.yaml serviceaccount "traefik-ingress" created
接下來,讓咱們建立一個具備一組權限的ClusterRole,該權限將應用於Traefik ServiceAccount
。經過ClusterRole
,Traefik能夠管理和監視集羣中全部命名空間中的資源,例如服務、endpoint、secret以及Ingress。
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: traefik-ingress rules: - apiGroups: - "" resources: - services - endpoints - secrets verbs: - get - list - watch - apiGroups: - extensions resources: - ingresses verbs: - get - list - watch
將這一規範保存到文件traefik-cr.yaml
中,並運行:
kubectl create -f traefik-cr.yaml clusterrole.rbac.authorization.k8s.io 「traefik-ingress」 created
最後,啓用這些權限,咱們應該將ClusterRole
綁定到Traefik ServiceAccount
中。使用ClusterRoleBinding
manifest能夠完成這一操做:
kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: traefik-ingress roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: traefik-ingress subjects: - kind: ServiceAccount name: traefik-ingress namespace: kube-system
保存這一規範到traefik-crb.yaml
中,並運行如下命令:
kubectl create -f traefik-crb.yaml clusterrolebinding.rbac.authorization.k8s.io 「traefik-ingress」 created
接下來,咱們將部署Traefik到Kubernetes集羣。官方Traefik文檔支持三種類型的部署:使用Deployment對象、使用DaemonSet對象或使用Helm Chart。
在本教程中,咱們將使用Deployment manifest。相比其餘選項,Deployment有諸多優點。例如,它們能確保更好的可伸縮性,併爲滾動更新提供良好支持。
讓咱們看一下 Deployment manifest:
kind: Deployment apiVersion: extensions/v1beta1 metadata: name: traefik-ingress namespace: kube-system labels: k8s-app: traefik-ingress-lb spec: replicas: 1 selector: matchLabels: k8s-app: traefik-ingress-lb template: metadata: labels: k8s-app: traefik-ingress-lb name: traefik-ingress-lb spec: serviceAccountName: traefik-ingress terminationGracePeriodSeconds: 60 containers: - image: traefik name: traefik-ingress-lb ports: - name: http containerPort: 80 - name: admin containerPort: 8080 args: - --api - --kubernetes - --logLevel=INFO
這個Deployment將在kube-system 命名空間中建立一個Traefik副本。Traefik容器將使用此manifest中指定的端口80和8080。
將這個manifest保存到traefik-deployment.yaml
文件中,並運行如下命令建立Deployment:
kubectl create -f traefik-deployment.yaml deployment.extensions 「traefik-ingress」 created
如今,讓咱們檢查一下Traefik Pod是否都成功建立了:
kubectl --namespace=kube-system get pods NAME READY STATUS RESTARTS AGE .... storage-provisioner 1/1 Running 3 23d traefik-ingress-54d6d8d9cc-ls6cs 1/1 Running 0 1m
如你所見,Deployment Controller啓動了一個Traefik副本,並在正在運行,敲棒的!
讓咱們建立一個服務來從集羣外部訪問Traefik。爲此,咱們須要一個暴露兩個NodePorts的服務。
kind: Service apiVersion: v1 metadata: name: traefik-ingress-service namespace: kube-system spec: selector: k8s-app: traefik-ingress-lb ports: - protocol: TCP port: 80 name: web - protocol: TCP port: 8080 name: admin type: NodePort
將這個manifest保存到traefik-svc.yaml
,並建立服務:
kubectl create -f traefik-svc.yaml service 「traefik-ingress-service」 created
如今,讓咱們驗證該服務是否建立:
kubectl describe svc traefik-ingress-service --namespace=kube-system Name: traefik-ingress-service Namespace: kube-system Labels: <none> Annotations: <none> Selector: k8s-app=traefik-ingress-lb Type: NodePort IP: 10.102.215.64 Port: web 80/TCP TargetPort: 80/TCP NodePort: web 30565/TCP Endpoints: 172.17.0.6:80 Port: admin 8080/TCP TargetPort: 8080/TCP NodePort: admin 30729/TCP Endpoints: 172.17.0.6:8080 Session Affinity: None External Traffic Policy: Cluster Events: <none>
如你所見,咱們如今有兩個NodePorts(web
和admin
),它們分別路由到Traefik Ingress Controller的80和8080容器端口。「admin」 NodePort將用於訪問Traefik Web UI,「web」 NodePort將用於訪問經過Ingress暴露的服務。
爲了能在瀏覽器中訪問Traefik Web UI,你可使用「admin」NodePort 30729(請注意,你的NodePort值可能會有所不一樣)。由於咱們尚未添加任何前端,因此UI此時應該是空的。
因爲咱們還沒有給Traefik進行任何配置,所以咱們會收到404的響應。
curl $(minikube ip):30565 404 page not found
如今咱們在Kubernetes集羣中已經將Traefik做爲Ingress Controller了。然而,咱們依舊須要定義Ingress資源和暴露Traefik Web UI的服務。
首先,咱們建立一個服務:
apiVersion: v1 kind: Service metadata: name: traefik-web-ui namespace: kube-system spec: selector: k8s-app: traefik-ingress-lb ports: - name: web port: 80 targetPort: 8080
保存manifest到traefik-webui-svc.yaml
中,並運行:
kubectl create -f traefik-webui-svc.yaml service 「traefik-web-ui」 created
讓咱們驗證服務是否已經建立:
kubectl describe svc traefik-web-ui --namespace=kube-system Name: traefik-web-ui Namespace: kube-system Labels: <none> Annotations: <none> Selector: k8s-app=traefik-ingress-lb Type: ClusterIP IP: 10.98.230.58 Port: web 80/TCP TargetPort: 8080/TCP Endpoints: 172.17.0.6:8080 Session Affinity: None Events: <none>
如你所見,服務的ClusterIP是10.98.230.58
,並在manifest中分配指定端口。
接下來,咱們須要建立一個Ingress資源,指向Traefik Web UI後端:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: traefik-web-ui namespace: kube-system spec: rules: - host: traefik-ui.minikube http: paths: - path: / backend: serviceName: traefik-web-ui servicePort: web
本質上,Ingress將全部請求路由到traefik-ui.minikube
,在上述步驟中建立的服務暴露Traefik Web UI。
將規範保存到traefik-ingress.yaml
,並運行:
kubectl create -f traefik-ingress.yaml ingress.extensions 「traefik-web-ui」 created
爲了可以經過traefik-ui.minikube
在瀏覽器中能夠訪問Traefik Web UI,咱們須要添加新的條目到咱們/etc/hosts
文件中。該條目將包含Minikube IP和主機名。你能夠經過運行minikube ip來獲取minkube實例的IP地址,而後將新主機的名稱保存到/etc/hosts
文件中,以下所示:
echo "$(minikube ip) traefik-ui.minikube" | sudo tee -a /etc/hosts 192.168.99.100 traefik-ui.minikube
如今,你應該可以在瀏覽器中訪問http://traefik-ui.minikube:<AdminNodePort>
並查看Traefik Web UI。別忘了附加」admin」NodePort到主機地址。
在dashboard中,你能夠點擊Health 連接來查看應用程序的健康情況:
如今,咱們來演示如何使用Traefik Ingress Controller爲前端列表設置基於名稱的路由。咱們將使用簡單的單頁網站建立3個Deployment,並顯示動物圖像:熊、野兔和駝鹿。
--- kind: Deployment apiVersion: extensions/v1beta1 metadata: name: bear labels: app: animals animal: bear spec: replicas: 2 selector: matchLabels: app: animals task: bear template: metadata: labels: app: animals task: bear version: v0.0.1 spec: containers: - name: bear image: supergiantkir/animals:bear ports: - containerPort: 80 --- kind: Deployment apiVersion: extensions/v1beta1 metadata: name: moose labels: app: animals animal: moose spec: replicas: 2 selector: matchLabels: app: animals task: moose template: metadata: labels: app: animals task: moose version: v0.0.1 spec: containers: - name: moose image: supergiantkir/animals:moose ports: - containerPort: 80 --- kind: Deployment apiVersion: extensions/v1beta1 metadata: name: hare labels: app: animals animal: hare spec: replicas: 2 selector: matchLabels: app: animals task: hare template: metadata: labels: app: animals task: hare version: v0.0.1 spec: containers: - name: hare image: supergiantkir/animals:hare ports: - containerPort: 80
每一個Deployment都將有兩個Pod副本,而每一個Pod將在containerPort
80上服務「動物「網站。
讓咱們保存這些Deployment manifest到animals-deployment.yaml
中,並運行:
kubectl create -f animals-deployment.yaml deployment.extensions 「bear」 created deployment.extensions 「moose」 created deployment.extensions 「hare」 created
如今,讓咱們爲每一個Deployment建立一個服務,使得Pod能夠訪問:
--- apiVersion: v1 kind: Service metadata: name: bear spec: ports: - name: http targetPort: 80 port: 80 selector: app: animals task: bear --- apiVersion: v1 kind: Service metadata: name: moose spec: ports: - name: http targetPort: 80 port: 80 selector: app: animals task: moose --- apiVersion: v1 kind: Service metadata: name: hare annotations: traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" spec: ports: - name: http targetPort: 80 port: 80 selector: app: animals task: hare
請注意:第三項服務使用斷路器annotation。斷路器是Traefik的一項功能,可防止發生故障的服務器承受高負載。在本例中,咱們防止服務器上的高負載超過50%。當此條件匹配時,CB進入「跳閘「狀態,在該狀態中它會使用預約義的HTTP狀態代碼進行響應或重定向到另外一個前端。
保存這些服務manifest到animals-svc.yaml
並運行:
kubectl create -f animals-svc.yaml service 「bear」 created service 「moose」 created service 「hare」 created
最後,爲每一個Deployment建立一個有3個先後端對的Ingress。bear.minikube
、moose.minikube
和hare.minikube
將是咱們指向相應後端服務的前端。
Ingress manifest以下所示:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: animals annotations: kubernetes.io/ingress.class: traefik spec: rules: - host: hare.minikube http: paths: - path: / backend: serviceName: hare servicePort: http - host: bear.minikube http: paths: - path: / backend: serviceName: bear servicePort: http - host: moose.minikube http: paths: - path: / backend: serviceName: moose servicePort: http
保存規範到animals-ingress.yaml
並運行:
kubectl create -f animals-ingress.yaml ingress.extensions 「animals」 created
如今,在Traefik dashboard內,你能夠看到每一個主機的前端以及相應的後端列表:
若是你再次編輯etc/hosts
,你應該可以在你的瀏覽器中訪問動物網頁:
echo 「$(minikube ip) bear.minikube hare.minikube moose.minikube」 | sudo tee -a /etc/hosts
你應該使用「web「NodePort來訪問特定網頁。例如,http://bear.minikube:<WebNodePort>
咱們也能夠將三個前端從新配置爲在一個域下提供服務,以下所示:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: all-animals annotations: kubernetes.io/ingress.class: traefik traefik.frontend.rule.type: PathPrefixStrip spec: rules: - host: animals.minikube http: paths: - path: /bear backend: serviceName: bear servicePort: http - path: /moose backend: serviceName: moose servicePort: http - path: /hare backend: serviceName: hare servicePort: http
若是你激活這個Ingress,使用相應的路徑,三個動物在一個域下都可以訪問——animals.minikube
。別忘了將這個域添加到/etc/hosts
。
echo 「$(minikube ip) animals.minikube」 | sudo tee -a /etc/hosts
請注意:咱們正在配置Traefik,以使用traefik.frontend.rule.type
註釋,從URL路徑中刪除前綴。這樣咱們能夠直接使用上一個示例中的容器。因爲traefik.frontend.rule.type: PathPrefixStrip
規則,你必須使用http://animals.minikube:32484/moose/
而不是http://animals.minikube:32484/moose
藉助Traefik,用戶可使用服務權重以受控方式在多個deployment之間分配Ingress流量。這一功能可用於金絲雀發佈,它最初應該得到少許但持續增加的流量。
讓咱們使用如下manifest在兩個微服務之間分配Traefik:
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: traefik.ingress.kubernetes.io/service-weights: | animals-app: 99% animals-app-canary: 1% name: animals-app spec: rules: - http: paths: - backend: serviceName: animals-app servicePort: 80 path: / - backend: serviceName: animals-app-canary servicePort: 80 path: /
請注意traefik.ingress.kubernetes.io/service-weights
的註釋。它指定了流量如何在指定後端服務(animals-app
和animals-app-canary
)之間分配。Traefik將把99%的用戶請求路由到animals-app
deployment支持的Pod,並將1%的用戶請求路由到animals-app-canary
deployment支持的Pod。
要使此設置正常工做,須要知足一些條件:
如你所見,Ingress是將外部流量路由到Kubernetes集羣中相應後端服務的強大工具。用戶可使用Kubernetes支持的許多Ingress controller來實現Ingress。在本教程中,咱們重點介紹了Traefik Ingress controller,該控制器支持基於名稱的路由,負載均衡以及Ingress controller的其餘常見任務。