내 컨테이너, 세상 밖으로! NodePort로 길을 열고, PV/PVC로 데이터를 지키는 방법 🚀
[들어가며: 쿠버네티스 실전 운영의 두 가지 큰 숙제!]
쿠버네티스 클러스터 위에 우리의 멋진 애플리케이션을 파드(Pod)로 띄웠다고 가정해보자. 여기서 우리는 두 가지 중요한 현실적인 문제에 부딪히게 돼.
- 외부 접속 문제: "클러스터 외부의 사용자들이 도대체 어떻게 이 파드에 접속할 수 있지?" 파드는 클러스터 내부에서만 통용되는 IP를 가지고, 언제든 사라졌다가 새로 생길 수 있는 임시적인 존재인데 말이야.
- 데이터 보존 문제: "만약 데이터를 저장하는 파드가 죽었다가 다시 살아나면, 그 안에 있던 중요한 데이터는 어떻게 되는 거지?" 컨테이너가 사라지면 데이터도 함께 사라지는 게 기본 원칙이라 큰일이지!
오늘 우리는 이 두 가지 숙제를 해결해 줄 똑똑한 해결사, 바로 쿠버네티스 서비스(Service), 그중에서도 NodePort 타입과, 영구적인 데이터 저장을 위한 **PV(PersistentVolume)**와 **PVC(PersistentVolumeClaim)**에 대해 자세히 알아볼 거야.
Part 1: 외부에서 파드에 접속하기 – Service(NodePort)와 로드 밸런서 🚪
파드는 직접 외부와 연결될 수 없기 때문에, 중간에 다리를 놓아주는 친구들이 필요해. 그 연결 흐름은 보통 이래.
외부 사용자 → 클라우드 로드 밸런서(AWS ELB 등) → 워커 노드의 특정 포트(NodePort) → 쿠버네티스 서비스 → 목적지 파드
이 흐름을 단계별로 실습해 보자.
1단계: 애플리케이션 배포 (Deployment 만들기)
먼저, 외부로 노출시킬 우리의 애플리케이션(여기서는 Tomcat WAS 서버)을 디플로이먼트(Deployment) 형태로 클러스터에 배포하자. tomcatdep.yaml 파일을 만들어봐.
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat
labels:
app: tomcat
spec:
replicas: 2
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: tomcatcontainer
image: tomcat:latest
- kind: Deployment: 파드와 레플리카셋(ReplicaSet)을 관리하는 오브젝트야. 파드가 죽으면 자동으로 다시 살려주는 등 안정적인 운영을 도와줘.
- replicas: 2: 동일한 톰캣 파드 2개를 실행하라는 의미.
- labels: app: tomcat: 이 디플로이먼트로 생성된 파드들에게 app=tomcat이라는 이름표를 붙여줘. 이 이름표는 나중에 서비스가 파드를 찾아올 때 사용돼.
2단계: 외부 접속 길 열기 (NodePort Service 만들기)
이제 디플로이먼트로 생성된 파드들을 외부와 연결해 줄 통로, 즉 **서비스(Service)**를 만들 차례야. 서비스 유형 중 NodePort는 외부에서 워커 노드의 IP와 특정 포트로 접근할 수 있게 해줘.
apiVersion: v1
kind: Service
metadata:
name: tc-svc
spec:
selector:
app: tomcat
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30000
type: NodePort
- selector: app: tomcat: 이름표가 app=tomcat인 파드들을 찾아 이 서비스와 연결하라는 의미.
- type: NodePort: 이 서비스의 타입을 NodePort로 지정.
- ports: 포트 설정이 조금 헷갈릴 수 있으니 잘 봐둬!
- port: 8080: 클러스터 내부에서 이 서비스가 사용할 포트 번호야.
- targetPort: 8080: 서비스가 트래픽을 전달할 목적지 파드(컨테이너)의 포트 번호야.
30000-32767 사이에서 지정돼.- nodePort: 30000: 클러스터의 모든 워커 노드에 개방될 외부 포트 번호야. 이 포트 범위는 보통
3단계: 외부 로드 밸런서 설정 (AWS 환경 예시)
이제 kubectl apply -f tomcatdep.yaml과 kubectl apply -f nodeport.yaml 명령으로 디플로이먼트와 서비스를 생성했어. 마지막으로 외부 사용자들이 쉽게 접속할 수 있도록 AWS 같은 클라우드 환경에서 **로드 밸런서(ELB/ALB)**를 설정해 주면 돼.
- 로드 밸런서의 **리스너(Listener)**는 보통 외부 사용자들이 접속하는 표준 포트(예: HTTP 80번)를 사용해.
- 로드 밸런서의 **대상 그룹(Target Group)**에는 우리 쿠버네티스 클러스터의
- 워커 노드들(w1, w2)을 등록하고, 대상 포트는 위에서 지정한 nodePort인 30000번으로 설정해 주는 거야.
이렇게 하면 외부 사용자가 로드 밸런서의 주소(예: http://my-tomcat.com)로 접속하면, 그 요청이 로드 밸런서를 거쳐 워커 노드의 30000번 포트로 전달되고, 최종적으로 우리 톰캣 파드의 8080번 포트까지 안전하게 도착하게 돼!
Part 2: 컨테이너 데이터를 영구적으로! – PV, PVC, 그리고 NFS 💾
컨테이너가 사라져도 데이터를 지키려면, 데이터를 컨테이너 바깥의 영구적인 저장 공간에 보관해야 해. 도커의 바인드 마운트나 볼륨 마운트와 비슷한 개념으로, 쿠버네티스에서는 **PV(PersistentVolume)**와 **PVC(PersistentVolumeClaim)**를 사용해.
이번 실습에서는 NFS(Network File System)를 영구 저장소로 사용해 볼 거야.
1단계: 스토리지 준비 (NFS 서버 설정)
먼저 클러스터의 컨트롤 플레인 노드(또는 별도의 스토리지 서버)에 NFS 서버를 간단히 구축하자.
# NFS 관련 유틸리티 설치
sudo dnf -y install nfs-utils [cite: 7875]
# 공유할 디렉터리 생성
sudo mkdir /nfs_shared [cite: 7876]
# NFS 공유 설정 파일에 내용 추가
# 10.0.1.28/20 대역에 /nfs_shared 디렉터리를 rw(읽기쓰기), sync, no_root_squash 옵션으로 공유
echo '/nfs_shared 10.0.1.28/20(rw,sync,no_root_squash)' | sudo tee -a /etc/exports [cite: 7877]
# NFS 서버 재시작 및 상태 확인
sudo systemctl restart nfs-server [cite: 7878]
sudo systemctl status nfs-server [cite: 7879]
# 공유 상태 확인
sudo exportfs -v [cite: 7880]
2단계: PersistentVolume (PV) 생성하기 – 관리자가 저장 공간 "제공"
PV는 클러스터 관리자가 미리 준비해 둔 실제 저장 공간의 조각이야. 이건 개발자가 마음대로 만드는 게 아니라, 인프라 관리자가 프로비저닝하는 리소스지. nfs-pv.yaml 파일을 만들어보자.
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
[cite_start]storage: 100Mi [cite: 7888]
accessModes:
- [cite_start]ReadWriteMany [cite: 7890]
[cite_start]persistentVolumeReclaimPolicy: Retain [cite: 7891]
[cite_start]nfs: [cite: 7892]
[cite_start]server: 10.0.1.28 [cite: 7893]
[cite_start]path: /nfs_shared [cite: 7894]
- capacity.storage: 이 PV가 제공하는 저장 공간의 전체 크기야. "이 PV는 대략 100Mi 정도 용량이 있는 것으로 알아 달라"는 의미지.
- accessModes: 볼륨에 접근하는 방식.
- ReadWriteMany는 여러 노드에서 동시에 읽고 쓸 수 있다는 의미로, NFS 같은 공유 스토리지에 적합해.
- persistentVolumeReclaimPolicy: Retain: 나중에 이 PV를 사용하던 PVC가 삭제되어도 실제 스토리지의 데이터를 삭제하지 말고 보존(Retain)하라는 정책이야.
3단계: PersistentVolumeClaim (PVC) 생성하기 – 개발자가 저장 공간 "요청"
PVC는 개발자가 "나 이 정도 저장 공간이 필요해요!"라고 쿠버네티스에 요청(Claim)하는 문서야. 파드가 노드의 자원을 요청해서 쓰듯이, PVC는 PV의 저장 공간 자원을 요청해서 사용해. nfs-pvc.yaml 파일을 만들어보자.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- [cite_start]ReadWriteMany [cite: 7902]
resources:
requests:
[cite_start]storage: 10Mi [cite: 7905]
- resources.requests.storage: 개발자가 실제로 필요로 하는 저장 공간의 크기야. "최소한 10Mi 용량을 제공할 수 있는 PV와 연결해 달라"는 요청이지.
- 이 PVC를 생성하면, 쿠버네티스는 조건에 맞는 PV(AccessMode가 같고, 용량이 10Mi 이상인)를 찾아서 둘을 연결(Bound)시켜 줘.
- kubectl get pvc 명령으로 상태를 확인하면 Bound라고 표시될 거야.
4단계: 파드에서 PVC 사용하기 (Deployment에 볼륨 마운트)
이제 마지막으로, 애플리케이션 파드에서 이 PVC를 가져다 쓰도록 설정하면 돼. nfs-pvc-deploy.yaml 파일을 보자.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-pvc-deploy
spec:
# ... (replicas, selector 등은 위와 유사) ...
template:
# ... (metadata는 위와 유사) ...
spec:
containers:
- name: httpd
image: httpd:latest
[cite_start]volumeMounts: [cite: 7929]
- [cite_start]name: nfs-vol [cite: 7930]
[cite_start]mountPath: /usr/local/apache2/htdocs [cite: 7931]
[cite_start]volumes: [cite: 7932]
- [cite_start]name: nfs-vol [cite: 7933]
[cite_start]persistentVolumeClaim: [cite: 7934]
[cite_start]claimName: nfs-pvc [cite: 7935]
- volumes: 파드에서 사용할 볼륨을 정의하는 부분이야. 여기서는
- nfs-vol이라는 이름의 볼륨을 정의하고, 그 소스로 nfs-pvc라는 PVC를 사용하겠다고 지정했어.
- volumeMounts: 위에서 정의한 nfs-vol 볼륨을 컨테이너 내부의 /usr/local/apache2/htdocs (아파치 웹 서버의 기본 웹 루트) 경로에 연결(마운트)하라는 의미야.
이제 이 디플로이먼트를 실행하면, 생성된 httpd 파드들은 /usr/local/apache2/htdocs 디렉터리에 파일을 읽고 쓸 때 실제로는 NFS 서버의 /nfs_shared 디렉터리에 데이터를 저장하게 돼. 덕분에 파드가 삭제되고 새로 만들어져도 데이터는 안전하게 보존되지!
[실전 종합 퀴즈! 🚀]
자, 오늘 배운 내용을 모두 활용해서 도전해 봐!
- nginx_dep이라는 이름의 Nginx 디플로이먼트를 생성하고, 파드의 웹 루트 경로(/usr/share/nginx/html)가 영구적으로 보존되도록 구성해 보세요.
- 이때, PV는 1G 용량을 제공하고, PVC는 100M 용량을 요청하도록 설정해서
- Bound 되는지 확인해 보세요.
- 최종적으로, NFS 서버의 공유 디렉터리에
- index.html 파일을 만들었을 때, 외부 AWS 로드 밸런서를 통해 접속하면 해당 페이지가 잘 보이는지 확인해 보세요!
'02. 클라우드 보안 공부 > 실습로그' 카테고리의 다른 글
| ✅ [실습로그] STP의 진화! 더 빠르고 효율적인 RSTP와 MSTP 알아보기 🌳 (3) | 2025.06.27 |
|---|---|
| ✅ [실습로그] STP 완전 정복: 네트워크 루프 방지부터 VLAN 로드밸런싱까지! 🌳 (3) | 2025.06.25 |
| ✅ [실습로그] EIGRP 라우팅 프로토콜 완벽 정복 🛡️ (0) | 2025.06.11 |
| ✅ [실습로그] Cisco ASA 방화벽 초보자 가이드: 기본 설정부터 원격 접속까지 🔒 (0) | 2025.06.05 |
| ✅ [실습로그] EIGRP 주요 특징 완벽 정리 🛡️ (1) | 2025.06.04 |