一文搞懂 Traefik2.1 的使用

原文鏈接:一文搞懂 Traefik2.1 的使用

一文搞懂 Traefik2.1 的使用

Traefik 是一個開源的可以使服務(wù)發(fā)布變得輕松有趣的邊緣路由器效五。它負(fù)責(zé)接收你系統(tǒng)的請求,然后使用合適的組件來對這些請求進行處理撵彻。

除了眾多的功能之外墙贱,Traefik 的與眾不同之處還在于它會自動發(fā)現(xiàn)適合你服務(wù)的配置艺演。當(dāng) Traefik 在檢查你的服務(wù)時粮呢,會找到服務(wù)的相關(guān)信息并找到合適的服務(wù)來滿足對應(yīng)的請求。

Traefik 兼容所有主流的集群技術(shù)钞艇,比如 Kubernetes啄寡,Docker,Docker Swarm哩照,AWS挺物,Mesos,Marathon飘弧,等等识藤;并且可以同時處理多種方式。(甚至可以用于在裸機上運行的比較舊的軟件次伶。)

traefik architecture

使用 Traefik痴昧,不需要維護或者同步一個獨立的配置文件:因為一切都會自動配置,實時操作的(無需重新啟動冠王,不會中斷連接)赶撰。使用 Traefik,你可以花更多的時間在系統(tǒng)的開發(fā)和新功能上面柱彻,而不是在配置和維護工作狀態(tài)上面花費大量時間豪娜。

核心概念

Traefik 是一個邊緣路由器,是你整個平臺的大門哟楷,攔截并路由每個傳入的請求:它知道所有的邏輯和規(guī)則瘤载,這些規(guī)則確定哪些服務(wù)處理哪些請求;傳統(tǒng)的反向代理需要一個配置文件卖擅,其中包含路由到你服務(wù)的所有可能路由鸣奔,而 Traefik 會實時檢測服務(wù)并自動更新路由規(guī)則,可以自動服務(wù)發(fā)現(xiàn)惩阶。

traefik architecture overview

首先挎狸,當(dāng)啟動 Traefik 時,需要定義 entrypoints(入口點)琳猫,然后伟叛,根據(jù)連接到這些 entrypoints 的路由來分析傳入的請求,來查看他們是否與一組規(guī)則相匹配脐嫂,如果匹配统刮,則路由可能會將請求通過一系列中間件轉(zhuǎn)換過后再轉(zhuǎn)發(fā)到你的服務(wù)上去。在了解 Traefik 之前有幾個核心概念我們必須要了解:

  • Providers 用來自動發(fā)現(xiàn)平臺上的服務(wù)账千,可以是編排工具侥蒙、容器引擎或者 key-value 存儲等,比如 Docker匀奏、Kubernetes鞭衩、File
  • Entrypoints 監(jiān)聽傳入的流量(端口等…),是網(wǎng)絡(luò)入口點娃善,它們定義了接收請求的端口(HTTP 或者 TCP)论衍。
  • Routers 分析請求(host, path, headers, SSL, …),負(fù)責(zé)將傳入請求連接到可以處理這些請求的服務(wù)上去聚磺。
  • Services 將請求轉(zhuǎn)發(fā)給你的應(yīng)用(load balancing, …)坯台,負(fù)責(zé)配置如何獲取最終將處理傳入請求的實際服務(wù)。
  • Middlewares 中間件瘫寝,用來修改請求或者根據(jù)請求來做出一些判斷(authentication, rate limiting, headers, ...)蜒蕾,中間件被附件到路由上,是一種在請求發(fā)送到你的服務(wù)之前(或者在服務(wù)的響應(yīng)發(fā)送到客戶端之前)調(diào)整請求的一種方法焕阿。

安裝

由于 Traefik 2.X 版本和之前的 1.X 版本不兼容咪啡,我們這里選擇功能更加強大的 2.X 版本來和大家進行講解,我們這里使用的鏡像是 traefik:2.1.1暮屡。

在 Traefik 中的配置可以使用兩種不同的方式:

  • 動態(tài)配置:完全動態(tài)的路由配置
  • 靜態(tài)配置:啟動配置

靜態(tài)配置中的元素(這些元素不會經(jīng)常更改)連接到 providers 并定義 Treafik 將要監(jiān)聽的 entrypoints撤摸。

在 Traefik 中有三種方式定義靜態(tài)配置:在配置文件中、在命令行參數(shù)中褒纲、通過環(huán)境變量傳遞

