Ingress 는 L7 네트워크 레이어에서 작동하는 로드 밸런서이다. 인그레스는 Service 종류의 하나가 아니라, 정해진 규칙에 따라 여러 Service들로 라우팅을 해주는 독립적인 리소스이다.
인그레스는 인그레스 리소스만을 가리키는 말이 아니라, Ingress 리소스 + Ingress 컨트롤러 + Ingress 클래스를 포괄하는 용어이다. 각각은 아래와 같은 역할을 한다.
- Ingress 리소스: 매니페스트에 라우팅 규칙을 등록하여 API 를 분산
- Ingress 컨트롤러: Ingress 리소스를 기반으로 실제 로드 밸런서를 생성하며, Ingress 리소스를 감시하여 변경된 사항을 로드 밸런서에 반영
- Ingress 클래스: Ingress 컨트롤러가 어떤 Ingress 리소스를 감시/처리할지의 기준을 명시하는 리소스
인그레스에는 크게 두가지 타입이 존재하는데, 하나는 클라우드 프로바이더에서 제공하는 인그레스로, k8s 클러스터 외부 로드 밸런서를 사용하는 인그레스이고, 또 하나는 k8s 클러스터 내부에 자체적으로 인그레스용 파드를 띄워서 사용하는 인그레스이다.
| 종류 | 전달순서 | 예시 |
| 클러스터 외부 로드 밸런서를 사용한 인그레스 | 클라이언트 -> 외부 L7 로드 밸런서(인그레스) -> NodePort 서비스 -> 목적지 파드 | GKE 인그레스 |
| 클러스터 내부 파드를 사용한 인그레스 | 클라이언트 -> 내부 L4 LoadBalancer 서비스 -> 인그레스 파드(L7) -> 목적지 파드 | Nginx 인그레스 |
Public Cloud Provider Ingress

Nginx Pod Ingress

