Azure - AKS - 使用 AGIC 當作 AKS Ingress

03 November 2020 — Written by Sky Chang
#Azure#Container#Kubernetes#Linux#AKS#ApplicationGateway#AGIC

前言

用過 K8S 的朋友都知道,目前讓 K8S 對外提供端點,不外乎透過 ClusterIP、Nodeport、Load Balancer、Ingress 這幾種方法,而地端 K8S 下,最常用的應該就是 NodePort,畢竟地端的 Load Balancer 需要自建 QQ ...( 不過在雲上的 AKS 自動送你了 ),但就算有了 Load Balancer,但 LB 能提供的 Port 還是那幾個,遠遠不能滿足裡面那麼多的應用程式,所以我們可能希望透過網址的方式進行 mapping,讓不同的網址對應到後面的 Service,又或是透過 url path 進行導向,而這就是 Ingress 的功用。

Ingress 有很多種,包含使用 Nginx、Traefik 或是一整包包好的 Istio ,都可以做到上述講的這些功能,但在 AKS 的選擇上,小弟更喜歡用 AGIC ( Application Gateway Ingress Control )。

AGIC

如下是官網提供的 AGIC 架構圖,其實 AGIC 就是一個放在 AKS 裡面的 Azure Application Gateway 的監控程式,他可以監控 AKS 的 Ingress yaml,並且自動地去修改 Application Gateway 的設定,換言之,若我們使用了其他的 Ingress,這些 Ingress 會在 AKS 裡面運作,在裡面去處理流量的導向,而 AGIC 的監控,雖然在裡面,但真實流量的導向的處理,則是在外部的 Application Gateway。因為他就是一個外部的雲端服務,所以不會消耗掉 AKS 裡面 Node 的資源,而且透過雲上的特性,也可以輕易的縮放 ( 但小弟也沒什麼流量就是了...= =|| ),除此之外,Application Gateway 也提供了內建的 WAF 等機制,最重要的是,使用的方式,也和一般的 Ingress 差不多,搭配 YAML 的設定,就可以同步到 Application Gateway 上。

2020 11 03 21 52 46

安裝 AGIC

目前安裝 AGIC 有兩種做法,以前很可憐的,只能透過 Helm 進行部署,而且還要去設定權限的部分,畢竟,我們要能讓 AGIC 去自動地去 Application Gateway 調整裡面的設定嘛~

而現在 AGIC 已經變成 AKS 的 addons 之一 ( ACI 的整合功能也是 addons 之一的功能 ),雖然這個 addons 還在 Preview ( 謎之聲 : 最近的文章怎麼都是 Preview XDD )。但基於方便安裝的立場上,而且還提供了自動更新等機制,覺得可以拿來使用了。 ( 請注意,Preview 功能是不提供 Support 的 )。

而開始前,還是要注意一下 AGIC 使用 Helm 和 addons 安裝的差異。

  • addons 版本目前 ( 未來會改 ),不支援其他服務共用一個 Application Gateway,因為 addons 不能設定 ProhibitedTargets。在 Helm 的時代,我們可以啟用 Heml 設定檔 裡面的 appgw.shared=true,並加上 ProhibitedTargets CRD 的 yaml 設定,來讓 Application Gateway 同時提供給 AKS 和 VM 等服務使用。 ( 例如,要進入 VM 的網址為 vm.study4.tw,而我們可以在 ProhibitedTargets CRD 的 yaml 裡面去設定,若網址為 vm.study4.tw 的部分,AGIC 不會自動覆蓋掉我們在 Application Gateway 的設定,如果沒此功能,我們在 Application Gateway 的設定,會被 AGIC 秒改.. 詳細資料 )
  • 同上,換言之,addons 就只能提供給這個 AKS 使用
  • 底下的值,無法使用

    • verbosityLevel 預設為 5,級別說明
    • usePrivateIp 預設為 false,但有機會自己改寫
    • shared 同上,不支援共用了
    • reconcilePeriodSeconds 預設每 30 秒去詢問差異
    • armAuth.type 因為不走 SP 託管

而最終的對應表,就如官方下圖。

在 addons 的情境如下

  • 1 AGIC : 1 AG : 正常情境
  • 1 AGIC : 2 AG : 目前沒辦法 1 AGIC 對應到多個 AG
  • 2 AGIC : 1 AG : addons 預設只能開一個 AGIC
  • 2 AGIC : 2 AG : addons 預設只能開一個 AGIC

2020 11 03 23 04 30

在 Helm 底下,的情境如下

  • 1 AGIC : 1 AG : 正常情境
  • 1 AGIC : 2 AG : 目前沒辦法 1 AGIC 對應到多個 AG
  • 2 AGIC : 1 AG : 同樣因為可以設定 ProhibitedTargets,所以支援放兩個以上的 AGIC 對到同一個 AG
  • 2 AGIC : 2 AG : 可行,如 1 AGIC : 1 AG 的情境

2020 11 03 23 05 11

若有設定多組的 AKS 叢集,目前支援度就不高,如下圖所示

  • 1 AGIC : 1 AG : 因為是 AKS 叢集,所以這個情境不合理
  • 1 AGIC : 2 AG : 同上,因為是 AKS 叢集,不可能只有一個 AGIC
  • 2 AGIC : 1 AG : 同樣因為可以設定 ProhibitedTargets,所以支援放兩個以上的 AGIC 對到同一個 AG
  • 2 AGIC : 2 AG : 因為是 AKS 叢集,目前多組的 AG 沒辦法讓流量自動分散到不同的 AKS 叢集上

2020 11 03 23 06 39

建立 Application Gateway

再將 Application Gateway 透過 AGIC 整合 AKS 之前,當然還是要先準備 Application Gateway,如果目前連 AKS 都沒有,這邊提供兩種做法,一個是 az cli,一個是 UI ( 但其實最近越來越喜歡用 az cli XDD )

另外,開始前,請先切一個 Application Gateway 專用的網段。至於為何要切 /24,底下為文件敘述。

應用程式閘道 (Standard_v2 或 WAF_v2 SKU) 最多可支援125個實例 (125 個實例 IP 位址 + 1 個私人前端 IP + 5 個 Azure 保留) –因此建議的子網大小下限為/24

所以~~

  • 要最大可以到 125 個 instance,就要切 /24
  • 若要使用私人端點,Standard_v2 必須要一個私人前端 IP,所以要 + 1
  • 預設會 5 個保留 ( 前四個和最後一個 IP 位址 )
  • 如果不會開那麼多個 instance 的話,可以少切一點

2020 11 15 16 01 07

而建立 Application Gateway,當然一樣可以透過 az cli 來建立,如下。而這邊我們會用兩個 az cli 來建立 Application Gateway。

透過 az cli

第一步,是建立 Public IP,因為 Application Gateway 是對外的,當然要有對外的公用 IP,但這邊有個選項是很有趣的,稱為 --ip-tags 'RoutingPreference=Internet',意思是說,當啟用了這個選項後,任何從 Application Gateway 出去的數據,都會走 Internet。你或許或說,不是全部都是走 Internet 嗎!? No.No.非也,如果啟用了這個選項,而且 Application Gateway 架設在東日本,那他會從東日本的 ISP,東繞繞,西繞繞,繞到不同的 ISP 回到台灣。

2020 11 05 23 37 59

而預設的情況下,則會走 Azure 的骨幹,換言之,若是東日本,然後台灣資料中心也已經完工了,那出來的資料,就會從東日本走 MS 骨幹到台灣資料中心,再出來到目的地,而不會透過東日本的 ISP 業者。

2020 11 05 23 39 52

當然,以效能來說,自然是 MS 骨幹的延遲最低了,但走 Internet 的話,會比較便宜喔。

另外,這邊建議選擇 --sku standard,因為只有 standard 才有支援 Zone-redundant ( 自動啟用,沒錯,連 IP 有 XDDD )。當然,如果想特別針對某一個 zone,可以加上 --zone 1 的參數。

# 建立 Public 首碼,讓我們的 ip 可以連續 ( 一次最多 /28 - 16個 , 最小 /31 - 2個 ip)
az network public-ip prefix create \
--length 28 \
--location JapanEast \
--name PublicIPPrefix-Study4Dev-JE \
--resource-group study4dev-je

# 如果想讓網路省錢,可以加上 --ip-tags 'RoutingPreference=Internet' 讓他走 Internet,而不是 Azure 骨幹 
#( 請先註冊 az feature register --namespace Microsoft.Network --name AllowRoutingPreferenceFeature )
az network public-ip create \
-n PublicIP-AG-AKS-Study4Dev-JE \
-g study4dev-je \
--allocation-method Static \
--sku Standard \
--public-ip-prefix PublicIPPrefix-Study4Dev-JE

建立 Application Gateway,這邊我們可以使用 --zones 1,2,3,來讓 Application Gateway 達到 Zone-redundant,但真的能不能達到高可用性,還是要看後面的 Work Node 的情況,如果大家還記得,之前小弟的 Work Node,基本上為了配合 PPG,所以只部署在 zone 1,所以雖然 Application Gateway 已經有了 Zone-redundant,但 zone 1 掛掉後,基本上,服務還是全死 XDDDD,不過這邊還是讓 Application Gateway 啟用 zones 1,2,3 吧~

# 建立 Application Gateway
# 目前使用 AZ CLI 建立 Standard_v2 必須指定 private ip addrss,所以要在 Application Gateway 的範圍內建立
# 底下只會建立一個 AG Instance
az network application-gateway create \
-n AG-AKS-Study4dev-JE \
-l JapanEast \
-g study4dev-je \
--sku Standard_v2 \
--public-ip-address \
PublicIP-AG-Study4Dev-JE \
--vnet-name Study4Dev-JE-VNet \
--subnet ApplicationGateway \
--http2 enabled \
--private-ip-address 10.99.181.80 \
--capacity 1 \
--zones {1,2,3}

# 只能建立完後,在默默地刪掉 QQ
# issue https://github.com/MicrosoftDocs/azure-docs/issues/64433
az network application-gateway frontend-ip delete \
--resource-group study4dev-je \
--gateway-name AG-AKS-Study4dev-JE \
--name appGatewayPrivateFrontendIP

透過 UI 建立

  • 目前搭配 AGIC,一定要 v2,若有需要,也可以開 WAF V2。
  • 因小弟流量小到可憐,所以就沒開自動縮放
  • 同上,所以預設只一個 instance
  • AG 要先切好一個子網路,專門給 AG 使用

2020 11 03 23 44 59

這一步驟,只是設定一個 Public IP

2020 11 03 23 45 21

未來會透過 AGIC,自動設定完這些參數,但初期透過 UI 建立的時候,這些還是必填....

2020 11 03 23 45 31

這邊也是必填....

2020 11 03 23 45 46

這邊也是必填....

2020 11 03 23 46 01

這邊也是必填.... ( 未來可不可以改成不要填啊 QQ )

2020 11 03 23 46 11

以上,就建立完成,完成後,我們可以透過屬性取得 ID。

2020 11 03 23 54 29

結論,還是指令比較方便 QQ ( 懶 )

安裝 AGIC

因為目前是 Preview,所還是要先註冊功能

# 確認是否有安裝 aks-preview 外掛套件
az extension list

# 若沒安裝過外掛套件,請先安裝
az extension add --name aks-preview

# 若有安裝過請先更新
az extension update --name aks-preview

# 註冊功能
az feature register --name AKS-IngressApplicationGatewayAddon --namespace microsoft.containerservice

# 確認是否註冊完畢
az feature list -o table --query "[?contains(name, 'microsoft.containerservice/AKS-IngressApplicationGatewayAddon')].{Name:name,State:properties.state}"

# 重新整理功能
az provider register --namespace Microsoft.ContainerService

方案一 在 AKS 建立時自動建立

這邊是第一個方案,用於下指令建立 AKS 的時候,可以順便把 AGIC 和 AG 帶起來,主要是透過這三行指令 -a ingress-appgw --appgw-name myApplicationGateway --appgw-subnet-prefix "10.2.0.0/16"

完整範例如下,若要透過指令建置,可以參考小弟的這篇

# 建立 AKS 時,自動產生 AG
az aks create \
-n myCluster \
-g myResourceGroup \
--network-plugin azure \
--enable-managed-identity \
-a ingress-appgw \
--appgw-name myApplicationGateway \
--appgw-subnet-prefix "10.2.0.0/16" \
--generate-ssh-keys

官網參考資料

方案二 已經有 AG 的情況下

這個情境是,當我們已經有 AG 的情況下,希望附加到 AKS 上。

# 設定 appgwId
appgwId=xxxxx/xxxxxx/xxxxx

# 懶惰一點也可以直接透過底下指令
appgwId=$(az network application-gateway show -n AG-AKS-Study4Dev-JE -g study4dev-je -o tsv --query "id") 

# 啟用 agic addons
az aks enable-addons \
-n aks-study4dev-je \
-g study4dev-je \
-a ingress-appgw \
--appgw-id $appgwId

# 若想關閉可以透過底下關閉
az aks disable-addons \
-n aks-study4dev-je \
-g study4dev-je \
-a ingress-appgw

官網參考資料

完成與測試

完成後,會產生一個監控用的 Pod。

2020 11 04 00 00 55

若要簡單測試,可以安裝底下的 yaml

# 安裝 asp.net pod ,裡面包含 ingress
kubectl apply -f https://raw.githubusercontent.com/Azure/application-gateway-kubernetes-ingress/master/docs/examples/aspnetapp.yaml 


kubectl get ingress

# 測試完成後刪除 asp.net pod
kubectl delete -f https://raw.githubusercontent.com/Azure/application-gateway-kubernetes-ingress/master/docs/examples/aspnetapp.yaml 

Note : 目前不確定是否因小弟的 AKS 有開 AAD 整合,所以 AGIC 會出現

403 錯誤 Unexpected status code '403' while performing a GET on Application Gateway. You can use .....

的錯誤,所以要針對 Resource 加入 Reader 的權限,而 AG 要給予 Contributor 的權限。

指令下完後,要稍微等一下,等待權限生效。

2020 11 04 00 14 08

# 對 Resource 給予 Reader 的權限
az role assignment create --role Reader --scope /subscriptions/xxxx-xxxx/resourceGroups/Study4Dev-JE --assignee xxxx

# 對 AG 給予 Contributor 的權限
az role assignment create --role Contributor --scope /subscriptions/xxxx/resourceGroups/Study4Dev-JE/providers/Microsoft.Network/applicationGateways/AG-AKS-Study4Dev-JE --assignee xxxx

最後,透過 Ingress 的 Public IP,就可以進行簡單的測試。

2020 11 04 00 16 38

關於自行定義的 Ingress

關於 AGIC 的 ingress 定義 sample,可以參考底下,底下有完整的 pod、svc 和 ingress。從這個 sample 可以看到 ingress 是讓所有 / 路徑,全部對應到 aspnetapp svc 。

apiVersion: v1
kind: Pod
metadata:
  name: aspnetapp
  labels:
    app: aspnetapp
spec:
  containers:
  - image: "mcr.microsoft.com/dotnet/core/samples:aspnetapp"
    name: aspnetapp-image
    ports:
    - containerPort: 80
      protocol: TCP

---

apiVersion: v1
kind: Service
metadata:
  name: aspnetapp
spec:
  selector:
    app: aspnetapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

---

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: aspnetapp
  annotations:
    kubernetes.io/ingress.class: azure/application-gateway
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: aspnetapp
          servicePort: 80

若要將特定路徑對應到特定 domain ,可參考底下 ingress 範例。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: go-server-ingress-timeout
  namespace: test-ag
  annotations:
    kubernetes.io/ingress.class: azure/application-gateway
    appgw.ingress.kubernetes.io/backend-hostname: "internal.example.com"
spec:
  rules:
  - http:
      paths:
      - path: /hello/
        backend:
          serviceName: go-server-service
          servicePort: 80

更多範例請參考 AGIC GitHub 文件

後記

其實東西不難,但最近在看 Azure 的時候,越來越發現,有很多的細節要注意,所以花了很長時間,終於寫完 (泣)。另外,採用 AGIC 當然是一種作法,但如果你喜歡內建 Pod 來使用 ingress 的方式,也是可以的,這邊,就帶給大家囉。

參考資料

Sky & Study4.TW