K8S之traefik高級特性


Traefik

Traefik是一個用Golang開發的輕量級的Http反向代理和負載均衡器。由於可以自動配置和刷新backend節點,目前可以被絕大部分容器平台支持,例如Kubernetes,Swarm,Rancher等。由於traefik會實時與Kubernetes API交互,所以對於Service的節點變化,traefik的反應會更加迅速。總體來說traefik可以在Kubernetes中完美的運行.

Traefik 還有很多特性如下:

  • 速度快
  • 不需要安裝其他依賴,使用 GO 語言編譯可執行文件
  • 支持最小化官方 Docker 鏡像
  • 支持多種后台,如 Docker, Swarm mode, Kubernetes, Marathon, Consul, Etcd, Rancher, Amazon ECS 等等
  • 支持 REST API
  • 配置文件熱重載,不需要重啟進程
  • 支持自動熔斷功能
  • 支持輪訓、負載均衡
  • 提供簡潔的 UI 界面
  • 支持 Websocket, HTTP/2, GRPC
  • 自動更新 HTTPS 證書
  • 支持高可用集群模式

接下來我們使用 Traefik 來替代 Nginx + Ingress Controller 來實現反向代理和服務暴漏。

那么二者有什么區別呢?簡單點說吧,在 Kubernetes 中使用 nginx 作為前端負載均衡,通過 Ingress Controller 不斷的跟 Kubernetes API 交互,實時獲取后端 Service、Pod 等的變化,然后動態更新 Nginx 配置,並刷新使配置生效,來達到服務自動發現的目的,而 Traefik 本身設計的就能夠實時跟 Kubernetes API 交互,感知后端 Service、Pod 等的變化,自動更新配置並熱重載。大體上差不多,但是 Traefik 更快速更方便,同時支持更多的特性,使反向代理、負載均衡更直接更高效。

1.Role Based Access Control configuration (Kubernetes 1.6+ only) 

  1. kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-rbac.yaml

授權,官方文檔不懂下下來看文檔

2.Deploy Træfik using a Deployment or DaemonSet

  1. To deploy Træfik to your cluster start by submitting one of the YAML files to the cluster with kubectl:
  2.  
  3. kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-deployment.yaml   此模板有些問題,我先用ds模板
  4.  
  5. kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-ds.yaml

deployment和ds的區別:ds會在每台node上都創造一個pod.而deploy是人為控制的副本。如果幾台很多了,沒有必要用ds,比如100台 會造100個pod,沒有意義。自己用ds模板改下,kind: Deployment

如下

  1. 直接找到DS模板吧kind改成deploy模式
  2. kind: Deployment

3.Check the Pods

  1. # kubectl --namespace=kube-system get pods -o wide 
  2. traefik-ingress-controller-79877bbc66-p29jh 1/1 Running 0 32m   10.249.243.182    k8snode2-175v136

 

查找一下在那台服務器上,deploy會隨機分配一台服務器

4.Ingress and UI

  1. kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/ui.yaml.

自己再造個web測試用

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4.   name: nginx-svc
  5. spec:
  6.   template:
  7.     metadata:
  8.       labels:
  9.         name: nginx-svc
  10.         namespace: default
  11. spec:
  12.   selector:
  13.     run: ngx-pod
  14.   ports:
  15.   - protocol: TCP
  16.     port: 80
  17.     targetPort: 80
  18. ---
  19. apiVersion: apps/v1beta1
  20. kind: Deployment
  21. metadata:
  22.   name: ngx-pod
  23. spec:
  24.   replicas: 4
  25.   template:
  26.     metadata:
  27.       labels:
  28.         run: ngx-pod
  29.     spec:
  30.       containers:
  31.       - name: nginx
  32.         image: nginx:1.10
  33.         ports:
  34.         - containerPort: 80
  35. ---
  36. apiVersion: extensions/v1beta1
  37. kind: Ingress
  38. metadata:
  39.   name: ngx-ing
  40.   annotations:
  41.     kubernetes.io/ingress.class: traefik
  42. spec:
  43.   rules:
  44.   - host: www.ha.com
  45.     http:
  46.       paths:
  47.       - backend:
  48.           serviceName: nginx-svc
  49.           servicePort: 80

