Ingress Nginx
인그레스(Ingress) 는 쿠버네티스에 설치하는 클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트이며, 일반적으로 HTTP를 관리한다. 인그레스를 위해서는 인그레스 오브젝트를 설치해야 하는데, 이를 구현한 것들이 꽤 있지만 nginx 가 대표적이다.
여기서는 Ingress-Nginx 에 대해서 간단히 알아 본다.
설치전 고려사항
첫째로 일단 쿠버네티스에 서비스(Service) 에 고려 해야 한다. 쿠버네티스의 서비스는 클러스터내에 접속지점을 생성해 준다. ClusterIP, LoadBalancer, NodePort 세 가지의 타입이 존재한다. 문제는 LoadBalancer 타입인데, 이 타입을 지정해주면 EXTERNAL-IP 가 할당되어야 하지만 일반적인 환경에서는 할당되지 않는다.
LoadBalancer 는 클라우드 서비스 제공 사업자를 위한 것으로 AWS, GCP, Azure 클라우드에서 제공하는 로드밸런서를 위한 것이다. 그래서 일반적인 베어메탈(Bare Metal) 이나 VM 환경(VMware, VirtualBox, KVM) 에서 쿠버네티스를 구성한 상태에서 LoadBalancer 를 사용하게 되면 EXTERNAL-IP 할당되지 않는다.
1 2 3 4 |
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.32.0.1 <none> 443/TCP 96d springboot-service ClusterIP 10.32.0.216 <none> 80/TCP 9s |
이렇게 하면 외부에서 접속이 되지 않는다. 이 접속은 클러스터내에 파드(Pod) 에서 호출할 수 있지만 외부에서는 호출이 되지 않는다.
그래서 베어메탈이나 가상환경에서 쿠버네티스에서 LoadBalancer 를 사용할 수 있도록 해주는 Metallb 을 이용했다. 이를 이용하면 서비스 타입을 LoadBalancer 로 지정했을 경우, EXTERNAL-IP 가 할당돼 외부에서 접속이 가능해 진다.
두번째로 ingress-nginx 를 Helm 으로 설치하지 말아야 한다. 현재 Helm 저장소에 올라온 ingress-nginx 는 api 버전이 과거에 버전이다. v1beta 버전으로 되어 있는데, 필자의 쿠버네티스에서는 오래된 버전으로 인식된다.
이를 해결하기 위해서는 github 저장소에 baremetal 버전에 deploy.yaml 파일을 이용해야 한다.
설치
먼저 ingress-nginx 의 github 에 접속해 baremetal 버전을 다운로드 받는다.
1 |
$ wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml |
이 deploy.yaml 은 baremetal 버전인데, 여기의 서비스 타입은 NodePort 로 되어 있다. 필자는 앞에서도 말했지만 Metallb 를 설치했기 때문에 LoadBalancer 타입으로 변경을 해줘야 한다. deploy.yaml 파일을 열어서 바꿔 준다.
1 2 3 4 5 6 7 8 9 10 11 12 |
spec: - type: NodePort + type: LoadBalancer ports: - name: http port: 80 protocol: TCP targetPort: http - name: https port: 443 protocol: TCP targetPort: https |
서비스 타입을 바꿨다면 이제 설치를 해 준다.
1 |
$ kubectl apply -f deploy.yaml |
이 방법으로 설치를 하게 되면 다음과 같은 특징을 갖게 된다.
- ingress-nginx 네임스페이스가 생성 된다.
- LoadBalancer 타입이며, Metallb 으로 인해 EXTERNAL-IP 가 할당 된다.
- apiVersion 이 networking.k8s.io/v1 최신 버전을 지원 한다.
1 2 3 4 5 |
$ kubectl get svc -A NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default kubernetes ClusterIP 10.32.0.1 <none> 443/TCP 97d ingress-nginx ingress-nginx-controller LoadBalancer 10.32.0.228 192.168.111.2 80:30077/TCP,443:31356/TCP 3m18s </none> |
LoadBalancer 에 EXTERNAL-IP 에 외부 접속을 하기 위한 IP가 할당되어 있다.
예제
예제는 springboot 를 이용한 서비스를 배포하고 ingress 를 통해서 접속해 본다. 이 예제는 하나의 서비스에 대한 것이다.
먼저 Deployment, Service 를 다음과 같이 작성 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
]$ vim springboot.yaml apiVersion: apps/v1 kind: Deployment metadata: name: springboot-deployment labels: app: springboot spec: replicas: 3 selector: matchLabels: app: springboot template: metadata: labels: app: springboot spec: containers: - name: springboot image: gazgeek/springboot-helloworld imagePullPolicy: Always ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: springboot-service spec: selector: app: springboot ports: - protocol: TCP port: 80 targetPort: 8080 ]$ kubectl apply -f springboot.yaml deployment.apps/springboot-deployment created service/springboot-service created |
정상적으로 생성이 되었다. 이제 이것을 인그래스와 연결을 해줘야 한다. 인그래스에서 URI 가 /springboot 이면 지금 배포한 springboot 의 메시지가 화면 표시되도록 했다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
]$ vim ingress-springboot.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: springboot-ingress annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - http: paths: - path: /springboot pathType: Prefix backend: service: name: springboot-service port: number: 80 ]$ kubectl apply -f ingress-springboot.yaml Error from server (InternalError): error when creating "ingress.yaml": Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io": Post "https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking/v1/ingresses?timeout=10s": context deadline exceeded |
직접해보면 위와같이 오류가 발생한다. 이는 보안 관련 쪽에 문제가 있는 것으로 보이는데, 아마도 TLS 설정에 문제가 있기 때문인 것으로 추정 된다. 이를 해결하기 위해서는 webhook 설정을 삭제해주면 된다.
1 2 |
]$ kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission validatingwebhookconfiguration.admissionregistration.k8s.io "ingress-nginx-admission" deleted |
그리고 다시 한번 ingress-springboot.yaml 파일을 적용해주면 인그래스가 생성 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ kubectl describe ingress springboot-ingress Name: springboot-ingress Namespace: default Address: 192.168.96.51 Default backend: default-http-backend:80 (<error: endpoints="" "default-http-backend"="" not="" found="">) Rules: Host Path Backends ---- ---- -------- * /springboot springboot-service:80 (10.31.4.55:8080,10.31.4.56:8080,10.31.4.57:8080) Annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/rewrite-target: / Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Sync 3s (x2 over 54s) nginx-ingress-controller Scheduled for sync |
/springboot URI 는 springboot-service 백엔드로 연결이 되어 있다걸 확인할 수 있다. 이제 인그레스 서비스에 LoadBalancer 의 외부 접속 IP 로 접속을 시도해 보자.
1 2 |
$ curl http://192.168.111.2/springboot Hello from GazGeek! |
위와같이 인그레스가 정상적으로 동작함을 알 수 있다.
정리
지금까지의 예제는 쿠버네티스 인그레스 문서의 첫번째 다이어그램과 정확하게 같은 것이다.
클라이언트가 인그레스 로드 밸런서로 접속이 가능해야 했기 때문에 Metallb 을 이용해서 외부접속 IP를 할당해 주도록 설정을 했다.
인그레스 서비스는 설치할때 한번 생성되어지고 이것을 통해서 뒤에 서비스들과 연결이 되어지는데, 이 백엔드 서비스들에 어떻게 연결을 할 것이지에 대한 설정은 인그레스 컨트롤러에 의해서 결정되게 된다.