Ingress 튜토리얼
Ingress는 클러스터 외부의 요청을 Ingress 리소스에 정의된 규칙에 따라 클러스터 내부의 서비스로 연결해줍니다. 더 자세한 설명은 Kubernetes의 Ingress 문서를 참고하시기 바랍니다. 이 가이드에서는 URI에 따른 라우팅과 호스트에 따른 라우팅 두 가지 방법을 설정해보겠습니다.
준비 사항
운영 중인 클러스터와 kubectl 설치 및 환경변수 설정이 필요합니다.
- 클러스터 생성은 클러스터 생성하기를 참고하시기 바랍니다.
- kubectl 설치 및 환경변수 설정은 kubectl 설치하기를 참고하시기 바랍니다.
클러스터 생성 시 설치 모듈에서 Ingress Nginx를 선택하여 생성하신 경우, Ingress Controller와 Service가 자동으로 생성되므로 아래의 EXTERNAL-IP 확인부터 진행하시기 바랍니다.
Ingress Controller 배포
아래의 명령을 수행하면 ingress-nginx라는 Namespace가 생성되며 Ingress 구현체인 ingress-nginx에 필요한 리소스들이 생성됩니다.
kubectl --kubeconfig $KUBE_CONFIG apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/2de5a893aa15f14102d714e918b0045b960ad1a5/deploy/static/mandatory.yaml
- 실행 결과
namespace/ingress-nginx created configmap/nginx-configuration created configmap/tcp-services created configmap/udp-services created serviceaccount/nginx-ingress-serviceaccount created clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created role.rbac.authorization.k8s.io/nginx-ingress-role created rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created deployment.apps/nginx-ingress-controller created
Ingress Service 생성
외부에서 접근할 수 있도록 LoadBalancer 타입의 Ingress Service를 생성합니다.
kubectl --kubeconfig $KUBE_CONFIG apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/2de5a893aa15f14102d714e918b0045b960ad1a5/deploy/static/provider/cloud-generic.yaml
- 실행 결과
service/ingress-nginx created
로드밸런서 생성 여부 실시간 확인
kubectl --kubeconfig $KUBE_CONFIG get service -n ingress-nginx --watch
- 실행 결과
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx LoadBalancer 172.17.116.11 <pending> 80:31583/TCP,443:32586/TCP 4s ingress-nginx LoadBalancer 172.17.116.11 slb-1976810.n... 80:31583/TCP,443:32586/TCP 27s
EXTERNAL-IP 확인
Service가pending
상태에서 생성이 완료되면EXTERNAL-IP
를 확인합니다.kubectl --kubeconfig $KUBE_CONFIG get service -n ingress-nginx
- 실행 결과
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx LoadBalancer 172.17.116.11 slb-1976810.ncloudslb.com 80:31583/TCP,443:32586/TCP 59s
Application 및 서비스 배포
각자 다른 정보를 가진 두 개의 예제용 Deployment 및 Service를 생성합니다. 예제용 Deployment는 자신의 호스트 정보를 보여주는 demo용 nginx container이며, 각 Service는 ClusterIP 타입으로 생성되어 외부에서 직접 접근이 불가능한 상태입니다.
kubectl --kubeconfig $KUBE_CONFIG apply -f https://gist.githubusercontent.com/NaverCloudPlatformDeveloper/c47620d8d25b2a0e08648f225043adf6/raw/675addde0a56ba727824f30f92a73b40550fb73c/nks-tutorial-hello-service.yaml
- 실행 결과
deployment.apps/a created service/a-svc created deployment.apps/b created service/b-svc created
URI 기반 라우팅
앞에 생성한 Ingress Service의 External IP 뒤에 붙는 Path별로 라우팅을 해서 /a
로 요청할 때와 /b
로 요청할 때 각각 다른 서비스로 연결되도록 설정해보겠습니다.
Ingress 생성
예제의 Ingress 리소스는 아래와 같이 각 path
에 따라 backend
를 다르게 설정하여 /a
로 접근할 경우 a-svc로, /b
로 접근할 경우는 b-svc로 접근하도록 설정했습니다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ab-ingress
annotations:
kubernetes.io/ingress.class: nginx
ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /a
backend:
serviceName: a-svc
servicePort: 80
- path: /b
backend:
serviceName: b-svc
servicePort: 80
아래의 명령으로 Ingress를 생성합니다.
kubectl --kubeconfig $KUBE_CONFIG apply -f https://gist.githubusercontent.com/NaverCloudPlatformDeveloper/eca9d12336e008f1c7102892750aeae5/raw/3f3d0916d89161a1d81ed19464b9991154a8b9f8/nks-tutorial-ab-ingress.yaml
- 실행 결과
ingress.extensions/ab-ingress created
예제에서는 TLS 설정을 하지 않았기 때문에 강제 redirection을 막기 위해서 ingress annotation에
nginx.ingress.kubernetes.io/ssl-redirect: "false"
를 추가했지만, TLS 설정 시에는 해당 annotation을 지워주시기 바랍니다.
Ingress 생성 확인
kubectl get ingress
명령으로 생성된 ingress를 확인할 수 있습니다.
kubectl --kubeconfig $KUBE_CONFIG get ingress
- 실행 결과
NAME HOSTS ADDRESS PORTS AGE ab-ingress * slb-1976810.ncloudslb.com 80 19s
서비스 접속 확인
브라우저 또는 curl을 통해 접속 결과를 확인하면 각자 다른 Service의 Pod로 접근하는 것을 확인할 수 있습니다.예시
http://slb-1976810.ncloudslb.com/a
$ curl http://slb-1976810.ncloudslb.com/a Server address: 172.24.21.10:80 Server name: a-57598bbddd-9hcc6 Date: 09/Jul/2019:09:03:36 +0000 URI: /a Request ID: add732582fb99d0cfffe3edc83169517
http://slb-1976810.ncloudslb.com/b
$ curl http://slb-1976810.ncloudslb.com/b Server address: 172.24.21.11:80 Server name: b-657f4794f4-k48hb Date: 09/Jul/2019:09:03:37 +0000 URI: /b Request ID: 6cfd25c99f677c75ad815eaf57fc24c5
호스트 기반 라우팅
이번에는 동일한 EXTERNAL-IP에 대해 각각 다른 도메인으로 요청 시 다른 서비스로 연결되도록 설정해보겠습니다.
기존 ingress 삭제
먼저 앞에 생성했던 ab-ingress를 삭제합니다.
kubectl --kubeconfig $KUBE_CONFIG delete ingress ab-ingress
- 실행 결과
ingress.extensions "ab-ingress" deleted
Ingress 생성
아래 예제는 a.svc.com
으로 요청할 경우는 a-svc
로, b.svc.com
으로 요청할 경우는 b-svc
로 연결하도록 각각의 host
에 따라 backend
를 다르게 했습니다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ab-host-ingress
annotations:
kubernetes.io/ingress.class: nginx
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: a.svc.com
http:
paths:
- path: /
backend:
serviceName: a-svc
servicePort: 80
- host: b.svc.com
http:
paths:
- path: /
backend:
serviceName: b-svc
servicePort: 80
아래의 명령으로 Ingress를 생성합니다.
kubectl --kubeconfig $KUBE_CONFIG apply -f https://gist.githubusercontent.com/NaverCloudPlatformDeveloper/39913ee1025c45aaa0d50753db8a7555/raw/91082b01c0f26313b0a11e61df8984ac6c6b5c46/nks-tutorial-ab-host-ingress.yaml
- 실행 결과
ingress.extensions/ab-host-ingress created
Ingress 생성 확인
kubectl get ingress
명령으로 생성된 ingress를 확인할 수 있고HOSTS
에a.svc.com
,b.svc.com
이 있는 것을 볼 수 있습니다.kubectl --kubeconfig $KUBE_CONFIG get ingress
- 실행 결과
NAME HOSTS ADDRESS PORTS AGE ab-host-ingress a.svc.com,b.svc.com slb-1976810.ncloudslb.com 80 3m57s
서비스 접속 확인
예제의 호스트로 설정한 도메인은 실제로는 없는 도메인이기 때문에 curl 명령에 -H host
옵션을 넣어서 호스트별 접속 시에 다른 서비스가 노출되는지 확인해봅니다.
예시
a.svc.com
$ curl -H host:a.svc.com http://slb-1976810.ncloudslb.com Server address: 172.24.21.10:80 Server name: a-57598bbddd-9hcc6 Date: 09/Jul/2019:08:33:03 +0000 URI: / Request ID: b340711ab142bef67fdb07e7fd077ddb
b.svc.com
$ curl -H host:b.svc.com http://slb-1976810.ncloudslb.com Server address: 172.24.21.11:80 Server name: b-657f4794f4-k48hb Date: 09/Jul/2019:08:33:12 +0000 URI: / Request ID: eb6a876acbb2db7155ff26992b6635e4
참고 사항
이름에 _(underscore)가 있는 Request Header는 서버에서 확인이 되지 않습니다.
ingress-nginx에서는 request header 이름에 _(underscore)가 들어가면 강제로 삭제합니다. 이를 회피하기 위해서는 ConfigMap에 enable-underscores-in-headers: true
를 추가해야 합니다. 자세한 내용은 ingress-nginx의 ConfigMaps 문서를 참고하시기 바랍니다.
서버에서 Request의 Client IP를 확인하면 Cluster 내부의 IP로 보입니다.
ingress-nginx를 통해 Client의 Real IP를 온전하게 취득하기 위해서는 LoadBalancer의 proxy protocol 설정과 ingress-nginx의 use-proxy-protocol: true
ConfigMap이 설정되어 있어야 합니다.
LoadBalancer의 proxy protocol 활성화는 "Kubernetes의 서비스를 통한 로드밸런서 상품 연동"을 참고해주시고
ingress-nginx의 ConfigMap 설정은 ingress-nginx의 ConfigMaps 문서를 참고해주시기 바랍니다.
Load Balancer에서 ingress-nginx Pod가 없는 Node는 Health Check에 실패하는 것으로 나옵니다.
위 예시로 ingress-nginx Service를 생성한 경우 Service .spec.externalTrafficPolicy: Local
로 설정되어 있는 것을 확인 할 수 있습니다.
.spec.externalTrafficPolicy
는 서비스에서 외부 트래픽을 어떻게 라우팅 하는지를 설정할 수 있습니다. 사용 가능한 값은 Cluster
(default)와 Local
입니다.
Cluster
: 외부 트래픽을 전체 Pod에 분산합니다. 다른 Node에 있는 Pod로 전달할 때 두 번째 홉을 유발할 수 있지만, Pod로의 트래픽은 균형있게 분산할 수 있습니다.Local
: 외부 트래픽을 로컬 Node에 있는 Pod로만 전달합니다. 다른 Node에 대한 두 번째 홉을 피하지만 불균형한 트래픽 분산이 발생할 수 있습니다.
ingress-nginx Service의 .spec.externalTrafficPolicy: Local
로 되어있다면 ingress-nginx Pod가 동작 중인 Node만 트래픽이 전달되므로 그 외의 서버는 Health Check에 실패하는 것으로 나옵니다.
동작에 대한 자세한 내용은 Kubernetes의 문서에서 확인할 수 있으며, 각 서비스에 맞는 설정으로 변경하시는 것을 권장해 드립니다.