이번 장에서는 Certified Kubernetes Administrator (CKA) 을 준비하며 "스토리지"에 대해서 자세하게 알아보도록 한다.
Storage in Docker
도커 데이터 저장 위치
도커는 기본적으로 /var/lib/docker 디렉토리에 데이터를 저장한다.
이 디렉토리에는 aufs, containers, image, volumes 등의 하위 디렉토리가 있다.
conatiners: 컨테이너 관련 파일 저장
image: 이미지 관련 파일 저장
volumes: 볼륨 관련 파일 저장
도커 레이어 아키텍처
도커 이미지는 레이어 구조로 빌드된다.
Dockerfile의 각 명령어에는 새로운 레이어를 생성하며, 각 레이어에는 이전 레이어의 변경 사항만 저장한다.
예시:
Ubuntu 기본 운영 체제 레이어
APT 패키지 설치 레이어
Python 패키지 설치 레이어
소스 코드 복사 레이어
이미지 엔트리 포인트 업데이트 레이어
레이어 구조의 장점:
이미지 빌드 속도 향상: 동일한 레이어 재사용 (캐시 활용)
디스크 공간 효율성 향상: 변경 사항만 저장
이미지 업데이트 속도 향상: 변경된 레이어만 재빌드
이미지 레이어와 컨테이너 레이어
이미지 레이어
docker build 명령어로 생성된 레이어
읽기 전용(read-only)
이미지 빌드 후에는 수정 불가
여러 컨테이너에서 공유
컨테이너 레이어
docker run 명령어로 컨테이너 실행 시 생성되는 쓰기 가능(writable) 레이어
컨테이너에서 생성된 데이터(로그 파일, 임시 파일, 수정된 파일 등) 저장
컨테이너 삭제 시 함께 삭제
Copy-on-Write 메커니즘
이미지 레이어의 파일 수정
컨테이너 내부에서 이미지 레이어의 파일을 수정하면 도커는 해당 파일의 복사본을 컨테이너 레이어에 생성한다.
이후 수정은 컨테이너 레이어의 복사본으로 적용된다.
이미지 레이어의 원본 파일은 변경되지 않는다.
장점
이미지 레이어의 무결성 유지
컨테이너별로 독립적인 파일 수정 가능
컨테이너 삭제 시 데이터 손실
컨테이너 삭제 시 컨테이너 레이어의 모든 데이터가 삭제된다.
수정된 파일 및 새로 생성된 파일도 함께 삭제된다.
데이터 영속성을 위해 볼륨(volumes)을 사용해야 한다.
데이터 영속성(Persistent Data)
컨테이너 삭제 시 데이터 손실: 컨테이너 레이어는 컨테이너 삭제 시 함께 삭제되므로 데이터가 손실된다.
데이터 영속성을 위한 볼륨(Volumes) 사용: 컨테이너 삭제 후에도 데이터를 유지하려면 볼륨을 사용해야 한다.
도커 볼륨 생성 및 마운트
볼륨 생성: docker volume create <볼륨 이름> 명령어를 사용하여 볼륨을 생성한다.
예: docker volume create data_volume
생성된 볼륨은 /var/lib/docker/volumes/<볼륨 이름>/_data 디렉토리에 저장된다.
컨테이너에 볼륨 마운트: docker run -v <볼륨 이름>:<컨테이너 내부 경로> <이미지 이름> 명령어를 사용하여 컨테이너에 볼륨을 마운트한다.
예: docker run -v data_volume:/var/lib/mysql mysql
컨테이너 내부에 지정된 경로에 볼륨이 마운트되어 데이터가 저장된다.
자동 볼륨 생성: docker run 명령어 실행 시 존재하지 않는 볼륨을 지정하면 도커가 자동으로 볼륨을 생성하고 마운트한다.
바인드 마운트(Bind Mount)
호스트 시스템의 디렉토리 마운트: 호스트 시스템의 특정 디렉토리를 컨테이너에 마운트한다.
명령어: docker run -v <호스트 디렉토리 경로>:<컨테이너 내부 경로> <이미지 이름>
예: docker run -v /host/data:/container/data nginx
호스트 시스템의 /data/mysql 디렉토리가 컨테이너의 /var/lib/mysql 디렉토리에 마운트된다.
볼륨 마운트 vs 바인드 마운트:
볼륨 마운트: 도커가 관리하는 볼륨 사용 (/var/lib/docker/volumes)
바인드 마운트: 호스트 시스템의 임의 디렉토리 사용
--mount 옵션(권장)
-v 옵션의 대체: --mount 옵션은 -v 옵션보다 명시적이고 유연하다.
명령어: docker run --mount type=<mount type>,source=<source>,target=<target> <이미지 이름>
type: volume 또는 bind
source: 볼륨 이름 또는 호스트 디렉토리 경로
target: 컨테이너 내부 경로
예시 (바인드 마운트): docker run --mount type=bind,source=/data/mysql,target=/var/lib/mysql mysql
스토리지 드라이버(Storage Drivers)
역할: 레이어 아키텍처 관리, 쓰기 가능 레이어 생성, Copy-on-Write 구현 등
종류: AUFS, VTRFS, Device Mapper, Overlay, Overlay2 등
자동 선택: 도커는 운영 체제에 따라 최적의 스토리지 드라이버를 자동으로 선택한다.
성능 및 안정성: 스토리지 드라이버마다 성능 및 안정성 특성이 다르므로 애플리케이션 요구 사항에 맞는 드라이버를 선택해야 한다.
Storage Driver
스토리지 드라이버와 볼륨 드라이버의 차이
스토리지 드라이버(Storage Driver)
이미지와 컨테이너의 스토리지 관리를 담당한다.
레이어 아키텍처, 쓰기 가능 레이어, Copy-on-Write 등을 처리한다.
볼륨 드라이버 플러그인(Volume Driver Plugin)
볼륨 관리를 담당한다.
데이터 영속성을 위한 볼륨 생성 및 관리를 처리한다.
스토리지 드라이버와 볼륨 드라이버는 서로 다른 역할을 수행한다.
기본 볼륨 드라이버 플로그인(Local)
기본 플러그인: 도커 설치 시 기본적으로 제공되는 플러그인이다.
기능: 도커 호스트에 볼륨을 생성하고 데이터를 /var/lib/docker/volumes 디렉토리에 저장한다.
다양한 볼륨 드라이버 플러그인
외부 스토리지 솔루션 지원: 다양한 볼륨 드라이버 플러그인을 사용하여 Azure File Storage, Convoy, DigitalOcean Block Storage, Google Compute Persistent Disks 등과 같은 외부 스토리지 솔루션에 볼륨을 생성할 수 있다.
예시:
Azure File Storage
Convoy
DigitalOcean Block Storage
Flocker
Google Compute Persistent Disks
Cluster FS
NetApp
REX-Ray
Portworx
VMware vSphere Storage
다양한 스토리지 제공업체 지원: 일부 볼륨 드라이버는 여러 스토리지 제공업체를 지원한다.
REX-Ray: AWS EBS, S3, EMC Isilon, ScaleIO, Google Persistent Disk, OpenStack Cinder 등 지원
외부 볼륨 드라이버 플러그인 사용
특정 볼륨 드라이버 지정: docker run 명령어 실행 시 특정 볼륨 드라이버를 지정하여 외부 스토리지에 볼륨을 생성하고 컨테이너에 연결할 수 있다.
예시: REX-Ray EBS 볼륨 드라이버를 사용하여 AWS EBS에서 볼륨을 프로비저닝하고 컨테이너에 연결한다.
데이터 영속성 보장: 컨테이너 종료 후에도 외부 스토리지에 데이터가 안전하게 보관된다.
Container Storage Interface
배경 및 필요성
과거 쿠버네티스와 도커: 과거에는 쿠버네티스가 도커만을 컨테이너 런타임 엔진으로 사용했으며, 도커 관련 코드가 쿠버네티스 소스 코드에 내장되어 있었다.
다양한 컨테이너 런타임 등장: RKT, CRI-O 등 다양한 컨테이너 런타임이 등장하면서 쿠버네티스는 다양한 런타임을 지원하고 독립성을 유지해야 했다.
CRI(Container Runtime Interface): 쿠버네티스와 같은 오케스트레이션 솔루션이 도커와 같은 컨테이너 런타임과 통신하는 방식을 정의하는 표준이다.
새로운 컨테이너 런타임은 CRI 표준을 준수하여 쿠버네티스 개발팀의 도움 없이 쿠버네티스와 연동될 수 있다.
CNI(Container Networking Interface): 다양한 네트워킹 솔루션을 지원하기 위해 도입되었다.
새로운 네트워킹 공급업체는 CNI 표준을 기반으로 플러그인을 개발하여 쿠버네티스와 연동할 수 있다.
CSI(Container Storage Interface): 다양한 스토리지 솔루션을 지원하기 위해 개발되었다.
CSI(Container Storage Interface)
목적: 쿠버네티스와 다양한 스토리지 벤더의 솔루션을 연동하기 위한 범용 표준이다.
CSI 드라이버: 각 스토리지 벤더(Portworx, Amazon EBS, Azure Disk, Dell EMC Isilon, NetApp 등)는 자체 CSI 드라이버를 제공한다.
범용 표준: CSI는 쿠버네티스 특정 표준이 아니며, 컨테이너 오케스트레이션 도구와 스토리지 벤더를 연결하는 범용 표준이다.
쿠버네티스, Cloud Foundry, Mesos 등이 CSI를 지원한다.
CSI 작동 방식
RPC(Remote Procedure Calls) 정의: CSI는 컨테이너 오케스트레이터가 호출해야 하는 RPC 집합을 정의한다.
스토리지 드라이버 구현: 스토리지 드라이버는 CSI에서 정의된 RPC를 구현해야 한다.
예시:
CreateVolume RPC: 파드 생성 시 볼륨이 필요한 경우 쿠버네티스는 CreateVolume RPC를 호출하고 볼륨 이름 등의 정보를 전달한다. 스토리지 드라이버는 이 요청을 처리하고 스토리지 어레이에 새 볼륨을 프로비저닝한 후 결과를 반환한다.
DeleteVOlume RPC: 볼륨 삭제 시 쿠버네티스는 DeleteVolume RPC를 호출한다. 스토리지 드라이버는 이 요청을 처리하고 스토리지 어레이에서 볼륨을 삭제한다.
명세: CSI 명세는 호출자가 전달해야 하는 매개변수, 솔루션이 수신해야 하는 매개변수, 교환해야 하는 오류 코드 등을 상세히 정의한다.
Volumes
쿠버네티스 볼륨의 기본 개념
도커 볼륨과의 유사성
도커 컨테이너와 마찬가지로 쿠버네티스 파드도 일시적인 성격을 가진다.
파드가 삭제되면 파드 내부의 데이터도 함께 삭제된다.
데이터를 영구적으로 유지하기 위해 볼륨을 파드에 연결한다.
파드 데이터의 영속성
볼륨에 데이터를 저장하면 파드가 삭제되어도 데이터는 유지된다.
쿠버네티스 볼륨 구현 예시
단일 노드 클러스터
1 ~ 100 사이의 난수를 생성하여 /opt/number.out 파일에 기록하는 파드를 생성한다.
파드 삭제 시 난수 데이터도 함께 삭제된다.
데이터 유지를 위해 볼륨을 생성한다.
볼륨 스토리지 설정
볼륨 스토리지는 다양한 방식으로 설정할 수 있다.
단순화를 위해 호스트 노드의 디렉토리(/data)를 스토리지로 사용한다.
볼륨 마운트
파드 컨테이너 내부의 /opt 디렉토리에 볼륨을 마운트한다.
난수는 컨테이너 내부의 /opt 디렉토리에 저장되고, 이는 호스트 노드의 /data 디렉토리에 실제로 저장된다.
파드 삭제 후 데이터 유지
파드가 삭제되어도 난수 파일은 호스트 노드의 /data 디렉토리에 남아있다.
볼륨 스토리지 옵션
호스트 경로 (hostPath)
호스트 노드의 디렉토리를 볼륨 스토리지로 사용한다.
단일 노드 클러스터에는 작동하지만 다중 노드 클러스터에서는 권장되지 않는다.
다중 노드 클러스터에서는 파드가 모든 노드의 /data 디렉토리를 사용하므로 데이터 불일치가 발생할 수 있다.
다양한 스토리지 솔루션 지원
쿠버네티스는 NFS, ClusterFS, Flocker, Fiber Channel, CephFS, ScaleIO와 같은 다양한 스토리지 솔루션을 지원한다.
AWS EBS, Azure Disk, Google Persistent Disk와 같은 퍼블릭 클라우드 스토리지 솔류션도 지원한다.
AWS EBS 볼륨 설정 예시
볼륨의 hostPath 필드를 awsElasticBlockStore 필드로 대체한다.
볼륨 ID와 파일시스템 유형을 지정한다.
볼륨 스토리지는 이제 AWS EBS에 위치한다.
Persistent Volume
볼륨의 한계와 영구 볼륨(Persistent Volume)의 필요성
기존 볼륨의 설정: 파드 정의 파일 내에 볼륨 설정을 직접 구성했다.
대규모 환경의 문제점
많은 사용자가 다양한 파드를 배포하는 대규모 환경에서는 각 파드마다 스토리지 설정을 반복해야 한다.
스토리지 솔루션 변경 시 모든 파드 정의 파일을 수정해야 한다.
중앙 집중적인 스토리지 관리가 필요하다.
Persistent Volume의 역할
관리자가 클러스터 전체에서 사용할 수 있는 스토리지 풀을 미리 구성한다.
사용자는 영구 볼륨 클레임(Persistent Volume Claims, VPC)을 통해 필요한 스토리지를 할당받는다.
중앙 집중적인 스토리지 관리 및 사용자 편의 성을 제공한다.
영구 볼륨(Persistent Volume, PV) 생성
기본 템플릿 및 설정
API 버전, 종류(PersistentVolume), 이름(pv-vol1), 용량, 액세스 모드, 스토리지 클래스 등을 설정한다.
spec 영역에서 세부 설정을 정의한다.
접근 모드(accessMode)
볼륨을 호스트에 마운트하는 방식(읽기 전용, 읽기/쓰기 등)을 정의한다.
readOnlyMany, ReadWriteOnce, ReadWriteMany 등의 값을 사용할 수 있다.
용량(capacity)
영구 볼륨에 할당할 스토리지 용량을 지정한다. (예: 1GB)
볼륨 유형(volumeType)
볼륨 스토리지의 유형을 설정한다.
hostPath 옵션을 사용하여 노드의 로컬 디렉토리를 사용할 수 있다. (개발/테스트 환경에서만 권장)
영구 볼륨 생성 및 조회
kubectl create 명령어를 사용하여 영구 볼륨을 생성한다.
kubectl get persistentvolume 명령어를 사용하여 생성된 영구 볼륨을 조회한다.
스토리지 솔루션 변경
hostPath 옵션을 지원되는 다른 스토리지 솔루션(AWS EBS 등)으로 변경하여 실제 스토리지 환경에 맞게 구성한다.
Persistent Volume Claim
영구 볼륨 클레임(Persistent Volume Claim, PVC)의 역할
영구 볼륨(PV)과의 관계: 영구 볼륨과 영구 볼륨 클레임은 쿠버네티스 네임스페이스의 별도 객체다.
관리자와 사용자의 역할 분담: 관리자는 영구 볼륨을 생성하고, 사용자는 영구 볼륨 클레임을 생성하여 스토리지를 사용한다.
영구 볼륨 바인딩: 쿠버네티스는 클레임의 요청과 볼륨의 속성을 기반으로 영구 볼륨을 클레임에 바인딩한다.
1:1 관계: 각 영구 볼륨 클레임은 하나의 영구 볼륨에 바인딩된다.
영구 볼륨 클레임 바인딩 과정
용량 확인: 쿠버네티스는 클레임에서 요청한 용량과 일치하거나 충분한 용량을 가진 영구 볼륨을 찾는다.
속성 확인: 접근 모드, 볼륨 모드, 스토리지 클래스 등 클레임의 다른 요청과 볼륨의 속성을 비교한다.
레이블 및 선택기: 여러 후보 볼륨이 있는 경우 레이블과 선택기를 사용하여 특정 볼륨을 선택할 수 있다.
용량 초과 바인딩: 다른 모든 조건이 충족되고 더 나은 옵션이 없는 경우, 더 작은 클레임이 더 큰 볼륨에 바인딩될 수 있다.
클레임 대기 상태: 사용 가능한 볼륨이 없는 경우 클레임은 대기 상태로 유지되며, 새 볼륨이 생성되면 자동으로 바인딩된다.
영구 볼륨 클레임 생성
기존 템플릿 및 설정
API 버전, 종류(PersistentVolumeClaim), 이름(My-Claim)을 설정한다.
spec 영역에서 세부 설정을 정의한다.
접근 모드(accessModes): 읽기/쓰기 한번(ReadWriteOnce)으로 설정한다.
리소스 요청(resources.requests): 500MB의 스토리지를 요청한다.
클레임 생성 및 조회
kubectl create 명령어를 사용하여 영구 볼륨 클레임을 생성한다.
kubectl get persistentvolumeclaim 명령어를 사용하여 생성된 영구 볼륨 클레임을 조회한다.
바인딩 상태 확인: kubectl get pv 명령어를 실행하여 클레임이 영구 볼륨에 바인딩되었는지 확인한다.
영구 볼륨 클레임 삭제 시 영구 볼륨 처리
삭제 명령어: kubectl delete persistentvolumeclaim 명령어를 사용하여 클레임을 삭제한다.
삭제 시 영구 볼륨 처리 옵션:
유지(Retain): 기본 설정으로 관리자가 수동으로 삭제할 때까지 영구 볼륨이 유지되며 다른 클레임에서 재사용할 수 없다.
삭제(Delete): 클레임 삭제 시 영구 볼륨도 자동으로 삭제되어 스토리지 장치의 공간을 확보한다.
재활용(Recycle): 데이터 볼륨의 스크럽(삭제)하여 다른 클레임에서 사용할 수 있도록 한다.
Using PVCs in Pods
PVC를 생성한 후에는 다음과 같은 볼륨 섹션의 persistentVolumeClaim 섹션에서 PVC 이름을 지정하여 파드 정의 파일에서 사용할 수 있다.