關於traefik
參考之前寫的一篇文檔:
https://blog.51cto.com/michaelkang/1918192
版本介紹
traefik:v1.7
k8s:v1.15.1
Ingress
Ingress是自kubernetes1.1版本後引入的資源類型。必須要部署Ingress controller才能創建Ingress資源,Ingress controller是以一種插件的形式提供。
使用 Ingress 時一般會有三個組件:
反向代理負載均衡器
Ingress Controller
Ingress
組件介紹
反向代理負載均衡器
反向代理負載均衡器很簡單,類似nginx,haproxy;在集羣中反向代理負載均衡器可以自由部署,可以使用 Replication Controller、Deployment、DaemonSet 等等,推薦DaemonSet 的方式部署
Ingress Controller
Ingress Controller 實質上可以理解爲是個監視器,Ingress Controller 通過不斷地跟 kubernetes API 打交道,實時的感知後端 service、pod 等變化,比如新增和減少 pod,service 增加與減少等;當得到這些變化信息後,Ingress Controller 再結合下文的 Ingress 生成配置,然後更新反向代理負載均衡器,並刷新其配置,達到服務發現的作用
Ingress
Ingress 簡單理解就是個規則定義;比如說某個域名對應某個 service,即當某個域名的請求進來時轉發給某個 service;這個規則將與 Ingress Controller 結合,然後 Ingress Controller 將其動態寫入到負載均衡器配置中,從而實現整體的服務發現和負載均衡
部署traefik ingress 服務
如果您不熟悉Kubernetes中的Ingresses,您可能需要閱讀Kubernetes用戶指南.
部署條件
一個正常工作Kubernetes集羣。可以是 minikube 集羣。
集羣信息介紹
[root@kubm-02 traefik]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP
kubm-01 Ready master 13d v1.15.1 172.20.101.157
kubm-02 Ready master 13d v1.15.1 172.20.101.164
kubm-03 Ready master 13d v1.15.1 172.20.101.165
kubnode-01 Ready <none> 13d v1.15.1 172.20.101.160
kubnode-02 Ready <none> 13d v1.15.1 172.20.101.166
kubnode-03 Ready <none> 13d v1.15.1 172.20.101.167
創建用戶訪問規則
Kubernetes在1.6+中引入了基於角色的訪問控制(RBAC),以允許對Kubernetes資源和API進行細粒度控制。
如果您的羣集配置了RBAC,則需要授權Traefik使用Kubernetes API。有兩種方法可以設置適當的權限:通過特定於命名空間的RoleBindings或單個全局ClusterRoleBinding。
每個命名空間的RoleBinding可以限制授予權限,只有Traefik正在監視的名稱空間才能使用,從而遵循最小權限原則。如果Traefik不應該監視所有名稱空間,並且名稱空間集不會動態更改,那麼這是首選方法。否則,必須使用單個ClusterRoleBinding。
ClusterRoleBinding:
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: kube-system
[root@kubm-02 ~]# kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/traefik-rbac.yaml
返回
clusterrole.rbac.authorization.k8s.io/traefik-ingress-controller created
clusterrolebinding.rbac.authorization.k8s.io/traefik-ingress-controller created
部署方式
差異
Deployment 部署的副本 Pod 會分佈在各個 Node 上,每個 Node 都可能運行好幾個副本。
DaemonSet的不同之處在於,每個 Node 上最多隻能運行一個副本。
本次採用DaemonSet方式部署
Deployment:
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/traefik-deployment.yaml
DaemonSet :
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/traefik-ds.yaml
驗證服務啓動:
查看服務信息
[root@kubm-02 traefik]# kubectl get rc,services -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
...
service/traefik-ingress-service ClusterIP 10.245.153.125 <none> 80/TCP,8080/TCP 3m42s
查看container 啓動狀態
[root@kubm-02 ~]# kubectl get pods --all-namespaces -o wide --selector=k8s-app=traefik-ingress-lb
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system traefik-ingress-controller-4d29d 1/1 Running 0 19m 10.244.3.107 kubnode-01 <none> <none>
kube-system traefik-ingress-controller-mgljm 1/1 Running 0 19m 10.244.5.143 kubnode-03 <none> <none>
kube-system traefik-ingress-controller-wcd5z 1/1 Running 0 19m 10.244.4.126 kubnode-02 <none> <none>
訪問traefik管理頁面
該服務將公開兩個允許訪問入口和Web界面的NodePort。
80 業務端口,後端服務啓動註冊到traefik後,寫hosts文件或者添加dns 解析才能訪問;
8080 traefik 管理頁面,訪問node節點的IP地址:8080即可訪問;
例如:http://172.20.101.167:8080
註冊服務測試訪問:
首先創建一個服務和一個將公開Traefik Web UI的Ingress
部署服務:
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
---
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
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/ui.yaml
任務執行完成,在/etc/hosts文件中將traefik-ui.minikube指向一個node節點
IP地址,然後瀏覽器訪問:http://traefik-ui.minikube
或者
先打開traefik管理頁面,通過curl訪問,health 頁面可以看到請求,指命令如下:
[root@kubm-02 ~]# curl http://172.20.101.166 --user-agent "Mozilla/5.0" -H "Host:traefik-ui.minikube"
<a href="/dashboard/">Found</a>.
使用basic驗證
創造祕密
A. htpasswd用於創建包含用戶名和MD5編碼密碼的文件:
yum install httpd -y
htpasswd -c ./auth myusername
系統將提示您輸入密碼,您必須輸入兩次密碼。 htpasswd將使用以下內容創建一個文件:
[root@kubm-02 traefik]# more auth
myusername:$apr1$3yj4XbDF$4ekQISLfP8HyX9nYH3x9E.
B.現在使用kubectl創建monitoring的文件在命名空間中創建一個祕密htpasswd。
[root@kubm-02 traefik]# kubectl create namespace monitoring
namespace/monitoring created
[root@kubm-02 traefik]# kubectl create secret generic mysecret --from-file auth --namespace=monitoring
secret/mysecret created
注意: Secret必須與Ingress對象位於相同的名稱空間中。
C.將以下注釋附加到Ingress對象:
traefik.ingress.kubernetes.io/auth-type: "basic"
traefik.ingress.kubernetes.io/auth-secret: "mysecret"
它們指定基本身份驗證並引用mysecret包含憑據的Secret 。
以下是基於普羅米修斯的完整Ingress示例:
cat >prometheus-ingress.yaml<<EOF
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: prometheus-dashboard
namespace: monitoring
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/auth-type: "basic"
traefik.ingress.kubernetes.io/auth-secret: "mysecret"
spec:
rules:
- host: dashboard.prometheus.example.com
http:
paths:
- backend:
serviceName: prometheus
servicePort: 9090
EOF
kubectl create -f prometheus-ingress.yaml -n monitoring
基於域名路由
首先啓動3個web站點
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: stilton
labels:
app: cheese
cheese: stilton
spec:
replicas: 2
selector:
matchLabels:
app: cheese
task: stilton
template:
metadata:
labels:
app: cheese
task: stilton
version: v0.0.1
spec:
containers:
- name: cheese
image: errm/cheese:stilton
ports:
- containerPort: 80
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: cheddar
labels:
app: cheese
cheese: cheddar
spec:
replicas: 2
selector:
matchLabels:
app: cheese
task: cheddar
template:
metadata:
labels:
app: cheese
task: cheddar
version: v0.0.1
spec:
containers:
- name: cheese
image: errm/cheese:cheddar
ports:
- containerPort: 80
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: wensleydale
labels:
app: cheese
cheese: wensleydale
spec:
replicas: 2
selector:
matchLabels:
app: cheese
task: wensleydale
template:
metadata:
labels:
app: cheese
task: wensleydale
version: v0.0.1
spec:
containers:
- name: cheese
image: errm/cheese:wensleydale
ports:
- containerPort: 80
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/cheese-deployments.yaml
驗證服務器啓動
[root@kubm-02 traefik]# kubectl get pods
NAME READY STATUS RESTARTS AGE
cheddar-845749dbd6-vht86 0/1 ContainerCreating 0 64s
cheddar-845749dbd6-z4zn6 1/1 Running 0 64s
curl-6bf6db5c4f-96nhg 1/1 Running 1 46h
stilton-f89c97cdb-dtgbx 1/1 Running 0 64s
stilton-f89c97cdb-nlhn5 1/1 Running 0 64s
wensleydale-7c5ff658b-lq5tn 0/1 ContainerCreating 0 64s
wensleydale-7c5ff658b-ps56g 1/1 Running 0 64s
爲每個站點設置一個服務。
---
apiVersion: v1
kind: Service
metadata:
name: stilton
spec:
ports:
- name: http
targetPort: 80
port: 80
selector:
app: cheese
task: stilton
---
apiVersion: v1
kind: Service
metadata:
name: cheddar
spec:
ports:
- name: http
targetPort: 80
port: 80
selector:
app: cheese
task: cheddar
---
apiVersion: v1
kind: Service
metadata:
name: wensleydale
annotations:
traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5"
spec:
ports:
- name: http
targetPort: 80
port: 80
selector:
app: cheese
task: wensleydale
OR
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/cheese-services.yaml
驗證服務器啓動
[root@kubm-02 traefik]# kubectl get svc --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default cheddar ClusterIP 10.245.80.192 <none> 80/TCP 50s
default stilton ClusterIP 10.245.177.114 <none> 80/TCP 50s
default wensleydale ClusterIP 10.245.242.131 <none> 80/TCP 50s
注意:我們還通過在服務上設置註釋來爲其中一個後端設置斷路器表達式traefik.backend.circuitbreaker。
將網站提註冊到traefik
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/cheese-ingress.yaml
驗證:
任務執行完成可以在traefik 管理頁面看到新的域名已經註冊到traefik,寫hosts文件在瀏覽器可以訪問:
hosts 文件信息
172.20.101.166 stilton.minikube
172.20.101.166 cheddar.minikube
172.20.101.166 wensleydale.minikube
瀏覽器訪問:
http://stilton.minikube
http://cheddar.minikube
http://wensleydale.minikube
基於路徑的路由
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cheeses
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.rule.type: PathPrefixStrip
spec:
rules:
- host: cheeses.minikube
http:
paths:
- path: /stilton
backend:
serviceName: stilton
servicePort: http
- path: /cheddar
backend:
serviceName: cheddar
servicePort: http
- path: /wensleydale
backend:
serviceName: wensleydale
servicePort: http
OR
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/cheeses-ingress.yaml
#寫 host
echo "172.20.101.166 cheeses.minikube" | sudo tee -a /etc/hosts
#訪問驗證
http://cheeses.minikube/cheddar
http://cheeses.minikube/stilton
http://cheeses.minikube/wensleydale
注意:配置Traefik以使用traefik.frontend.rule.type註釋從url路徑中去除前綴,以便我們可以使用前一個示例中的容器而無需修改。
指定路由優先級
有時您需要爲入口路由指定優先級,尤其是在處理通配符路由時。這可以通過添加traefik.frontend.priority註釋來完成,即:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: wildcard-cheeses
annotations:
traefik.frontend.priority: "1"
spec:
rules:
- host: *.minikube
http:
paths:
- path: /
backend:
serviceName: stilton
servicePort: http
kind: Ingress
metadata:
name: specific-cheeses
annotations:
traefik.frontend.priority: "2"
spec:
rules:
- host: specific.minikube
http:
paths:
- path: /
backend:
serviceName: stilton
servicePort: http
請注意,必須引用優先級值以避免數字解釋(對於註釋是非法的)。
轉發到擴展域名
指定擴展域名時,Traefik會相應地將請求轉發給給定主機,並在服務端口與443匹配時使用HTTPS。這仍然需要在服務上從Ingress端口到(外部)服務端口設置正確的端口映射。
禁用傳遞主機頭,默認情況下,Traefik會將傳入的主機頭傳遞給上游資源。但是,有時可能不希望出現這種情況。例如,如果您的服務屬於需要使用很多域名的類型。
禁用方法
1:全局禁用:
將以下內容添加到TOML配置文件中:
disablePassHostHeaders = true
2:每個Ingress禁用:
要禁用每個入口資源傳遞主機標頭traefik.frontend.passHostHeader,請將入口上的註釋設置爲"false"。
示例定義:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.passHostHeader: "false"
spec:
rules:
- host: example.com
http:
paths:
- path: /static
backend:
serviceName: static
servicePort: https
以及一個示例服務定義:
apiVersion: v1
kind: Service
metadata:
name: static
spec:
ports:
- name: https
port: 443
type: ExternalName
externalName: static.otherdomain.com
如果您要訪問example.com/static該請求,那麼將傳遞給static.otherdomain.com/static,static.otherdomain.com並將收到帶有Host頭的請求static.otherdomain.com。
注意:
每個入口註釋會覆蓋設置爲全局值的任何內容。所以,你可以設置disablePassHostHeaders到true您的TOML配置文件,然後使通過每一個想要的域名訪問。
部署多個Traefik
一般部署兩種不同類型的traefik:
面向內部(internal)服務的traefik,建議可以使用deployment的方式
面向外部(external)服務的traefik,建議可以使用daemonset的方式
建議使用traffic-type標籤
traffic-type: external
traffic-type: internal
traefik相應地使用labelSelector
traffic-type=internal
traffic-type=external
負載權重分配
可以使用服務權重在多個部署之間以細粒度方式拆分Ingress流量。讓較新版本的部署將隨着時間的推移接收最初較小但不斷增加的請求部分。在Traefik中可以這樣做的方法是指定應該進入每個部署的請求的百分比。
例如,假設一個應用程序my-app在版本1中運行。較新的版本2即將發佈,但對生產中運行的新版本的穩健性和可靠性的信心只能逐漸獲得。因此,my-app-canary創建新部署並將其縮放到足以獲得1%流量份額的副本計數。與此同時,像往常一樣創建一個Service對象。
Ingress規範看起來像這樣:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
traefik.ingress.kubernetes.io/service-weights: |
my-app: 99%
my-app-canary: 1%
name: my-app
spec:
rules:
- http:
paths:
- backend:
serviceName: my-app
servicePort: 80
path: /
- backend:
serviceName: my-app-canary
servicePort: 80
path: /
traefik.ingress.kubernetes.io/service-weights註釋:它指定引用的後端服務之間的請求分配,my-app以及my-app-canary。根據這一定義,Traefik將99%的請求路由到my-app部署支持的pod ,並將1%的請求路由到支持的pod my-app-canary。隨着時間的推移,該比例可能會慢慢轉向金絲雀部署,直到它被認爲取代之前的主要應用程序,步驟如5%/ 95%,10%/ 90%,50%/ 50%,最後100%/ 0%。
負載權重分配、優化配置
指定服務權重時,出於方便原因,可以省略一個服務。
例如,以下定義顯示瞭如何在金絲雀發佈伴隨基線部署的情況下拆分請求,以便更輕鬆地進行指標比較或自動化金絲雀分析:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
traefik.ingress.kubernetes.io/service-weights: |
my-app-canary: 10%
my-app-baseline: 10%
name: app
spec:
rules:
- http:
paths:
- backend:
serviceName: my-app-canary
servicePort: 80
path: /
- backend:
serviceName: my-app-baseline
servicePort: 80
path: /
- backend:
serviceName: my-app-main
servicePort: 80
path: /
此配置my-app-main自動分配80%的流量,從而使用戶無需手動完成百分比值。當連續增加金絲雀釋放的份額時,這變得很方便。
使用Traefik舵表部署¶
注意
Helm Chart由社區維護,而不是Traefik項目維護人員。
您也可以使用Traefik Helm圖表,而不是直接通過Kubernetes對象安裝Traefik。
通過以下方式安裝Traefik圖表:
helm install stable/traefik
使用values.yaml文件安裝Traefik圖表。
helm install --values values.yaml stable/traefik
dashboard:
enabled: true
domain: traefik-ui.minikube
kubernetes:
namespaces:
- default
- kube-system
有關更多信息,請查看文檔。
清理測試環境
kubectl delete -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/cheeses-ingress.yaml
kubectl delete -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/cheese-ingress.yaml
kubectl delete -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/cheese-services.yaml
kubectl delete -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/cheese-deployments.yaml
kubectl delete -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/ui.yaml
kubectl delete -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/traefik-ds.yaml
kubectl delete -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/traefik-rbac.yaml
參考文檔:
https://docs.traefik.io/user-guide/kubernetes/
https://github.com/containous/traefik/tree/v1.7.14
https://juejin.im/post/5b46119ce51d455d94713787