動態(tài)配置包含定義系統(tǒng)如何處理請求的所有配置內(nèi)容愁溜,這些配置是可以改變的,而且是無縫熱更新的外厂,沒有任何請求中斷或連接損耗冕象。

安裝 Traefik 到 Kubernetes 集群中的資源清單文件我這里提前準(zhǔn)備好了,直接執(zhí)行下面的安裝命令即可:

$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/crd.yaml
$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/rbac.yaml
$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/deployment.yaml
$ kubectl apply -f https://www.qikqiak.com/k8strain/network/manifests/traefik/dashboard.yaml

其中 deployment.yaml 我這里是固定到 master 節(jié)點上的汁蝶,如果你需要修改可以下載下來做相應(yīng)的修改即可渐扮。我們這里是通過命令行參數(shù)來做的靜態(tài)配置:

args:
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --api=true
- --api.dashboard=true
- --ping=true
- --providers.kubernetesingress
- --providers.kubernetescrd
- --log.level=INFO
- --accesslog

其中前兩項配置是來定義 webwebsecure 這兩個入口點的,--api=true 開啟,=掖棉,就會創(chuàng)建一個名為 api@internal 的特殊 service墓律,在 dashboard 中可以直接使用這個 service 來訪問,然后其他比較重要的就是開啟 kubernetesingresskubernetescrd 這兩個 provider幔亥。

dashboard.yaml 中定義的是訪問 dashboard 的資源清單文件耻讽,可以根據(jù)自己的需求修改。

$ kubectl get pods -n kube-system                       
NAME                                  READY   STATUS    RESTARTS   AGE
traefik-867bd6b9c-lbrlx               1/1     Running   0          6m17s
......
$ kubectl get ingressroute
NAME                 AGE
traefik-dashboard    30m

部署完成后我們可以通過在本地 /etc/hosts 中添加上域名 traefik.domain.com 的映射即可訪問 Traefik 的 Dashboard 頁面了:

traefik dashboard demo

ACME

Traefik 通過擴展 CRD 的方式來擴展 Ingress 的功能帕棉,除了默認(rèn)的用 Secret 的方式可以支持應(yīng)用的 HTTPS 之外针肥,還支持自動生成 HTTPS 證書饼记。

比如現(xiàn)在我們有一個如下所示的 whoami 應(yīng)用:

apiVersion: v1
kind: Service
metadata:
  name: whoami
spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
  selector:
    app: whoami
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: whoami
  labels:
    app: whoami
spec:
  replicas: 2
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
        - name: whoami
          image: containous/whoami
          ports:
            - name: web
              containerPort: 80

