在 Kubernetes 叢集中,有效管理外部流量的路由至關重要,尤其在微服務架構下,NodePort 的外部 IP 變動問題會影響服務的穩定性。Ingress 提供更穩定的入口點,能根據路由規則將流量導向不同的服務,並整合 TLS 證書提升安全性。本文將以 AWS EKS 為例,示範如何使用 ALB Ingress Controller 組態 Ingress,解決 NodePort 的問題,並提供逐步操作與程式碼範例。

由於 NodePort 服務的外部 IP 會隨著節點變化而改變,不適合長期使用。為瞭解決此問題,我們可以使用 Ingress 作為穩定的入口點,並搭配 AWS ALB Ingress Controller 自動組態 ALB 進行流量路由。首先,安裝 ALB Ingress Controller,接著建立 Ingress 資源定義路由規則,例如將特定網域名稱和路徑的流量導向指定的服務埠。

網路與入口(Networking and Ingress)

在現代的雲端原生應用程式中,網路與入口(Ingress)是至關重要的組成部分。隨著微服務架構的普及,Kubernetes 已成為託管多個微服務的理想平台,使每個微服務能夠根據交易需求的變化進行擴充套件或縮減。在本章中,我們將探討 AWS EKS 中的網路與入口概念。

使用 NodePort 暴露服務的問題

到目前為止,我們一直使用 NodePort 服務來暴露我們的 Web 應用程式,並透過 http://<節點的外部 IP>:<應用程式的 NodePort> 的方式進行存取。只要節點的外部 IP 不變,這種方式就可以正常工作。

然而,節點可能會發生故障,叢集可能會組態新的節點,並且 Pod 可能會被重新排程到其他節點上,這意味著我們無法將節點的外部 IP 作為長期穩定的 IP 地址來存取我們的 Web 應用程式。

實驗:驗證 NodePort 的問題

為了說明這個問題,讓我們進行一個簡單的實驗。刪除目前執行 primeornot 應用程式的節點組,並重新建立一個新的節點組,迫使我們的叢集將佈署遷移到新的節點上。這樣,節點的外部 IP 將會改變,我們將無法再透過舊的節點 IP 地址存取我們的應用程式。

首先,建立一個新的節點組,以確保在我們刪除舊節點組時,工作負載能夠遷移過去。命令格式如下:

aws eks create-nodegroup --cluster-name <叢集名稱> --nodegroup-name <新節點組名稱> --instance-types <例項型別>

程式碼解密:

此命令建立了一個新的節點組,其中:

  • --cluster-name 指定了 EKS 叢集的名稱。
  • --nodegroup-name 指定了新節點組的名稱。
  • --instance-types 指定了節點組中例項的型別。

建立新節點組後,我們可以刪除舊的節點組,並觀察到我們的佈署會自動遷移到新的節點組上。

aws eks delete-nodegroup --cluster-name <叢集名稱> --nodegroup-name <舊節點組名稱>

程式碼解密:

此命令刪除了指定的節點組,其中:

  • --cluster-name 指定了 EKS 叢集的名稱。
  • --nodegroup-name 指定了要刪除的節點組的名稱。

刪除節點組後,我們可以觀察到節點的外部 IP 發生了變化,這將導致我們無法再透過原來的 IP 地址存取我們的應用程式。

網路與入口(Ingress)的必要性

由於 NodePort 的限制,我們需要一種更穩定、更靈活的方式來暴露我們的服務。這就是入口(Ingress)的作用。入口是一種 Kubernetes 資源,它允許我們定義如何將外部流量路由到叢集內的服務。

為什麼需要 Ingress?

  1. 穩定性:Ingress 提供了一個穩定的入口點,無論後端 Pod 如何變化。
  2. 靈活性:Ingress 可以根據不同的路由規則將流量分配到不同的服務。
  3. 安全性:Ingress 可以與 TLS 證書整合,提供 HTTPS 加密連線。

