建立非受控輸入控制器

輸入控制器是一項可為 Kubernetes 服務提供反向 Proxy、可設定的流量路由和 TLS 終止的軟體。 Kubernetes 輸入資源可用來設定個別 Kubernetes 服務的輸入規則和路由。 您可以透過輸入控制器和輸入規則,使用單一 IP 位址將流量路由至 Kubernetes 叢集中的多個服務。

本文示範如何在 Azure Kubernetes Service (AKS) 叢集中部署 NGINX 輸入控制器。 然後,會有兩個應用程式在 AKS 叢集中執行,且均可透過單一 IP 位址來存取。

重要

建議將應用程式路由附加元件用於 AKS 中的輸入。 如需詳細資訊,請參閱具有應用程式路由附加元件的受控 nginx 輸入

注意

以 Nginx 為基礎的 Kubernetes 具有兩個開放原始碼輸入控制器:一個由 Kubernetes 社群維護 (kubernetes/ingress-nginx),一個則由 NGINX, Inc. 維護 (nginxinc/kubernetes-ingress)。 本文將使用 Kubernetes 社群來輸入控制器。

開始之前

  • 本文使用 Helm 3,在Kubernetes 的已支援版本上安裝 NGINX 輸入控制器。 確定您使用的是最新版的 Helm,並且可以存取 ingress-nginx Helm 存放庫。 本文所述的步驟可能與舊版 Helm 圖表、NGINX 輸入控制器或 Kubernetes 不相容。
  • 此文章假設您有具有整合式 Azure Container Registry (ACR) 的現有 AKS 叢集。 如需使用整合式 ACR 來建立 AKS 叢集的詳細資訊,請參閱從 Azure Kubernetes Service 對 Azure Container Registry 進行驗證
  • Kubernetes API 健康情況端點,healthz 在 Kubernetes v1.16 中已被取代。 您可以改用 livezreadyz 端點來取代此端點。 請參閱 Kubernetes API 端點以瞭解健康情況,以判斷要用於您情節的端點。
  • 如果您使用 Azure CLI,此文章會要求您執行 Azure CLI 2.0.64 版或更新版本。 執行 az --version 以尋找版本。 如果您需要安裝或升級,請參閱安裝 Azure CLI
  • 如果您使用 Azure PowerShell,此文章會要求您執行 Azure PowerShell 5.9.0 版或更新版本。 執行 Get-InstalledModule -Name Az 以尋找版本。 如果您需要安裝或升級,請參閱安裝 Azure PowerShell

基本設定

如果要建立基本的 NGINX 輸入控制器,而不自訂預設值,您將使用 Helm。 下列設定會使用預設設定來簡化。 您可以新增參數來自訂部署,例如 --set controller.replicaCount=3

注意

如果您想要針對叢集中容器的要求啟用 用戶端來源 IP 保留,請將--set controller.service.externalTrafficPolicy=Local新增至 Helm 安裝命令。 用戶端來源 IP 儲存於 X-Forwarded-For 下的要求標頭中。 使用已啟用用戶端來源 IP 保留的輸入控制器時,TLS 傳遞將不會運作。

NAMESPACE=ingress-basic

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

helm install ingress-nginx ingress-nginx/ingress-nginx \
  --create-namespace \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \
  --set controller.service.externalTrafficPolicy=Local

注意

在本教學課程中,service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path 設定為 /healthz。 這表示如果對 /healthz 的要求回應碼不是 200,則整個輸入控制器將會關閉。 您可以在自己的情節中將值修改為其他 URI。 您無法刪除此元件或取消設定值,或輸入控制器仍會關閉。 本教學課程中使用的套件 ingress-nginx,由 Kubernetes 官方提供,如果是要求 /healthz 時,一律會傳回 200 回應碼,因為它是設計為預設後端,讓使用者才能快速啟動,除非輸入規則會覆寫它。

自訂組態

除了上一節中呈現的基本組態外,下一組步驟將示範如何部署自訂輸入控制器。 您可以選擇使用內部靜態 IP 位址,或使用動態公用 IP 位址。

將 Helm 圖表所使用的映像匯入至您的 ACR

如果要控制映像版本,則建議您將其匯入您自己的 Azure Container Registry。 本文使用依賴三個容器映像的 NGINX 輸入控制器 Helm 圖表。 使用 az acr import 將這些映像匯入至您的 ACR。