然后定義一個 IngressRoute 對象:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: simpleingressroute
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/notls`)
    kind: Rule
    services:
    - name: whoami
      port: 80

通過 entryPoints 指定了我們這個應(yīng)用的入口點是 web,也就是通過 80 端口訪問慰枕,然后訪問的規(guī)則就是要匹配 who.qikqiak.com 這個域名具则,并且具有 /notls 的路徑前綴的請求才會被 whoami 這個 Service 所匹配。我們可以直接創(chuàng)建上面的幾個資源對象具帮,然后對域名做對應(yīng)的解析后博肋,就可以訪問應(yīng)用了:

traefik whoami http demo

IngressRoute 對象中我們定義了一些匹配規(guī)則,這些規(guī)則在 Traefik 中有如下定義方式:

traefik route matcher

如果我們需要用 HTTPS 來訪問我們這個應(yīng)用的話蜂厅,就需要監(jiān)聽 websecure 這個入口點匪凡,也就是通過 443 端口來訪問,同樣用 HTTPS 訪問應(yīng)用必然就需要證書掘猿,這里我們用 openssl 來創(chuàng)建一個自簽名的證書:

$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=who.qikqiak.com"

然后通過 Secret 對象來引用證書文件:

# 要注意證書文件名稱必須是 tls.crt 和 tls.key
$ kubectl create secret tls who-tls --cert=tls.crt --key=tls.key
secret/who-tls created

這個時候我們就可以創(chuàng)建一個 HTTPS 訪問應(yīng)用的 IngressRoute 對象了:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroutetls
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
    kind: Rule
    services:
    - name: whoami
      port: 80
  tls:
    secretName: who-tls

創(chuàng)建完成后就可以通過 HTTPS 來訪問應(yīng)用了病游,由于我們是自簽名的證書,所以證書是不受信任的:

traefik whoami https demo

除了手動提供證書的方式之外 Traefik 還支持使用 Let’s Encrypt 自動生成證書术奖,要使用 Let’s Encrypt 來進行自動化 HTTPS礁遵,就需要首先開啟 ACME,開啟 ACME 需要通過靜態(tài)配置的方式采记,也就是說可以通過環(huán)境變量佣耐、啟動參數(shù)等方式來提供,我們這里還是直接使用啟動參數(shù)的形式來開啟唧龄,在 Traefik 的部署文件中添加如下命令行參數(shù):

args:
......
# 使用 dns 驗證方式
- --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns
# 郵箱配置
- --certificatesResolvers.ali.acme.email=ych_1024@163.com
# 保存 ACME 證書的位置
- --certificatesResolvers.ali.acme.storage=/etc/acme/acme.json

ACME 有多種校驗方式 tlsChallenge兼砖、httpChallengednsChallenge 三種驗證方式,之前更常用的是 http 這種驗證方式既棺,關(guān)于這幾種驗證方式的使用可以查看文檔:https://www.qikqiak.com/traefik-book/https/acme/ 了解他們之間的區(qū)別讽挟。要使用 tls 校驗方式的話需要保證 Traefik 的 443 端口是可達(dá)的,dns 校驗方式可以生成通配符的證書丸冕,只需要配置上 DNS 解析服務(wù)商的 API 訪問密鑰即可校驗耽梅。我們這里用 DNS 校驗的方式來為大家說明如何配置 ACME。

上面我們通過設(shè)置 --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns 參數(shù)來指定指定阿里云的 DNS 校驗胖烛,要使用阿里云的 DNS 校驗我們還需要配置3個環(huán)境變量:ALICLOUD_ACCESS_KEY眼姐、ALICLOUD_SECRET_KEYALICLOUD_REGION_ID佩番,分別對應(yīng)我們平時開發(fā)阿里云應(yīng)用的時候的密鑰众旗,可以登錄阿里云后臺獲取,由于這是比較私密的信息趟畏,所以我們用 Secret 對象來創(chuàng)建:

$ kubectl create secret generic traefik-alidns-secret --from-literal=ALICLOUD_ACCESS_KEY=<aliyun ak> --from-literal=ALICLOUD_SECRET_KEY=<aliyun sk>--from-literal=ALICLOUD_REGION_ID=cn-beijing -n kube-system

創(chuàng)建完成后將這個 Secret 通過環(huán)境變量配置到 Traefik 的應(yīng)用中贡歧。還有一個值得注意的是驗證通過的證書我們這里存到 /etc/acme/acme.json 文件中,我們一定要將這個文件持久化,否則每次 Traefik 重建后就需要重新認(rèn)證利朵,而 Let’s Encrypt 本身校驗次數(shù)是有限制的律想。最后我們這里完整的 Traefik 的配置資源清單如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: traefik
  namespace: kube-system
  labels:
    app: traefik
spec:
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik
      terminationGracePeriodSeconds: 60
      tolerations:
      - operator: "Exists"
      nodeSelector:
        kubernetes.io/hostname: ydzs-master
      volumes:
      - name: acme
        hostPath:
          path: /data/k8s/traefik/acme
      containers:
      - image: traefik:2.1.1
        name: traefik
        ports:
        - name: web
          containerPort: 80
          hostPort: 80
        - name: websecure
          containerPort: 443
          hostPort: 443
        args:
        - --entryPoints.web.address=:80
        - --entryPoints.websecure.address=:443
        - --api=true
        - --api.dashboard=true
        - --ping=true
        - --providers.kubernetesingress
        - --providers.kubernetescrd
        - --log.level=INFO
        - --accesslog
        # 使用 dns 驗證方式
        - --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns
        # 郵箱配置
        - --certificatesResolvers.ali.acme.email=ych_1024@163.com
        # 保存 ACME 證書的位置
        - --certificatesResolvers.ali.acme.storage=/etc/acme/acme.json
        # 下面是用于測試的ca服務(wù),如果https證書生成成功了哗咆,則移除下面參數(shù)
        # - --certificatesresolvers.ali.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
        envFrom:
        - secretRef:
            name: traefik-alidns-secret
            # ALICLOUD_ACCESS_KEY
            # ALICLOUD_SECRET_KEY
            # ALICLOUD_REGION_ID
        volumeMounts:
        - name: acme
          mountPath: /etc/acme
        resources:
          requests:
            cpu: "50m"
            memory: "50Mi"
          limits:
            cpu: "200m"
            memory: "100Mi"
        securityContext:
          allowPrivilegeEscalation: true
          capabilities:
            drop:
            - ALL
            add:
            - NET_BIND_SERVICE
        readinessProbe:
          httpGet:
            path: /ping
            port: 8080
          failureThreshold: 1
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
        livenessProbe:
          httpGet:
            path: /ping
            port: 8080
          failureThreshold: 3
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2

直接更新 Traefik 應(yīng)用即可蜘欲。更新完成后現(xiàn)在我們來修改上面我們的 whoami 應(yīng)用:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroutetls
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
    kind: Rule
    services:
    - name: whoami
      port: 80
  tls:
    certResolver: ali
    domains:
    - main: "*.qikqiak.com"

其他的都不變益眉,只需要將 tls 部分改成我們定義的 ali 這個證書解析器晌柬,如果我們想要生成一個通配符的域名證書的話可以定義 domains 參數(shù)來指定,然后更新 IngressRoute 對象郭脂,這個時候我們再去用 HTTPS 訪問我們的應(yīng)用(當(dāng)然需要將域名在阿里云 DNS 上做解析):

traefik wildcard domain

我們可以看到訪問應(yīng)用已經(jīng)是受瀏覽器信任的證書了年碘,查看證書我們還可以發(fā)現(xiàn)該證書是一個通配符的證書。

中間件

中間件是 Traefik2.0 中一個非常有特色的功能展鸡,我們可以根據(jù)自己的各種需求去選擇不同的中間件來滿足服務(wù)屿衅,Traefik 官方已經(jīng)內(nèi)置了許多不同功能的中間件,其中一些可以修改請求莹弊,頭信息涤久,一些負(fù)責(zé)重定向,一些添加身份驗證等等忍弛,而且中間件還可以通過鏈?zhǔn)浇M合的方式來適用各種情況响迂。

traefik middleware overview

同樣比如上面我們定義的 whoami 這個應(yīng)用,我們可以通過 https://who.qikqiak.com/tls 來訪問到應(yīng)用细疚,但是如果我們用 http 來訪問的話呢就不行了蔗彤,就會404了,因為我們根本就沒有簡單80端口這個入口點疯兼,所以要想通過 http 來訪問應(yīng)用的話自然我們需要監(jiān)聽下 web 這個入口點:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroutetls-http
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
    kind: Rule
    services:
    - name: whoami
      port: 80

注意這里我們創(chuàng)建的 IngressRoute 的 entryPoints 是 web然遏,然后創(chuàng)建這個對象,這個時候我們就可以通過 http 訪問到這個應(yīng)用了吧彪。

但是我們?nèi)绻幌M脩敉ㄟ^ https 來訪問應(yīng)用的話呢待侵?按照以前的知識,我們是不是可以讓 http 強制跳轉(zhuǎn)到 https 服務(wù)去姨裸,對的秧倾,在 Traefik 中也是可以配置強制跳轉(zhuǎn)的,只是這個功能現(xiàn)在是通過中間件來提供的了啦扬。如下所示中狂,我們使用 redirectScheme 中間件來創(chuàng)建提供強制跳轉(zhuǎn)服務(wù):

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: redirect-https
spec:
  redirectScheme:
    scheme: https

然后將這個中間件附加到 http 的服務(wù)上面去,因為 https 的不需要跳轉(zhuǎn):

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroutetls-http
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
    kind: Rule
    services:
    - name: whoami
      port: 80
    middlewares: 
    - name: redirect-https

這個時候我們再去訪問 http 服務(wù)可以發(fā)現(xiàn)就會自動跳轉(zhuǎn)到 https 去了扑毡。關(guān)于更多中間件的用法可以查看文檔 Traefik Docs胃榕。

灰度發(fā)布

Traefik2.0 的一個更強大的功能就是灰度發(fā)布,灰度發(fā)布我們有時候也會稱為金絲雀發(fā)布(Canary),主要就是讓一部分測試的服務(wù)也參與到線上去勋又,經(jīng)過測試觀察看是否符號上線要求苦掘。

canary deployment

比如現(xiàn)在我們有兩個名為 appv1appv2 的服務(wù),我們希望通過 Traefik 來控制我們的流量楔壤,將 3?4 的流量路由到 appv1鹤啡,1/4 的流量路由到 appv2 去,這個時候就可以利用 Traefik2.0 中提供的帶權(quán)重的輪詢(WRR)來實現(xiàn)該功能蹲嚣,首先在 Kubernetes 集群中部署上面的兩個服務(wù)递瑰。為了對比結(jié)果我們這里提供的兩個服務(wù)一個是 whoami,一個是 nginx隙畜,方便測試抖部。

appv1 服務(wù)的資源清單如下所示:(appv1.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv1
spec:
  selector:
    matchLabels:
      app: appv1
  template:
    metadata:
      labels:
        use: test
        app: appv1
    spec:
      containers:
      - name: whoami
        image: containous/whoami
        ports:
        - containerPort: 80
          name: portv1
---
apiVersion: v1
kind: Service
metadata:
  name: appv1
spec:
  selector:
    app: appv1
  ports:
  - name: http
    port: 80
    targetPort: portv1

appv2 服務(wù)的資源清單如下所示:(appv2.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv2
spec:
  selector:
    matchLabels:
      app: appv2
  template:
    metadata:
      labels:
        use: test
        app: appv2
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: portv2
---
apiVersion: v1
kind: Service
metadata:
  name: appv2
spec:
  selector:
    app: appv2
  ports:
  - name: http
    port: 80
    targetPort: portv2

直接創(chuàng)建上面兩個服務(wù):

$ kubectl apply -f appv1.yaml
$ kubectl apply -f appv2.yaml
# 通過下面的命令可以查看服務(wù)是否運行成功
$ kubectl get pods -l use=test
NAME                     READY   STATUS    RESTARTS   AGE
appv1-58f856c665-shm9j   1/1     Running   0          12s
appv2-ff5db55cf-qjtrf    1/1     Running   0          12s

在 Traefik2.1 中新增了一個 TraefikService 的 CRD 資源,我們可以直接利用這個對象來配置 WRR议惰,之前的版本需要通過 File Provider慎颗,比較麻煩,新建一個描述 WRR 的資源清單:(wrr.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:
  name: app-wrr
spec:
  weighted:
    services:
      - name: appv1
        weight: 3  # 定義權(quán)重
        port: 80
        kind: Service  # 可選言询,默認(rèn)就是 Service
      - name: appv2
        weight: 1
        port: 80

然后為我們的灰度發(fā)布的服務(wù)創(chuàng)建一個 IngressRoute 資源對象:(ingressroute.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: wrringressroute
  namespace: default
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`wrr.qikqiak.com`)
    kind: Rule
    services:
    - name: app-wrr
      kind: TraefikService

不過需要注意的是現(xiàn)在我們配置的 Service 不再是直接的 Kubernetes 對象了俯萎,而是上面我們定義的 TraefikService 對象,直接創(chuàng)建上面的兩個資源對象运杭,這個時候我們對域名 wrr.qikqiak.com 做上解析夫啊,去瀏覽器中連續(xù)訪問 4 次,我們可以觀察到 appv1 這應(yīng)用會收到 3 次請求县习,而 appv2 這個應(yīng)用只收到 1 次請求涮母,符合上面我們的 3:1 的權(quán)重配置。

traefik wrr demo

流量復(fù)制

除了灰度發(fā)布之外躁愿,Traefik 2.0 還引入了流量鏡像服務(wù)叛本,是一種可以將流入流量復(fù)制并同時將其發(fā)送給其他服務(wù)的方法,鏡像服務(wù)可以獲得給定百分比的請求同時也會忽略這部分請求的響應(yīng)彤钟。

traefik mirror

同樣的在 2.0 中只能通過 FileProvider 進行配置来候,在 2.1 版本中我們已經(jīng)可以通過 TraefikService 資源對象來進行配置了,現(xiàn)在我們部署兩個 whoami 的服務(wù)逸雹,資源清單文件如下所示:

apiVersion: v1
kind: Service
metadata:
  name: v1
spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
  selector:
    app: v1
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: v1
  labels:
    app: v1
spec:
  selector:
    matchLabels:
      app: v1
  template:
    metadata:
      labels:
        app: v1
    spec:
      containers:
        - name: v1
          image: nginx
          ports:
            - name: web
              containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: v2
spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
  selector:
    app: v2
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: v2
  labels:
    app: v2
spec:
  selector:
    matchLabels:
      app: v2
  template:
    metadata:
      labels:
        app: v2
    spec:
      containers:
        - name: v2
          image: nginx
          ports:
            - name: web
              containerPort: 80

直接創(chuàng)建上面的資源對象:

$ kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
v1-77cfb86999-wfbl2                       1/1     Running   0          94s
v2-6f45d498b7-g6qjt                       1/1     Running   0          91s
$ kubectl get svc 
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
v1              ClusterIP   10.96.218.173   <none>        80/TCP      99s
v2              ClusterIP   10.99.98.48     <none>        80/TCP      96s

現(xiàn)在我們創(chuàng)建一個 IngressRoute 對象营搅,將服務(wù) v1 的流量復(fù)制 50% 到服務(wù) v2,如下資源對象所示:(mirror-ingress-route.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:
  name: app-mirror
spec:
  mirroring:
    name: v1 # 發(fā)送 100% 的請求到 K8S 的 Service "v1"
    port: 80
    mirrors:
    - name: v2 # 然后復(fù)制 50% 的請求到 v2
      percent: 50
      port: 80
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: mirror-ingress-route
  namespace: default
spec:
  entryPoints:
  - web
  routes:   
  - match: Host(`mirror.qikqiak.com`)
    kind: Rule
    services:
    - name: app-mirror
      kind: TraefikService # 使用聲明的 TraefikService 服務(wù)梆砸,而不是 K8S 的 Service

然后直接創(chuàng)建這個資源對象即可:

$ kubectl apply -f mirror-ingress-route.yaml 
ingressroute.traefik.containo.us/mirror-ingress-route created
traefikservice.traefik.containo.us/mirroring-example created

這個時候我們在瀏覽器中去連續(xù)訪問4次 mirror.qikqiak.com 可以發(fā)現(xiàn)有一半的請求也出現(xiàn)在了 v2 這個服務(wù)中:

traefik mirror demo

TCP

另外 Traefik2.0 已經(jīng)支持了 TCP 服務(wù)的转质,下面我們以 mongo 為例來了解下 Traefik 是如何支持 TCP 服務(wù)得。

簡單 TCP 服務(wù)

首先部署一個普通的 mongo 服務(wù)帖世,資源清單文件如下所示:(mongo.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-traefik
  labels:
    app: mongo-traefik
spec:
  selector:
    matchLabels:
      app: mongo-traefik
  template:
    metadata:
      labels:
        app: mongo-traefik
    spec:
      containers:
      - name: mongo
        image: mongo:4.0
        ports:
        - containerPort: 27017
---
apiVersion: v1
kind: Service
metadata:
  name: mongo-traefik
spec:
  selector:
    app: mongo-traefik
  ports:
  - port: 27017

直接創(chuàng)建 mongo 應(yīng)用:

$ kubectl apply -f mongo.yaml
deployment.apps/mongo-traefik created
service/mongo-traefik created

創(chuàng)建成功后就可以來為 mongo 服務(wù)配置一個路由了休蟹。由于 Traefik 中使用 TCP 路由配置需要 SNI,而 SNI 又是依賴 TLS 的,所以我們需要配置證書才行赂弓,如果沒有證書的話绑榴,我們可以使用通配符 * 進行配置,我們這里創(chuàng)建一個 IngressRouteTCP 類型的 CRD 對象(前面我們就已經(jīng)安裝了對應(yīng)的 CRD 資源):(mongo-ingressroute-tcp.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: mongo-traefik-tcp
spec:
  entryPoints:
    - mongo
  routes:
  - match: HostSNI(`*`)
    services:
    - name: mongo-traefik
      port: 27017

要注意的是這里的 entryPoints 部分盈魁,是根據(jù)我們啟動的 Traefik 的靜態(tài)配置中的 entryPoints 來決定的翔怎,我們當(dāng)然可以使用前面我們定義得 80 和 443 這兩個入口點,但是也可以可以自己添加一個用于 mongo 服務(wù)的專門入口點:

......
- image: traefik:2.1.1
  name: traefik
  ports:
  - name: web
    containerPort: 80
    hostPort: 80
  - name: websecure
    containerPort: 443
    hostPort: 443
  - name: mongo
    hostPort: 27017
    containerPort: 27017
  args:
  - --entryPoints.web.address=:80
  - --entryPoints.websecure.address=:443
  - --entryPoints.mongo.address=:27017
  ......

這里給入口點添加 hostPort 是為了能夠通過節(jié)點的端口訪問到服務(wù)杨耙,關(guān)于 entryPoints 入口點的更多信息赤套,可以查看文檔 entrypoints 了解更多信息。

然后更新 Traefik 后我們就可以直接創(chuàng)建上面的資源對象:

$ mongo-ingressroute-tcp.yaml
ingressroutetcp.traefik.containo.us/mongo-traefik-tcp created

創(chuàng)建完成后按脚,同樣我們可以去 Traefik 的 Dashboard 頁面上查看是否生效:

traefik-tcp-mongo-1

然后我們配置一個域名 mongo.local 解析到 Traefik 所在的節(jié)點于毙,然后通過 27017 端口來連接 mongo 服務(wù):

$ mongo --host mongo.local --port 27017
mongo(75243,0x1075295c0) malloc: *** malloc_zone_unregister() failed for 0x7fffa56f4000
MongoDB shell version: 2.6.1
connecting to: mongo.local:27017/test
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

到這里我們就完成了將 mongo(TCP)服務(wù)暴露給外部用戶了敦冬。

帶 TLS 證書的 TCP

上面我們部署的 mongo 是一個普通的服務(wù)辅搬,然后用 Traefik 代理的,但是有時候為了安全 mongo 服務(wù)本身還會使用 TLS 證書的形式提供服務(wù)脖旱,下面是用來生成 mongo tls 證書的腳本文件:(generate-certificates.sh)

#!/bin/bash
#
# From https://medium.com/@rajanmaharjan/secure-your-mongodb-connections-ssl-tls-92e2addb3c89

set -eu -o pipefail

DOMAINS="${1}"
CERTS_DIR="${2}"
[ -d "${CERTS_DIR}" ]
CURRENT_DIR="$(cd "$(dirname "${0}")" && pwd -P)"

GENERATION_DIRNAME="$(echo "${DOMAINS}" | cut -d, -f1)"

rm -rf "${CERTS_DIR}/${GENERATION_DIRNAME:?}" "${CERTS_DIR}/certs"

echo "== Checking Requirements..."
command -v go >/dev/null 2>&1 || echo "Golang is required"
command -v minica >/dev/null 2>&1 || go get github.com/jsha/minica >/dev/null

echo "== Generating Certificates for the following domains: ${DOMAINS}..."
cd "${CERTS_DIR}"
minica --ca-cert "${CURRENT_DIR}/minica.pem" --ca-key="${CURRENT_DIR}/minica-key.pem" --domains="${DOMAINS}"
mv "${GENERATION_DIRNAME}" "certs"
cat certs/key.pem certs/cert.pem > certs/mongo.pem

echo "== Certificates Generated in the directory ${CERTS_DIR}/certs"

將上面證書放置到 certs 目錄下面堪遂,然后我們新建一個 02-tls-mongo 的目錄,在該目錄下面執(zhí)行如下命令來生成證書:

$ bash ../certs/generate-certificates.sh mongo.local .
== Checking Requirements...
== Generating Certificates for the following domains: mongo.local...

最后的目錄如下所示萌庆,在 02-tls-mongo 目錄下面會生成包含證書的 certs 目錄:

$ tree .
.
├── 01-mongo
│   ├── mongo-ingressroute-tcp.yaml
│   └── mongo.yaml
├── 02-tls-mongo
│   └── certs
│       ├── cert.pem
│       ├── key.pem
│       └── mongo.pem
└── certs
    ├── generate-certificates.sh
    ├── minica-key.pem
    └── minica.pem

02-tls-mongo/certs 目錄下面執(zhí)行如下命令通過 Secret 來包含證書內(nèi)容:

$ kubectl create secret tls traefik-mongo-certs --cert=cert.pem --key=key.pem
secret/traefik-mongo-certs created

然后重新更新 IngressRouteTCP 對象溶褪,增加 TLS 配置:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: mongo-traefik-tcp
spec:
  entryPoints:
    - mongo
  routes:
  - match: HostSNI(`mongo.local`)
    services:
    - name: mongo-traefik
      port: 27017
  tls: 
    secretName: traefik-mongo-certs

同樣更新后,現(xiàn)在我們直接去訪問應(yīng)用就會被 hang 住践险,因為我們沒有提供證書:

$ mongo --host mongo.local --port 27017
MongoDB shell version: 2.6.1
connecting to: mongo1.local:27017/test

這個時候我們可以帶上證書來進行連接:

$ mongo --host mongo.local --port 27017 --ssl --sslCAFile=../certs/minica.pem --sslPEMKeyFile=./certs/mongo.pem
MongoDB shell version v4.0.3
connecting to: mongodb://mongo.local:27017/
Implicit session: session { "id" : UUID("e7409ef6-8ebe-4c5a-9642-42059bdb477b") }
MongoDB server version: 4.0.14
......
> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB

可以看到現(xiàn)在就可以連接成功了猿妈,這樣就完成了一個使用 TLS 證書代理 TCP 服務(wù)的功能,這個時候如果我們使用其他的域名去進行連接就會報錯了巍虫,因為現(xiàn)在我們指定的是特定的 HostSNI:

$ mongo --host mongo.k8s.local --port 27017 --ssl --sslCAFile=../certs/minica.pem --sslPEMKeyFile=./certs/mongo.pem
MongoDB shell version v4.0.3
connecting to: mongodb://mongo.k8s.local:27017/
2019-12-29T15:03:52.424+0800 E NETWORK  [js] SSL peer certificate validation failed: Certificate trust failure: CSSMERR_TP_NOT_TRUSTED; connection rejected
2019-12-29T15:03:52.429+0800 E QUERY    [js] Error: couldn't connect to server mongo.qikqiak.com:27017, connection attempt failed: SSLHandshakeFailed: SSL peer certificate validation failed: Certificate trust failure: CSSMERR_TP_NOT_TRUSTED; connection rejected :
connect@src/mongo/shell/mongo.js:257:13
@(connect):1:6
exception: connect failed

當(dāng)然我們也可以使用 ACME 來為我們提供一個合法的證書彭则,這樣在連接的使用就不需要指定證書了,如下所示:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: mongo-traefik-tcp
spec:
  entryPoints:
    - mongo
  routes:
  - match: HostSNI(`mongo.qikqiak.com`)
    services:
    - name: mongo-traefik
      port: 27017
  tls:
    certResolver: ali
    domains:
    - main: "*.qikqiak.com"

這樣當(dāng)我們連接的時候就只需要如下的命令即可:

$ mongo --host mongo.qikqiak.com --port 27017 --ssl

掃描下面的二維碼(或微信搜索k8s技術(shù)圈)關(guān)注我們的微信公眾帳號占遥,在微信公眾帳號中回復(fù) 加群 即可加入到我們的 kubernetes 討論群里面共同學(xué)習(xí)俯抖。

k8s技術(shù)圈二維碼
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瓦胎,隨后出現(xiàn)的幾起案子芬萍,更是在濱河造成了極大的恐慌,老刑警劉巖搔啊,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柬祠,死亡現(xiàn)場離奇詭異,居然都是意外死亡负芋,警方通過查閱死者的電腦和手機漫蛔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惩猫,你說我怎么就攤上這事芝硬。” “怎么了轧房?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵拌阴,是天一觀的道長。 經(jīng)常有香客問我奶镶,道長迟赃,這世上最難降的妖魔是什么歉备? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任竞滓,我火速辦了婚禮,結(jié)果婚禮上襟雷,老公的妹妹穿的比我還像新娘捺信。我一直安慰自己酌媒,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布迄靠。 她就那樣靜靜地躺著秒咨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掌挚。 梳的紋絲不亂的頭發(fā)上雨席,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機與錄音吠式,去河邊找鬼陡厘。 笑死,一個胖子當(dāng)著我的面吹牛特占,可吹牛的內(nèi)容都是我干的糙置。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼摩钙,長吁一口氣:“原來是場噩夢啊……” “哼罢低!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起胖笛,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤网持,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后长踊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體功舀,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年身弊,在試婚紗的時候發(fā)現(xiàn)自己被綠了辟汰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片列敲。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖帖汞,靈堂內(nèi)的尸體忽然破棺而出戴而,到底是詐尸還是另有隱情,我是刑警寧澤翩蘸,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布所意,位于F島的核電站,受9級特大地震影響催首,放射性物質(zhì)發(fā)生泄漏扶踊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一郎任、第九天 我趴在偏房一處隱蔽的房頂上張望秧耗。 院中可真熱鬧,春花似錦舶治、人聲如沸分井。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杂抽。三九已至,卻和暖如春韩脏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背铸磅。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工赡矢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人阅仔。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓吹散,卻偏偏與公主長得像,于是被迫代替她去往敵國和親八酒。 傳聞我的和親對象是個殘疾皇子空民,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容