AWS EKS에서 NGINX Ingress rewrite annotation 사용하기

2023. 5. 1. 23:09Dev/EKS

728x90
반응형

이 글은 AWS EKS에서 NGINX-Ingress Controller를 설치하고
nginx.ingress.kubernetes.io/rewrite-target annotations를 사용해 여러 애플리케이션을 여러 경로로 라우팅 하는 예제입니다.

nginx ingress rewrite url

해결하려는 문제
EKS에서 ALB와 ingress로만 Path-based routing을 하면 경로 영향을 받습니다. (ALB ingress는 rewrite를 지원하지 않습니다)
아래 Ingress는 example.com/two 로 온 요청을  service-two로 보냅니다. (example.com/two -> service-two의 /two )
하위 경로를 내부 서비스의 root로 보내려면 (example.com/two -> service-two의 / )
nginx ingress annotation 중 rewrite-target을 사용합니다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-example
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: service-one
              port:
                number: 80
        - path: "/two"
          pathType: Prefix
          backend:
            service:
              name: service-two
              port:
                number: 80

 

사전 준비

EKS v1.25 클러스터와 AWS 로드밸런서 컨트롤러 v2.5가 있다고 가정하고 진행합니다.
AWS EKS cluster 프로비저닝과 Aws-load balancer-controller 설치는 아래 포스트와 다른 문서들을 참고하세요.
(아래 포스트는 EKS v1.24와 controller v2.4.7을 설치합니다.)
https://nauco.tistory.com/89

EKS에 CLB, NLB, ALB 만들기, AWS Load Balancer Controller 사용

AWS EKS에서 AWS Load Balancer Controller를 사용해 CLB(Classic Load Balancer), NLB(Network Load Balancer), ALB(Application Load Balancer)를 만들어 보겠습니다. AWS Load Balancer Controller란? Elastic Load Balancer를 Kubernetes cluster에서

nauco.tistory.com

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/getting-started-eksctl.html

Amazon EKS 시작하기 - eksctl - Amazon EKS

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.5/deploy/installation/

Installation Guide - AWS Load Balancer Controller

If you want to run the controller on Fargate, use the Helm chart, since it doesn't depend on the cert-manager. Detailed instructions Follow the instructions in the aws-load-balancer-controller Helm chart. Summary Add the EKS chart repo to Helm helm repo ad

kubernetes-sigs.github.io

 

사전 준비 중 생길 수 있는 오류들 

1.
AWS에서 소개하는 AWS Load Balancer Controller 설치 가이드는 최신버전이 아닐 수 있으니
위에서 링크한 https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.5/ 공식문서에서 확인하세요.
(구글에서 검색해서 들어가면 이전 버전으로 링크될 때가 많습니다)
2.
로드밸런서 컨트롤러 설치 중 IAM 정책 생성 중에 아래와 같은 에러가 발생한다면 
An error occurred (EntityAlreadyExists) when calling the CreatePolicy operation: A policy called AWSLoadBalancerControllerIAMPolicy already exists. Duplicate names are not allowed.
-> iam policy에서 해당 이름의 policy를 지우고 새로 만들거나 aws iam update-policy 사용해서 최신 정책으로 업데이트합니다.

3. aws-load balancer-controller 설치 전에
serviceaccount가 잘 만들어지지 않는다면 기존에 같은 이름의 클러스터를 생성하다 실패한 것이 원인일 수 있습니다.
aws console에서 cloudformation에서 위와 비슷한 이름의 iamserviceaccount 스택을 지우고 다시 시도합니다. 

첫 번째 명령어는 실패, 두 번째처럼 나와야 성공입니다.
CloudFormation에서는 이렇게 나와야 성공
serviceaccount 줄여서 sa 확인

 
 

Nginx-ingress Controller 설치

 
Nginx ingress controller YAML로 설치하는 방법과
Nginx ingress controller Helm 으로 설치하는 방법이 있습니다.
아래 명령어를 사용해서 헬름으로 ingress-nginx를 설치합니다. 

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace

성공하면 아래와 같이 ingress리소스에서 ingressClassName을 nginx 세팅하고 사용하는 예제를 보여줍니다. 

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace
Release "ingress-nginx" does not exist. Installing it now.
NAME: ingress-nginx
LAST DEPLOYED: Sat Apr 29 17:59:59 2023
NAMESPACE: ingress-nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller'

An example Ingress that makes use of the controller:
  apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    name: example
    namespace: foo
  spec:
    ingressClassName: nginx
    rules:
      - host: www.example.com
        http:
          paths:
            - pathType: Prefix
              backend:
                service:
                  name: exampleService
                  port:
                    number: 80
              path: /
    # This section is only required if TLS is to be enabled for the Ingress
    tls:
      - hosts:
        - www.example.com
        secretName: example-tls

If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:

  apiVersion: v1
  kind: Secret
  metadata:
    name: example-tls
    namespace: foo
  data:
    tls.crt: <base64 encoded cert>
    tls.key: <base64 encoded key>
  type: kubernetes.io/tls


헬름 성공 메시지에서 알려주는대로
kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller
명령어를 입력하고 잘 떴는지 확인합니다.
저는 클러스터에 특별히 설치된 리소스들이 없어서
kubectl get svc -A
명령어로 확인했습니다.

이름이 ingress-nginx-controller 이고 TYPE이 LoadBalancer인 서비스를 확인 가능합니다.
주소가 k8s- 로 시작하는 NLB가 생성 된 것을 확인할 수 있습니다.