使用 AWS ALB Ingress Controller

AWS 提供了一個 ALB Ingress Controller,它允許我們使用 AWS Application Load Balancer(ALB)作為入口控制器。ALB Ingress Controller 自動組態 ALB,以根據我們的 Ingress 資源定義路由流量。

組態 ALB Ingress Controller

首先,我們需要安裝 ALB Ingress Controller。可以使用 Helm Chart 或直接應用官方提供的 YAML 檔案進行安裝。

kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.2/docs/examples/iam-policy.json

程式碼解密:

此命令應用了一個 IAM 策略,該策略定義了 ALB Ingress Controller 所需的許可權。

接下來,我們需要建立一個 Ingress 資源,以定義我們的路由規則。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: example-service
            port:
              number: 80

程式碼解密:

此 Ingress 資源定義了一個路由規則,其中:

  • host 指定了網域名稱。
  • http.paths 定義了路徑規則,將根路徑 / 的流量路由到 example-service 服務的 80 埠。

應用此 Ingress 資源後,ALB Ingress Controller 將自動組態 ALB,以根據我們的定義路由流量。

在下一章中,我們將探討 Kubernetes 中的服務網格(Service Mesh)概念,並瞭解如何使用 AWS App Mesh 提供服務間的流量管理、服務發現和安全性。敬請期待!

Ingress 流程圖

  graph LR
    A[外部流量] -->|進入| B[Ingress]
    B -->|路由規則| C[服務1]
    B -->|路由規則| D[服務2]
    C -->|處理請求| E[後端Pod1]
    D -->|處理請求| F[後端Pod2]

圖表翻譯: 此圖示展示了 Ingress 的基本流程。外部流量首先進入 Ingress,然後根據定義的路由規則被路由到不同的服務,最終由後端的 Pod 處理請求。

程式碼範例:Ingress YAML 檔案

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /service1
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80
      - path: /service2
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 80

內容解密:

此 YAML 檔案定義了一個 Ingress 資源,其中包含兩個路由規則,分別將 /service1/service2 路徑的流量路由到不同的服務。具體來說:

  • metadata.name 指定了 Ingress 資源的名稱。
  • spec.rules 定義了路由規則。
  • host 指定了網域名稱。
  • http.paths 定義了路徑規則,將特定路徑的流量路由到指定的服務和埠。

在Amazon EKS中建立和管理NodeGroup

在前面的章節中,我們已經成功建立了一個EKS叢集,接下來我們將探討如何在該叢集中建立和管理NodeGroup。NodeGroup是EKS中的一個重要概念,它代表了一組具有相同組態的EC2例項,用於執行我們的Kubernetes工作負載。

建立NodeGroup

要建立NodeGroup,我們可以使用AWS CLI命令。以下是一個範例命令:

aws eks create-nodegroup \
--cluster-name myeks01 \
--nodegroup-name myng02 \
--subnets subnet-046606aaf23a20416 subnet-068ac163d2cbd074b subnet-0f03119b46d02a63a \
--instance-types t3.medium \
--scaling-config minSize=1,maxSize=2,desiredSize=1 \
--ami-type AL2_x86_64 \
--node-role arn:aws:iam::000381057009:role/myAmazonEKSNodeRole

內容解密:

  • --cluster-name:指定要在哪個EKS叢集中建立NodeGroup。
  • --nodegroup-name:為新的NodeGroup指定名稱。
  • --subnets:指定NodeGroup中的EC2例項將被放置在哪個子網中。在這個例子中,我們使用了三個公有子網。
  • --instance-types:指定NodeGroup中的EC2例項型別。在這個例子中,我們使用了t3.medium例項。
  • --scaling-config:組態NodeGroup的擴充套件引數,包括最小例項數、最大例項數和期望例項數。
  • --ami-type:指定NodeGroup中的EC2例項將使用的AMI型別。
  • --node-role:指定NodeGroup中的EC2例項將承擔的IAM角色。

