使用traefik反向代理k8s dashboard


生產環境下,k8s集群對外暴露服務主要有LoadBalancer和Ingress兩種方式:

  • LoadBalancer:需要雲廠商支持,使用k8s service的負載均衡能力,也就是依靠iptables/ipvs的能力,可用於各種協議
  • Ingress:相對更加靈活,通過反向代理服務器實現負載均衡,僅用於http/https協議,這種場景下需要額外的反向代理服務以及ingress controller,nginx是大家熟知的反向代理,在k8s時代,出現了nginx-ingress,就是nginx+ingress controller的組合,ingress controller負責根據ingress資源生成nginx配置,當配置有變化是重啟nginx。同時也出現了雲原生的反向代理traefik,它相當於把ingress controller包含到其中合為一體,並且能夠動態感知路由規則變化,不需重啟。

traefik是一個相對較新的反向代理,網上相關資料不是特別豐富,研究了好幾天,才成功訪問到k8s dashboard,將其中的關鍵點記錄於此。

安裝traefik

使用helm安裝,最新chart使用的traefik 1.7.19:

helm install stable/traefik -f traefik-values.yaml

traefik-values.yaml:

rbac:
  enabled: true
dashboard:
  enabled: true # 啟用traefik dashboard
  ingress:
    annotations:
      traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
deployment:
  hostPort:
    httpEnabled: true # traefik pod所在node上開啟80端口
    httpsEnabled: true # traefik pod所在node上開啟443端口
    dashboardEnabled: true # traefik pod所在node上開啟8080端口,共traefik dashboard使用
ssl:
  insecureSkipVerify: true # frontend不驗證https的benkend
  enabled: true # 啟用https入口
extraVolumes:
  - name: traefik-ssl
    hostPath:
      path: /share/k8s/traefik/ssl # 其中存放https入口的證書和key,名字必須為tls.crt,tls.key
      type: DirectoryOrCreate
extraVolumeMounts:
  - name: traefik-ssl
    mountPath: /ssl   # traefik pod從/ssl目錄讀取上述tls.crt,tls.key

詳細的配置方法見官方文檔,上述關鍵點如下:

  1. 開啟https入口,設置ssl.enabled=true,然后提供證書和key,上述通過從node節點本地目錄mount到pod的方式,所以每個node節點要先放好證書和key,更好的方式是通過k8s secret,創建secret然后mount到pod
  2. 如何訪問到入口,我是通過在node上打開端口,這時通過pod所在node就可以訪問到入口,通過http://nodeip或https://nodeip;還可以使用NodePort類型service,這樣通過http://any-nodeip:http-nodeport或https://any-nodeip:https-nodeport訪問,value設置 serviceType: NodePort
  3. 路由匹配規則我使用的PathPrefixStrip,默認是host名匹配

因為啟用了traefik dashboard,安裝traefik會自動創建dashboard的ingress:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
  labels:
    app: traefik
    chart: traefik-1.82.1
    heritage: Tiller
    release: traefik
  name: traefik-dashboard
  namespace: default
spec:
  rules:
  - host: traefik.example.com
    http:
      paths:
      - backend:
          serviceName: traefik-dashboard
          servicePort: dashboard-http

traefik是通過標簽app: traefik選擇到需要感知的ingress。自己添加的ingress注意包含這個標簽。上述annotations和host是從value而來。因為我不想配host,所以用PathPrefixStrip路由規則,我修改了上述ingress如下:

spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: traefik-dashboard
          servicePort: dashboard-http
        path: /traefik

這樣當使用http://nodeip/traefik就可以訪問到dashboard,因為在node上也開啟了dashboard端口,也可以通過http://nodeip:8080訪問。

代理k8s dashboard

目前最新的k8s dashboard(v2.0.0-beta6)安裝在kubernetes-dashboard namespace:

kubectl get svc -n kubernetes-dashboard
NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
dashboard-metrics-scraper   ClusterIP   10.254.238.13    <none>        8000/TCP        21d
kubernetes-dashboard        LoadBalancer   10.254.253.226   <pending>     443:30223/TCP   21d

增加ingress:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
  labels:
    app: traefik
  name: kubernetes-dashboard
  namespace: default
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: kubernetes-dashboard
          servicePort: 443
        path: /k8s

