1. 程式人生 > 實用技巧 >第二篇 kubernetes 叢集部署 Traefik-ingress

第二篇 kubernetes 叢集部署 Traefik-ingress

1.什麼是ingress?

k8s 對外暴露服務(service)主要有兩種方式:NotePort, LoadBalance;
此外externalIP也可以使各類service對外提供服務,但是當叢集服務很多的時候,NodePort方式最大的缺點是會佔用很多叢集機器的埠;
LB方式最大的缺點則是每個service一個LB又有點浪費和麻煩,並且需要k8s之外的支援;
而ingress則只需要一個NodePort或者一個LB就可以滿足所有service對外服務的需求。

2.ingress介紹

#k8s內部並沒有自帶代理程式完成這種規則轉發。
ingress-controller 是一個代理伺服器,將ingress的規則能真正實現的方式。
常用的有Nginx-Ingress-Controller,Traefik-Ingress-Controller,  Haproxy-Ingress-Controller。

要理解ingress,需要區分兩個概念,ingress和ingress-controller:
#ingress物件:
指的是k8s中的一個api物件,一般用yaml配置。作用是定義請求如何轉發到service的規則,可以理解為配置模板。
#ingress-controller:
具體實現反向代理及負載均衡的程式,對ingress定義的規則進行解析,根據配置的規則來實現請求轉發。
簡單來說,ingress-controller才是負責具體轉發的元件,通過各種方式將它暴露在叢集入口,外部對叢集的請求流量會先到ingress-controller,而ingress物件是用來告訴ingress-controller該如何轉發請求,比如哪些域名哪些path要轉發到哪些服務等等。

3.對比nginx 和 traefik

#nginx:
使用nginx作為前端負載均衡,通過ingress controller不斷的和kubernetes api互動,實時獲取後端service,pod等的變化,然後動態更新nginx配置,並重新整理使配置生效,達到服務發現的目的。

#traefik:
traefik本身設計的就能夠實時跟kubernetes api互動,感知後端service,pod等的變化,自動更新配置並重載。

相對來說traefik更快速方便,同時支援更多的特性,使反向代理,負載均衡更直接更高效。可參考下圖功能對比:

4.在 kubernetes 叢集部署 Traefik-ingress

#traefik簡介
https://traefik.cn/
https://docs.traefik.io/

Traefik 是一個為了讓部署微服務更加便捷而誕生的現代HTTP反向代理、負載均衡工具。 它支援多種後臺 (Docker, Swarm, Kubernetes, Marathon, Mesos, Consul, Etcd, Zookeeper, BoltDB, Rest API, file…) 來自動化、動態的應用它的配置檔案設定。

#kubernetes部署
traefik有多種部署方式,可以以deploymen/daemonset方式手動部署,也可以使用helm來快速部署。

#helm部署參考:https://github.com/containous/traefik-helm-chart

#下面使用daemonset方式部署,部署版本:traefik v2.1.2

#mkdir /root/k8s/ingress  &&  cd  /root/k8s/ingress

(1)建立 CRD 資源

參考:https://docs.traefik.io/routing/providers/kubernetes-crd/
展開Configuration Examples有相關示例yaml。
在 traefik v2.1 版本後,開始使用 CRD(Custom Resource Definition)來完成路由配置等,所以需要提前建立 CRD 資源。
#cat traefik-crd.yaml
## IngressRoute
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutes.traefik.containo.us
spec:
  scope: Namespaced
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: IngressRoute
    plural: ingressroutes
    singular: ingressroute
---
## IngressRouteTCP
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutetcps.traefik.containo.us
spec:
  scope: Namespaced
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: IngressRouteTCP
    plural: ingressroutetcps
    singular: ingressroutetcp
---
## Middleware
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: middlewares.traefik.containo.us
spec:
  scope: Namespaced
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: Middleware
    plural: middlewares
    singular: middleware
---
## TLSOption
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: tlsoptions.traefik.containo.us
spec:
  scope: Namespaced
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: TLSOption
    plural: tlsoptions
    singular: tlsoption
---
## TraefikService
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: traefikservices.traefik.containo.us
spec:
  scope: Namespaced
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: TraefikService
    plural: traefikservices
    singular: traefikservice

#kubectl apply -f traefik-crd.yaml

(2)建立RBAC資源