우리는 ingress-nginx 를 사용하는 방법을 알아본다.
1. nginx 인그레스 컨트롤러 설치
https://github.com/kubernetes/ingress-nginx/blob/main/docs/deploy/index.md#bare-metal-clusters 을 참고하여 설치
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.14.1/deploy/static/provider/baremetal/deploy.yaml
단, 기본적으로 NodePort 서비스가 생성되는데, 자동으로 30000-32767 사이의 포트를 할당받고, Node IP 의 해당 포트로 호출하여야 한다. 아래 커맨드로 생성된 NodePort 서비스를 확인한다.
$ kubectl -n ingress-nginx get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.110.81.89 <none> 80:32321/TCP,443:32165/TCP 23s
ingress-nginx-controller-admission ClusterIP 10.110.134.192 <none> 443/TCP 23s
아래 커맨드로 Ingress 디플로이먼트, 레플리카셋, 파드를 확인한다.
$ kubectl -n ingress-nginx get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
ingress-nginx-controller 1/1 1 1 2m51s
$ kubectl -n ingress-nginx get rs
NAME DESIRED CURRENT READY AGE
ingress-nginx-controller-68f58fbbcc 1 1 1 3m17s
$ kubectl -n ingress-nginx get pods
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-68f58fbbcc-2tqhj 1/1 Running 0 4m27s
2. LoadBalancer 를 사용하기 위해 metallb 설치
https://github.com/kubernetes/ingress-nginx/blob/main/docs/deploy/baremetal.md#a-pure-software-solution-metallb 을 참고하여 metallb를 설치한다.
# 1) kube-proxy IPVS 모드를 사용하는 경우 strick ARP 모드 활성화
$ kubectl edit configmap -n kube-system kube-proxy
# mode: "ipvs" 로 수정
# ipvs.strictARP: true 로 수정
# 아래 커맨드로 바로 수정도 가능
# see what changes would be made, returns nonzero returncode if different
$ kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl diff -f - -n kube-system
# actually apply the changes, returns nonzero returncode on errors only
$ kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system
# 2) manifest 를 사용하여 metallb 설치
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml
3. IPAddressPool, L2Advertisement 리소스 생성
아래 매니페스트로 LoadBalancer 생성에 필요한 IPAddressPool, L2Advertisement 를 생성한다.
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 203.0.113.10-203.0.113.15
autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
단, IPAddressPool 의 spec.addresses 의 IP 대역은 실제 사용하지 않고있고, 앞으로도 사용할 가능성이 없는 대역으로 지정해야 한다.
아래 커맨드를 참고하여 사용하지 않는 IP 를 확인한다.
# 1) 현재 노드가 속한 네트워크 대역 확인
$ ip -4 addr
...
inet 172.30.1.3/24
...
# 2) 현재 네트워크에서 이미 사용중인 IP 확인
$ sudo apt install -y arp-scan
$ sudo arp-scan 172.30.1.0/24
# 3) DHCP가 사용하는 범위 확인
# 공유기/라우터 관리 페이지 DHCP 설정 대역 확인
3. LoadBalancer 생성
아래 커맨드를 실행해서 기본 서비스 타입인 NodePort 가 아닌 LoadBalancer 타입으로 서비스를 띄워줘야 함.(공식 제공되는 ingress-nginx-controller 초기 yaml 에는 NodePort 로 지정되어있기 때문)
$ kubectl -n ingress-nginx patch svc ingress-nginx-controller -p '{"spec":{"type":"LoadBalancer"}}'
4. Backend 파드와 서비스 생성
아래 매니페스트로 파드와 서비스를 생성한다.
---
apiVersion: v1
kind: Service
metadata:
name: sample-ingress-svc-1
spec:
type: NodePort
ports:
- name: "http-port"
protocol: "TCP"
port: 8888
targetPort: 80
selector:
ingress-app: sample1
---
apiVersion: v1
kind: Pod
metadata:
name: sample-ingress-apps-1
labels:
ingress-app: sample1
spec:
containers:
- name: nginx-container
image: nginx:1.27
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: sample-ingress-svc-2
spec:
type: NodePort
ports:
- name: "http-port"
protocol: "TCP"
port: 8888
targetPort: 80
selector:
ingress-app: sample2
---
apiVersion: v1
kind: Pod
metadata:
name: sample-ingress-apps-2
labels:
ingress-app: sample2
spec:
containers:
- name: nginx-container
image: nginx:1.27
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: sample-ingress-default
spec:
type: NodePort
ports:
- name: "http-port"
protocol: "TCP"
port: 8888
targetPort: 80
selector:
ingress-app: default
---
apiVersion: v1
kind: Pod
metadata:
name: sample-ingress-default
labels:
ingress-app: default
spec:
containers:
- name: nginx-container
image: nginx:1.27
ports:
- containerPort: 80
5. ingress 리소스 생성
아래 매니페스트로 인그레스 리소스를 생성한다. 리소스가 생성되면 인그레스 컨트롤러가 자동으로 읽어 인그레스 디플로이먼트 파드에서 라우팅이 된다.
Ingress 는 기본적으로 http 요청을 https 로 리다이렉트 해주는데 nginx.ingress.kubernetes.io/ssl-redirect: "false" 어노테이션을 주어 비활성화 한다. spec.ingressClassName 항목은 ingressClass 를 지정하는 항목인데, 기본적으로 생성되는 ingressClass인 nginx 를 지정하면 된다. spec.defaultBackend 에 지정한 서비스는 매칭되는 경로가 없을 때 라우팅되는 서비스이다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sample-ingress-by-nginx
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: sample.example.com
http:
paths:
- path: /path1/
pathType: Prefix
backend:
service:
name: sample-ingress-svc-1
port:
number: 8888
- path: /path2/
pathType: Prefix
backend:
service:
name: sample-ingress-svc-2
port:
number: 8888
defaultBackend:
service:
name: sample-ingress-default
port:
number: 8888
tls:
- hosts:
- sample.example.com
secretName: tls-sample
spec.rules[].http.paths[].pathType 항목은 요청 URL 의 path 를 어떤 방식으로 매칭할 것인지를 정의한다. Ingress Controller 는 이 설정을 기반으로 어느 backend service 로 라우팅할지 결정한다.
값별 설명은 아래와 같다.
| pathType | 매칭 방식 | 정밀도 | 실무 사용 | 특이사항 |
| Exact | 정확히 일치 | 가장 엄격 | 드물게 사용 health check 엔드포인트 등 특수한 경우 |
trailing slash 도 엄격히 비교 |
| Prefix | URL prefix | 일반적 | 권장 | "/" 를 구분자로 path segment 를 분리하여 전방 일치 판단. 즉, "/api" 인 경우 "/apis" 는 매칭되지 않음. 여러 prefix 가 중복된 경로를 가진 경우, path segment 가 긴 path 일수록 우선순위 높음 |
| ImplementationSpecific | 컨트롤러에 따라 다름 | 불명확 | 비권장 | 컨트롤러 교체시 동작 변경 위험 |
6. 확인
# 각 노드의 IP 확인
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master01 Ready control-plane 172m v1.31.3 192.168.64.5 <none> Ubuntu 24.04.3 LTS 6.8.0-90-generic containerd://1.7.28
worker01 Ready <none> 144m v1.31.14 192.168.64.6 <none> Ubuntu 24.04.3 LTS 6.8.0-90-generic containerd://1.7.28
worker02 Ready <none> 136m v1.31.14 192.168.64.7 <none> Ubuntu 24.04.3 LTS 6.8.0-90-generic containerd://1.7.28
# ingress 컨트롤러로 접근할 수 있는 IP 확인(worker02 의 IP 가 확인되는데, 이는 진입점이 worker02 에 떠있는 NodePort 서비스가 된다는 소리임)
$ kubectl get ingresses
NAME CLASS HOSTS ADDRESS PORTS AGE
sample-ingress-by-nginx nginx sample.example.com 192.168.64.7 80, 443 3m41s
# (NodePort 로 사용하는 경우)NodePort 서비스이기 때문에 NodePort 의 Port 를 확인하여야 함
$ kubectl -n ingress-nginx get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.108.27.225 <none> 80:30329/TCP,443:32630/TCP 115m
ingress-nginx-controller-admission ClusterIP 10.97.149.209 <none> 443/TCP 115m
# LoadBalancer 서비스로 바꾼 후에는 EXTERNAL-IP 로 바로 접속하여야 함
$ kubectl -n ingress-nginx get svc ingress-nginx-controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.108.27.225 203.0.113.10 80:30329/TCP,443:32630/TCP 3h59m
# LoadBalancer IP를 변수로 저장
INGRESS_LB_IP=`kubectl -n ingress-nginx get svc ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'`
# 경로별 라우팅 확인
curl http://${INGRESS_LB_IP}/path1/ -H "Host: sample.example.com"
curl http://${INGRESS_LB_IP}/path2/ -H "Host: sample.example.com"
curl http://${INGRESS_LB_IP}/ -H "Host: sample.example.com"
IngressClass 란?
Ingress Controller 가 Ingress 리소스를 식별하는 기준이 된다. 아래와 같은 매니페스트로 생성한다.
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx-external
spec:
controller: example.com/ingress-nginx-external
| 항목명 | 의미 |
| metadata.name | 인그레스 클래스명. 인스레스 리소스에 spec.ingressClassName 을 지정하고, 인그레스 컨트롤러 파드에서 --ingress-class 옵션으로 추가하여 컨트롤러(파드)가 어떤 인그레스 리소스를 감시/처리할지 판단하는 기준이 됨 |
| spec.controller | 어떤 인그레스 컨트롤러가 사용할지 명시하는 고유 문자열 |
이렇게 생성한 IngressClass명을 Ingress 리소스의 spec.ingressClassName 에 지정해주고, Ingress Controller 에 어떤 IngressClass 를 감시/처리 실행 옵션으로 아래와 같이 지정한다. Ingress Controller 는 보통 Deployment 로 관리되는 Pod 이므로, Pod Template 의 spec.containers[].args 에 아래와 같이 지정하면 된다.
# ingress-nginx 기준 예시
...
args:
- /nginx-ingress-controller
- --controller-class=example.com/ingress-nginx-external
- --ingress-class=nginx-external
- --watch-ingress-without-class=false
옵션의 의미
| 옵션명 | 의미 |
| /nginx-ingress-controller | 컨테이너 내부 실행 바이너리 |
| --controller-class | IngressClass 리소스의 spec.controller 와 매칭 |
| --ingress-class | Ingress 리소스의 spec.ingressClassName 와 매칭 |
| --watch-ingress-without-class=false | class 없는 ingress 무시(운영 권장) |
'Kubernetes' 카테고리의 다른 글
| [Kubernetes] Secret 이해 (0) | 2026.01.07 |
|---|---|
| [Kubernetes] 파드에 환경 변수 주입하는 5가지 방법 (0) | 2026.01.07 |
| [Kubernetes] None-Selector 서비스(외부 서비스로의 로드 밸런싱) (0) | 2025.12.05 |
| [Kubernetes] ExternalName 서비스(클러스터 내부에서 외부 도메인의 CNAME 사용하기) (0) | 2025.12.05 |
| [Kubernetes] 헤드리스 서비스(개별 파드를 서비스로 노출하기) (0) | 2025.12.05 |