5.測試成功

6.HTTPS證書

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4.   name: traefik-web-ui
  5.   namespace: kube-system
  6.   annotations:
  7.     kubernetes.io/ingress.class: traefik
  8. spec:
  9.   rules:
  10.   - host: traefik-ui.minikube
  11.     http:
  12.       paths:
  13.       - backend:
  14.           serviceName: traefik-web-ui
  15.           servicePort: 80
  16.   tls:
  17.    - secretName: traefik-ui-tls-cert

官方是怎么導入證書的呢? 注:key和crt必須要有

  1. openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=traefik-ui.minikube"
  2. kubectl -n kube-system create secret tls traefik-ui-tls-cert --key=tls.key --cert=tls.crt

7.Basic Authentication

 

  1. A. Use htpasswd to create a file containing the username and the MD5-encoded password:
  2. htpasswd -./auth myusername
  3. You will be prompted for a password which you will have to enter twice. htpasswd will create a file with the following:
  4. cat auth
  5. myusername:$apr1$78Jyn/1K$ERHKVRPPlzAX8eBtLuvRZ0
  6. B. Now use kubectl to create a secret in the monitoring namespace using the file created by htpasswd
  7. kubectl create secret generic mysecret --from-file auth --namespace=monitoring
  8. Note
  9. Secret must be in same namespace as the Ingress object.
  10. C. Attach the following annotations to the Ingress object:
  11.     ingress.kubernetes.io/auth-type: "basic"
  12.     ingress.kubernetes.io/auth-secret: "mysecret"
  13. They specify basic authentication and reference the Secret mysecret containing the credentials.
  14. Following is a full Ingress example based on Prometheus:
  15. #配置文件如下
  16. apiVersion: extensions/v1beta1
  17. kind: Ingress
  18. metadata:
  19.  name: prometheus-dashboard
  20.  namespace: monitoring
  21.  annotations:
  22.    kubernetes.io/ingress.class: traefik
  23.    ingress.kubernetes.io/auth-type: "basic"
  24.    ingress.kubernetes.io/auth-secret: "mysecret"
  25. spec:
  26.  rules:
  27.  - host: dashboard.prometheus.example.com
  28.    http:
  29.      paths:
  30.      - backend:
  31.          serviceName: prometheus
  32.          servicePort: 9090

模板1 多域名暴漏端口:再看一下 UI 頁面,立馬更新過來,可以看到剛剛配置的 dashboard.k8s.traefik 和 ela.k8s.traefik

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4.   name: dashboard-ela-k8s-traefik
  5.   namespace: kube-system
  6.   annotations:
  7.     kubernetes.io/ingress.class: traefik
  8. spec:
  9.   rules:
  10.   - host: dashboard.k8s.traefik
  11.     http:
  12.       paths:
  13.       - path: /  
  14.         backend:
  15.           serviceName: kubernetes-dashboard
  16.           servicePort: 80
  17.   - host: ela.k8s.traefik
  18.     http:
  19.       paths:
  20.       - path: /  
  21.         backend:
  22.           serviceName: elasticsearch-logging
  23.           servicePort: 9200

模板2

注意:這里我們根據路徑來轉發,需要指明 rule 為 PathPrefixStrip,配置為 traefik.frontend.rule.type: PathPrefixStrip

再看一下 UI 頁面,也是立馬更新過來,可以看到剛剛配置的 my.k8s.traefik/dashboard 和 my.k8s.traefik/kibana

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4.   name: my-k8s-traefik
  5.   namespace: kube-system
  6.   annotations:
  7.     kubernetes.io/ingress.class: traefik
  8.     traefik.frontend.rule.type: PathPrefixStrip
  9. spec:
  10.   rules:
  11.   - host: my.k8s.traefik
  12.     http:
  13.       paths:
  14.       - path: /dashboard
  15.         backend:
  16.           serviceName: kubernetes-dashboard
  17.           servicePort: 80
  18.       - path: /kibana
  19.         backend:
  20.           serviceName: kibana-logging
  21.           servicePort: 5601

