우리 인터넷 쇼핑몰은 GCP 클라우드에 인프라를 구축한다.
옷을 판매하는 기능을 wear라는 서비스에서 처리하고, 비디오 스트리밍 기능을 video라는 서비스에서 처리한다고 가정한다.
사용자가 우리 서비스에 접속하기 위해 아래와 같은 작업이 필요하다.
wear서비스와 video서비스에 각각 GCP LB를 붙이고, 이 두 LB를 묶는 상위 LB를 추가로 생성하여 붙인다.
그래서 /apparel
url로 들어오는 요청은 wear서비스로, /video
url로 들어오는 요청은 video서비스로 리다이렉트 시킨다.
이 모든 것을 k8s 클러스터 내부에서 관리하고 프로비저닝 하며, 다른 애플리케이션 배포 파일과 함께 배포할 수 있다면 어떨까? 이때 Ingress가 등장한다.
ingress는 외부 사용자가 접속 가능한 단일 url로 경로 기반 라우팅기능을 사용하여 클러스터 내 여러 서비스에 접속할 수 있게 한다. (+ssl 포함)
즉, Ingress는 k8s 클러스터에 내장된 Layer 7 계층의 LB라고 보면 된다.
그러나 여전히 ingress도 외부에 서비스를 노출하려면 nodeport 또는 lb를 사용한다.
GCE, Nginx, Contour, HAProxy, Traefik, Istio 같이 여러 종류가 있지만, k8s가 지원하고 관리하는 GCE, Nginx로 설명한다.
ingress controller를 배포하려면 최소한 아래와 같은 객체들이 필요하다.
ingress controller로써의 nginx는 조금 특이하게 배포된다.
manifest file을 보면 다른 부분은 큰 차이가 없지만, args 항목에 /nginx-ingress-controller
라고 있다.
ingress controller로써 nginx가 배포되어야 한다면 이 부분이 반드시 존재해야한다.
# 예시
apiVersion: apps/v1
kind: Deployment
metadata:
name: ingress-nginx-controller
spec:
selector:
matchLabels:
name: nginx-ingress
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
spec:
containers:
- args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.k8s.io/ingress-nginx/controller:v1.8.2@sha256:74834d3d25b336b62cabeb8bf7f1d788706e2cf1cfd64022de4137ade8881ff2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
...
그리고 nginx 설정 파일은 configMap 객체를 만들어 넘겨줘야 한다.
설정 파일을 수정할 필요는 없고 일단 이름만 넣어서 만들면 된다고 함
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller
그리고 ingress를 외부로 노출할 Service도 필요하다.
이 서비스는 nodeport 형식이며 위에서 생성한 deploy와 연결시킨다.
apiVersion: v1
kind: Service
metadata:
labels:
name: ingress-nginx-controller-admission
spec:
ports:
- name: https
port: 443
targetPort: 443
protocol: TCP
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app.kubernetes.io/name: ingress-nginx
type: NodePort
---
ingress가 클러스터 내에서 발생하는 변화를 감지하기 위해서 충분한 권한을 가진 Role, ClusterRoles, RoleBindings, SerivceAccount도 생성한다.
apiVersion: v1
kind: ServiceAccount
metadata:
name: ingress-nginx
경로 기반으로 라우팅하는 규칙 생성하는 것
manifest file 생성 후 다른 k8s객체처럼 create 명령어로 생성한다.
네임스페이스 구분이 있으므로 주의해서 확인할 것
1개의 규칙으로 2개의 경로를 라우팅하는 예시
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wear-watch
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
이렇게 생성된 ingress를 자세히 살펴보면 path항목에 /wear
, /watch
2가지가 생성된 것을 확인
www.my-online-store.com/wear → wear 서비스
www.my-online-store.com/watch → watch 서비스
www.my-online-store.com/eat → path 존재하지 않으므로 Default backend 서비스로 이동
2개의 규칙으로 각각 1개씩 라우팅하는 예시(서브도메인으로 구분)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wear-watch
spec:
rules:
- host: wear.my-online-store.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: wear-service
port:
number: 80
- host: watch.my-online-store.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: watch-service
port:
number: 80
host 라는 필드가 추가되었음을 주의할 것
host 필드 없으면, all host (*)를 의미함
# 이렇게도 확인할 수 있음
controlplane ~ ✖ k get ingress -A
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
app-space ingress-wear-watch <none> * 10.111.95.12 80 18m
critical-space ingress-pay <none> * 80 7s
www.wear.my-online-store.com → wear 서비스
www.watch.my-online-store.com → watch 서비스
강의에서는 구버전(왼쪽)으로 설명되었는데, 최신 버전은 오른쪽이라고 한다.
ingress manifest file 중 rewrite-target 설정이 존재한다.
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
...
spec:
rules:
- http:
paths:
- backend:
service:
name: pay-service
port:
number: 8282
path: /pay
pathType: Prefix
위와 같은 상황에서 사용자가 www.my-store.com/pay 로 접속하면, pay-service의 “/” 경로로 리다이렉트 된다.
이것은 rewrite-target 옵션 덕분인데 이 옵션이 현재 “/”로 설정되어 있어서 /pay로 접속하더라도, 목적지 서비스의 “/”로 이동하라고 경로를 덮어써주는? 것이다.
http://<ingress-service>:<ingress-port>/pay
→ http://<pay-service>:<port>/
만약 이 파일에서 rewrite-target 옵션이 존재하지 않았다면, www.my-store.com/pay 로 접속한 사용자는 서비스의 “/pay” 경로로 리다이렉트 될 것이다.
http://<ingress-service>:<ingress-port>/pay
→ http://<pay-service>:<port>/pay