티스토리 뷰
쿠버네티스 실습: Nginx Ingress Controller와 Nginx Proxy Manager로 외부 접근 구성하기
octo54 2025. 8. 28. 11:54쿠버네티스 실습: Nginx Ingress Controller와 Nginx Proxy Manager로 외부 접근 구성하기
앞선 글에서는 Redis를 쿠버네티스에 배포하고 NestJS 애플리케이션에서 캐시 레이어로 활용하는 방법을 실습했습니다.
이번 글에서는 외부 사용자가 도메인으로 서비스에 접근할 수 있도록 Nginx Ingress Controller를 설치하고, Nginx Proxy Manager를 이용해 SSL(HTTPS)까지 적용하는 방법을 다룹니다.
1) 왜 Ingress인가?
쿠버네티스에서 **Service(NodePort, LoadBalancer)**만으로도 외부 노출이 가능합니다.
하지만:
- NodePort는 포트 번호가 랜덤/불편합니다.
- LoadBalancer는 클라우드 환경에서만 유효합니다.
- 도메인 기반 라우팅, HTTPS 적용은 직접 관리해야 합니다.
Ingress는 이 문제를 해결합니다:
- 하나의 LoadBalancer로 여러 도메인을 라우팅
- 도메인별 라우팅 규칙 지정 가능
- TLS/SSL 적용 지원
2) Ingress Controller 설치
Minikube에서는 ingress 애드온을 켜는 게 가장 쉽습니다.
minikube addons enable ingress
kubectl get pods -n kube-system
출력 예시:
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-7c65d8d49d-abcde 1/1 Running 0 1m
이제 Ingress Controller가 준비되었습니다.
3) 예시 애플리케이션 배포 (NextJS/NestJS 서비스)
우리가 이미 배포한 NestJS와 NextJS 서비스가 있다고 가정합니다.
서비스 이름이 다음과 같다고 해봅시다:
- nestjs-svc (port 3000)
- nextjs-svc (port 3000)
4) Ingress 리소스 작성
app-ingress.yaml 작성:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: nest.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nestjs-svc
port:
number: 3000
- host: next.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nextjs-svc
port:
number: 3000
적용:
kubectl apply -f app-ingress.yaml
kubectl get ingress
출력 예시:
NAME CLASS HOSTS ADDRESS PORTS AGE
app-ingress nginx nest.local,next.local 192.168.49.2 80 30s
5) 로컬 도메인 매핑
맥북/맥미니의 /etc/hosts 파일에 다음을 추가:
192.168.49.2 nest.local next.local
192.168.49.2는 minikube ip로 확인하세요.
이제 브라우저에서:
- http://nest.local → NestJS 서비스
- http://next.local → NextJS 서비스
6) Nginx Proxy Manager로 SSL 적용
Ingress만으로도 TLS는 적용 가능합니다. 하지만 UI 기반 관리를 원한다면 **Nginx Proxy Manager(NPM)**를 추가로 붙일 수 있습니다.
6-1. Nginx Proxy Manager 배포 (예시 Deployment)
apiVersion: apps/v1
kind: Deployment
metadata:
name: npm
spec:
replicas: 1
selector:
matchLabels:
app: npm
template:
metadata:
labels:
app: npm
spec:
containers:
- name: npm
image: jc21/nginx-proxy-manager:2
ports:
- containerPort: 81 # 관리 UI
- containerPort: 80 # HTTP
- containerPort: 443 # HTTPS
Service:
apiVersion: v1
kind: Service
metadata:
name: npm
spec:
type: NodePort
selector:
app: npm
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
- name: https
port: 443
targetPort: 443
nodePort: 30443
- name: admin
port: 81
targetPort: 81
nodePort: 30081
적용:
kubectl apply -f npm-deployment.yaml
kubectl apply -f npm-service.yaml
6-2. 접속 확인
minikube service npm --url
브라우저에서 접속 → Nginx Proxy Manager UI를 통해 도메인 추가 + SSL(Let’s Encrypt) 설정 가능.
7) 정리
- Minikube Ingress 애드온을 활성화하여 도메인 기반 라우팅 구현.
- /etc/hosts 수정으로 로컬에서도 도메인 기반 접근 가능.
- Nginx Proxy Manager를 추가하면 UI에서 SSL 발급과 프록시 설정을 관리할 수 있음.
다음 글에서는 CI/CD 파이프라인을 연결하여 코드 푸시 시 자동으로 NestJS/NextJS 이미지를 빌드하고, 쿠버네티스에 배포되는 워크플로우를 구성해보겠습니다.
쿠버네티스,Ingress,Nginx,프록시,NginxProxyManager,Minikube,도메인매핑,SSL,클라우드네이티브,K8s실습
바로 고칠 것 (핵심 4가지)
- 컨트롤러 확인 네임스페이스
minikube addons enable ingress 이후 컨트롤러 파드는 ingress-nginx 네임스페이스에 뜹니다.
# 기존: kubectl get pods -n kube-system (X)
kubectl get pods -n ingress-nginx # 이것이 정답
(쿠버네티스 공식 튜토리얼이 -n ingress-nginx로 안내합니다.) (Kubernetes)
- Ingress에 ingressClassName 지정
요즘은 주로 spec.ingressClassName: nginx를 씁니다(예전 annotation 방식은 점차 폐기).
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
ingressClassName: nginx # 추가
rules:
...
(ingress-nginx는 kubernetes.io/ingress.class: "nginx" 또는 ingressClassName: nginx를 인식합니다.) (kubernetes.github.io)
- rewrite-target 주석은 불필요(오히려 혼동)
현재 경로가 둘 다 / 인 단순 라우팅이라면 nginx.ingress.kubernetes.io/rewrite-target: / 없애세요. 이 주석은 보통 /app(/|$)(.*)처럼 캡처 그룹을 써서 하위 경로를 /로 재작성할 때 필요합니다. 불필요한 rewrite는 디버깅을 어렵게 만듭니다. (공식 예제 확인) (kubernetes.github.io)
- 로컬 도메인: /etc/hosts 외에 대안도 소개
/etc/hosts는 맞는 방법이지만, Minikube에는 ingress-dns 애드온이 있어 /etc/hosts 편집 없이도 로컬 DNS로 Ingress 호스트를 해석하게 할 수 있습니다(원리: 질의 시 Ingress 목록을 조회). 선택지로 한 줄 소개해 두면 좋아요. (minikube)
Nginx Proxy Manager(NPM) 관련 현실 체크 (2가지)
- 로컬 Minikube에서 Let’s Encrypt 발급 한계
NPM UI에서 Let’s Encrypt HTTP-01로 발급하려면 공인 DNS가 실제로 외부에서 접근 가능한 IP로 향하고, 방화벽/포트80이 열려 있어야 합니다. 로컬 Minikube(NodePort 30080/30443 등)로는 일반적으로 검증이 통과하지 않습니다. 이런 경우는
- DNS-01(TXT 레코드)로 검증하거나,
- 자체 서명/사내 CA로 테스트용 인증서를 만들어 Ingress에 붙이는 편이 현실적입니다. (letsencrypt.org, Let's Encrypt Community Support, docs.certifytheweb.com)
실습 난이도를 낮추려면: cert-manager로 self-signed(또는 staging) 발급 → Ingress에 TLS Secret 연결 방식을 권장합니다. 설치 한 줄:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.18.2/cert-manager.yaml (cert-manager)
Ingress에 수동으로 자체 서명 키/인증서를 넣을 때는 다음처럼 만듭니다:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt -subj "/CN=nest.local/O=nest.local" \
-addext "subjectAltName = DNS:nest.local,DNS:next.local"
kubectl create secret tls app-tls --cert=tls.crt --key=tls.key
(이후 Ingress spec.tls에 secretName: app-tls 추가) (kubernetes.github.io, Kubernetes)
- NPM 배포 시 영속 볼륨 필수
jc21/nginx-proxy-manager는 /data(설정/DB)와 /etc/letsencrypt(인증서) 볼륨이 필요합니다. 질문의 Deployment에는 볼륨이 없어 재시작 시 설정이 유실됩니다. PVC 또는 hostPath를 마운트하세요(프로젝트 가이드/풀 셋업 문서 참고). (nginxproxymanager.com)
예) (요지)
volumeMounts:
- name: data
mountPath: /data
- name: letsencrypt
mountPath: /etc/letsencrypt
volumes:
- name: data
persistentVolumeClaim:
claimName: npm-data
- name: letsencrypt
persistentVolumeClaim:
claimName: npm-le
보너스 팁
- TLS를 Ingress에서 바로 종료: 운영/표준 패턴은 보통 ingress-nginx + cert-manager 조합입니다. NPM을 추가 프록시로 두면 레이어가 겹쳐 관리 복잡도가 증가합니다(반드시 UI가 필요할 때만 채택). (NGINX 문서, cert-manager)
- Ingress 동작 확인 포인트: 컨트롤러는 80/443을 리슨하며 호스트 헤더 일치가 중요합니다. 접근 실패 시 kubectl logs -n ingress-nginx deploy/ingress-nginx-controller로 규칙 매칭을 먼저 확인하세요. (minikube)
최소 수정본 요약
- 컨트롤러 확인: kubectl get pods -n ingress-nginx (네임스페이스 수정). (Kubernetes)
- Ingress에 spec.ingressClassName: nginx 추가. (kubernetes.github.io)
- rewrite-target 주석 제거(현재 규칙에서는 불필요). (kubernetes.github.io)
- 로컬 도메인: /etc/hosts 또는 minikube addons enable ingress-dns 소개. (minikube)
- NPM로 HTTPS 발급은 로컬에서 HTTP-01이 어려움 → cert-manager/DNS-01/자체서명으로 실습. (letsencrypt.org, Let's Encrypt Community Support, cert-manager)
- NPM에 /data, /etc/letsencrypt 볼륨 추가. (nginxproxymanager.com)
'project > 맥미니로 시작하는 쿠버네티스' 카테고리의 다른 글
| 쿠버네티스 실습: Horizontal Pod Autoscaler(HPA)로 오토스케일링 구현하기 (0) | 2025.09.02 |
|---|---|
| 쿠버네티스 실습: GitHub Actions로 CI/CD 파이프라인 구축하기 (0) | 2025.08.29 |
| 쿠버네티스 실습: Redis 배포와 NestJS 애플리케이션 연동 (0) | 2025.08.27 |
| 쿠버네티스 실습: StatefulSet으로 PostgreSQL 배포하기 (PVC 연동) (0) | 2025.08.26 |
| 쿠버네티스 실습: PersistentVolume과 PersistentVolumeClaim으로 데이터 저장하기 (0) | 2025.08.25 |
- Total
- Today
- Yesterday
- Python
- flax
- kotlin
- CI/CD
- NestJS
- Redis
- 쿠버네티스
- REACT
- Express
- 생성형AI
- ai철학
- Docker
- 딥러닝
- DevOps
- llm
- Next.js
- 웹개발
- 백엔드개발
- SEO최적화
- nextJS
- JWT
- fastapi
- PostgreSQL
- node.js
- 개발블로그
- rag
- LangChain
- seo 최적화 10개
- Prisma
- JAX
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |

