02. 클라우드 보안 공부/실습로그

✅ [실습로그] 쿠버네티스 외부 접속 & 데이터 영구 보존

taegi- 2025. 7. 7. 17:07

내 컨테이너, 세상 밖으로! NodePort로 길을 열고, PV/PVC로 데이터를 지키는 방법 🚀

[들어가며: 쿠버네티스 실전 운영의 두 가지 큰 숙제!]

쿠버네티스 클러스터 위에 우리의 멋진 애플리케이션을 파드(Pod)로 띄웠다고 가정해보자. 여기서 우리는 두 가지 중요한 현실적인 문제에 부딪히게 돼.

  1. 외부 접속 문제: "클러스터 외부의 사용자들이 도대체 어떻게 이 파드에 접속할 수 있지?" 파드는 클러스터 내부에서만 통용되는 IP를 가지고, 언제든 사라졌다가 새로 생길 수 있는 임시적인 존재인데 말이야.
  2. 데이터 보존 문제: "만약 데이터를 저장하는 파드가 죽었다가 다시 살아나면, 그 안에 있던 중요한 데이터는 어떻게 되는 거지?" 컨테이너가 사라지면 데이터도 함께 사라지는 게 기본 원칙이라 큰일이지!

오늘 우리는 이 두 가지 숙제를 해결해 줄 똑똑한 해결사, 바로 쿠버네티스 서비스(Service), 그중에서도 NodePort 타입과, 영구적인 데이터 저장을 위한 **PV(PersistentVolume)**와 **PVC(PersistentVolumeClaim)**에 대해 자세히 알아볼 거야.


Part 1: 외부에서 파드에 접속하기 – Service(NodePort)와 로드 밸런서 🚪

파드는 직접 외부와 연결될 수 없기 때문에, 중간에 다리를 놓아주는 친구들이 필요해. 그 연결 흐름은 보통 이래.

 

외부 사용자 → 클라우드 로드 밸런서(AWS ELB 등) → 워커 노드의 특정 포트(NodePort) → 쿠버네티스 서비스 → 목적지 파드

이 흐름을 단계별로 실습해 보자.

1단계: 애플리케이션 배포 (Deployment 만들기)

먼저, 외부로 노출시킬 우리의 애플리케이션(여기서는 Tomcat WAS 서버)을 디플로이먼트(Deployment) 형태로 클러스터에 배포하자. tomcatdep.yaml 파일을 만들어봐.

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와 특정 포트로 접근할 수 있게 해줘.

YAML
 
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.yamlkubectl 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 서버를 간단히 구축하자.

Bash
 
# 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 파일을 만들어보자.

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 파일을 만들어보자.

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 파일을 보자.

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 로드 밸런서를 통해 접속하면 해당 페이지가 잘 보이는지 확인해 보세요!