Table of Contents
인그레스(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 할당되지 않는다.
$ 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 버전을 다운로드 받는다.
$ wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml
이 deploy.yaml 은 baremetal 버전인데, 여기의 서비스 타입은 NodePort 로 되어 있다. 필자는 앞에서도 말했지만 Metallb 를 설치했기 때문에 LoadBalancer 타입으로 변경을 해줘야 한다. deploy.yaml 파일을 열어서 바꿔 준다.
spec:
- type: NodePort
+ type: LoadBalancer
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
- name: https
port: 443
protocol: TCP
targetPort: https
서비스 타입을 바꿨다면 이제 설치를 해 준다.
$ kubectl apply -f deploy.yaml
이 방법으로 설치를 하게 되면 다음과 같은 특징을 갖게 된다.
- ingress-nginx 네임스페이스가 생성 된다.
- LoadBalancer 타입이며, Metallb 으로 인해 EXTERNAL-IP 가 할당 된다.
- apiVersion 이 networking.k8s.io/v1 최신 버전을 지원 한다.
$ 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 를 다음과 같이 작성 한다.
]$ 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 의 메시지가 화면 표시되도록 했다.
]$ 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 설정을 삭제해주면 된다.
]$ kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission validatingwebhookconfiguration.admissionregistration.k8s.io "ingress-nginx-admission" deleted
그리고 다시 한번 ingress-springboot.yaml 파일을 적용해주면 인그래스가 생성 된다.
$ 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 로 접속을 시도해 보자.
$ curl http://192.168.111.2/springboot Hello from GazGeek!
위와같이 인그레스가 정상적으로 동작함을 알 수 있다.
정리
지금까지의 예제는 쿠버네티스 인그레스 문서의 첫번째 다이어그램과 정확하게 같은 것이다.
클라이언트가 인그레스 로드 밸런서로 접속이 가능해야 했기 때문에 Metallb 을 이용해서 외부접속 IP를 할당해 주도록 설정을 했다.
인그레스 서비스는 설치할때 한번 생성되어지고 이것을 통해서 뒤에 서비스들과 연결이 되어지는데, 이 백엔드 서비스들에 어떻게 연결을 할 것이지에 대한 설정은 인그레스 컨트롤러에 의해서 결정되게 된다.
