Ingress
Ingress는 클러스터 외부에서 내부 서비스로 들어오는 HTTP/HTTPS 트래픽을 관리하는 리소스이다.
단순히 외부 요청을 내부 서비스로 전달하는 것 뿐 아니라, 도메인(URL) 기반 라우팅, SSL, 리버스 프록시 기능 등을 제공한다.
👉 서비스들에 대한 단일 진입점을 만들어 내부의 서비스를 외부에서 접속 가능하도록 해준다.
- L7 스위치 역할을 논리적으로 수행 (Application LB, ALB)
- 클러스터로 접근하는 URL 별로 다른 서비스에 트래픽을 분산
- Ingress 기능
- Service에 외부 URL 제공
- 트래픽을 로드밸런싱
- SSL 인증서 처리
- Virtual Hosting 지
Ingress를 사용하면,
LoadBalancer를 공유하여 비용 절감이 가능하며, TLS(SSL) 인증서 관리, 트래픽 라우팅 및 리다이렉션등이 설정 가능하다.
→ 하나의 LB로 여러 서비스를 도메인 또는 경로 기반으로 분배 가능하다.
기존의 서비스?
- ClusterIP: 내부 네트워크에서만 접근 가능 (외부에서 직접 접근 불가능)
- NodePort: 모든 노드의 특정 포트를 열어 외부에서 접근 가능 (포트 충돌 위험, 보안 취약 및 유지보수 어려움)
- LoadBalancer: 클라우드 제공 로드 밸런서(L4)를 사용하지만, 서비스마다 비용이 발생할 수 있음.
Ingress Controller
Ingress가 트래픽 라우팅 규칙을 정의하는 리소스라면, Ingress Controller는 Ingress 규칙을 실제로 실행하는 컨트롤러이다. (Ingress - 규칙 설정 / Ingress Controller - 실제 동작)
- Ingress controller가 있어야 Ingress를 충족할 수 있다. (https://kubernetes.github.io/ingress-nginx/deploy/)
단순히 인그레스 리소스만 생성한다면 효과가 없다. - 만약 Ingress Controller가 설치되어 있지 않으면 트래픽을 처리할 Endpoint가 없기 때문에 Ingress의 ADDRESS가 NULL이 된다.
- Kubernetes as a project supports and maintains AWS, GCE, and nginx ingress controllers
# ingress controller 배포
controlplane:~$ helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
Release "ingress-nginx" does not exist. Installing it now.
NAME: ingress-nginx
LAST DEPLOYED: Fri Feb 28 16:15:05 2025
NAMESPACE: ingress-nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
# 또는 하기 명령어로 배포
controlplane:~$ #kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml
controlplane:~$ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-cd9d6bbd7-vq75w 1/1 Running 0 57s
서비스 Rule을 지정해서 Ingress Controller에 넣는다.
그러면 사용자가 도메인에 요청을 보내면 Ingress Controller가 요청을 받아 분석하고,
설정된 Ingress Rule에 따라 적절한 서비스로 전달한다.
ex] Multi Path
http://www.examle.com/ -->svc Main
http://www.examle.com/login -->svc Login
http://www.examle.com/order -->svc Order
외부 클라이언트의 접속 URL이 뭔지에 따라 연결되는 Service가 다르다.
Ingress Resource
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
spec:
ingressClassName: nginx-example
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80
Ingress 생성 명령어
# 형식
# kubectl create ingress <ingress-name> --rule="host/path=service:port"
$ kubectl create ingress ingress-test --rule="wear.my-online-store.com/wear*=wear-service:80"
[ 실습 ]
1. nginx pod 구성하기
controlplane:~$ kubectl run nginx -n ingress-nginx --image=nginx --port 80 --labels=app=nginx
pod/nginx created
controlplane:~$ kubectl get pods -n ingress-nginx -L app
NAME READY STATUS RESTARTS AGE APP
ingress-nginx-controller-cd9d6bbd7-vq75w 1/1 Running 0 11m
nginx 0/1 ContainerCreating 0 7s nginx
2. appjs-service와 nginx 서비스는 이미 동작중이다.
controlplane:~$ kubectl get pods -n ingress-nginx -L app
NAME READY STATUS RESTARTS AGE APP
appjs-d2j47 1/1 Running 0 4m15s appjs
appjs-r7j8c 1/1 Running 0 4m15s appjs
appjs-spwsh 1/1 Running 0 4m15s appjs
ingress-nginx-controller-cd9d6bbd7-vq75w 1/1 Running 0 26m
nginx 1/1 Running 0 15m nginx
controlplane:~$ kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
appjs-service ClusterIP 10.105.112.152 <none> 80/TCP 21s
ingress-nginx-controller LoadBalancer 10.106.6.47 <pending> 80:31410/TCP,443:32406/TCP 26m
ingress-nginx-controller-admission ClusterIP 10.109.249.142 <none> 443/TCP 26m
nginx ClusterIP 10.96.173.231 <none> 80/TCP 12m
nginx-svc NodePort 10.103.20.8 <none> 80:31513/TCP 11m
controlplane:~$ kubectl get endpoints -n ingress-nginx
NAME ENDPOINTS AGE
appjs-service 192.168.1.11:80,192.168.1.12:80,192.168.1.13:80 28s
ingress-nginx-controller 192.168.1.5:443,192.168.1.5:80 26m
ingress-nginx-controller-admission 192.168.1.5:8443 26m
nginx 192.168.1.7:80 12m
nginx-svc 192.168.1.7:80 11m
3. Ingress Resource deploy
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: ingress-nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
rules:
- http:
paths:
- path: / # 모든 경로 의미
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
- path: /app
pathType: Prefix
backend:
service:
name: appjs-service
port:
number: 80
controlplane:~$ kubectl get ingress -n ingress-nginx
NAME CLASS HOSTS ADDRESS PORTS AGE
app-ingress <none> * 80 16s
controlplane:~$ kubectl describe ingress -n ingress-nginx
Name: app-ingress
Labels: <none>
Namespace: ingress-nginx
Address:
Ingress Class: <none>
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
*
/ nginx:80 (192.168.1.7:80)
/app appjs-service:80 (192.168.1.12:80,192.168.1.11:80,192.168.1.13:80)
Annotations: kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 27s nginx-ingress-controller Scheduled for sync
4. 동작 확인
controlplane:~$ curl node01:31513/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
[ 실습 ]
controlplane ~ ➜ kubectl get deploy -A
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
app-space default-backend 1/1 1 1 34s # application
app-space webapp-video 1/1 1 1 35s
app-space webapp-wear 1/1 1 1 35s
ingress-nginx ingress-nginx-controller 1/1 1 1 33s
kube-system coredns 2/2 2 2 3m58s
controlplane ~ ➜ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-zz8vf 0/1 Completed 0 66s
ingress-nginx-admission-patch-bvh5f 0/1 Completed 0 66s
ingress-nginx-controller-7f45764b55-6p74w 1/1 Running 0 66s
controlplane ~ ➜ kubectl get deploy -n ingress-nginx
NAME READY UP-TO-DATE AVAILABLE AGE
ingress-nginx-controller 1/1 1 1 3m39s
controlplane ~ ➜ kubectl get ingress -A
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
app-space ingress-wear-watch <none> * 172.20.101.15 80 5m24s
- Rule 확인
controlplane ~ ➜ kubectl describe ingress ingress-wear-watch -n app-space
Name: ingress-wear-watch
Labels: <none>
Namespace: app-space
Address: 172.20.101.15
Ingress Class: <none>
Default backend: <default> # Rule이 매치가 안된다면 여기를 참고한다.
Rules:
Host Path Backends
---- ---- --------
*
/wear wear-service:8080 (172.17.0.5:8080)
/watch video-service:8080 (172.17.0.6:8080)
Annotations: nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: false
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 7m53s (x2 over 7m53s) nginx-ingress-controller Scheduled for sync
# <default>라고 되어있어 확인이 불가능하다면 controller에서 확인 가능하다 -> default-backend-service
controlplane ~ ➜ kubectl get deploy ingress-nginx-controller -n ingress-nginx -o yaml | grep -i default
- --default-backend-service=app-space/default-backend-service
schedulerName: default-scheduler
defaultMode: 420
- Rule 변경
# ingress에서 룰 수정하기
kubectl edit ingress ingress-wear-watch -n app-space
- backend:
service:
name: video-service
port:
number: 8080
path: /stream # 이렇게 수정해보기
pathType: Prefix
- 기존의 Ingress에 새로운 서비스 추가하기
controlplane ~ ➜ kubectl get deploy -n app-space
NAME READY UP-TO-DATE AVAILABLE AGE
default-backend 1/1 1 1 19m
webapp-food 1/1 1 1 28s
webapp-video 1/1 1 1 19m
webapp-wear 1/1 1 1 19m
controlplane ~ ➜ kubectl get svc -n app-space
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default-backend-service ClusterIP 172.20.83.127 <none> 80/TCP 19m
food-service ClusterIP 172.20.55.63 <none> 8080/TCP 55s
video-service ClusterIP 172.20.219.151 <none> 8080/TCP 19m
wear-service ClusterIP 172.20.25.205 <none> 8080/TCP 19m
controlplane ~ ➜ kubectl edit ingress ingress-wear-watch -n app-space
ingress.networking.k8s.io/ingress-wear-watch edited
- backend:
service:
name: wear-service
port:
number: 8080
path: /wear
pathType: Prefix
- backend:
service:
name: video-service
port:
number: 8080
path: /stream
pathType: Prefix
- backend: # 새로 추가된 부분
service:
name: food-service
port:
number: 8080
path: /eat
pathType: Prefix
- 다른 네임스페이스에 존재하는 서비스라면 ingress를 따로 만들어 주는 것이 좋다.
controlplane ~ ➜ kubectl get svc -n critical-space
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
pay-service ClusterIP 172.20.122.165 <none> 8282/TCP 2m33s
controlplane ~ ➜ kubectl create ingress ingress-pay -n critical-space --rule="/pa
y=pay-service:8282"
ingress.networking.k8s.io/ingress-pay created
controlplane ~ ➜ kubectl get ingress -n critical-space
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-pay <none> * 80 10s
controlplane ~ ➜ kubectl describe ingress -n critical-space
Name: ingress-pay
Labels: <none>
Namespace: critical-space
Address:
Ingress Class: <none>
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
*
/pay pay-service:8282 (172.17.0.11:8080)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 25s nginx-ingress-controller Scheduled for sync
- "GET /pay HTTP/1.1" 404 - 이런 에러가 발생한다면?
- nginx.ingress.kubernetes.io/rewrite-target 어노테이션은 Ingress에서 들어오는 요청의 URL 경로를 변경하는 기능을 제공한다.
controlplane ~ ➜ kubectl edit ingress ingress-pay -n critical-space
..
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # 이 부분을 추가해 주어야 한다.
# /로 변경 → pay-service의 루트 경로(/)로 전달됨.
# 요청: http://example.com/pay
# 변경됨: /
# 백엔드: http://pay-service/
controlplane ~ ➜ kubectl logs webapp-pay-6888bbb889-8rf5q -n critical-space
* Serving Flask app 'app' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on all addresses.
WARNING: This is a development server. Do not use it in a production deployment.
* Running on http://172.17.0.11:8080/ (Press CTRL+C to quit)
172.17.0.9 - - [08/Feb/2025 12:03:24] "GET /pay HTTP/1.1" 404 - # Ingress를 통과했지만 백엔드 서비스에서 해당 경로(/pay)를 찾지 못함
172.17.0.9 - - [08/Feb/2025 12:06:54] "GET / HTTP/1.1" 200 - # 그래야 이렇게 해결됨!
# Ingress를 이용한 웹서비스 운영 실습
http://www.XXX/ --> svc marvel-service
http://www.XXX/pay --> svc pay-service
# ingress namespace 확인
[master ~/ingress]$kubectl get namespaces
NAME STATUS AGE
default Active 9d
gmp-public Active 9d
gmp-system Active 9d
ingress-nginx Active 50m
kube-node-lease Active 9d
kube-public Active 9d
kube-system Active 9d
[master ~/ingress]$kubectl get all -n ingress-nginx
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-admission-create-v8kkc 0/1 Completed 0 50m
pod/ingress-nginx-admission-patch-8zv6j 0/1 Completed 0 50m
pod/ingress-nginx-controller-654497b5fc-q65w8 1/1 Running 0 50m ## 동작 중 확인
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller LoadBalancer 10.8.11.186 34.30.207.184 80:32581/TCP,443:32714/TCP 50m
service/ingress-nginx-controller-admission ClusterIP 10.8.2.34 <none> 443/TCP 50m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ingress-nginx-controller 1/1 1 1 50m
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-nginx-controller-654497b5fc 1 1 1 50m
NAME COMPLETIONS DURATION AGE
job.batch/ingress-nginx-admission-create 1/1 7s 50m
job.batch/ingress-nginx-admission-patch 1/1 7s 50m
- 따배쿠 강의에서 제공해주는 Hub : https://hub.docker.com/search?q=smlinux
namespace를 default에서 ingress로 치환
root@master:~/ingress# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.107.101.97 <none> 80:31821/TCP,443:32755/TCP 49s
ingress-nginx-controller-admission ClusterIP 10.110.244.50 <none> 443/TCP 49s
root@master:~/ingress# kubectl get namespaces
NAME STATUS AGE
default Active 21m
ingress-nginx Active 57s
kube-node-lease Active 21m
kube-public Active 21m
kube-system Active 21m
root@master:~/ingress# kubectl get all -n ingress-nginx
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-admission-create-mzgm2 0/1 Completed 0 68s
pod/ingress-nginx-admission-patch-pc7f5 0/1 Completed 2 68s
pod/ingress-nginx-controller-5458dd5f6-zkd58 1/1 Running 0 68s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller NodePort 10.107.101.97 <none> 80:31821/TCP,443:32755/TCP 68s
service/ingress-nginx-controller-admission ClusterIP 10.110.244.50 <none> 443/TCP 68s
# 31821으로 들어오면 web기반 서비스를 ingress controller가 지원
# 32755로 들어오면 인증서 기반의 웹서비스를 지원해주도록 구성되어 있다.
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ingress-nginx-controller 1/1 1 1 68s
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-nginx-controller-5458dd5f6 1 1 1 68s
NAME COMPLETIONS DURATION AGE
job.batch/ingress-nginx-admission-create 1/1 16s 68s
job.batch/ingress-nginx-admission-patch 1/1 24s 68s
root@master:~/ingress# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.100.0.104:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
[master ~]$kubectl config set-context ingress-admin@kubernetes --cluster=kubernetes --user=kubernetes-admin --namespace ingress-nginx
Context "ingress-admin@kubernetes" created.
# context switch
[master ~]$kubectl config use-context ingress-admin@kubernetes
Switched to context "ingress-admin@kubernetes".
# 또는 하기 명령어 사용
[master ~]$kubectl config set-context --current --namespace=ingress-nginx
Context "gke_caramel-element-415606_us-central1-c_cluster-1" modified.
# 웹 서비스 동작
[master ~/ingress]$tree marvel-collection/
marvel-collection/
├── Dockerfile
└── html
├── images
│ ├── category.png
│ └── marvel_logo.png
└── index.html
2 directories, 4 files
[master ~/ingress]$cat pay.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: pay-rc
spec:
replicas: 3
template:
metadata:
labels:
app: pay
spec:
containers:
- image: smlinux/pay
name: pay
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: pay-service
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: pay
[master ~/ingress]$cat marvel-home.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: marvel-home
spec:
replicas: 1
selector:
matchLabels:
name: marvel
template:
metadata:
labels:
name: marvel
spec:
containers:
- image: smlinux/marvel-collection
name: marvel-container
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: marvel-service
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
name: marvel
[master ~/ingress]$kubectl apply -f marvel-home.yaml -f pay.yaml
deployment.apps/marvel-home created
service/marvel-service created
replicationcontroller/pay-rc created
service/pay-service created
# 서비스 확인
[master ~/ingress]$kubectl get all
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-admission-create-v8kkc 0/1 Completed 0 92m
pod/ingress-nginx-admission-patch-8zv6j 0/1 Completed 0 92m
pod/ingress-nginx-controller-654497b5fc-q65w8 1/1 Running 0 92m
pod/marvel-home-6b586d7bfc-jpbjw 1/1 Running 0 119s
pod/pay-rc-2f99n 1/1 Running 0 118s
pod/pay-rc-2ztdc 1/1 Running 0 118s
pod/pay-rc-zgjb5 1/1 Running 0 118s
NAME DESIRED CURRENT READY AGE
replicationcontroller/pay-rc 3 3 3 119s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller LoadBalancer 10.8.11.186 34.30.207.184 80:32581/TCP,443:32714/TCP 92m
service/ingress-nginx-controller-admission ClusterIP 10.8.2.34 <none> 443/TCP 92m
service/marvel-service ClusterIP 10.8.14.217 <none> 80/TCP 2m
service/pay-service ClusterIP 10.8.2.128 <none> 80/TCP 119s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ingress-nginx-controller 1/1 1 1 92m
deployment.apps/marvel-home 1/1 1 1 2m
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-nginx-controller-654497b5fc 1 1 1 92m
replicaset.apps/marvel-home-6b586d7bfc 1 1 1 2m
NAME COMPLETIONS DURATION AGE
job.batch/ingress-nginx-admission-create 1/1 7s 92m
job.batch/ingress-nginx-admission-patch 1/1 7s 92m
[master ~/ingress]$cat ingress_new.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: marvel-ingress
namespace: ingress-nginx
annotations:
kubernetes.io/ingress.class: nginx
spec:
defaultBackend:
service:
name: nginx
port:
number: 80
rules:
- host: node1.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: marvel-service
port:
number: 80
- host: node2.example.com
http:
paths:
- path: /pay
pathType: Prefix
backend:
service:
name: pay-service
port:
number: 80
[master ~/ingress]$kubectl create -f ingress_new.yaml
Warning: annotation "kubernetes.io/ingress.class" is deprecated, please use 'spec.ingressClassName' instead
ingress.networking.k8s.io/marvel-ingress created
[master ~/ingress]$kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
marvel-ingress <none> node1.example.com,node2.example.com 34.30.207.184 80 75s
[master ~/ingress]$kubectl describe ingress marvel-ingress
Name: marvel-ingress
Labels: <none>
Namespace: ingress-nginx
Address: 34.30.207.184
Ingress Class: <none>
Default backend: nginx:80 (<error: endpoints "nginx" not found>)
Rules:
Host Path Backends
---- ---- --------
node1.example.com
/ marvel-service:80 (10.4.0.23:80)
node2.example.com
/pay pay-service:80 (10.4.0.24:8080,10.4.1.15:8080,10.4.2.9:8080)
Annotations: kubernetes.io/ingress.class: nginx
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 20s (x2 over 61s) nginx-ingress-controller Scheduled for sync
참고 문서
'Container > Kubernetes' 카테고리의 다른 글
[K8S] Node Label & Selector (0) | 2024.03.17 |
---|---|
[K8S] 쿠버네티스 레이블 (0) | 2024.03.17 |
[K8S] Service (1) | 2024.03.05 |
[K8S] Cronjob Controller (0) | 2024.02.28 |
[K8S] Job Controller (0) | 2024.02.27 |