많은 사람들이 헷갈려하는 것 중 하나가 service와 ingress이다.
Ingress는 kubernetes object로서 layer 7에 해당하는 network 기능을 제공해준다. 가령 TLS를 통한 https제공, host name기반의 라우팅, path기반의 라우팅, oauth2 등의 기능을 제공해준다.
wear-pod1---| ---ingress---
wear-pod2---|--wear service -->| http,https|
wear-pod3---| | oauth, tls|
| routing |
video-pod1---| | |
video-pod2---|--video service -->| |
video-pod3---| -------------
wear
기능을 제공하는 pod들이 있다고 하자. 이는 my-app:80/wear
로 요청을 받고 싶다. 또한, video
역시도 my-app:80/wear
로 요청을 받고 싶다.
그러나, 기존의 NodePort로는 port를 30000이상 밖에 사용할 수 밖에 없고, 각 service마다 서로 다른 NodePort를 만들어주는 수 밖에 없다. 즉, wear
는 32080
, video
는 32081
로 말이다.
이렇게 하나의 platform이 기능마다 port가 달라지면 사용자도 힘들고, 관리하는 입장에서 oauth, https 적용 등을 매번 각 port마다 따로 해주는 방법 밖에 없다.
그래서, ingress
가 등장한 것이다. ingress
는 ingress-controller
라는 component를 통해 동작하게 되는데, cluster의 특정 service와 특정 path를 연결해 layer 7의 기능인 https, oauth 등의 기능을 제공해준다.
이때 ingress-controller
는 대부분 NodePort로 열거나 AWS, GCP와 같은 퍼블릭 클라우드에서는 로드밸런서로 외부에 오픈이 된다.
wear-pod1---| ---ingress---
wear-pod2---|--wear service -->| http,https|
wear-pod3---| | oauth, tls|
| routing |-->38080
video-pod1---| | |
video-pod2---|--video service -->| |
video-pod3---| -------------
위와 같이 38080으로 ingress-controller를 외부에 노출시키고, waer service
를 /wear
로 맵핑해주는 ingress를 만들어준다. 이렇게하면 38080
으로 온 요청 중에 my-app:38080/wear
가 있다면 wear service
로 맵핑된다.
똑같이 video
도 마찬가지이다. video
도 /video
와 video service
를 연결해주는 ingress를 만들어준다. 따라서 my-app:38080/video
로 온 요청은 video service
가 받아내게 된다.
그래서 ingress라는 것은 사실 두 가지로 분해할 수 있다.
deploy: ingress 기능을 배포하는 주요 컴포넌트로 ingress controller가 있다. nginx-ingress-controller, traefic이 대표적이다.
configure: 어느 service를 어떤 path, host로 맵핑하고 https, oauth, 로드밸런싱과 같은 기능을 설정하는 부분이다. 이는 Ingress라는 kubernetes object로 설정할 수 있다.
기본적으로 Ingress controller는 설치되지 않아있따.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
spec:
replicas: 1
selector:
matchLabels:
name: nginx-ingress
template:
metadata:
labels:
name: nginx-ingress
spec:
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.21.0
args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
ingress-controller 역시도 다른 pod와 마찬가지인 것이다.
다음으로 ingress-controller를 위한 NodePort service를 만들어주도록 하자.
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress
spec:
type: NodePort
selector:
name: nginx-ingress
ports:
- port: 80
targetPort: 80
nodePort: 38080
다음으로 ingress-controller를 위한 ServiceAccount를 제공해주어야 한다.
따라서, ingress controller는 'Deployment', 'Service', 'ServiceAccount'가 필요하다.
다음으로는 'Ingress'를 만들어보도록 하자. Ingress
resource는 위에서 설명했듯이 L7 layer의 고도화된 기능을 제공해주는데 path을 기반으로한 라우팅, https, oauth2 등의 기능을 제공해준다. 이 기능들을 어떻게 사용할 것인지 각 Ingress resource에 정의하여 제공해줄 수 있는 것이다.
다음은 위에서 만든 wear
pod에 관한 wear-service
를 /wear
요청으로부터 온 packet에 연결해주는 code이다. 가령 ingress controller
가 30080
으로 열렸다면 host:30080/wear
로 요청이 온 것을 wear-service
로 전달해주는 것이다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wear
spec:
rules:
- http:
paths:
- path: /wear
pathType: Prefix
backend:
service:
name: wear-service
port:
number: 80
만약 /watch
path를 watch-service
와 연결하고 싶다면 다음과 같이 쓸 수 있다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wear
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /wear
pathType: Prefix
backend:
service:
name: wear-service
port:
number: 80
- path: /watch
pathType: Prefix
backend:
service:
name: watch-service
port:
number: 80
참고로 annotation부분의 rewrite-target
은 host:30080/wear
나 host:30080/watch
와 같은 요청을 host:30080/wear/
와 host:30080/watch/
로 바꿔준다.
왜 이렇게 바꿔주냐면 보통 웹 서버의 경우 /
로 시작하는 경우가 많기 때문이다. 즉 watch
pod의 경우 다음과 같이 server를 열었을 것이다.
http://<wear-service>:<port>/
그런데, 만약 rewrite
없이 실했다면 host:30080/watch
대로 요청이 watch-service
로 갔었을 텐데, 그러면 다음에 요청이 간다.
http://<wear-service>:<port>
이렇게 되면 실패하게된다. 이와 같이 요청이 온 path를 보고 연결된 service를 위해 rewrite작업을 거쳐주는 것이다.
https://kubernetes.github.io/ingress-nginx/examples/
위의 링크에서 자세한 내용을 볼 수 있다.
참고로 ingress-nginx-controller를 만들 때, ingress
에서 설정한 path가 없다면 default로 적용할 service를 설정할 수 있는데, 다음과 같다.
spec:
containers:
- args:
...
- --default-backend-service=app-space/default-backend-service
다음은 default-backend-service로 맵핑되어 있다.
마지막으로 주의할 것은 ingress-controller
는 namespace와 상관없이 사용이 가능하지만, ingress
의 경우는 namespace에 종속을 받기 때문에 namespace가 서로 다른 service에 대한 연결이 불가능하다.