
지금까지 다룬 대부분의 서비스(ClusterIP, NodePort, LoadBalancer)는 L4(TCP/UDP) 계층에서 동작하는 로드밸런싱을 제공한다. 하지만 실제 웹 서비스 환경에서는 도메인 이름이나 URL 경로에 따라 트래픽을 나누는 정교한 규칙이 필요하다.
이번 포스트에서는 L7(HTTP/HTTPS) 계층에서 동작하며, 단일 진입점으로 여러 서비스를 라우팅할 수 있는 인그레스(Ingress)에 대해 정리한다.
참고: 인그레스는 서비스(Service)의 한 종류가 아니라, 독립적인 kind: Ingress 리소스이다. 또한 NetworkPolicy의 Ingress(수신 트래픽) 규칙과는 다른 개념이므로 혼동하지 말아야 한다.
애플리케이션을 외부에 노출하기 위해 NodePort나 LoadBalancer 서비스를 사용할 수 있다. 하지만 이 방식은 서비스가 늘어날 때마다 포트를 관리해야 하거나, 비싼 클라우드 로드밸런서 비용이 증가하는 단점이 있다.
인그레스(Ingress)는 클러스터 외부에서 내부로 들어오는 HTTP/HTTPS 트래픽을 처리하는 규칙들의 집합이다. 이를 통해 단 하나의 외부 IP 주소만으로 호스트나 경로에 따라 여러 서비스로 트래픽을 분산할 수 있다.
| 구분 | Service (NodePort/LB) | Ingress |
|---|---|---|
| 계층 | L4 (TCP/UDP) | L7 (HTTP/HTTPS) |
| 기능 | "단순 부하 분산, 포트 포워딩" | "URL 기반 라우팅, SSL/TLS 종료" |
| 특징 | 서비스마다 IP/포트 할당 필요 | 단일 IP로 여러 서비스 연결 가능 |
인그레스를 이해하기 위해서는 쿠버네티스의 리소스(Resource)와 컨트롤러(Controller) 모델을 알아야 한다. 인그레스 리소스를 생성한다고 해서 바로 접속이 되는 것이 아니라, 이를 실행해 줄 구현체가 필요하기 때문이다.
인그레스 리소스 (Ingress Resource):
사용자가 작성하는 YAML 파일(설계도).
"어떤 도메인(example.com)의 어떤 경로(/api)로 들어오면 A 서비스로 보내라"는 라우팅 규칙을 정의한다.
인그레스 컨트롤러 (Ingress Controller):
실제 작업을 수행하는 시스템(작업자).
리소스의 규칙을 감시하고 있다가, 실제 리버스 프록시 서버(Nginx, HAProxy 등)의 설정을 변경하고 리로드하여 트래픽을 처리한다.

인그레스 컨트롤러를 구성하는 방식은 크게 두 가지로 나뉜다.
사용자가 Ingress 리소스를 만들면, 클라우드 제공업체의 L7 로드밸런서(AWS ALB 등)가 자동으로 생성되어 연결된다.
특징: 간편하지만 클라우드 종속적이다.
클러스터 내부에 Nginx, Traefik, HAProxy 등 오픈소스 L7 로드밸런서를 파드(Pod) 형태로 직접 배포하여 사용한다.
트래픽 흐름: Client → External LB (Service) → Ingress Controller Pod → Target Pod
특징: 컨트롤러 파드가 목적지 파드로 트래픽을 보낼 때, 파드 IP로 직접 전송하므로 효율적이다. 또한, 트래픽 부하에 따라 인그레스 컨트롤러 파드의 수를 조절하는 오토스케일링(HPA) 사용을 고려해야 한다.


가장 널리 사용되는 Nginx Ingress Controller를 실습 환경에 배포해 본다. 공식적으로 제공되는 매니페스트를 사용하면 쉽게 설치할 수 있다.
# Nginx 인그레스 컨트롤러 설치
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.6.4/deploy/static/provider/cloud/deploy.yaml
설치 후 ingress-nginx 네임스페이스를 확인하여 컨트롤러 파드가 실행 중인지, 그리고 외부 접속을 위한 서비스(LoadBalancer 혹은 NodePort)가 생성되었는지 확인한다.
kubectl get all -n ingress-nginx
확인 사항: ingress-nginx-controller 서비스의 EXTERNAL-IP 또는 포트 번호.

