使用 Traefik 引導 Kubernetes 流量

2020-04-07 10:35:00

將流量引入 Kubernetes 樹莓派叢集的分步指南。

在本文中,我們將部署幾個簡單的網站,並學習如何使用 Traefik 將來自外部世界的流量引入到我們的叢集中。之後,我們還將學習如何刪除 Kubernetes 資源。讓我們開始吧!

準備

要繼續閱讀本文,你只需要我們在上一篇文章中構建的 。由於你的叢集將從網路上拉取映象,因此該叢集需要能夠存取網際網路。

出於解釋目的,本文將顯示一些組態檔和範例 HTML 檔案。所有範例檔案都可以在此處下載。

部署一個簡單的網站

之前,我們使用 kubectl 進行了直接部署。但是,這不是典型的部署方法。一般情況都會使用 YAML 組態檔,這也是我們要在本文中使用的組態檔。我們將從頂部開始,並以自頂向下的方式建立該組態檔。

部署設定

首先是部署設定。設定如下所示,並在下面進行說明。我通常以 Kubernetes 文件中的範例為起點,然後根據需要對其進行修改。例如,下面的設定是複製了部署文件中的範例後修改的。

建立一個檔案 mysite.yaml,其內容如下:

apiVersion: apps/v1kind: Deploymentmetadata:  name: mysite-nginx  labels:    app: mysite-nginxspec:  replicas: 1  selector:    matchLabels:      app: mysite-nginx  template:    metadata:      labels:        app: mysite-nginx    spec:      containers:      - name: nginx        image: nginx        ports:        - containerPort: 80

其中大部分是樣板。重要的部分,我們會將該部署命名為 mysite-nginx,並為其加上同名的 app 標籤。我們指定了一個副本replica,這意味著將只建立一個 Pod。我們還指定了一個容器,我們將其命名為 nginx。我們將映象image指定為 nginx。這意味著在部署時,k3s 將從 DockerHub 下載 nginx 映象並從中建立一個 Pod。最後,我們指定了容器埠containerPort80,這只意味著在容器內部 Pod 會監聽 80 埠。

我在上面強調了“在容器內部”,因為這是一個重要的區別。由於我們是按容器設定的,因此只能在容器內部存取它,並且進一步將其限制為內部網路。這對於允許多個容器在同一容器埠上監聽所是必要的。換句話說,通過這種設定,其他一些 Pod 也可以在其容器埠 80 上偵聽,並且不會與此容器衝突。為了提供對該 Pod 的正式存取許可權,我們需要一個服務service設定。

服務設定

在 Kubernetes 中,服務service是一種抽象。它提供了一種存取 Pod 或 Pod 集合的方法。當連線到服務時,服務會路由到單個 Pod,或者如果定義了多個 Pod 副本,會通過負載均衡路由到多個 Pod。

可以在同一組態檔中指定該服務,這就是我們將在此處要做的。用 --- 分隔設定區域,將以下內容新增到 mysite.yaml 中:

---apiVersion: v1kind: Servicemetadata:  name: mysite-nginx-servicespec:  selector:    app: mysite-nginx  ports:    - protocol: TCP      port: 80

在此設定中,我們將服務命名為 mysite-nginx-service。我們提供了一個選擇器selectorapp: mysite-nginx。這是服務選擇其路由到的應用程式容器的方式。請記住,我們為容器提供了 app 標籤:mysite-nginx 。這就是服務用來查詢我們的容器的方式。最後,我們指定服務協定為 TCP,在埠 80 上監聽。

入口設定

入口Ingress設定指定了如何將流量從叢集外部傳遞到叢集內部的服務。請記住,k3s 預先設定了 Traefik 作為入口控制器。因此,我們將編寫特定於 Traefik 的入口設定。將以下內容新增到 mysite.yaml 中(不要忘了用 --- 分隔):

---apiVersion: networking.k8s.io/v1beta1kind: Ingressmetadata:  name: mysite-nginx-ingress  annotations:    kubernetes.io/ingress.class: "traefik"spec:  rules:  - http:      paths:      - path: /        backend:          serviceName: mysite-nginx-service          servicePort: 80

