Ingress
인그레스는 쿠버네티스 내부의 서비스를 외부로 노출하되 L7으로 노출하는 역할로 프록시와 비슷한 역할을 수행합니다. K8s에서는 Ingress는 API로만 구현이 되어있고, 별도의 구현체(Nginx, Kong 등)으로 사용하게됩니다. 인그레스는 앞 문장에 서술했듯이 Service는 L4 수준의 통신이라면, 인그레스는 L7 수준의 통신으로 SSL 관련 처리까지 가능해서, 앞에서는 SSL 처리를 완료하고 뒤에서는 http로 통신을 할수 있기도 합니다. 하지만, 이제는 Gateway API가 새로이 나오면서 Ingress API는 더이상 추가 개발을 하지 않는 상태가 되었습니다.
통신흐름
# 인스턴스 모드, Ingress -> Service -> Application
Client => LB[Service - Ingress Controller Pod] => Service => POD
# IP모드, Ingress -> Application
Client => LB[Service - Ingress Controller Pod] => POD
지원 기능
HTTP/HTTPS 트래픽을 호스트(Doamin) 기반 라우팅으로 부하분산, 카나리 지원으로 유연한 어플리케이션 업데이트, SSL/TLS 종료 지원
설정 동기화
Nginx Ingress Controller의 목표중 하나는 설정파일을 자동으로 적용하는 것으로 ConfigMap에 nginx.conf 파일설정 변경시 자동으로 reload 되도록 Lua로 작성된 모듈 사용
실습
Nginx Ingress Controller 배포
# manifest 파일 생성
cat << EOT > ingress-nginx-values.yaml
controller:
service:
type: NodePort
nodePorts:
http: 30080
https: 30443
nodeSelector:
kubernetes.io/hostname: "k3s-s"
metrics:
enabled: true
serviceMonitor:
enabled: true
EOT
네임스페이스 생성
k create ns ingress
ingress-nginx helm chart 배포
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx -f ingress-nginx-values.yaml --namespace ingress --version 4.11.2
확인
k get all -n ingress
---
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-controller-979fc89cf-rk86h 0/1 ContainerCreating 0 16s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller NodePort 10.10.200.90 <none> 80:30080/TCP,443:30443/TCP 16s
service/ingress-nginx-controller-admission ClusterIP 10.10.200.52 <none> 443/TCP 16s
service/ingress-nginx-controller-metrics ClusterIP 10.10.200.30 <none> 10254/TCP 16s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ingress-nginx-controller 0/1 1 0 16s
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-nginx-controller-979fc89cf 1 1 0 16s
---
k describe svc -n ingress ingress-nginx-controller
externalTrafficPolicy 를 local 로 설정
k patch svc -n ingress ingress-nginx-controller -p '{"spec":{"externalTrafficPolicy": "Local"}}'
기본 nginx conf 파일 확인
k describe cm -n ingress ingress-nginx-controller
---
Name: ingress-nginx-controller
Namespace: ingress
Labels: app.kubernetes.io/component=controller
app.kubernetes.io/instance=ingress-nginx
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=ingress-nginx
app.kubernetes.io/part-of=ingress-nginx
app.kubernetes.io/version=1.11.2
helm.sh/chart=ingress-nginx-4.11.2
Annotations: meta.helm.sh/release-name: ingress-nginx
meta.helm.sh/release-namespace: ingress
Data
====
allow-snippet-annotations:
----
false
BinaryData
====
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE 60s nginx-ingress-controller ConfigMap ingress/ingress-nginx-controller
---
k exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf
---
Configuration checksum: 13949063550686361986
setup custom paths that do not require root access
pid /tmp/nginx/nginx.pid;
daemon off;
worker_processes 2;
worker_rlimit_nofile 1047552;
worker_shutdown_timeout 240s ;
events {
multi_accept on;
worker_connections 16384;
use epoll;
}
http {
lua_package_path "/etc/nginx/lua/?.lua;;";
lua_shared_dict balancer_ewma 10M;
lua_shared_dict balancer_ewma_last_touched_at 10M;
lua_shared_dict balancer_ewma_locks 1M;
lua_shared_dict certificate_data 20M;
lua_shared_dict certificate_servers 5M;
lua_shared_dict configuration_data 20M;
lua_shared_dict global_throttle_cache 10M;
lua_shared_dict ocsp_response_cache 5M;
---
Nginx Ingress Controller의 버전 확인
POD_NAMESPACE=ingress
POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app.kubernetes.io/name=ingress-nginx --field-selector=status.phase=Running -o name)
kubectl exec $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version
---
NGINX Ingress controller
Release: v1.11.2
Build: 46e76e5916813cfca2a9b0bfdc34b69a0000f6b9
Repository: https://github.com/kubernetes/ingress-nginx
nginx version: nginx/1.25.5
---
실습용 오브젝트 배포
cat <<EOT > svc1-pod.yml
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
EOT
cat <<EOT > svc2-pod.yml
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
EOT
cat <<EOT > svc3-pod.yml
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
EOT
배포
k apply -f svc1-pod.yml
k apply -f svc2-pod.yml
k apply -f svc3-pod.yml
정책 배포
Ingress 정책 생성 및 배포
cat <<EOT> 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:
- 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
EOT
k apply -f ingress1.yaml
생성확인
kubectl get ingress
---
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-1 nginx * 80 26s
---
kc describe ingress ingress-1
---
Name: ingress-1
Labels: <none>
Namespace: default
Address:
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
*
/ svc1-web:80 ()
/guest svc2-guest:8080 ()
/admin svc3-admin:8080 ()
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 40s nginx-ingress-controller Scheduled for sync
---
설정 반영 확인
kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf | grep 'location /' -A5
---
location /guest/ {
set $namespace "default";
set $ingress_name "ingress-1";
set $service_name "svc2-guest";
set $service_port "8080";
--
location /admin/ {
set $namespace "default";
set $ingress_name "ingress-1";
set $service_name "svc3-admin";
set $service_port "8080";
--
location / {
set $namespace "default";
set $ingress_name "ingress-1";
set $service_name "svc1-web";
set $service_port "80";
--
location /healthz {
access_log off;
return 200;
}
--
location /nginx_status {
allow 127.0.0.1;
allow ::1;
---
접속테스트
echo -e "Ingress1 sv1-web URL = http://$(curl -s ipinfo.io/ip):30080"
echo -e "Ingress1 sv2-guest URL = http://$(curl -s ipinfo.io/ip):30080/guest"
echo -e "Ingress1 sv3-admin URL = http://$(curl -s ipinfo.io/ip):30080/admin"
X-Forwarded-For / X-Forwarded-Proto 헤더?
X-Forwarded-For 는 클라이언트 IP를 포함하여 거쳐가는 환경에 대한 IP를 저장합니다.
X-Forwarded-Proto 는 프로토콜이 변하기 전 정보를 저장합니다.
X-Forwarded-For의 헤더는 Client Ip, Proxy(LB), Proxy(LB)… 등등 ,(콤마)로 구분되어 순차 기록되는데요.
어플리케이션에서 실제 클라이언트의 IP를 알고자 한다면, Client IP가 가장 먼저 오기 때문에 첫번째로 오는 IP로 구분을 하도록 작성합니다.
이 부분은 AccessLog 설정에도 사용한다면 정확한 클라이언트의 Ip 확인이 가능합니다.