參考:https://docs.traefik.io/routing/providers/kubernetes-crd/
Kubernetes 在 1.6 版本中引入了基於角色的訪問控制(RBAC)策略,方便對 Kubernetes 資源和 API 進行細粒度控制。Traefik 需要一定的許可權,所以這裡提前建立好 Traefik ServiceAccount 並分配一定的許可權。
#cat traefik-rbac.yaml
## ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: kube-system
  name: traefik-ingress-controller
---
## ClusterRole
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"]
  - apiGroups: ["extensions"]
    resources: ["ingresses/status"]
    verbs: ["update"]
  - apiGroups: ["traefik.containo.us"]
    resources: ["middlewares"]
    verbs: ["get","list","watch"]
  - apiGroups: ["traefik.containo.us"]
    resources: ["ingressroutes"]
    verbs: ["get","list","watch"]
  - apiGroups: ["traefik.containo.us"]
    resources: ["ingressroutetcps"]
    verbs: ["get","list","watch"]
  - apiGroups: ["traefik.containo.us"]
    resources: ["tlsoptions"]
    verbs: ["get","list","watch"]
  - apiGroups: ["traefik.containo.us"]
    resources: ["traefikservices"]
    verbs: ["get","list","watch"]
---
## ClusterRoleBinding
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

# kubectl apply -f traefik-rbac.yaml -n kube-system

(3)建立configmap

由於 Traefik 配置很多,通過 CLI 定義不是很方便,一般選擇將其配置選項放到配置檔案中,然後存入 ConfigMap,將其掛入 traefik 中。

#cat  traefik-config.yaml :
kind: ConfigMap
apiVersion: v1
metadata:
  name: traefik-config
data:
  traefik.yaml: |-
    ping: ""                    ## 啟用 Ping
    serversTransport:
      insecureSkipVerify: true  ## Traefik 忽略驗證代理服務的 TLS 證書
    api:
      insecure: true            ## 允許 HTTP 方式訪問 API
      dashboard: true           ## 啟用 Dashboard
      debug: false              ## 啟用 Debug 除錯模式
    metrics:
      prometheus: ""            ## 配置 Prometheus 監控指標資料,並使用預設配置
    entryPoints:
      web:
        address: ":80"          ## 配置 80 埠,並設定入口名稱為 web
      websecure:
        address: ":443"         ## 配置 443 埠,並設定入口名稱為 websecure
    providers:
      kubernetesCRD: ""         ## 啟用 Kubernetes CRD 方式來配置路由規則
      kubernetesIngress: ""     ## 啟動 Kubernetes Ingress 方式來配置路由規則
    log:
      filePath: ""              ## 設定除錯日誌檔案儲存路徑,如果為空則輸出到控制檯
      level: error              ## 設定除錯日誌級別
      format: json              ## 設定除錯日誌格式
    accessLog:
      filePath: ""              ## 設定訪問日誌檔案儲存路徑,如果為空則輸出到控制檯
      format: json              ## 設定訪問除錯日誌格式
      bufferingSize: 0          ## 設定訪問日誌快取行數
      filters:
        #statusCodes: ["200"]   ## 設定只保留指定狀態碼範圍內的訪問日誌
        retryAttempts: true     ## 設定代理訪問重試失敗時,保留訪問日誌
        minDuration: 20         ## 設定保留請求時間超過指定持續時間的訪問日誌
      fields:                   ## 設定訪問日誌中的欄位是否保留(keep 保留、drop 不保留)
        defaultMode: keep       ## 設定預設保留訪問日誌欄位
        names:                  ## 針對訪問日誌特別欄位特別配置保留模式
          ClientUsername: drop  
        headers:                ## 設定 Header 中欄位是否保留
          defaultMode: keep     ## 設定預設保留 Header 中欄位
          names:                ## 針對 Header 中特別欄位特別配置保留模式
            User-Agent: redact
            Authorization: drop
            Content-Type: keep

#建立Traefik ConfigMap 資源

# kubectl apply -f traefik-config.yaml -n kube-system

(4)節點設定label標籤

由於是 Kubernetes DeamonSet 這種方式部署 Traefik,所以需要提前給節點設定 Label,這樣當程式部署時 Pod 會自動排程到設定 Label 的節點上。

#節點設定 Label 標籤
#kubectl label nodes master.k8s.com IngressProxy=true
#kubectl label nodes node.k8s.com IngressProxy=true
#檢視節點是否設定 Label 成功
#kubectl get nodes --show-labels