在此設定中,我們將入口記錄命名為 mysite-nginx-ingress。我們告訴 Kubernetes,我們希望 traefik 成為我們的入口控制器,再加上 kubernetes.io/ingress.class 的註解。

規則rules部分中,我們基本上是說,當 http 流量進入時,並且 path 匹配 /(或其下的任何內容),將其路由到由 serviceName mysite-nginx-service 指定的後端backend服務中,並將其路由到 servicePort 80。這會將傳入的 HTTP 流量連線到我們之前定義的服務。

需要部署的東西

就設定而言,就是這樣了。如果我們現在部署,我們將獲得預設的 nginx 頁面,但這不是我們想要的。讓我們建立一些簡單但可自定義的部署方式。建立具有以下內容的檔案 index.html

<html><head><title>K3S!</title>  <style>    html {      font-size: 62.5%;    }    body {      font-family: sans-serif;      background-color: midnightblue;      color: white;      display: flex;      flex-direction: column;      justify-content: center;      height: 100vh;    }    div {      text-align: center;      font-size: 8rem;      text-shadow: 3px 3px 4px dimgrey;    }  </style></head><body>  <div>Hello from K3S!</div></body></html>

我們尚未介紹 Kubernetes 中的儲存機制,因此在這裡我們偷懶一下,僅將該檔案儲存在 Kubernetes 設定對映中。這不是我們推薦的部署網站的方式,但對於我們的目的來說是可行的。執行以下命令:

kubectl create configmap mysite-html --from-file index.html

該命令從本地檔案 index.html 建立名為 mysite-html設定對映configmap資源。這實際上是在 Kubernetes 資源中儲存一個檔案(或一組檔案),我們可以在設定中調出該檔案。它通常用於儲存組態檔(因此而得名),我們在這裡稍加濫用。在以後的文章中,我們將討論 Kubernetes 中適當的儲存解決方案。

建立設定對映後,讓我們將其掛載在我們的 nginx 容器中。我們分兩個步驟進行。首先,我們需要指定一個volume來調出設定對映。然後我們需要將該捲掛載到 nginx 容器中。通過在 mysite.yaml 中的 container 後面的 spec 標簽下新增以下內容來完成第一步:

      volumes:      - name: html-volume        configMap:          name: mysite-html

這告訴 Kubernetes 我們要定義一個名為 html-volume 的卷,並且該捲應包含名為 html-volume(我們在上一步中建立的)的設定對映的內容。

接下來,在 nginx 容器規範中的ports下方,新增以下內容:

        volumeMounts:        - name: html-volume          mountPath: /usr/share/nginx/html

這告訴 Kubernetes,對於 nginx 容器,我們想在容器中的 /usr/share/nginx/html 路徑上掛載名為 html-volume 的卷。 為什麼要使用 /usr/share/nginx/html?那個位置就是 nginx 映象提供 HTML 服務的地方。通過在該路徑上掛載卷,我們用該卷內容替換了預設內容。

作為參考,組態檔的 deployment 部分現在應如下所示:

apiVersion: apps/v1kind: Deploymentmetadata:  name: mysite-nginx  labels:    app: mysite-nginxspec:  replicas: 1  selector:    matchLabels:      app: mysite-nginx  template:    metadata:      labels:        app: mysite-nginx    spec:      containers:      - name: nginx        image: nginx        ports:        - containerPort: 80        volumeMounts:        - name: html-volume          mountPath: /usr/share/nginx/html      volumes:      - name: html-volume        configMap:          name: mysite-html

部署它!

現在我們準備部署! 我們可以這樣做:

kubectl apply -f mysite.yaml

你應該看到類似於以下內容:

deployment.apps/mysite-nginx createdservice/mysite-nginx-service createdingress.networking.k8s.io/mysite-nginx-ingress created

這意味著 Kubernetes 為我們指定的三個設定分別建立了資源。使用以下方法檢查 Pod 的狀態:

kubectl get pods

如果看到狀態為 ContainerCreating,請給它一些時間並再次執行 kubectl get pods。通常,第一次會花一些時間,因為 k3s 必須下載 nginx 映象來建立 Pod。一段時間後,你應該看到 Running 的狀態。

嘗試一下!

Pod 執行之後,就該嘗試了。開啟瀏覽器,然後在位址列中輸入 kmaster

恭喜你!你已經在 k3s 叢集上部署了一個網站!

另一個

因此,現在我們有了一個執行單個網站的整個 k3s 叢集。但是我們可以有更多的網站!如果我們要在同一叢集中提供另一個網站怎麼辦?讓我們看看如何做到這一點。

同樣,我們需要部署一些東西。碰巧我的狗有一條她想讓全世界都知道的資訊,她想了好久了。因此,我專門為她製作了一些 HTML(可從範例 zip 檔案中獲得)。同樣,我們將使用設定對映的技巧來託管這些 HTML。這次我們將把整個目錄(html 目錄)放到設定對映中,但是呼叫是相同的。

kubectl create configmap mydog-html --from-file html

現在,我們需要為此站點建立一個組態檔。它幾乎與用於 mysite.yaml 的完全相同,因此首先將 mysite.yaml 複製為 mydog.yaml。現在將 mydog.yaml 修改為:

apiVersion: apps/v1kind: Deploymentmetadata:  name: mydog-nginx  labels:    app: mydog-nginxspec:  replicas: 1  selector:    matchLabels:      app: mydog-nginx  template:    metadata:      labels:        app: mydog-nginx    spec:      containers:      - name: nginx        image: nginx        ports:        - containerPort: 80        volumeMounts:        - name: html-volume          mountPath: /usr/share/nginx/html      volumes:      - name: html-volume        configMap:          name: mydog-html---apiVersion: v1kind: Servicemetadata:  name: mydog-nginx-servicespec:  selector:    app: mydog-nginx  ports:    - protocol: TCP      port: 80---apiVersion: networking.k8s.io/v1beta1kind: Ingressmetadata:  name: mydog-nginx-ingress  annotations:    kubernetes.io/ingress.class: "traefik"    traefik.frontend.rule.type: PathPrefixStripspec:  rules:  - http:      paths:      - path: /mydog        backend:          serviceName: mydog-nginx-service          servicePort: 80

我們只需進行搜尋並將 mysite 替換為 mydog即可完成大多數修改。其他兩個修改在入口部分中。我們將 path 更改為 /mydog,並新增了一個註解 traefik.frontend.rule.type: PathPrefixStrip

/mydog 路徑的規範指示 Traefik 將以 /mydog 路徑開頭的所有傳入請求路由到 mydog-nginx-service。任何其他路徑將繼續路由到 mysite-nginx-service

新的註解 PathPrefixStrip 告訴 Traefik 在將請求傳送到 mydog-nginx-service 之前先去除字首 /mydog。我們這樣做是因為 mydog-nginx 應用程式不需要字首。這意味著我們可以簡單地通過更改入口記錄中的字首來更改掛載的服務的位置。

現在我們可以像以前一樣進行部署:

kubectl apply -f mydog.yaml

現在,我的狗的訊息應該可以在 http://kmaster/mydog/ 上找到。

呼!訊息發出去了!也許今晚我們都可以睡一覺。

因此,現在,我們有了一個 k3s 叢集,該叢集托管了兩個網站,Traefik 根據路徑名決定將請求傳遞給哪個服務!但是,不僅限於基於路徑的路由,我們也可以使用基於主機名的路由,我們將在以後的文章中進行探討。

另外,我們剛剛托管的網站是標準的未加密 HTML 網站,而如今的所有內容都使用 SSL/TLS 加密。在我們的下一篇文章中,我們將為 k3s 叢集新增支援以託管 SSL/TLS HTTPS 站點!

清理

在開始之前,由於本文主要涉及的是範例站點,因此我想向你展示如何刪除內容,以防萬一你不希望將這些範例丟在叢集中。

對於大多數設定,只需使用與部署時使用的相同組態檔執行 delete 命令即可撤消設定。因此,讓我們同時清理 mysitemydog

kubectl delete -f mysite.yamlkubectl delete -f mydog.yaml

由於我們是手動建立設定對映的,因此我們也需要手動刪除它們。

kubectl delete configmap mysite-htmlkubectl delete configmap mydog-html

現在,如果我們執行 kubectl get pods,我們應該看到我們的 nginx Pod 不存在了。

$ kubectl get podsNo resources found in default namespace.

一切都清理了。

請在下面的評論中告訴我你對這個專案有什麼想法。