Azure

AKS - Multi Nginx Ingress Controller 설정

shj4895 2024. 5. 30. 13:52

이 글에서는 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에 접근 가능하도록 권한 부여

https://learn.microsoft.com/ko-kr/azure/aks/csi-secrets-store-identity-access#access-with-managed-identity

 

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/k8s-122-migration/#how-can-i-easily-install-multiple-instances-of-the-ingress-nginx-controller-in-the-same-cluster

https://kubernetes.github.io/ingress-nginx/user-guide/multiple-ingress/