#如果想刪除標籤,可以使用
#kubectl label nodes node.k8s.com IngressProxy-

(5)部署traefik
使用 DaemonSet 方式部署,便於在多伺服器間擴充套件,用 hostport 方式佔用伺服器 80、443 埠,方便流量進入。

#建立 traefik 部署檔案 traefik-deploy.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik-ingress-controller
---
apiVersion: v1
kind: Service
metadata:
  name: traefik
spec:
  ports:
    - name: web
      port: 80
    - name: websecure
      port: 443
    - name: admin
      port: 8080
  selector:
    app: traefik
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: traefik-ingress-controller
  labels:
    app: traefik
spec:
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      name: traefik
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik-ingress-controller
      terminationGracePeriodSeconds: 1
      containers:
        - image: traefik:v2.1.2
          name: traefik-ingress-lb
          ports:
            - name: web
              containerPort: 80
              hostPort: 80         ## 將容器埠繫結所在伺服器的 80 埠
            - name: websecure
              containerPort: 443
              hostPort: 443        ## 將容器埠繫結所在伺服器的 443 埠
            - name: admin
              containerPort: 8080  ## Traefik Dashboard 埠
          resources:
            limits:
              cpu: 2000m
              memory: 1024Mi
            requests:
              cpu: 1000m
              memory: 1024Mi
          securityContext:
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
          args:
            - --configfile=/config/traefik.yaml
          volumeMounts:
            - mountPath: "/config"
              name: "config"
      volumes:
        - name: config
          configMap:
            name: traefik-config 
      tolerations:              ## 設定容忍所有汙點,防止節點被設定汙點
        - operator: "Exists"
      nodeSelector:             ## 設定node篩選器,在特定label的節點上啟動
        IngressProxy: "true"

#部署 Traefik
#kubectl apply -f traefik-deploy.yaml  -n kube-system

#到此 Traefik v2.1 應用已經部署完成。

Traefik 路由規則配置

(1)、配置 HTTP 路由規則 (Traefik Dashboard 為例)
Traefik 應用已經部署完成,但是想讓外部訪問 Kubernetes 內部服務,還需要配置路由規則,這裡開啟了 Traefik Dashboard 配置,所以首先配置 Traefik Dashboard 看板的路由規則,使外部能夠訪問 Traefik Dashboard。

建立 Traefik Dashboard 路由規則檔案 traefik-dashboard-route.yaml

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard-route
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`traefik.k8s.com`)
      kind: Rule
      services:
        - name: traefik
          port: 8080
建立 Traefik Dashboard 路由規則物件

# kubectl apply -f traefik-dashboard-route.yaml -n kube-system

接下來配置 Hosts,客戶端想通過域名訪問服務,必須要進行 DNS 解析,由於這裡沒有 DNS 伺服器進行域名解析,所以修改 hosts 檔案將 Traefik 指定節點的 IP 和自定義 host 繫結。開啟電腦的 Hosts 配置檔案,往其加入下面配置:

192.168.25.66  traefik.k8s.com

配置完成後,開啟瀏覽器輸入地址:http://traefik.k8s.com開啟 Traefik Dashboard。

(2)、配置 HTTPS 路由規則(Kubernetes Dashboard 為例)
這裡我們建立 Kubernetes 的 Dashboard 看板,它是 Https 協議方式,由於它是需要使用 Https 請求,所以我們配置基於 Https 的路由規則並指定證書。

建立證書檔案

# 建立自簽名證書
# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=master.k8s.com"

# 將證書儲存到 Kubernetes Secret 中
# kubectl create secret generic cloud-mydlq-tls --from-file=tls.crt --from-file=tls.key -n kube-system
建立 Traefik Dashboard 路由規則檔案 kubernetes-dashboard-route.yaml

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: kubernetes-dashboard-route
spec:
  entryPoints:
    - websecure
  tls:
    secretName: cloud-mydlq-tls
  routes:
    - match: Host(`master.k8s.com`) 
      kind: Rule
      services:
        - name: kubernetes-dashboard
          port: 443
建立 Kubernetes Dashboard 路由規則物件

# kubectl apply -f kubernetes-dashboard-route.yaml -n kube-system
跟上面一樣,配置 Hosts 檔案

192.168.25.65  master.k8s.com
配置完成後,開啟瀏覽器輸入地址:https://master.k8s.com 開啟 Dashboard Dashboard。