REGISTRY_NAME=<REGISTRY_NAME>
SOURCE_REGISTRY=registry.k8s.io
CONTROLLER_IMAGE=ingress-nginx/controller
CONTROLLER_TAG=v1.8.1
PATCH_IMAGE=ingress-nginx/kube-webhook-certgen
PATCH_TAG=v20230407
DEFAULTBACKEND_IMAGE=defaultbackend-amd64
DEFAULTBACKEND_TAG=1.5

az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$CONTROLLER_IMAGE:$CONTROLLER_TAG --image $CONTROLLER_IMAGE:$CONTROLLER_TAG
az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$PATCH_IMAGE:$PATCH_TAG --image $PATCH_IMAGE:$PATCH_TAG
az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$DEFAULTBACKEND_IMAGE:$DEFAULTBACKEND_TAG --image $DEFAULTBACKEND_IMAGE:$DEFAULTBACKEND_TAG

注意

除了將容器映像匯入至您的 ACR 外,您也可以將 Helm 圖表匯入至其中。 如需詳細資訊,請參閱將 Helm 圖表推送並提取至 Azure Container Registry

建立輸入控制器

如果要建立輸入控制器,請使用 Helm 來安裝 ingress-nginx。 需要在 Linux 節點上排程輸入控制器。 Windows Server 節點不應執行輸入控制器。 您可以使用 --set nodeSelector 參數來指定節點選取器,以告知 Kubernetes 排程器在 Linux 式節點上執行 NGINX 輸入控制器。

針對新增的備援,會使用 --set controller.replicaCount 參數來部署 NGINX 輸入控制器的兩個複本。 為充分享有執行輸入控制器複本的好處,請確定 AKS 叢集中有多個節點。

下列範例會對名為 ingress-basic 的輸入資源建立 Kubernetes 命名空間,並打算在該命名空間內運作。 視需要為您自己的環境指定命名空間。 如果您的 AKS 叢集未啟用 Kubernetes 角色型存取控制,請將 --set rbac.create=false 新增至 Helm 命令。

注意

如果您想要針對叢集中容器的要求啟用 用戶端來源 IP 保留,請將--set controller.service.externalTrafficPolicy=Local新增至 Helm 安裝命令。 用戶端來源 IP 儲存於 X-Forwarded-For 下的要求標頭中。 使用已啟用用戶端來源 IP 保留的輸入控制器時,TLS 傳遞將不會運作。

# Add the ingress-nginx repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# Set variable for ACR location to use for pulling images
ACR_LOGIN_SERVER=<REGISTRY_LOGIN_SERVER>

# Use Helm to deploy an NGINX ingress controller
helm install ingress-nginx ingress-nginx/ingress-nginx \
    --version 4.7.1 \
    --namespace ingress-basic \
    --create-namespace \
    --set controller.replicaCount=2 \
    --set controller.nodeSelector."kubernetes\.io/os"=linux \
    --set controller.image.registry=$ACR_LOGIN_SERVER \
    --set controller.image.image=$CONTROLLER_IMAGE \
    --set controller.image.tag=$CONTROLLER_TAG \
    --set controller.image.digest="" \
    --set controller.admissionWebhooks.patch.nodeSelector."kubernetes\.io/os"=linux \
    --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \
    --set controller.service.externalTrafficPolicy=Local \
    --set controller.admissionWebhooks.patch.image.registry=$ACR_LOGIN_SERVER \
    --set controller.admissionWebhooks.patch.image.image=$PATCH_IMAGE \
    --set controller.admissionWebhooks.patch.image.tag=$PATCH_TAG \
    --set controller.admissionWebhooks.patch.image.digest="" \
    --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \
    --set defaultBackend.image.registry=$ACR_LOGIN_SERVER \
    --set defaultBackend.image.image=$DEFAULTBACKEND_IMAGE \
    --set defaultBackend.image.tag=$DEFAULTBACKEND_TAG \
    --set defaultBackend.image.digest=""

使用內部 IP 位址建立輸入控制器

根據預設,NGINX 輸入控制器會使用靜態公用 IP 位址指派來建立。 常見的設定需求是使用內部私人網路和 IP 位址。 此方法可讓您將對服務的存取限定於內部使用者,而不提供外部存取。

使用 --set controller.service.loadBalancerIP--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-internal"=true 參數,將內部 IP 位址指派給輸入控制器。 請提供您自己的內部 IP 位址,用於輸入控制器。 請確定此 IP 位址在您的虛擬網路內尚未被使用。 如果您使用的是現有虛擬網路和子網路,則必須使用正確的權限設定 AKS 叢集,以管理虛擬網路和子網路。 如需詳細資訊,請參閱在 Azure Kubernetes Service (AKS) 中您自己的 IP 位址範圍使用 kubenet 網路,或是在 Azure Kubernetes Service (AKS) 中設定 Azure CNI 網路