8.自動熔斷

在集群中,當某一個服務大量出現請求錯誤,或者請求響應時間過久,或者返回500+錯誤狀態碼時,我們希望可以主動剔除該服務,也就是不在將請求轉發到該服務上,而這一個過程是自動完成,不需要人工執行。Traefik 通過配置很容易就能幫我們實現,Traefik 可以通過定義策略來主動熔斷服務。

  • NetworkErrorRatio() > 0.5:監測服務錯誤率達到50%時,熔斷。
  • LatencyAtQuantileMS(50.0) > 50:監測延時大於50ms時,熔斷。
  • ResponseCodeRatio(500, 600, 0, 600) > 0.5:監測返回狀態碼為[500-600]在[0-600]區間占比超過50%時,熔斷。

案例

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4.   name: wensleydale
  5.   annotations:
  6.     traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" 
  7.     traefik.backend.circuitbreaker: LatencyAtQuantileMS(50.0) > 2000 #>2秒熔斷

9.官方文檔:

其他多看官方文檔

https://docs.traefik.io/user-guide/kubernetes/

10.update

由於業務需求,node會擴充, ds模式多了會浪費資源 20台node+,我們怎么把traefik固定在幾台機器上。查了一些文檔找到了這個解決方法。

給node打標簽,用ds模式啟動標簽化節點 :https://www.kubernetes.org.cn/daemonset 參考文檔。

案例:

給三台node打標簽

  1. kubectl label node k8snode10-146v78-taiji traefik=svc
  2. kubectl label node k8snode10-146v78-taiji traefik=svc
  3. kubectl label node k8snode10-146v78-taiji traefik=svc
  4. ##########取消標簽
  5. kubectl label node k8snode1-174v136-taiji traefik-
  6. 查看標簽
  7. [root@k8s-m1 Traefik]# kubectl get nodes --show-labels
  8. NAME                     STATUS    ROLES     AGE       VERSION   LABELS
  9. k8snode1-174v136-taiji   Ready     node      42d       v1.10.4   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8snode1-174v136-taiji,node-role.kubernetes.io/node=,traefik=svc
  10. [root@k8s-m1 Traefik]# cat traefik-ds.yaml 
  11. kind: DaemonSet
  12. apiVersion: extensions/v1beta1
  13. metadata:
  14.   name: traefik-ingress-controller
  15.   namespace: kube-system
  16.   labels:
  17.     k8s-app: traefik-ingress-lb
  18. spec:
  19.   template:
  20.     metadata:
  21.       labels:
  22.         k8s-app: traefik-ingress-lb
  23.         name: traefik-ingress-lb
  24.     spec:
  25.       nodeSelector:
  26.         traefik: "svc"            #重點2行
  27. ...................
  28. 驗證
  29. [root@k8s-m1 Traefik]# kubectl get ds -n kube-system 
  30. NAME                         DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR  
  31. traefik-ingress-controller   3         3         3         3            3           traefik=svc

 總結:后期可以根據業務量加標簽擴展traefik節點

11.限流限速

官文 : Valid values for extractorfunc are: * client.ip * request.host * request.header.<header name>

我們根據2個維度 (request.host | client.ip)

重點首選保障前端HAPROXY,LVS,nginx,CDN傳遞過來的IP是用戶IP,而不是上層負載IP

haproxy可以用配置 實現

  1. option forwardfor                      #2者選一個即可
  2. option forwardfor header Client-IP

ngx可以通過upstream通過 X-Forwarded-For傳遞IP

  1. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

 

 

