쿠버네티스 기본 오브젝트 Ingress
Ingress는 클러스터로 들어오는 http 트래픽을 관리해주는 쿠버네티스 오브젝트다. Ingress 는 로드밸런싱, TLS 종료, 가상 호스팅 등 서비스를 제공해주게 된다.
인그레스(Ingress)
FEATURE STATE: Kubernetes v1.19 [stable] 클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트이며, 일반적으로 HTTP를 관리함. 인그레스는 부하 분산, SSL 종료, 명칭 기반의 가상 호스팅을 제공
kubernetes.io
Ingress 리소스는 트래픽 처리를 위한 하나의 규칙이며 이 규칙을 동작시켜 주는것이 Ingress Controller다.
이러한 Ingress Controller가 실질적으로 http 트래픽을 관리 해주게 되며, 이 관리 규칙이 Ingress 리소스 인것이다.
Ingress Controller에는 많은 종류들이 있지만 여기서는 Nginx Ingress Controller에 대해 살펴본다.
인그레스 컨트롤러
인그레스 리소스가 작동하려면, 클러스터는 실행 중인 인그레스 컨트롤러가 반드시 필요하다. kube-controller-manager 바이너리의 일부로 실행되는 컨트롤러의 다른 타입과 달리 인그레스 컨트롤러
kubernetes.io
GitHub - kubernetes/ingress-nginx: NGINX Ingress Controller for Kubernetes
NGINX Ingress Controller for Kubernetes. Contribute to kubernetes/ingress-nginx development by creating an account on GitHub.
github.com
Ingress Controller 설치
Nginx Ingress Controller 설치는 다음 링크를 참조해 진행한다.
https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal-clusters
Installation Guide - NGINX Ingress Controller
Installation Guide There are multiple ways to install the NGINX ingress controller: with Helm, using the project repository chart; with kubectl apply, using YAML manifests; with specific addons (e.g. for minikube or MicroK8s). On most Kubernetes clusters,
kubernetes.github.io
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.2.0/deploy/static/provider/baremetal/deploy.yaml
위 yml 파일을 그대로 사용하지 않고 약간 수정하여 사용하기 위해 kubectl apply 명령 대신 wget 명령을 통해 파일을 받아온다.
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.2.0/deploy/static/provider/baremetal/deploy.yaml
해당 파일은 Ingress Controller를 위한 파일로써 이번 포스팅에서는 해당 파일을 약간 수정하여 사용한다.
해당 파일을 열어보면 다음과 같이 되어있다.
해당 파일에는 Namespace에 대한 설정과, ServiceAccount, Role, NodePort에 대한 설정들이 들어있다.
여기서 기본으로 ingress-nginx로 되어있는 Namespace를 바꿔 사용할 것이다.
우선 7줄에 있는 Namespace의 이름을 바꿔준다.
이후 다음 명령을 통해 해당 파일 내에서 사용하는 모든 namespace를 바꿔준다.
sed -i 's/namespace: ingress-nginx/namespace: {some_namespace}/g' deploy.yaml
이후 아래 명령을 통해 Ingress Controller를 생성한다.
kubectl create -f deploy.yaml
이후 아래 명령을 통해 생성한 Ingress Controller를 확인할 수 있다.
kubectl get po -n {설정한 ns}
kubectl get svc -n {설정한 namespace}
NodePort로 설정된 nginx-controller를 확인할 수 있다. (외부 포트는 32206)
이 Ingress Controller는 클러스터내 어떠한 노드를 통해서도 접근할 수 있다.
즉 현재 master, worker1, worker2 노드가 운영중이고 어떠한 노드의 IP든 32206 포트로 접근하기만 하면 해당 Ingress Controller로 접근이 가능하다.
네임스페이스 변경
네임 스페이스를 위에서 설정한 Ingress Controller가 사용되는 네임스페이스로 변경해야한다.
현재는 아마 default namespace로 되어있을 것이다.
kubectl config set-context --current --namespace {namespace name}
위 명령을 통해 사용중인 네임스페이스를 변경한다.
Ingress 리소스 생성
이제 Ingress Controller가 사용할 Ingress 규칙을 만들어 준다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: madpt-ingress
annotations:
kubernetes.io/ingress.class: nginx
ingressclass.kubernetes.io/is-default-class: "true"
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
- path: /test1
pathType: Prefix
backend:
service:
name: nginx-service2
port:
number: 80
- path: /test2
pathType: Prefix
backend:
service:
name: nginx-service3
port:
number: 80
위의 예시는 간단하게 3개의 path를 라우팅 해주는 Ingress 룰이다.
/ 로 들어오는 요청들은 nginx-service라는 서비스로 보내주게 되고
/test1로 들어오는 요청들은 nginx-service2라는 서비스로 보내주게 되고
/test2로 들어오는 요청들은 nginx-service3라는 서비스로 보내주게 된다.
실제 서비스를 만들어 테스트를 해보자.
3개의 nginx-service를 만들어서 각각 하나의 pod를 endpoint로 할당해줬다.
이제 각 end point들에게 attach를 해서 접속을 확인해 본다.
kubectl attach {pod name}
이제 각 path로 요청을 넣게되면
당연히 각 pod에서는 /test1, /test2에 대한 대응이 안되어 있으므로 오류 페이지가 날라오지만, 요청이 각 서비스로 나뉘어 들어간다는것은 알 수 있다.
rewrite
GitHub - kubernetes/ingress-nginx: NGINX Ingress Controller for Kubernetes
NGINX Ingress Controller for Kubernetes. Contribute to kubernetes/ingress-nginx development by creating an account on GitHub.
github.com
ingress는 요청이 들어오는 경로를 rewrite하여 새로운 경로를 만들 수 있다.
위의 예시에선 /test1, /test2 경로로 나뉘어 서비스를 제공했다. 요청으로 들어온 url이 /test1, test2냐에 따라 제공할 서비스를 다르게 구분한 것이다.
하지만 우리는 다음과 같은 구분또한 하고싶을 수 있다.
/test1/{something}/{something}...
/test2/{something}/{something}...
즉 요청하게 될 root path가 test1, test2냐에 따라 제공되는 서비스를 다르게 하는것이다.
이때는
nginx.ingress.kubernetes.io/rewrite-target
라는 어노테이션을 사용한다.
만약 위 예시처럼 동작하게 하는 서비스를 제공하고자 한다면, 아래와 같이 yml 파일을 작성한다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
ingressclass.kubernetes.io/is-default-class: "true"
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- http:
paths:
- path: /test1(/|$)(.*)
pathType: Prefix
backend:
service:
name: test1-service
port:
number: 8080
- path: /test2(/|$)(.*)
pathType: Prefix
backend:
service:
name: test2-service
port:
number: 8080
example
클라이언트는 /test1/foo/bar 라는 경로로 http 요청을 하게 된다.
이 요청은 rule에 따라 test1-service로 가게될 것이다.
하지만 요청 그대로 /test1/foo/bar 경로에 대한 요청이 가는것이 아닌 /foo/bar 요청이 가게 된다.
만약 /test1/bar/foo 라는 경로로 요청이 들어오게 되어도 rewrite를 통해 /bar/foo 요청이 test1-service로 전달되게 된다.
실제 요청경로 | Service로 전달될 경로 |
/test1/foo/bar | /foo/bar |
/test2/foo/ | /foo |
내가 사용한 예시로는, 이미 서버 개발이 완료된 시점에, 정책상 get, post요청을 나눠야 할 일이 생겼다.
서버 소스코드를 건들지 않고, 클라이언트쪽 소스코드만 수정하여 문제를 해결해야 하는 상황이였다.
이때 클라이언트측에서 요청하게 될 경로에 /get, /post를 추가하여 요청을 진행했다.
즉 /account/login 이라는 요청의 경우 /post/account/login 이라는 요청으로만 바꿔준 것이다.
이후 ingress의 rewrite 기능을 사용하여 클라이언트측으로부터 들어온 /post/account/login이라는 요청은 /account/login이라는 요청으로 바뀌어 서버측 변경 없이 서비스를 제공해주었다.