인그레스(ingress)는 클러스터 외부에서 내부로 접근하는 요청들을 어떻게 처리할 지 정의해둔 규칙들의 모음이다.
인그레스는 아래와 같은 기능들을 제공한다.
인그레스는 위와 같은 기능들에 대해 정의해둔 규칙들을 정의해둔 리소스이고, 이를 실제 동작하기 위해서는 인그레스 컨트롤러가 필요하다.
인그레스 컨트롤러(Ingress Controller)는 클러스터에서 실행되고 수신 리소스에 따라 HTTP 로드 밸런서를 구성하는 응용 프로그램이다.
| ⭐ 인그레스가 동작하기 위해서는 인그레스 컨트롤러가 반드시 필요하다.
인그레스 컨트롤러는 자동으로 실행되지 않고 상황에 맞게 적합한 컨트롤러를 선택하여 설치해야 한다. 쿠버네티스에서는 GCE와 NGINX를 오픈소스로 제공하고 있다.
이외에도 써드파티 솔루션으로 아래와 같은 인그레스 컨트롤러를 쿠버네티스 웹사이트에서 볼 수 있다.
Ingress와 Ingress Controller에 대한 간단한 아키텍쳐를 살펴보면 아래와 같다.
(https://kubetm.github.io/k8s/08-intermediate-controller/ingress/)
외부에서 사용자가 특정 경로로 접속하게 되면 인그레스를 통해 정의해둔 규칙에 따라 인그레스 컨트롤러가 동작하여 서비스에 맞는 파드로 연결해준다.
외부 클라이언트가 인그레스를 통해 클러스터 내부 파드로 접속하는 통신 흐름을 살펴본다.
인그레스와 인그레스 컨트롤러를 직접 설치하여 실습을 해본다.
인그레스 컨트롤러는 쿠버네티스에서 공식적으로 제공하는 Nginx 인그레스 컨트롤러를 사용한다.
(스터디장 가시나님 제공 🙏)
Nginx 인그레스 컨트롤러를 설치한다. (공식 문서)
# 설치
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/cloud/deploy.yaml
# 설치 확인
$ kubectl get namespaces
$ kubectl get all -n ingress-nginx
디플로이먼트와 서비스를 생성한다.
svc1-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy1-websrv
spec:
replicas: 1
selector:
matchLabels:
app: websrv
template:
metadata:
labels:
app: websrv
spec:
containers:
- name: pod-web
image: nginx
---
apiVersion: v1
kind: Service
metadata:
name: svc1-web
spec:
ports:
- name: web-port
port: 9001
targetPort: 80
selector:
app: websrv
type: ClusterIP
svc2-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy2-guestsrv
spec:
replicas: 2
selector:
matchLabels:
app: guestsrv
template:
metadata:
labels:
app: guestsrv
spec:
containers:
- name: pod-guest
image: gcr.io/google-samples/kubernetes-bootcamp:v1
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: svc2-guest
spec:
ports:
- name: guest-port
port: 9002
targetPort: 8080
selector:
app: guestsrv
type: NodePort
svc3-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy3-adminsrv
spec:
replicas: 3
selector:
matchLabels:
app: adminsrv
template:
metadata:
labels:
app: adminsrv
spec:
containers:
- name: pod-admin
image: k8s.gcr.io/echoserver:1.5
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: svc3-admin
spec:
ports:
- name: admin-port
port: 9003
targetPort: 8080
selector:
app: adminsrv
# 생성 및 확인
$ kubectl apply -f svc1-pod.yaml,svc2-pod.yaml,svc3-pod.yaml
$ kubectl get pod,svc,ep
인그레스를 생성한다.
ingress1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-1
annotations:
#nginx.ingress.kubernetes.io/upstream-hash-by: "true"
spec:
ingressClassName: nginx
rules:
#- host: foo.bar.com
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc1-web
port:
number: 80
- path: /guest
pathType: Prefix
backend:
service:
name: svc2-guest
port:
number: 8080
- path: /admin
pathType: Prefix
backend:
service:
name: svc3-admin
port:
number: 8080
인그레스 정의 내역을 살펴본다.
.spec.ingressClassName
: 인그레스 컨트롤러 리소스의 이름으로 어떤 컨트롤러를 구현할 것인지 정의한다.
.spec.rules.host
: host를 지정할 수 있다. 만약 host를 지정하지 않는다면 ip로 연결된다.
.spec.rules.http.paths.path
: 각 path는 아래 .spec.rules.http.paths.backend
로 연결된다.
# 생성
$ kubectl apply -f ingress1.yaml
# 생성 확인
$ kubectl get ingress
$ kubectl describe ingress ingress-1
$ kubectl describe ingressclasses
외부 클라이언트에서 인그레스를 통한 접속을 확인해본다.
# 외부 클라이언트 환경 접속
## ingress-nginx-controller NodePort(HTTP 접속용) 변수 지정
$ export IngHttp=$(kubectl get service -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.ports[0].nodePort}')
$ echo $IngHttp
## 인그레스 접속 테스트
$ curl <마스터노드 IP>:<Nginx Controller 의 Service 의 NodePort 중 HTTP 접속용>
# svc1-web 접속
$ curl -s 192.168.10.10:$IngHttp
svc1-web에 연결된 파드로 접속이 되는 것을 확인할 수 있다.
# svc2-web 접속
$ curl -s 192.168.10.10:$IngHttp/guest
# 부하분산 테스트
$ for i in {1..100}; do curl -s 192.168.10.10:$IngHttp/guest ; done | sort | uniq -c | sort -nr
$ for i in {1..1000}; do curl -s 192.168.10.10:$IngHttp/guest ; done | sort | uniq -c | sort -nr
svc2-web에 연결된 파드로 접속이 잘 되고, 100과 1000번 반복 접속했을 때 대략 50% 확률로 부하분산되는 것을 확인할 수 있다.
# svc3-web 접속
$ curl -s 192.168.10.10:$IngHttp/admin
# 부하분산 테스트
$ for i in {1..100}; do curl -s k8s-m:$IngHttp/admin | grep Hostname ; done | sort | uniq -c | sort -nr
svc3-web에 연결된 파드로 접속이 잘되고, 3개의 파드가 존재할 경우에는 33% 확률로 부하분산이 되는 것을 확인할 수 있다.
그리고 헤더 정보들을 살펴보면 다음과 같다.
❓ Nginx 파드가 endpoint 정보 등을 모니터링 가능한 이유는 무엇일가?
-> clusterrole
과 role
에 endpoints 리소스에 각각 [list, watch], [get, list, watch] 동작을 가능하도록 설정했기 때문이다.
# clusterrole 확인
$ kubectl describe clusterrole ingress-nginx
# role 확인
$ kubectl describe role ingress-nginx -n ingress-nginx
코드에서 살펴보면 svc의 endpoint 정보를 가져오는 것을 알 수 있고, nginx 파드에는 아래와 같이 ingress에서 설정한 path와 서비스 정보가 등록되어 있다.
# nginx 파드 접속
$ kubectl exec -n ingress-nginx -it ingress-nginx-controller-6f4c4d95cb-r6czf -- /bin/bash
$ vi /etc/nginx/nginx.conf
최종적인 동작 흐름은 아래와 같이 외부 클라이언트에서 들어온 트래픽이 인그레스에 정의된 규칙에 따라 라우팅 되는데, 이때 파드의 서비스를 거치지 않고 엔드포인트 API를 통해 바로 pod로 접속하게 된다.
추가적으로 nginx 인그레스 컨트롤러를 promethues와 grafana를 이용하여 모니터링까지 하는 환경을 구축해본다.
위에서 진행한 실습 환경을 같지만 이번에는 helm을 이용하여 nginx 인그레스 컨트롤러를 설치한다.
# ingress-nginx 저장소 추가 및 업데이트
$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
$ helm repo update
# ingress-nginx 패키지 설치
$ helm install ingress-nginx ingress-nginx/ingress-nginx --version 4.0.17 --create-namespace --namespace ingress-nginx
kustomize를 이용하여 prometheus와 grafana를 디플로이한다.
# kustomize를 이용하여 prometheus 디플로이
$ kubectl apply --kustomize github.com/kubernetes/ingress-nginx/deploy/prometheus/
# 설치 확인
$ kubectl get pods,svc -n ingress-nginx
서비스가 정상적으로 생성되었다면 할당받은 포트로 프로메테우스에 접속한다.
# kustomize를 이용하여 grafana 디플로이
$ kubectl apply --kustomize github.com/kubernetes/ingress-nginx/deploy/grafana/
# 설치 확인
$ kubectl get pods,svc -n ingress-nginx
그라파나 서비스가 정상적으로 설치되었다면 할당받은 포트로 그라파나에 접속한다.
그라파나 초기 계정은 admin/admin 이다.
로그인을 한 후, 프로메테우스에서 수집하는 메트릭을 그라파나에서 보기 위해서는 datasource에 등록해야 한다.
[datasource 등록하는 방법]
위 과정을 거치면 datasource에 prometheus가 등록된 것을 확인할 수 있다.
이제 prometheus를 통해 메트릭을 받아볼 수 있는데 이때 그라파나에서는 PromQL
이라는 프로메테우스 쿼리 언어를 통해 메트릭을 활용하여 원하는 값을 얻을 수 있다. 그리고 얻어진 값을 바탕으로 그래프나 표 등으로 시각화하여 표현할 수 있다.
요구사항에 맞게 대시보드를 자신이 직접 구성할 수도 있지만, 이번 실습에서는 Grafana Labs에 공유되어진 nginx 인그레스 컨트롤러 대시보드를 활용한다.
[그라파나 대시보드 등록하는 방법]
Dashboards -> Browse -> Import
Import via grafana.com에 대시보드 ID 적고 Load
Prometheus에 등록한 데이터소스 선택하고 Import
정상적으로 Import 된다면 아래와 같이 nginx 인그레스 컨트롤러를 모니터링하는 대시보드를 확인할 수 있다.
(⚠ 9614 ID의 그라파나 대시보드를 사용하면 메트릭 네임이 일치하지 않는 것이 있어 일부 수정이 필요합니다.)
쿠버네티스 네트워킹 스터디 자료(by GasidaSeo)
https://arisu1000.tistory.com/27840
https://medium.com/swlh/kubernetes-ingress-controller-overview-81abbaca19ec
https://gruuuuu.github.io/cloud/k8s-service/
https://kubernetes.github.io/ingress-nginx/
https://kubernetes.github.io/ingress-nginx/user-guide/monitoring/