만들어진 로드밸런서의 주소가 a로 시작한다면 클래식 로드밸런서(CLB)가 생성된 것입니다.
(service/ingress-nginx-controller의 EXTERNAL-IP 확인)
AWS LoadBalancer Controller를 설치 안했거나, v2.5보다 낮은 버전인지 확인해보세요.

k get all -n ingress-nginx
NAME                                            READY   STATUS    RESTARTS   AGE
pod/ingress-nginx-controller-6b8bfd7f69-gk469   1/1     Running   0          7m15s

NAME                                         TYPE           CLUSTER-IP       EXTERNAL-IP                                                                    PORT(S)                      AGE
service/ingress-nginx-controller             LoadBalancer   10.100.208.234   a70eaf767a3c54dbaa1d6069010724c4-1121914811.ap-northeast-2.elb.amazonaws.com   80:30653/TCP,443:31686/TCP   7m15s
service/ingress-nginx-controller-admission   ClusterIP      10.100.121.211   <none>                                                                         443/TCP                      7m15s

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ingress-nginx-controller   1/1     1            1           7m15s

NAME                                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/ingress-nginx-controller-6b8bfd7f69   1         1         1       7m15s

 

ingress-nginx-controller가 사용하는 Network Loadbalancer를 Internet-facing으로 재 설치

default로 만들어진 NLB는 Internal입니다.
NLB를 테스트하기 편하도록 외부로 노출해서 다시 만들겠습니다.
helm uninstall ingress-nginx -n ingress-nginx
명령어를 실행하고 나오는
release "ingress-nginx" uninstalled
위 결과는 helm으로 설치한 ingress-nginx를 삭제한 것이지, 로드밸런서의 삭제를 의미하지 않습니다.

aws console에서 로드밸런서 삭제된 것 확인하고 아래 옵션을 추가해서 다시 설치합니다.

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --set controller.service.annotations."service\.beta\.kubernetes\.io\/aws-load-balancer-scheme"=internet-facing \
  --namespace ingress-nginx --create-namespace

 
(사실 아래 명령어로 될 줄 알았는데 안되네요...)

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --set controller.service.external.enabled=true \
  --namespace ingress-nginx --create-namespace

 로드밸런서가 프로비저닝 된 후 (약 3분 소요)
콘솔에서 확인 가능한 LoadBalancer의 DNS name (또는 svc의 EXTERNAL-IP)으로 접근했을 때, 404 Not Found가 나오면 성공

 

샘플 웹 애플리케이션 배포해서 Ingress-nginx 테스트 


위 소스를 사용해서 테스트합니다.
1. nginx ingress example
namespace를 만들고 app-one과 ingress-one을 apply합니다.

kubectl create ns app
kubectl apply -f app-one.yaml
kubectl apply -f ingress-one.yaml

 로드밸런서의 주소로 접근하면 첫 번째 앱으로 연결됩니다.


2. nginx ingress rewrite example
ingress-one을 지우고 rewrite annotation이 적용 된 ingress-two를 적용합니다.

kubectl delete -f ingress-one.yaml
kubectl apply -f ingress-two.yaml

 루트경로는 연결된 서비스가 없으니 404페이지가 뜹니다.

/red로 접근하면 service-one의 루트경로 ( / )가 호출됩니다.
/red/abc는 service-one에서 (/abc)로 연결됩니다.

 
3. nginx ingress rewrite-target routing
ingress-two를 지우고
app-two와 ingress-app을 apply합니다. 

kubectl apply -f app-two.yaml
kubectl delete -f ingress-two.yaml
kubectl apply -f ingress-app.yaml


아래와 같은 결과를 확인합니다.
  

 
ALB path-based routing과 (no rewrite) 
nginx-ingress rewrite를 써서 라우팅한것을 비교해봅니다.
eks nlb ingressNginx (위)  vs eks alb ingress (아래) 

nginx-ingress rewrite를 안 썼을 때

https://kubernetes.github.io/ingress-nginx/

Welcome - NGINX Ingress Controller

Overview This is the documentation for the Ingress NGINX Controller. It is built around the Kubernetes Ingress resource, using a ConfigMap to store the controller configuration. You can learn more about using Ingress in the official Kubernetes documentatio

kubernetes.github.io

 

정리

 
k get svc -A
명령어로 로드밸런서를 확인하고
k delete svc <service-name> -n <namespace>
명령어로 로드밸런서를 만든 서비스를 지워줍니다.
(혹은 aws 콘솔에서 로드밸런서를 직접 지웁니다.)
eksctl delete cluster --name <cluster-name>
명령어로 클러스터를 삭제합니다.

LB삭제 안하고 eksctl delete 하면 로드밸런서 안지워집니다.
클러스터만 지워지고 LoadBalancer 남아있으면 aws 콘솔가서 지우고
클라우드포메이션까지 확인해서 테스트에 사용한 aws 리소스들 지워줍니다.

 

후기


AWS에서? ALB에서? AWS Load Balancer Controller(LBC)에서?
왜 심플한 rewrite path를 지원하지 않는지 모르겠습니다.
도메인과 서브도메인 문제는 인그레스에서 라우팅하면 당연히 겪을 문제일텐데요. 
물론 애플리케이션에서 처리할 수도 있고, 이 글에서 처럼 nginx-ingress로 해결할 수 있지만
2019년에 작성된 issue에 아직도 코멘트가 달리는것만 봐도 저만 가진 생각은 아닌것 같습니다.
https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/835 

URL rewrite? · Issue #835 · kubernetes-sigs/aws-load-balancer-controller

Hi; I know you have mentioned to me before that "the only benefit of using NGINX is URL rewrite". I now bump into issue with an application not using TOMCAT web server. I deploy a kibana Service an...

github.com