간단한 웹 서버를 띄우고 인그레스를 통해 접속하는 기본 실습을 진행한다.
Deployment (deploy-test.yaml): Python을 이용한 간단한 HTTP 서버
Service (svc-test.yaml): 위 디플로이먼트를 80번 포트로 노출
#deploy-test.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: service-test
spec:
replicas: 3
selector:
matchLabels:
app: service_test_pod
template:
metadata:
labels:
app: service_test_pod
spec:
containers:
- name: simple-http
image: python:2.7
imagePullPolicy: IfNotPresent
command: ["/bin/bash"]
# -c "..." 안에 전체 명령을 넣고, SimpleHTTPServer에 포트 8080을 명시합니다.
args: ["-c", "echo '<p>Hello from $(hostname)</p>' > index.html; python -m SimpleHTTPServer 8080"]
ports:
- name: http
containerPort: 8080
# svc-test.yaml
apiVersion: v1
kind: Service
metadata:
name: service-test
spec:
selector:
app: service_test_pod
ports:
- protocol: TCP
port: 80
targetPort: 8080
ingress.test.com 이라는 도메인의 /test 경로로 들어오는 요청을 service-test 로 연결한다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
# 요청 경로를 재작성하는 규칙. /test로 들어온 요청의 /test 부분을 제거하고 백엔드로 전달한다.
nginx.ingress.kubernetes.io/rewrite-target: /
# 이 Ingress 규칙을 "nginx" 클래스의 컨트롤러가 처리하도록 지정한다.
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: "ingress.test.com" # 이 도메인으로 들어오는 요청에 대해
http:
paths:
- pathType: Prefix
path: /test # 이 경로로 시작하는 요청을
backend:
service:
name: service-test # 'service-test' 서비스의
port:
number: 80 # 80번 포트로 전달한다.
실제 도메인이 없으므로 로컬 호스트 파일이나 curl을 이용해 테스트한다.
1. 로컬 PC 호스트 매핑:
실제 도메인이 없으므로, 테스트를 위해 로컬 PC의 /etc/hosts 파일에 워커 노드의 IP와 Ingress에 설정한 호스트 이름을 매핑한다.
# /etc/hosts 파일
192.168.11.101 ingress.test.com
2. 포트번호 확인
Ingress 컨트롤러 서비스가 외부로 노출한 포트(NodePort)를 확인 (예: 80:30402/TCP ).
kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.101.89.165 192.168.11.101 80:30402/TCP,443:31940/TCP 40m
ingress-nginx-controller-admission ClusterIP 10.101.203.26 <none> 443/TCP 40m
3. 최종 요청:
curl을 사용하여 Ingress를 통해 서비스에 접근되는지 확인한다.
# <NodePort>는 2번 단계에서 확인한 포트 번호
curl http://ingress.test.com:30402/test
# 정상적으로 응답이 오면 성공!
<p>Hello from $(hostname)</p>
실무에서 가장 많이 쓰이는 두 가지 라우팅 패턴을 실습한다. 이를 위해 backend1 과 backend2 라는 두 개의 서로 다른 애플리케이션을 미리 배포해 둔다.
먼저 라우팅 테스트를 위한 두 개의 다른 백엔드 애플리케이션(Deployment)과 이를 연결하는 서비스(Service)를 배포한다.
ingress-resource.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend1
spec:
replicas: 2
selector:
matchLabels:
app: backend1
template:
metadata:
labels:
app: backend1
spec:
containers:
- name: backend1
image: nginxdemos/nginx-hello:plain-text
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: backend1-svc
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: backend1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend2
spec:
replicas: 1
selector:
matchLabels:
app: backend2
template:
metadata:
labels:
app: backend2
spec:
containers:
- name: backend2
image: nginxdemos/nginx-hello:plain-text
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: backend2-svc
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: backend2
위 파일을 적용하여 리소스를 생성한다.
kubectl apply -f ingress-resource.yaml
# 배포 확인
kubectl get pod,service
NAME READY STATUS RESTARTS AGE
pod/backend1-656f7c6885-949hn 1/1 Running 0 25s
pod/backend1-656f7c6885-s4pfw 1/1 Running 0 25s
pod/backend2-6c84bb867-w8kb2 1/1 Running 0 24s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/backend1-svc ClusterIP 10.110.34.95 <none> 80/TCP 6s
service/backend2-svc ClusterIP 10.101.54.17 <none> 80/TCP 5s
클라이언트가 요청한 도메인 이름(Host Header)에 따라 서로 다른 서비스로 연결한다.
example1.com → backend1-svc
example2.com → backend2-svc
# ingress-host-based.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: "example1.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend1-svc
port:
number: 80
- host: "example2.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend2-svc
port:
number: 80
실행 및 확인
1. Ingress 리소스 배포:
kubectl apply -f ingress-host-based.yaml
2. Ingress 상태 확인:
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-nginx <none> example1.com,example2.com 192.168.11.101 80 20m
3. Ingress Controller의 NodePort 확인:
kubectl get svc -n ingress-nginx (e.g., 80:30402/TCP)
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.101.89.165 192.168.11.101 80:30402/TCP,443:31940/TCP 59m
ingress-nginx-controller-admission ClusterIP 10.101.203.26 <none> 443/TCP 59m
4. 로컬 PC의 /etc/hosts 파일에 워커 노드 IP와 도메인 매핑 추가 (테스트 목적).
192.168.11.101 example1.com
192.168.11.101 example2.com
5. curl로 요청하여 라우팅 확인.
# backend1-svc로 라우팅되어야 함
curl example1.com:30402
# 실행결과
Server address: 10.244.2.20:8080
Server name: backend1-656f7c6885-s4pfw
Date: 22/Jul/2025:02:44:56 +0000
URI: /
Request ID: ec53759064d14a9d3c032cc624c4a98c
# backend2-svc로 라우팅되어야 함
curl example2.com:30402
# 실행결과
Server address: 10.244.1.23:8080
Server name: backend2-6c84bb867-w8kb2
Date: 22/Jul/2025:02:45:02 +0000
URI: /
Request ID: 05d53f02a3b4a0d2b7cc6e242f206701
테스트 결과: /etc/hosts 에 두 도메인을 모두 노드 IP로 등록한 후 curl을 보내면, 도메인에 따라 서로 다른 파드(backend1 또는 backend2)가 응답하는 것을 확인할 수 있다.
동일한 도메인 내에서 URL 경로(Path)에 따라 서비스를 분기한다.
example.com/backend1 → backend1
example.com/backend2 → backend2
# ingress-path-based.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: "example.com"
http:
paths:
- path: /backend1
pathType: Prefix
backend:
service:
name: backend1-svc
port:
number: 80
- path: /backend2
pathType: Prefix
backend:
service:
name: backend2-svc
port:
number: 80
실행 및 확인
1. Ingress 리소스 배포:
kubectl apply -f ingress-path-based.yaml
2. 로컬 PC의 /etc/hosts 파일에 매핑 추가.
192.168.11.101 example.com
3. curl로 요청하여 라우팅 확인.
# backend1-svc로 라우팅
curl example.com:30402/backend1
# 실행결과
Server address: 10.244.2.20:8080
Server name: backend1-656f7c6885-s4pfw
Date: 22/Jul/2025:02:53:31 +0000
URI: /
Request ID: cc22bbe3351412e5c8bd3891711a2b0c
# backend2-svc로 라우팅
curl example.com:30402/backend2
#실행결과
Server address: 10.244.1.23:8080
Server name: backend2-6c84bb867-w8kb2
Date: 22/Jul/2025:02:53:33 +0000
URI: /
Request ID: b3d18e917c68811ddcb136136247832f

테스트 결과: curl example.com:port/backend1 요청 시 backend1 파드가, /backend2 요청 시 backend2 파드가 응답한다. 이를 통해 마이크로서비스 아키텍처에서 API 게이트웨이와 같은 역할을 수행할 수 있다.
인그레스(Ingress)는 쿠버네티스 네트워크 환경에서 외부와 내부를 연결하는 가장 표준적인 방법이다.
효율성: 단일 IP/포트로 수많은 서비스를 관리한다.
유연성: 도메인 및 경로 기반의 섬세한 트래픽 제어가 가능하다.
확장성: SSL/TLS 보안 설정, 세션 고정 등 다양한 부가 기능을 인그레스 레벨에서 통합 관리할 수 있다.