執行上述命令後,我們將得到一個建立NodeGroup的任務輸出,如下所示:

{
    "nodegroup": {
        "nodegroupName": "myEKSNodeGroup02",
        "nodegroupArn": "arn:aws:eks:us-east-2:000381057009:nodegroup/myeks01/myEKSNodeGroup02/dcc51c1a-47f2-f3f4-feae-b93bc0015a99",
        "clusterName": "myeks01",
        "version": "1.27",
        "releaseVersion": "1.27.3-20230816",
        "createdAt": "2023-08-27T18:14:44.223000+00:00",
        "modifiedAt": "2023-08-27T18:14:44.223000+00:00",
        "status": "CREATING",
        "capacityType": "ON_DEMAND",
        "scalingConfig": {
            "minSize": 1,
            "maxSize": 2,
            "desiredSize": 1
        },
        "instanceTypes": [
            "t3a.medium"
        ],
        "subnets": [
            "subnet-046606aaf23a20416",
            "subnet-068ac163d2cbd074b",
            "subnet-0f03119b46d02a63a"
        ],
        "amiType": "AL2_x86_64",
        "nodeRole": "arn:aws:iam::000381057009:role/myAWSEKSNodeRole",
        "diskSize": 20,
        "health": {
            "issues": []
        },
        "updateConfig": {
            "maxUnavailable": 1
        },
        "tags": {}
    }
}

刪除NodeGroup

在建立新的NodeGroup之後,我們可以刪除舊的NodeGroup,以實作工作負載的遷移。使用以下命令刪除NodeGroup:

aws eks delete-nodegroup --cluster-name myeks01 --nodegroup-name myEKSNodeGroup01

內容解密:

  • --cluster-name:指定EKS叢集的名稱。
  • --nodegroup-name:指定要刪除的NodeGroup名稱。

執行上述命令後,我們將得到一個刪除NodeGroup的任務輸出,顯示NodeGroup的狀態已變為DELETING

查詢Node的外部IP

在建立新的NodeGroup之後,我們可以使用以下命令查詢新Node的外部IP:

kubectl get nodes
kubectl describe node ip-172-31-45-58.us-east-2.compute.internal | grep -i [E]xternalIP

內容解密:

  • kubectl get nodes:列出叢集中的所有Node。
  • kubectl describe node <node-name>:查詢指定Node的詳細資訊。
  • grep -i [E]xternalIP:過濾出外部IP地址。

執行上述命令後,我們可以獲得新Node的外部IP地址,例如52.15.199.187

存取應用程式

由於Kubernetes會將我們的Deployment重新佈署到新的Node上,因此我們可以使用新的外部IP地址存取我們的應用程式,格式為http://<Node’s External IP>:<Application’s NodePort>。例如:http://52.14.201.94:30969

問題與解決方案

然而,這種方法存在一個問題:每次更新NodeGroup或Node時,外部IP地址可能會發生變化,這對於需要固定DNS名稱或IP地址的生產環境應用程式來說並不理想。此外,如果Node被放置在私有子網中,它們可能沒有外部IP地址。

為瞭解決這個問題,我們可以使用Kubernetes中的Ingress和LoadBalancer資源。

Ingress和LoadBalancer簡介

Ingress是Kubernetes中的一個API物件,用於管理叢集外部對內部服務的存取,通常是HTTP或HTTPS流量。LoadBalancer是一種服務型別,用於將外部流量分配到叢集內的服務。

  graph LR
    A[使用者] -->|HTTP/HTTPS流量|> B[Ingress]
    B --> C[LoadBalancer]
    C --> D[Kubernetes服務]
    D --> E[Pod]

圖表翻譯: 此圖示展示了使用者如何透過Ingress和LoadBalancer存取Kubernetes叢集內的服務。