# Add the ingress-nginx repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# Set variable for ACR location to use for pulling images
ACR_LOGIN_SERVER=<REGISTRY_LOGIN_SERVER>

# Use Helm to deploy an NGINX ingress controller
helm install ingress-nginx ingress-nginx/ingress-nginx \
    --version 4.7.1 \
    --namespace ingress-basic \
    --create-namespace \
    --set controller.replicaCount=2 \
    --set controller.nodeSelector."kubernetes\.io/os"=linux \
    --set controller.image.registry=$ACR_LOGIN_SERVER \
    --set controller.image.image=$CONTROLLER_IMAGE \
    --set controller.image.tag=$CONTROLLER_TAG \
    --set controller.image.digest="" \
    --set controller.admissionWebhooks.patch.nodeSelector."kubernetes\.io/os"=linux \
    --set controller.service.loadBalancerIP=10.224.0.42 \
    --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-internal"=true \
    --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \
    --set controller.admissionWebhooks.patch.image.registry=$ACR_LOGIN_SERVER \
    --set controller.admissionWebhooks.patch.image.image=$PATCH_IMAGE \
    --set controller.admissionWebhooks.patch.image.tag=$PATCH_TAG \
    --set controller.admissionWebhooks.patch.image.digest="" \
    --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \
    --set defaultBackend.image.registry=$ACR_LOGIN_SERVER \
    --set defaultBackend.image.image=$DEFAULTBACKEND_IMAGE \
    --set defaultBackend.image.tag=$DEFAULTBACKEND_TAG \
    --set defaultBackend.image.digest="" 

檢查負載平衡器服務

使用 kubectl get services 檢查負載平衡器服務。

kubectl get services --namespace ingress-basic -o wide -w ingress-nginx-controller

為 NGINX 輸入控制器建立 Kubernetes 負載平衡器服務時,會在 EXTERNAL-IP 底下指派 IP 位址,如下列範例輸出所示:

NAME                       TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                      AGE   SELECTOR
ingress-nginx-controller   LoadBalancer   10.0.65.205   EXTERNAL-IP     80:30957/TCP,443:32414/TCP   1m   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx

如果您流覽至此階段的外部 IP 位址,您會看到顯示 404 頁面。 這是因為您仍然需要設定與外部 IP 的連線,這會在下一區段中完成。

執行示範應用程式

若要查看運作中的輸入控制器,請在 AKS 叢集中執行兩個示範應用程式。 在此範例中,您會使用kubectl apply來部署簡單 Hello world 應用程式的兩個執行個體。

  1. 建立 aks-helloworld-one.yaml 檔案,並複製到下列範例 YAML 中:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: aks-helloworld-one  
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: aks-helloworld-one
      template:
        metadata:
          labels:
            app: aks-helloworld-one
        spec:
          containers:
          - name: aks-helloworld-one
            image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
            ports:
            - containerPort: 80
            env:
            - name: TITLE
              value: "Welcome to Azure Kubernetes Service (AKS)"
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: aks-helloworld-one  
    spec:
      type: ClusterIP
      ports:
      - port: 80
      selector:
        app: aks-helloworld-one
    
  2. 建立 aks-helloworld-two.yaml 檔案,並複製到下列範例 YAML 中:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: aks-helloworld-two  
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: aks-helloworld-two
      template:
        metadata:
          labels:
            app: aks-helloworld-two
        spec:
          containers:
          - name: aks-helloworld-two
            image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
            ports:
            - containerPort: 80
            env:
            - name: TITLE
              value: "AKS Ingress Demo"
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: aks-helloworld-two  
    spec:
      type: ClusterIP
      ports:
      - port: 80
      selector:
        app: aks-helloworld-two
    
  3. 使用kubectl apply執行兩個示範應用程式:

    kubectl apply -f aks-helloworld-one.yaml --namespace ingress-basic
    kubectl apply -f aks-helloworld-two.yaml --namespace ingress-basic
    

建立輸入路由

這兩個應用程式現在都已在您的 Kubernetes 叢集上執行。 若要將流量路由至每個應用程式,請建立 Kubernetes 輸入資源。 輸入資源會設定將流量路由至這兩個應用程式之一的規則。