代理https后端

k8s dashboard只支持https訪問,首先卡住的問題是如何代理https服務,frontend到backend的路由會出現以下幾種情形:

  1. http->http

  2. http->https

  3. https->http

  4. https->https

當backend為https時,無論frontend是http或https,也就是2和4,都會報500錯誤,因為frontend無法驗證backend,此時解決方法:

  • 要么設置insecureSkipVerify,這樣比較簡單,如果采用這種方式frontend最好總是采用https,也就是設置redirect
  • 要么設置ingress tls,配置host的tls證書信息

我采用的設置insecureSkipVerify的方法。一般最佳的使用方式也是入口總是用https,然后終結tls,后端是否https不重要。

代理不同namespace服務

解決上述問題后,接下來遇到k8s dashboard服務無法訪問問題,在traefik dashboard中顯示為紅色,原因是helm安裝traefik默認在default namespace中,而k8s dashboard安裝在kubernetes-dashboard namespace中,不能跨namespace訪問到服務,解決方法:

  • 要么將traefik安裝到和k8s dashboard同一空間

  • 要么通過ExternalName將dashboard service引入到default namespace

    apiVersion: v1
    kind: Service
    metadata:
     name: kubernetes-dashboard
     namespace: default
    spec:
     ports:
     - name: https
       port: 443
       protocol: TCP
       targetPort: 443
     sessionAffinity: None
     type: ExternalName
     externalName: kubernetes-dashboard.kubernetes-dashboard.svc.cluster.local
    
    

我采用的ExternalName方法。service的完整域名是servicename.namespace.svc.cluster.local,cluster.local是kubelet中配置的。

基於path路由

服務可以訪問了,但是又出現了MIME type is not a supported stylesheet MIME type錯誤。

image-20191129064738766

一開始以為是traefik在reponse header中加入了 X-Content-Type-Options: nosniff,但是發現traefik默認是不加入的。

最后發現是url路徑問題,我的ingress僅使用path路由,沒有使用host。

當使用https://nodeip/k8s訪問k8s dashboard時,因為路由規則是PathPrefixStrip,到后端的請求是https://nodeip,這時得到主頁,文件名是k8s,主頁面k8s中的css,js等文件路徑是相對於當前文檔路徑的,所以request url是https://nodeip/xxx.css,這時就匹配不上路由規則,出現上述錯誤。

如果使用https://nodeip/k8s/訪問dashboard,就一切正常了。

所以使用路徑匹配路由時是存在一定風險的,和主頁中的資源路徑定義有關:

主頁中css,js等資源路徑定義方式 說明
沒有定義base,資源路徑不以./或../或/開頭
<base href="./">,資源路徑以./開頭
1.匹配/path時,只能通過https://xxxx/path/訪問
2.匹配/path,並且后端重定向到sub/,這時通過https://xxxx/path/或https://xxxx/path都可以訪問
<base href="/">,資源路徑不以./或../或/開頭 只能匹配/,其他路徑匹配都無法正常工作
確實碰到這種情況,例如monocular

所以最好的方式還是通過host匹配路由。

dashboard認證

了解上述問題后,終於進入到dashboard登陸界面:

image-20191129063718980

一開始我是使用的http入口,使用Token方式登陸,沒有任何響應,通過開發者工具查看,發現問題是在使用http入口時,header中沒有攜帶jweToken,導致認證失敗,必須使用https入口。

回想起之前通過kubectl proxy,即http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/也是登陸不了,其實是一樣的問題。

使用http入口登陸失敗:

image-20191129064020553

使用https入口時,jweToken是攜帶了,登陸成功:

image-20191129064137163 )

所以果斷設置frontend總是https,values增加traefik.ingress.kubernetes.io/redirect-entry-point: https,然后helm upgrade,自己增加的ingress需要自己修改:

dashboard:
  enabled: true
  ingress:
    annotations:
      traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
      traefik.ingress.kubernetes.io/redirect-entry-point: https
      # 不要使用ingress.kubernetes.io/ssl-redirect: "true",因為會丟掉path

這樣無論使用http://nodeip/k8s/還是https://nodeip/k8s/都可以成功登陸。

歡迎訪問鍾潘的博客


免責聲明!

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



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