內容解密:

  • Ingress用於管理外部對叢集內服務的存取。
  • LoadBalancer用於將外部流量分配到叢集內的服務。

透過使用Ingress和LoadBalancer,我們可以為我們的應用程式提供一個固定的入口點,無論NodeGroup或Node的變化如何。

網路組態與Ingress實作詳解

在Kubernetes叢集中,Ingress扮演著至關重要的角色,它提供了外部存取叢集內部服務的途徑。本文將探討Ingress的基本原理、實作方式以及相關的網路組態。

Ingress基本原理

Ingress是Kubernetes中的一個API物件,它定義瞭如何將外部請求路由到叢集內部的服務。簡單來說,Ingress充當了外部網路與叢集內部服務之間的橋樑。

Ingress的基本組成

  1. Ingress Controller:負責實作Ingress規則的控制器。
  2. Ingress資源:定義了外部請求如何路由到叢集內部服務的規則。

在microk8s中實作Ingress

首先,我們需要在microk8s環境中啟用Ingress控制器。然後,透過一系列的連通性測試來驗證Ingress的功能。

連通性測試

在啟用Ingress控制器之前,我們先進行一系列的連通性測試,以瞭解目前的網路組態狀況。

檢查目前的佈署狀態
microk8s kubectl get deployments

輸出結果顯示目前預設名稱空間下沒有任何佈署。

重新建立必要的資源
microk8s kubectl apply -f pv.yaml
microk8s kubectl apply -f pvc.yaml
microk8s kubectl apply -f mynginx-pvc.yaml

這些命令重新建立了Persistent Volume(PV)、Persistent Volume Claim(PVC)以及佈署了nginx服務。

檢查服務狀態

microk8s kubectl get service

輸出結果顯示目前的服務狀態,包括myservice服務,它被組態為LoadBalancer型別。

測試服務可連通性
curl -L localhost:32614

成功存取到nginx服務的內容。

使用Ingress暴露服務

刪除現有的LoadBalancer服務

microk8s kubectl delete service myservice

刪除myservice後,再次嘗試存取服務,發現連線被拒絕。

建立新的Service組態

建立一個新的myservice02.yaml檔案,內容如下:

apiVersion: v1
kind: Service
metadata:
  name: "myservice"
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: "mynginx"

這個組態建立了一個ClusterIP型別的服務。

套用新的Service組態

microk8s kubectl apply -f myservice02.yaml

套用新的組態後,檢查服務狀態:

microk8s kubectl get service myservice

輸出結果顯示myservice現在是ClusterIP型別,並且可以透過ClusterIP存取。

從叢集內部存取服務

microk8s kubectl exec -it mydeployment-ch15pvc-fb65494b8-mjkdn -- curl localhost:80

成功存取到nginx服務的內容。

從其他Pod存取服務

microk8s kubectl exec -it mydeployment-ch15pvc-fb65494b8-mjkdn -- curl 10.152.183.153:80

同樣成功存取到服務內容。

#### 內容解密:

  1. Ingress的基本原理:Ingress作為Kubernetes的一個API物件,定義了外部請求如何路由到叢集內部服務的規則。它依賴於Ingress控制器來實作這些規則。
  2. 連通性測試的重要性:透過連通性測試,我們可以瞭解目前的網路組態狀況,驗證服務的可連通性,以及Ingress功能的正確性。
  3. Service型別的選擇:在這個例子中,我們首先使用了LoadBalancer型別的服務來暴露nginx服務。後來,我們切換到ClusterIP型別的服務,並透過Ingress來暴露服務。
  4. 從叢集內部存取服務:無論是透過localhost還是ClusterIP,從叢集內部存取服務都是可行的。這驗證了服務的可連通性。

隨著Kubernetes叢集規模的擴大和複雜度的增加,Ingress將扮演越來越重要的角色。未來,我們可以期待更多的Ingress控制器實作和更豐富的Ingress功能,以滿足不同的業務需求。