1. Client.ip驗證:我們通過HAPROXY 進行測試,出傳遞了client-IP到 traefik上進行測試。client.ip限流限速效果滿足

  1. "time":"2019-01-10T02:03:25Z"} "BackendName":"test.if.org/" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  2. "time":"2019-01-10T02:03:25Z"} "BackendName":"test.if.org/" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  3. "time":"2019-01-10T02:03:26Z"} "BackendName":"Træfik" "DownstreamStatusLine":"429 Too Many Requests" "request_Client-Ip":"127.0.0.1"
  4. "time":"2019-01-10T02:03:26Z"} "BackendName":"Træfik" "DownstreamStatusLine":"429 Too Many Requests" "request_Client-Ip":"127.0.0.1" 
  5. "time":"2019-01-10T02:03:26Z"} "BackendName":"Træfik" "DownstreamStatusLine":"429 Too Many Requests" "request_Client-Ip":"127.0.0.1"
  6. "time":"2019-01-10T02:03:29Z"} "BackendName":"test.if.org/" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  7. "time":"2019-01-10T02:03:29Z"} "BackendName":"Træfik" "DownstreamStatusLine":"429 Too Many Requests"  "request_Client-Ip":"127.0.0.1"
  8. "time":"2019-01-10T02:03:29Z"} "BackendName":"Træfik" "DownstreamStatusLine":"429 Too Many Requests"  "request_Client-Ip":"127.0.0.1"
  9. "time":"2019-01-10T02:03:32Z"} "BackendName":"test.if.org/" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  10. "time":"2019-01-10T02:03:32Z"} "BackendName":"test.if.org/" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"  

2.Request.host驗證:我們通過HAPROXY 進行測試 ,client.ip限流限速效果滿足

  1. "time":"2019-01-10T03:14:10Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  2. "time":"2019-01-10T03:14:11Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  3. "time":"2019-01-10T03:14:11Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  4. "time":"2019-01-10T03:14:11Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  5. "time":"2019-01-10T03:14:13Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  6. "time":"2019-01-10T03:14:14Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  7. "time":"2019-01-10T03:14:14Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"429 Too Many Requests" "request_Client-Ip":"127.0.0.1"
  8. "time":"2019-01-10T03:14:14Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"429 Too Many Requests" "request_Client-Ip":"127.0.0.1"
  9. "time":"2019-01-10T03:14:15Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  10. "time":"2019-01-10T03:14:15Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"429 Too Many Requests" "request_Client-Ip":"127.0.0.1"
  11. "time":"2019-01-10T03:14:21Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  12. "time":"2019-01-10T03:14:22Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  13. "time":"2019-01-10T03:14:22Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  14. "time":"2019-01-10T03:14:22Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  15. "time":"2019-01-10T03:14:23Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  16. "time":"2019-01-10T03:14:23Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"200 OK" "request_Client-Ip":"127.0.0.1"
  17. "time":"2019-01-10T03:14:23Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"429 Too Many Requests" "request_Client-Ip":"127.0.0.1"
  18. "time":"2019-01-10T03:14:24Z"} "RequestHost":"test.if.org" "DownstreamStatusLine":"429 Too Many Requests" "request_Client-Ip":"127.0.0.1" 

12.金絲雀發布 (A,B)發布

金絲雀發布功能,在K8S-traefik里在v1.7.5時官方進行了修正

  • [k8s] Support canary weight for external name service (#4135 by yue9944882)
  1.       "test.if.org/": {
  2.         "servers": {
  3.           "hpa-httpd-5856fd66bf-2qpm6": {
  4.             "url": "http://10.249.221.61:80",
  5.             "weight": 90000
  6.           },
  7.           "hpb-httpd-6bc6f55488-mllq2": {
  8.             "url": "http://10.249.89.29:80",
  9.             "weight": 10000
  10.           }
  11.         },

13.保持會話,session親和性,sticky特性

原理會話粘粘:在客戶端第一次發起請求時,反向代理為客戶端分配一個服務端,並且將該服務端的地址以SetCookie的形式發送給客戶端,這樣客戶端下一次訪問該反向代理時,便會帶着這個cookie,里面包含了上一次反向代理分配給該客戶端的服務端信息。這種機制是通過一個名為Sticky的插件實現的。而Traefik則集成了與Nginx的Sticky相同功能,並且可以在Kubernetes中方便的開啟和配置該特性。

解決:認證服務器第一次認證到A POD 第2次訪問到B POD導致,認證失效問題,保障一致性

service層配置

  1. metadata:
  2.   annotations:
  3.     traefik.ingress.kubernetes.io/affinity: "true" 

驗證

web請求頭里帶了Cookie信息


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM