AKS - Multi Nginx Ingress Controller 설정
이 글에서는 AKS 환경에서 Multi Ingress Controller를 설정하여 운영하는 방법을 다룬다.
Multi Ingress Controller란?
- 하나의 쿠버네티스 클러스터 안에서 Ingress Controller를 여러 개 사용하여 운영 하는 것
Multi Ingress Controller를 사용하는 이유?
- 클러스터 안에 많은 서비스가 운영되는 경우 하나의 인그레스 컨트롤러만 사용하면 처리량, 안정성 부분에서 성능이 떨어질 수 있음.
- 서비스별로 네임스페이스를 나누어 배포된 인그레스는 TLS 통신을 위해 인증서를 참조해야함. 인그레스는 본인의 네임스페이스에 할당된 인증서만 참조가 가능. 만약 각 네임스페이스별로 인증서를 배포하게 된다면 관리적인 측면에서 좋지 않음(갱신 작업 등).
- 또한 Azure Key Vault에 저장되어 있는 인증서를 연동할 시에는 SecretProviderClass가 필요한데 SPC와 Ingress Controller를 생성해야지만 인증서(Secret)가 한 네임스페이스에만 생성됨. 따라서 여러 네임스페이스에 배포된 인그레스들이 인증서를 참조하려면 Ingress Controller가 각 네임스페이스 별로 존재해야하므로 이와 같은 방식을 사용함.
1. pem 파일을 pfx로 변환
$ openssl pkcs12 -export -in <cert_pem> -inkey <키 파일명> -out <pfx파일명>
2. Azure Key Vault에 인증서 업로드
$ az keyvault certificate import --vault-name <AKV_NAME> -n <CERT_NAME> -f <PFX_NAME>.pfx
3. AKS에 csi-secrets-store-driver 설정
https://learn.microsoft.com/ko-kr/azure/aks/csi-secrets-store-driver
4. AKS에서 Key Vault에 접근 가능하도록 권한 부여
5. 네임스페이스 생성
$ kubectl create ns a
6. Secret Provider Class생성
아래 내용 파일로 저장한 후 kubectl apply -f 명령어로 생성
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: azure-tls
namespace: a #SecretProviderClass와 인증서(Secret)을 생성할 네임스페이스
spec:
provider: azure
secretObjects: # secretObjects defines the desired state of synced K8s secret objects
- secretName: ingress-tls-csi
type: kubernetes.io/tls
data:
- objectName: <인증서 이름> #kv에 업로드한 인증서 이름과 동일하게 맞춰야됨
key: tls.key
- objectName: <인증서 이름>
key: tls.crt
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true" # Set to true for using managed identity
userAssignedIdentityID: <client ID> # 위의 과정에서 설정한 Managed ID의 Client ID 입력
keyvaultName: <Key Vault> # Key Vault의 이름
cloudName: "" # [OPTIONAL for Azure] if not provided, the Azure environment defaults to AzurePublicCloud
objects: |
array:
- |
objectName: <인증서 이름> # kv에 업로드한 인증서 이름, secretObjects.data의 objectName하고 동일
objectType: secret # object types에는 secret, key, cert이 있지만 인증서의 crt와 key를 가져오려면 secret 타입으로 지정해야됨.
objectVersion: "" # [OPTIONAL] object versions, default to latest if empty
tenantId: <Tenant ID> # 테넌트의 ID 입력
7. Nginx Ingress Controller - Helm 배포
배포 시 values 파일을 두어 설정 값 저장해두고 배포하였음.
$ helm install nginx-a ingress-nginx/ingress-nginx \
--namespace ns-a \
--set controller.replicaCount=2 \
--set controller.ingressClass="nginx-a" \
--set controller.ingressClassResource.name="nginx-a" \
--set controller.ingressClassResource.enabled=true \
--set controller.ingressClassResource.controllerValue="k8s.io/nginx-a" \
--set controller.ingressClassByName=true \
--set controller.nodeSelector."kubernetes\.io/os"=linux \
--set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \
--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \
-f ingress-helm-values.yaml
ingress-helm-values.yaml 파일의 내용
controller: #nginx ingress controller에 대한 values 설정
extraVolumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "azure-tls" #이전에 생성한 SecretProviderClass의 이름
namespace: a #ingress controller와 다른 네임스페이스여도 되지만 같은 네임스페이스에 두었음.
extraVolumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
Ingress Controller 배포가 완료되면 인증서(Secret)와 Ingress Class가 생성되는데, 인그레스는 spec.ingressClassName에 Ingress Controller의 Class를 지정하여 사용.
#아래 명령어로 인증서, Ingress Class 확인
$ kubectl get secret -n a
$ kubectl get ingressclass
8. SVC, Pod 생성
아래 파일 내용 저장 후 kubectl apply -f 명령어로 생성
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
namespace: a
spec:
replicas: 1
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
env:
- name: TITLE
value: "AKS Nginx Ingress Demo"
---
apiVersion: v1
kind: Service
metadata:
name: svc
namespace: a
spec:
type: ClusterIP
ports:
- name: https
protocol: TCP
port: 80
targetPort: 80
selector:
app: app
9. Ingress 생성
아래 파일 내용 저장 후 kubectl apply -f 명령어로 생성
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
namespace: a
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx-a # 이전에 생성한 인그레스 컨트롤러의 클래스 이름 지정
tls:
- hosts:
- <도메인 명>
secretName: ingress-tls-csi
rules:
- host: <도메인 명> #tls.hosts와 동일
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc
port:
number: 80
추후 다른 서비스가 생겨나 규모가 확장 되더라도 인그레스 컨트롤러와 클래스를 각 네임스페이스별로 나누어 배포하면 됨
참고
https://github.com/kubernetes/ingress-nginx/issues/10246
https://kubernetes.github.io/ingress-nginx/user-guide/multiple-ingress/