在下列範例中,傳送至 EXTERNAL_IP/hello-world-one 的流量會路由至名為 aks-helloworld-one 的服務。 傳送至 EXTERNAL_IP/hello-world-two 的流量會路由至aks-helloworld-two服務。 針對靜態資產,傳送至 EXTERNAL_IP/static 的流量會路由至名為aks-helloworld-one的服務。

  1. 建立名為 hello-world-ingress.yaml 的檔案,然後將下列範例 YAML 複製進來:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-world-ingress
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "false"
        nginx.ingress.kubernetes.io/use-regex: "true"
        nginx.ingress.kubernetes.io/rewrite-target: /$2
    spec:
      ingressClassName: nginx
      rules:
      - http:
          paths:
          - path: /hello-world-one(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
          - path: /hello-world-two(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-two
                port:
                  number: 80
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-world-ingress-static
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "false"
        nginx.ingress.kubernetes.io/rewrite-target: /static/$2
    spec:
      ingressClassName: nginx
      rules:
      - http:
          paths:
          - path: /static(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port: 
                  number: 80
    
  2. 使用 kubectl apply 命令建立輸入資源。

    kubectl apply -f hello-world-ingress.yaml --namespace ingress-basic
    

測試輸入控制器

若要測試輸入控制器的路由,請瀏覽至這兩個應用程式。 開啟網頁瀏覽器並前往您 NGINX 輸入控制器的 IP 位址,例如 EXTERNAL_IP。 第一個示範應用程式會顯示在網頁瀏覽器中,如下列範例所示:

First app running behind the ingress controller

現在,將 /hello-world-two 路徑新增至 IP 位址,例如 EXTERNAL_IP/hello-world-two。 此時會顯示具有自訂標題的第二個示範應用程式:

Second app running behind the ingress controller

測試內部 IP 位址

  1. 建立測試 Pod,並將終端機工作階段與它連結。

    kubectl run -it --rm aks-ingress-test --image=mcr.microsoft.com/dotnet/runtime-deps:6.0 --namespace ingress-basic
    
  2. 使用 apt-get 在 Pod 中安裝 curl

    apt-get update && apt-get install -y curl
    
  3. 請使用 curl 存取 Kubernetes 輸入控制器的位址,例如 http://10.224.0.42。 請提供您在部署輸入控制器時所指定的內部 IP 位址。

    curl -L http://10.224.0.42
    

    先前並未提供位址的其他路徑,因此輸入控制器預設為 / 路由。 此時會傳回第一個示範應用程式,如下列簡要範例輸出所示:

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <link rel="stylesheet" type="text/css" href="/static/default.css">
        <title>Welcome to Azure Kubernetes Service (AKS)</title>
    [...]
    
  4. /hello-world-two 路徑新增至位址,例如 http://10.224.0.42/hello-world-two

    curl -L -k http://10.224.0.42/hello-world-two
    

    此時會傳回含有自訂標題的第二個示範應用程式,如下列簡要範例輸出所示:

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <link rel="stylesheet" type="text/css" href="/static/default.css">
        <title>AKS Ingress Demo</title>
    [...]
    

清除資源

本文使用 Helm 來安裝輸入元件和範例應用程式。 部署 Helm 圖表時會建立許多 Kubernetes 資源。 這些資源包含 Pod、部署和服務。 若要清除這些資源,您可以刪除整個範例命名空間或個別資源。

刪除範例命名空間和所有資源

如果要刪除整個範例命名空間,請使用kubectl delete命令並指定命名空間的名稱。 命名空間中的所有資源都會刪除。

kubectl delete namespace ingress-basic

個別刪除資源

或者,更精細的方法就是刪除所建立的個別資源。

  1. 使用helm list命令,列出 Helm 版本。

    helm list --namespace ingress-basic
    

    尋找名為 ingress-nginxaks-helloworld 的圖表,如下列範例輸出所示:

    NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
    ingress-nginx           ingress-basic   1               2020-01-06 19:55:46.358275 -0600 CST    deployed        nginx-ingress-1.27.1    0.26.1  
    
  2. 使用helm uninstall命令,解除安裝這些版本。

    helm uninstall ingress-nginx --namespace ingress-basic
    
  3. 移除這兩個範例應用程式。

    kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic
    kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic
    
  4. 移除將流量導向範例應用程式的輸入路由。

    kubectl delete -f hello-world-ingress.yaml
    
  5. 使用 kubectl delete 命令刪除命名空間,並指定命名空間名稱。

    kubectl delete namespace ingress-basic
    

下一步

若要使用現有的輸入元件設定 TLS,請參閱搭配輸入控制器使用 TLS

若要將 AKS 叢集設定為使用 HTTP 應用程式路由,請參閱啟用 HTTP 應用程式路由附加元件

本文包含 AKS 的一些外部元件。 若要深入了解這些元件,請參閱下列專案頁面: