파드가 저장용 PersistentVolume을 사용하도록 구성하기
파드가 저장용 PersistentVolume을 사용하도록 구성하기 (Configure a Pod to Use a PersistentVolume for Storage)
이 페이지는 파드가 저장용 PersistentVolumeClaim을 사용하도록 구성하는 방법을 보여줘요. 과정 요약은 다음과 같아요.
출처: 문서
본문
시작하기 전에 (Before you begin)
노드에 index.html 파일 만들기
클러스터의 단일 노드에 셸을 엽니다. 셸을 여는 방법은 클러스터를 어떻게 설정했는지에 따라 달라져요. 예를 들어 Minikube를 사용한다면 minikube ssh 를 입력해 노드에 셸을 열 수 있어요.
그 노드의 셸에서 /mnt/data 디렉토리를 만들어요:
# This assumes that your Node uses "sudo" to run commands
# as the superuser
sudo mkdir /mnt/data
/mnt/data 디렉토리에 index.html 파일을 만들어요:
# This again assumes that your Node uses "sudo" to run commands
# as the superuser
sudo sh -c "echo 'Hello from Kubernetes storage' > /mnt/data/index.html"
참고:
index.html 파일이 존재하는지 테스트해요:
cat /mnt/data/index.html
출력은 다음과 같아야 해요:
Hello from Kubernetes storage
이제 노드에 대한 셸을 닫을 수 있어요.
PersistentVolume 만들기
이 실습에서 hostPath PersistentVolume을 만들어요. 쿠버네티스는 단일 노드 클러스터에서 개발·테스트용으로 hostPath를 지원해요. hostPath PersistentVolume은 노드의 파일이나 디렉토리를 사용해 네트워크 연결 저장소를 에뮬레이션해요.
프로덕션 클러스터에서는 hostPath를 사용하지 않을 거예요. 대신 클러스터 관리자가 Google Compute Engine 영구 디스크, NFS 공유, Amazon Elastic Block Store 볼륨 같은 네트워크 리소스를 프로비저닝할 거예요. 클러스터 관리자는 또한 StorageClass를 사용해 동적 프로비저닝을 설정할 수 있어요.
다음은 hostPath PersistentVolume의 구성 파일이에요:
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
구성 파일은 볼륨이 클러스터의 노드 /mnt/data 에 있음을 지정해요. 구성은 또한 10GiB 크기와 ReadWriteOnce 접근 모드를 지정하는데, 이는 볼륨이 단일 노드에 의해 읽기-쓰기로 마운트될 수 있다는 뜻이에요. PersistentVolume의 StorageClass 이름 manual 을 정의하며, 이는 PersistentVolumeClaim의 요청을 이 PersistentVolume에 바인딩하는 데 사용될 거예요.
참고:
PersistentVolume을 만들어요:
kubectl apply -f https://k8s.io/examples/pods/storage/pv-volume.yaml
PersistentVolume에 대한 정보를 봐요:
kubectl get pv task-pv-volume
출력은 PersistentVolume의 STATUS 가 Available 임을 보여줘요. 이는 아직 PersistentVolumeClaim에 바인딩되지 않았음을 의미해요.
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Available manual 4s
PersistentVolumeClaim 만들기
다음 단계는 PersistentVolumeClaim을 만드는 것이에요. 파드는 물리 저장소를 요청하기 위해 PersistentVolumeClaim을 사용해요. 이 실습에서 한 번에 최대 한 개의 노드에 읽기-쓰기 접근을 제공할 수 있는 최소 3GiB의 볼륨을 요청하는 PersistentVolumeClaim을 만들어요.
다음은 PersistentVolumeClaim의 구성 파일이에요:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
PersistentVolumeClaim을 만들어요:
kubectl apply -f https://k8s.io/examples/pods/storage/pv-claim.yaml
PersistentVolumeClaim을 만든 후 쿠버네티스 제어 플레인은 클레임의 요구 사항을 충족하는 PersistentVolume을 찾아요. 제어 플레인이 같은 StorageClass를 가진 적합한 PersistentVolume을 찾으면 클레임을 볼륨에 바인딩해요.
PersistentVolume을 다시 봐요:
kubectl get pv task-pv-volume
이제 출력은 STATUS 가 Bound 임을 보여줘요.
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Bound default/task-pv-claim manual 2m
PersistentVolumeClaim을 봐요:
kubectl get pvc task-pv-claim
출력은 PersistentVolumeClaim이 PersistentVolume task-pv-volume 에 바인딩됐음을 보여줘요.
NAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGE
task-pv-claim Bound task-pv-volume 10Gi RWO manual 30s
파드 만들기
다음 단계는 PersistentVolumeClaim을 볼륨으로 사용하는 파드를 만드는 것이에요.
다음은 파드의 구성 파일이에요:
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
containers:
- name: task-pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage
파드의 구성 파일이 PersistentVolumeClaim을 지정하지만 PersistentVolume은 지정하지 않는다는 점을 주목해요. 파드의 관점에서 클레임은 볼륨이에요.
파드를 만들어요:
kubectl apply -f https://k8s.io/examples/pods/storage/pv-pod.yaml
파드의 컨테이너가 실행 중인지 확인해요:
kubectl get pod task-pv-pod
파드에서 실행되는 컨테이너에 셸을 얻어요:
kubectl exec -it task-pv-pod -- /bin/bash
셸에서 nginx가 hostPath 볼륨에서 index.html 파일을 제공하는지 확인해요:
# Be sure to run these 3 commands inside the root shell that comes from
# running "kubectl exec" in the previous step
apt update
apt install curl
curl http://localhost/
출력은 hostPath 볼륨의 index.html 파일에 기록한 텍스트를 보여줘요:
Hello from Kubernetes storage
그 메시지가 보이면 PersistentVolumeClaim에서 저장소를 사용하도록 파드를 성공적으로 구성한 것이에요.
정리 (Clean up)
파드를 삭제해요:
kubectl delete pod task-pv-pod
같은 PersistentVolume을 두 곳에 마운트하기
PersistentVolume & PersistentVolumeClaim을 만드는 방법과 볼륨을 컨테이너의 단일 위치에 마운트하는 방법을 이해했어요. 같은 PersistentVolume을 컨테이너의 서로 다른 두 위치에 마운트할 수 있는 방법을 살펴봐요. 아래는 예시예요:
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- name: test
image: nginx
volumeMounts:
# a mount for site-data
- name: config
mountPath: /usr/share/nginx/html
subPath: html
# another mount for nginx config
- name: config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: config
persistentVolumeClaim:
claimName: task-pv-claim
여기서:
subPath: 이 필드는 마운트된 PersistentVolume에서 특정 파일이나 디렉토리가 컨테이너 안의 다른 위치에 노출되도록 허용해요. 이 예시에서:
첫 번째 subPath가 html 이므로 /mnt/data/ 안에 html 디렉토리가 노드에 생성되어야 해요.
두 번째 subPath nginx.conf 는 /mnt/data/ 디렉토리 안의 파일이 사용될 것임을 의미해요. 다른 디렉토리는 만들 필요가 없어요.
nginx 컨테이너에 두 개의 볼륨 마운트가 이루어질 거예요:
- 정적 웹사이트용
/usr/share/nginx/html - 기본 구성용
/etc/nginx/nginx.conf
노드의 index.html 파일을 새 폴더로 옮기기
여기서 언급하는 index.html 파일은 "노드에 index.html 파일 만들기" 섹션에서 만든 것을 가리켜요.
클러스터의 단일 노드에 셸을 엽니다. 셸을 여는 방법은 클러스터를 어떻게 설정했는지에 따라 달라져요. 예를 들어 Minikube를 사용한다면 minikube ssh 를 입력해 노드에 셸을 열 수 있어요.
/mnt/data/html 디렉토리를 만들어요:
# This assumes that your Node uses "sudo" to run commands
# as the superuser
sudo mkdir /mnt/data/html
index.html을 그 디렉토리로 옮겨요:
# Move index.html from its current location to the html sub-directory
sudo mv /mnt/data/index.html /mnt/data/html/index.html
새 nginx.conf 파일 만들기
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 60;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
이것은 기본 nginx.conf 파일의 수정된 버전이에요. 여기서 기본 keepalive_timeout 이 60 으로 수정됐어요.
nginx.conf 파일을 만들어요:
cat <<EOF > /mnt/data/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
'\$status \$body_bytes_sent "\$http_referer" '
'"\$http_user_agent" "\$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 60;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
EOF
파드 만들기
여기서는 기존 persistentVolume과 persistentVolumeClaim을 사용하는 파드를 만들 거예요. 하지만 파드는 nginx.conf 라는 특정 파일과 html 디렉토리만 컨테이너에 마운트해요.
파드를 만들어요:
kubectl apply -f https://k8s.io/examples/pods/storage/pv-duplicate.yaml
파드의 컨테이너가 실행 중인지 확인해요:
kubectl get pod test
파드에서 실행되는 컨테이너에 셸을 얻어요:
kubectl exec -it test -- /bin/bash
셸에서 nginx가 hostPath 볼륨에서 index.html 파일을 제공하는지 확인해요:
# Be sure to run these 3 commands inside the root shell that comes from
# running "kubectl exec" in the previous step
apt update
apt install curl
curl http://localhost/
출력은 hostPath 볼륨의 index.html 파일에 기록한 텍스트를 보여줘요:
Hello from Kubernetes storage
셸에서 nginx가 hostPath 볼륨에서 nginx.conf 파일을 제공하는지도 확인해요:
# Be sure to run these commands inside the root shell that comes from
# running "kubectl exec" in the previous step
cat /etc/nginx/nginx.conf | grep keepalive_timeout
출력은 hostPath 볼륨의 nginx.conf 파일에 기록한 수정된 텍스트를 보여줘요:
keepalive_timeout 60;
이 메시지들이 보이면 PersistentVolumeClaim의 저장소에서 특정 파일과 디렉토리를 사용하도록 파드를 성공적으로 구성한 것이에요.
정리 (Clean up)
파드를 삭제해요:
kubectl delete pod test
kubectl delete pvc task-pv-claim
kubectl delete pv task-pv-volume
클러스터의 노드에 열린 셸이 없다면 이전에 했던 것과 같은 방식으로 새 셸을 열어요.
노드의 셸에서 만든 파일과 디렉토리를 제거해요:
# This assumes that your Node uses "sudo" to run commands
# as the superuser
sudo rm /mnt/data/html/index.html
sudo rm /mnt/data/nginx.conf
sudo rmdir /mnt/data/html
sudo rmdir /mnt/data
이제 노드에 대한 셸을 닫을 수 있어요.
접근 제어 (Access control)
그룹 ID(GID)로 구성된 저장소는 같은 GID를 사용하는 파드만 쓸 수 있어요. 불일치하거나 없는 GID는 권한 거부 오류를 일으켜요. 사용자와의 조정 필요를 줄이기 위해 관리자는 PersistentVolume에 GID로 애노테이션을 붙일 수 있어요. 그러면 GID가 그 PersistentVolume을 사용하는 모든 파드에 자동으로 추가돼요.
다음과 같이 pv.beta.kubernetes.io/gid 애노테이션을 사용해요:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
annotations:
pv.beta.kubernetes.io/gid: "1234"
파드가 GID 애노테이션이 있는 PersistentVolume을 소비하면, 애노테이션된 GID는 파드의 보안 컨텍스트에 지정된 GID와 같은 방식으로 파드의 모든 컨테이너에 적용돼요. PersistentVolume 애노테이션에서 오든 파드 스펙에서 오든 모든 GID는 각 컨테이너에서 실행되는 첫 번째 프로세스에 적용돼요.
참고:
더 알아보기 (Learn more)
- PersistentVolume에 대해 더 알아보기
- Persistent Storage 디자인 문서 읽기