전자책 출간 알림 [마이크로서비스패턴 쉽게 개발하기]

티스토리 뷰

11. 데이터 저장소 사용을 위한 PV/PVC

여러분이 고객을 위해 만드는 애플리케이션은 거의 대부분 파일이나 데이터베이스를 이용하여 데이터를 읽거나 써야 합니다.
파일이나 데이터베이스에 데이터가 저장되기 위해서는 물리적인 스토리지가 있어야 하고요.
이러한 물리적인 스토리지를 파티션으로 나눈 후 읽고 쓰기가 가능하게 만든 저장 영역을 볼륨Volume이라고 합니다.
여러분이 스토리지인 하드 디스크를 사서 파티션 C드라이브와 D드라이브로 나누고 포맷하면 볼륨이 만들어 지는 겁니다.
이번 장에서는 파드 내의 어플리케이션이 볼륨을 어떻게 사용하는지 좀 더 알아 보겠습니다.
스토리지는 짐작 하시겠지만 개발자가 알기에는 너무 방대하고 어려운 영역입니다.
하지만 걱정하실 필요 없습니다.
쿠버네티스는 개발자가 스토리지에 대한 전문 지식이 없어도 쉽게 볼륨을 사용할 수 있는 훌륭한 방법을 제공 합니다.

첫번째로는 쿠버네티스 환경에서의 볼륨에 대해 이해하는 시간을 가지도록 하겠습니다.
두번째로 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트를 정의하는 방법에 대해 좀 더 알아 보겠습니다.
세번째로 쿠버네티스 볼륨의 유형별로 어떻게 정의하고 사용하는지 배워 보도록 하겠습니다.
네번째로 MySQL 데이터베이스를 배포하면서 워크로드 컨트롤러에 퍼시스턴트 볼륨 클레임 오브젝트를 같이 정의 하는 방법을 학습 하겠습니다.
마지막으로는 자동으로 볼륨을 만드는 방법을 학습 하도록 하겠습니다.

11.1 쿠버네티스 환경에서의 볼륨 이해

쿠버네티스 환경에서는 모든 어플리케이션이 파드안에 컨테이너로 실행이 됩니다.
물리 머신이나 가상 머신에 실행되는 어플리케이션이 볼륨을 사용하는 방법과는 차이가 날 수 밖에 없습니다.
우선 컨테이너에서 왜 외부 볼륨을 사용해야 하는가 부터 얘기해 보겠습니다.
그리고 파드가 볼륨을 사용하는 목적에 따른 볼륨의 유형을 알아 보겠습니다.
그 다음으로는 파드가 볼륨을 어떻게 사용할 수 있는지를 알아야겠지요 ? 파드의 볼륨 사용 아키텍처와 퍼시스턴트볼륨의 라이프사이클을 설명 하겠습니다.
쿠버네티스가 지원하는 네트워크 스토리지 제품도 참고삼아 말씀 드리겠습니다.
파드가 볼륨을 사용하다 보면 데이터가 쌓이면서 볼륨의 용량을 늘릴 필요가 있습니다. 어떻게 볼륨의 크기를 늘릴 수 있는지까지 해 보겠습니다.

1) 컨테이너에서 외부 볼륨의 필요성
당연히 데이터를 읽고 저장하기 위해 볼륨이 필요 합니다.
컨테이너가 아닐때는 각 서버가 자신만의 로컬 스토리지 볼륨을 이용해서 데이처를 처리하는 경우도 많습니다.
특히 데이터의 양이 많지 않을때는 굳이 복잡하게 네트워크 스토리지를 사용하지 않는게 더 편하고 비용도 절약할 수 있기 때문입니다.
그런데 왜 컨테이너는 자신의 내부 볼륨을 이용하지 않고 외부 볼륨을 사용하는걸까요 ?
컨테이너는 언제라도 사라질 수 있기 때문입니다. 컨테이너가 사라지면 당연히 내부 볼륨도 없어지고 그럼 소중한 데이터를 잃어 버릴 수 있습니다.
따라서 그 이유를 좀 더 정확히 말한다면 데이터를 안전하게 보존하면서 읽고 쓰기 위해서 외부 볼륨이 필요한 겁니다.

2) 사용 목적별 볼륨 유형
파드안에 컨테이너화되어 실행되는 것을 크게 두가지로 생각해 보면 어플리케이션과 데이터베이스입니다.
어플리케이션은 데이터베이스에 요청해서 데이터를 읽거나 쓰게 되므로 볼륨을 주로 필요로 하는 것은 데이터베이스가 되겠지요.
볼륨을 크게 나누면 파드 로컬 볼륨, 노드 로컬 볼륨, 네트워크 볼륨입니다.
파드 로컬 볼륨은 파드 안에만 만들어지는 볼륨이고 노드 로컬 볼륨은 쿠버네티스 클러스터 노드의 볼륨이며 네트워크 볼륨은 클러스터 외부에 존재하는 볼륨입니다.
이러한 분류는 공식적인 것은 아니고 여러분들의 이해를 돕기 위한 분류입니다.
파드가 볼륨을 사용하는 목적을 어플리케이션과 데이터베이스 관점에서 나눠보고 거기에 맞는 볼륨 유형을 정리하면 아래와 같습니다.

구분 사용 목적 파드 삭제시
볼륨 폐기
볼륨 유형
어플리케이션 어떤 처리를 위한 임시 공간 Y 파드 로컬 볼륨
컨피그맵, 시크릿, 파드 정보 참조 Y 파드 로컬 볼륨
파드가 실행된 노드의 파일 접근 N 노드 로컬 볼륨
특정 노드의 파일 접근  N 노드 로컬 볼륨
클러스터 외부 스토리지의 파일 접근 N 네트워크 볼륨
데이터베이스 컨피그맵, 시크릿, 파드 정보 참조 Y 파드 로컬 볼륨
파드가 실행된 노드에만 데이터 저장 N 노드 로컬 볼륨
특정 노드에만 데이터 저장 N 노드 로컬 볼륨
클러스터 외부 스토리지에 데이터 저장 N 노드 로컬 볼륨



3) 파드의 볼륨 접근 아키텍처와 퍼시스턴트 볼륨 라이프 사이클
그럼 파드가 어떻게 볼륨을 사용하는지를 알아 보겠습니다.
핵심적인 방법은 ‘마운트'입니다.

마운트 개념을 쉽게 이해하려면 여러분 PC에 외장하드를 연결하면 탐색기에 E드라이브나 F드라이브가 생기는 것을 생각하시면 됩니다. 


파드내에 볼륨을 ‘마운트'함으로써 어떤 유형의 볼륨이든 상관 없이 마치 파드 내부의 파일 시스템인것처럼 사용할 수 있게 됩니다.

그런데 이 아키텍처는 치명적인 문제가 있습니다.
쿠버네티스와 인프라스트럭처가 너무 강결합Tightly Coupled 되어 버립니다.
이런 강결합으로 인해 스토리지 제품의 변화나 스토리지 서버의 변화가 파드에 직접적인 영향을 미칩니다.
예를들어 ‘nfs’라는 네트워크 볼륨을 파드에 마운트 하려면 nfs 서버의 IP나 호스트를 지정해야 하는데 nfs서버의 IP가 변경되면 서비스에 문제가 발생할 수 있습니다.
또한 파드 명세를 정의하는 사람은 스토리지에 대한 어느 정도의 지식이 필요 합니다. 인프라스트럭처를 운영하는 사람에게 의존적이 될 수밖에 없게 됩니다.

어떻게 해결해야 할까요 ? 쿠버네티스와 인프라스트럭처를 느슨하게 결합Loosly Coupled시키면 됩니다.
느슨한 결함을 하려면 항상 중간에 중계자 역할을 만들면 됩니다.
쿠버네티스는 인프라스트럭처와의 느슨한 결합을 위해 퍼시스턴트 볼륨PV(Persistent Volume)/퍼시스턴트 볼륨 클레임PVC(Persistent Volume Claim)와 CSIContainer Storage Interface라는 중계자 역할을 만들었습니다.
그래서 파드가 볼륨을 사용하는 아키텍처는 아래와 같은 모습이 됩니다.

❶ 파드정보, 컨피그맵, 시크릿은 파드 명세에 정의하여 마운트 합니다.
❷ 노드 로컬 볼륨과 네트워크 볼륨은 퍼시스턴트볼륨 리소스로 정의하고 퍼시스턴트 볼륨 클레임에 바인딩(연결) 합니다. 파드 명세에서는 퍼시스턴트 볼륨 클레임만 지정해 주면 연결된 볼륨이 마운트 됩니다.
❸ 퍼시스턴트 볼륨은 CSI(Container Storage Interface)라는 표준적인 방법으로 정의합니다. CSI 표준 명세대로 퍼시스턴트 볼륨을 만들면 스토리지 제품별 CSI 드라이버를 통해 물리적인 네트워크 볼륨을 접근 합니다.
❹ 스토리지 제품별로 퍼시스턴트 볼륨을 정의하여 볼륨을 접근할 수도 있습니다.

이렇게 되면 파드를 만드는 사람은 퍼시스턴트 볼륨 클레임만 만들면 되고 퍼시스턴트 볼륨을 만드는 사람은 CSI명세만 알면 됩니다. 물론 CSI를 이용하지 않을때는 사용하려는 스토리지 제품별로 어떻게 퍼시스턴트 볼륨을 정의해야 하는지 알아야 합니다.

이 책은 개발을 위해 필요한 정보를 전달하는게 목적이므로 퍼시스턴트 볼륨을 ❸ CSI명세로 정의하여 만들고 ❹ 제품별로 정의하여 만드는 방법은 다루지 않겠습니다. 단 실습을 위해 Network File Server로 퍼시스턴트 볼륨을 만드는 방법만 설명 하겠습니다.

CSI를 이용한 퍼시스턴트 볼륨 정의는 아래 글을 참고하세요.
https://kubernetes.io/ko/docs/concepts/storage/volumes/#csi

쿠버네티스 커뮤니티에서는 각 스토리지 제품별 CSI 드라이버를 아래 GitHub에서 제공하고 있습니다.
https://github.com/orgs/kubernetes-sigs/repositories?q=csi

제품별 퍼시스턴트 볼륨 정의는 아래 글을 참고하세요.
이 가이드는 첫번째 아키텍처대로 파드 명세에 직접 제품별 볼륨을 정의하는 방법을 안내하고 있습니다.
각 제품별 파드 명세에서 ‘volumes’ 항목을 참고하여 퍼시스턴트 볼륨을 만들면 됩니다.
https://kubernetes.io/ko/docs/concepts/storage/volumes/#volume-types

쿠버네티스는 위 가이드처럼 파드 명세에 직접 볼륨을 정의하는 방법을 제공하고 있습니다.
하지만 인프라스트럭처와의 느슨한 결합을 위해 퍼시스턴트볼륨과 퍼시스턴트 볼륨 클레임을 이용하는 것이 더 좋습니다.

퍼시스턴트 볼륨의 생성부터 소멸까지의 라이프 사이클은 아래와 같습니다.

❶ 프로비저닝: 퍼시스턴트 볼륨 오브젝트에 정의된 대로 물리적인 볼륨이 프로비저닝(공급)되는 단계입니다.
❷ 바인딩: 퍼시스턴트 볼륨 오브젝트가 퍼시스턴트 볼륨 클레임 오브젝트와 연결되는 단계입니다. 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트는 항상 1:1로 바인딩 되어야 한다는 걸 꼭 기억해 두십시오.
❸ 사용중: 파드에 볼륨이 마운트 되어 볼륨을 사용하는 단계 입니다. 파드 명세에 정의된 퍼시스턴트 볼륨 클레임과 바인딩된 퍼시스턴트 볼륨이 마운트 됩니다.
반환중: 퍼시스턴트 볼륨 클레임 오브젝트가 삭제 되어 볼륨이 반환 되는 단계입니다.
퍼시스턴트 볼륨 오브젝트에 정의한 반환 정책Reclaim Policy에 따라서 아래와 같이 다르게 처리 됩니다.

  • Retain: 퍼시스턴트 볼륨 오브젝트는 프로비저닝 단계로 돌아가고 물리적 볼륨의 데이터도 유지 됩니다.
    퍼시스턴트 볼륨 클레임과 바인딩 되려면 이전 바인딩 정보를 없애야 합니다.
  • Delete: 퍼시스턴트 볼륨 오브젝트가 자동으로 삭제되고 볼륨 종류에 따라 물리적 볼륨의 데이터도 삭제 됩니다. 현재 물리적 볼륨 삭제가 되는 볼륨 종류는 AWS EBS, GCE PD, Azure Disk 입니다.
  • Recycle: 볼륨 디렉토리 안의 파일들을 모두 삭제하고 프로비저닝 단계로 돌아갑니다. 아무 작업 없이도 퍼시스턴트 볼륨 클레임과 바인딩 될 수 있습니다. 이 정책은 향후 hostPath와 NFS 볼륨에서만 지원될 예정입니다.

Delete와 Recycle 반환 정책은 데이터가 사라질 수 있으니 주의해서 사용하셔야 합니다.
❺ 삭제: 반환 정책이 Delete인 경우 퍼시스턴트 볼륨이 삭제 됩니다.
<팁>
프로비저닝된 퍼시스턴트 볼륨을 바인딩 되기 전에 삭제하면 반환 정책과 상관 없이 물리 볼륨 데이터는 유지 됩니다.
</>
<주의>
파드에 마운트 되어 사용중인 퍼시스턴트 볼륨을 지우려면 먼저 파드를 삭제하고 퍼시스턴트 볼륨 클레임까지 지워야 합니다. 바인딩까지만 되어 있으면 퍼시스턴트 볼륨 클레임만 먼저 지우면 삭제할 수 있습니다.
</>

퍼시스턴트 볼륨 라이프 사이클을 실습해 보겠습니다.
현재 실습을 위해 생성한 퍼시스턴트 볼륨과 퍼시스턴트 볼륨 클레임은 hostPath볼륨을 사용하고 워커노드의 ‘/data/ott’볼륨과 연결되어 있습니다. hostPath볼륨은 Recycle과 Delete 반환 정책이 동작하려면 ‘/tmp’밑의 볼륨을 사용해야 합니다.
워커노드를 로그인하여 ‘/tmp/ott’디렉토리를 만들고 ‘/data/ott’의 파일들을 복사 하십시오.

[root@osboxes ~]# ssh w1
[root@worker1 ~]# mkdir -p /tmp/ott
[root@worker1 ~]# cp /data/ott/* /tmp/ott
[root@worker1 ~]# ll /tmp/ott
합계 8
-rw-r--r--. 1 root root 117  1월 21 03:55 bestott.properties
-rw-r--r--. 1 root root 116  1월 21 03:55 members.properties


배천노드의 작업 디렉토리로 돌아가서 퍼시스턴트 볼륨 오브젝트 야믈파일과 퍼시스턴트 볼륨 클레임 오브젝트 야믈을 다운로드 합니다.

[root@worker1 ~]# exit
logout
Connection to 169.56.70.201 closed.
[root@osboxes ~]# cd k8s/yaml
[root@osboxes yaml]# wget https://hiondal.github.io/k8s-yaml/3.11/pv-ott.yaml
[root@osboxes yaml]# wget https://hiondal.github.io/k8s-yaml/3.11/pvc-ott.yaml


파드를 모두 지우고 기존 퍼시스턴트 볼륨과 퍼시스턴트 볼륨 클레임을 삭제 합니다.

[root@osboxes yaml]# k delete deploy member recommend
[root@osboxes yaml]# k delete sts member recommend

[root@osboxes yaml]# k delete pvc ott
[root@osboxes yaml]# k delete pv ott


‘pv-ott.yaml’파일을 열어 ‘spec.persistentVolumeReclaimPolicy’를 ‘Retain’으로 바꾸십시오. hostPath값이 ‘/tmp/ott’인지 확인 하십시오.

kind: PersistentVolume
apiVersion: v1
metadata:
  name: ott
  labels:
    service: ott
spec:
  storageClassName: standard
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /tmp/ott


퍼시스턴트 볼륨 오브젝트를 생성하십시오. hostPath볼륨이 프로비저닝 됩니다.

[root@osboxes yaml]# k apply -f pv-ott.yaml


퍼시스턴트 볼륨 클레임 오브젝트를 생성 하십시오.

[root@osboxes yaml]# k apply -f pvc-ott.yaml


퍼시스턴트 볼륨 오브젝트는 프로비저닝에서 바인딩으로 바뀌게 됩니다.
조금 후 퍼시스턴트 볼륨 클레임 오브젝트를 확인해 보면 ‘STATUS’가 바운드 인것을 볼 수 있습니다.

[root@osboxes yaml]# k get pvc
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ott    Bound    ott      1Gi        RWO            standard       2m41s


퍼시스턴트 볼륨 오브젝트도 확인해 보면 ‘STATUS’가 바운드이고 ‘CLAIM’열에서 어떤 퍼시스턴트 볼륨 클레임 오브젝트와 바인딩 되었는지 볼 수 있습니다.

NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM ...
ott    1Gi        RWO            Retain           Bound    ott/ott


‘sts-member.yaml’로 파드까지 실행 하십시오. 이제 퍼시스턴트 볼륨 오브젝트는 사용중 단계로 바뀐 겁니다.

[root@osboxes yaml]# k apply -f sts-member.yaml


이제 퍼시스턴트 볼륨 클레임 오브젝트를 지웠을 때 어떻게 되는지 테스트 하겠습니다.
먼저 파드부터 지우고 퍼시스턴트 볼륨 클레임 오브젝트를 지우십시오.

[root@osboxes yaml]# k delete sts member
statefulset.apps "member" deleted
[root@osboxes yaml]# k delete pvc ott
persistentvolumeclaim "ott" deleted


반환 정책이 ‘Retain’일때 퍼시스턴트 볼륨 클레임 오브젝트를 지웠습니다.
퍼시스턴트 볼륨 오브젝트와 프로비저닝된 볼륨 모두 그대로 있을 겁니다.

[root@osboxes yaml]# k get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM  …
ott    1Gi        RWO            Retain           Released   ott/ott ..
[root@osboxes yaml]# ssh w1

[root@worker1 ~]# ll /tmp/ott
합계 8
-rw-r--r--. 1 root root 117  1월 21 04:10 bestott.properties
-rw-r--r--. 1 root root 116  1월 21 04:10 membe


다시 퍼시스턴트 볼륨 클레임 오브젝트와 바인딩 해 보겠습니다.
아무리 기다려도 바인딩이 되지 않을 겁니다.

[root@osboxes yaml]# k apply -f pvc-ott.yaml
persistentvolumeclaim/ott created
[root@osboxes yaml]# k get pvc -w
NAME   STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ott    Pending   ott      0                         standard       6s


퍼시스턴트 볼륨 오브젝트에 이전 퍼시스턴트 볼륨 클레임 오브젝트 정보가 남아서 그렇습니다.
퍼시스턴트 볼륨 오브젝트를 편집하여 그 정보를 지웁니다. 아래 리마크된 항목을 지우시면 됩니다.
또는 퍼시스턴트 볼륨 오브젝트를 지우고 다시 만들어도 됩니다.

[root@osboxes yaml]# k edit pv ott

 


spec:
  accessModes:
  …
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: ott
    namespace: ott
    #resourceVersion: "606004"
    #uid: db75fd01-dddd-4e19-a67c-69e6eab3fd44
  hostPath:
  …


이제 다시 확인해 보면 잘 바인딩 되었을 겁니다.

[root@osboxes yaml]# k get pvc
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ott    Bound    ott      1Gi        RWO            standard       5m47s


다음으로 반환정책 ‘Delete’를 테스트 해 봅시다.
아래 순서로 직접 테스트 해 보십시오.

  • 기존 오브젝트 삭제: 파드, 퍼시스턴트 볼륨 클레임 오브젝트, 퍼시스턴트 볼륨 오브젝트
  • ‘pv-ott.yaml’을 열고 ‘persistentVolumeReclaimPolicy’를 ‘Delete’로 변경
  • ‘pv-ott.yaml’ 이용하여 퍼시스턴트 볼륨 오브젝트 배포
  • ‘pvc-ott.yaml’ 이용하여 퍼시스턴트 볼륨 클레임 오브젝트 배포
  • 바인딩 확인
  • 퍼시스턴트 볼륨 클레임 오브젝트 삭제
  • 결과 확인: 퍼시스턴트 볼륨 오브젝트 자동 삭제, 프로비저닝된 볼륨 자동 삭제

위 결과 확인에서 퍼시스턴트 볼륨 오브젝트는 삭제되었는데 볼륨은 그대로일겁니다. hostPath볼륨은 자동 볼륨 삭제를 지원하지 않기 때문입니다.

마지막으로 반환정책 ‘Recycle’을 테스트 해 보십시오.
아래 순서로 직접 테스트 해 보십시오.

  • 기존 오브젝트 삭제: 파드, 퍼시스턴트 볼륨 클레임 오브젝트, 퍼시스턴트 볼륨 오브젝트
  • ‘pv-ott.yaml’을 열고 ‘persistentVolumeReclaimPolicy’를 ‘Recycle’로 변경
  • ‘pv-ott.yaml’ 이용하여 퍼시스턴트 볼륨 오브젝트 배포
  • ‘pvc-ott.yaml’ 이용하여 퍼시스턴트 볼륨 클레임 오브젝트 배포
  • 바인딩 확인
  • 퍼시스턴트 볼륨 클레임 오브젝트 삭제
  • 결과 확인: 퍼시스턴트 볼륨 오브젝트 유지, 프로비저닝된 볼륨의 디렉토리는 있고 파일들은 자동 삭제


아래와 같이 프로비저닝된 볼륨의 파일들이 전부 삭제 됩니다.

[root@osboxes yaml]# ssh w1
Last login: Fri Jan 21 04:50:32 2022 from 223.62.212.38
[root@worker1 ~]# ll /tmp/ott
합계 0


다시 퍼시스턴트 볼륨 클레임 오브젝트를 배포하면 바로 바인딩 되는 것도 확인해 보십시오.


4) 쿠버네티스가 지원하는 네트워크 스토리지 제품
쿠버네티스가 현재 지원하는 각 벤더별 네트워크 스토리지 제품은 아래와 같습니다.
볼륨 확장, RWO, ROX, RWX에 대해서는 조금 이따 설명 하겠습니다.

벤더 제품명 쿠버네티스 사용명 볼륨
확장
RWO ROX RWX
아마존 AWS AWS EBS(Elastic Block Store) awsElasticBlockStore O O    
MS Azure Azure Disk azureDisk O O    
Azure File azureFile   O O O
구글 GCP GCE PD(Persistent Disk) gcePersistentDisk O O O  
레드햇RedHat GlusterFS GlusterFS O O O O
포트웍스Portworx Portworx Volume portworxVolume O O   O
VMWare vSphere Volume vsphereVolume   O    
Ceph Ceph FS  cephfs   O O O
Ceph RBD rbd O O O  
기타 CSI csi O
NFS nfs   O O O
FlexVolume flexVolume O O O  
FC fc   O O  
iSCSI iscsi   O O  


제품별 퍼시스턴트 볼륨 정의는 아래 글을 참고하세요.
이 가이드는 파드 명세에 직접 제품별 볼륨을 정의하는 방법을 안내하고 있습니다.
각 제품별 파드 명세에서 ‘volumes’ 항목을 참고하여 퍼시스턴트 볼륨을 만들면 됩니다.
https://kubernetes.io/ko/docs/concepts/storage/volumes/#volume-types

5) 볼륨 크기 증가 방법
파드 안의 데이터베이스나 어플리케이션이 볼륨을 사용하다 원래 예상 보다 더 많은 데이터를 저장해야 한다면 볼륨 크기를 늘려야 합니다.
파드를 재시작하지 않고 볼륨 확장이 가능 합니다.
먼저 컨트롤 플레인의 ‘/etc/kubernetes/manifests/kube-apiserver.yaml’에 ‘ExpandInUsePersistentVolumes’ 옵션을 추가 해야 합니다.


spec:
  containers:
  - command:
    - kube-apiserver
    …
    - --feature-gates=ExpandInUsePersistentVolumes=true

<주의>
kube-apiserver.yaml을 저장하면 모든 파드가 재시작 됩니다.
서비스 중에는 하시면 안됩니다.
</>

아래와 같은 순서로 작업 하시면 됩니다.

  • 스토리지 제품이 볼륨 확장을 지원하는지와 스토리지 클래스가 볼륨 확장을 허용하는지 체크
  • 퍼시스턴트 볼륨 클레임 오브젝트의 볼륨 요청 크기 증가


첫번째 작업은 퍼시스턴트 볼륨 오브젝트와 스토리지 클래스를 관리하는 사람이 하면 되고 볼륨을 사용하는 사람은 퍼시스턴트 볼륨 클레임 오브젝트의 볼륨 요청 크기만 증가시키면 됩니다.

먼저 스토리지 제품이 볼륨 확장을 지원하는지는 ‘4) 쿠버네티스가 지원하는 네트워크 스토리지 제품’의 ‘볼륨확장'컬럼을 참고하시면 됩니다. 볼륨 확장을 지원하지 않는 제품도 CSI를 지원한다면 확장이 가능 합니다.
NFS는 퍼시스턴트 볼륨 오브젝트에 볼륨 제한을 하는 것이 의미 없습니다.
예를 들어 퍼시스턴트 볼륨 오브젝트에 1Gi로 지정해도 파일 서버의 스토리지에 100Gi가 할당되어 있다면 100Gi까지 쓸 수 있습니다.

스토리지 클래스가 볼륨 확장을 허용하는지 체크 합니다.
사용하고 있는 스토리지 클래스에 ‘allowVolumeExpansion’이 ‘true’로 되어 있어야 합니다.
실습에 사용하고 있는 스토리지 클래스 ‘standard’를 편집하여 이 항목을 추가 하십시오.

[root@osboxes yaml]# k edit sc standard

 


provisioner: kubernetes.io/no-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true


퍼시스턴트 볼륨 클레임 오브젝트의 볼륨 요청 크기만 증가 시키면 됩니다.
기존 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트를 모두 지우고 테스트 해 보겠습니다.

[root@osboxes yaml]# k delete pvc ott
[root@osboxes yaml]# k delete pv ott


‘pv-ott.yaml’에서 볼륨 반환 정책을 ‘Retain’으로 바꾸고 생성 하십시오. 용량은 1Gi로 그대로 놔둡니다.

[root@osboxes yaml]# vim pv-ott.yaml

 


spec: 
  …
  capacity:
    storage: 1Gi
  …
  persistentVolumeReclaimPolicy: Retain
  …

 

[root@osboxes yaml]# k apply -f pv-ott.yaml


‘pvc-ott.yaml’로 퍼시스턴트 볼륨 클레임 오브젝트를 생성 하십시오.

[root@osboxes yaml]# k apply -f pvc-ott.yaml
❯ k get pvc
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ott    Bound    ott      1Gi        RWO            standard       6s


퍼시스턴트 볼륨 클레임 오브젝트의 용량을 2Gi로 늘립니다.

[root@osboxes yaml]# k edit pvc ott

 


spec: 
  …
  resource:
    requests: 
      storage: 2Gi
  …


퍼시스턴트 볼륨 클레임 오브젝트를 다시 확인해 봅니다. 여전히 1Gi로 나올 겁니다.
NFS는 볼륨 확장을 제대로 지원하지 않기 때문입니다.
볼륨 확장을 지원하는 스토리지 제품은 자동으로 용량이 증가되어 표시 됩니다.

❯ k get pvc
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ott    Bound    ott      1Gi        RWO            standard       3m


별 의미는 없지만 NFS도 증가된 용량으로 표시하고 싶으면 아래와 같이 하시면 됩니다.
퍼시스턴트 볼륨 클레임 오브젝트를 지웁니다.

[root@osboxes yaml]# k delete pvc ott


퍼시스턴트 볼륨 오브젝트를 편집해서 볼륨을 증가 시킵니다. ‘claimRef’항목에서 ‘resourceVersion’과 ‘uid’를 지웁니다.

[root@osboxes yaml]# k edit pv ott

 


spec: 
  …
  capacity:
    storage: 3Gi  
  …
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: ott
    namespace: ott




‘pvc-ott.yaml’에서 요청 볼륨 사이즈는 증가 시키고 다시 생성 합니다.

[root@osboxes yaml]# vim pvc-ott.yaml

 


spec: 
  …
  resource:
    requests: 
      storage: 3Gi
  …

 

[root@osboxes yaml]# k apply -f pvc-ott.yaml
❯ k get pvc
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ott    Bound    ott      3Gi        RWO            standard       19s




 

11.2 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트 정의하기

파드에서 볼륨을 마운트 하기 위해서는 퍼시스턴트 볼륨 오브젝트를 먼저 만들고 퍼시스턴트 볼륨 클레임 오브젝트를 생성하여 바인딩해야 합니다.
퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트를 생성하기 위한 야믈 파일의 구조를 좀 더 알아 보겠습니다.
그리고 퍼시스턴트 볼륨 오브젝트를 정의할 때 바인딩할 퍼시스턴트 볼륨 클레임 오브젝트를 미리 예약하는 방법도 배워 보겠습니다.

1) 퍼시스턴트 볼륨
퍼시스턴트 볼륨의 구조는 아래와 같습니다.
이중에 생략이 가능한 항목은 ❶ labels, ❷ storageClassName, ❺ persistentVolumeReclaimPolicy, ❻ volumeMode 입니다.

레이블은 퍼시스턴트 볼륨 클레임 오브젝트의 ‘selector’에서 이용되어 정확한 바인딩이 되게 합니다.
각 스토리지 제품은 프로비저닝을 위한 스토리지 클래스가 있습니다.
우리가 사용하고 있는 ‘standard’ 스토리지 클래스의 내용을 보면 아래와 같이 프로비저너는 ‘kubernetes.io/no-provisioner’, 볼륨 반환 정책은 ‘Delete’, 볼륨 바인딩 모드는 ‘Immediate’로 되어 있고 볼륨 확장도 허용하고 있습니다.
볼륨 바인딩 모드를 ‘waitForFirstConsumer’로 지정하면 볼륨을 마운트하는 첫번째 파드가 실행될때까지 프로비저닝과 바인딩을 보류 합니다.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: standard
provisioner: kubernetes.io/no-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true


스토리지 종류에 따라 프로비저너 이름과 스토리지 클래스 정의 항목이 약간씩 다릅니다.
퍼시스턴트 볼륨 오브젝트를 관리하시는 분은 아래 글을 참고 하여 스토리지 클래스를 만드시면 됩니다.
https://kubernetes.io/ko/docs/concepts/storage/storage-classes

프로비저닝할 볼륨 용량을 메가바이트나 기가바이트로 지정 합니다. ‘m’과 ‘Gi’ 단위를 쓸 수 있습니다.
접근 모드accessMode는 볼륨 마운트를 한 노드에서만 하게 할지와 읽기/쓰기 권한을 정의 합니다.
아래와 같이 4개의 접근 모드를 지원 합니다.

  • ReadWriteOnce: RWO-한 노드에서만 볼륨 마운트를 할 수 있고 읽기/쓰기 허용
  • ReadWriteMany: RWX- 여러 노드에서 볼륨 마운트를 할 수 있고 읽기/쓰기 허용
  • ReadOnlyMany: ROX-여러 노드에서 볼륨 마운트를 할 수 있고 읽기만 허용
  • ReadWriteOncePod: RWOP-한 파드에서만 볼륨 마운트를 할 수 있고 읽기/쓰기 허용


RWO, RWX, ROX, RWOP는 CLI에서 퍼시스턴트 볼륨 오브젝트 정보를 볼 때 표시되는 약어 입니다.
ReadWriteOncePod는 CSI만 허용되며 쿠버네티스 1.22 이상에서만 지원 됩니다.
NFS는 어떤 접근 모드로 지정하든 여러 노드에서 마운트가 됩니다. 즉 RWX로 동작 합니다.
각 스토리지 제품별 허용하는 접근 모드는 ‘11.1의 쿠버네티스가 지원하는 네트워크 스토리지 제품'을 참고 하십시오.
CSI에 세모로 표시한 이유는 스토리지 제품에 따라 지원하지 못하는 것도 있기 때문입니다.

한 노드에서만 볼륨 마운트를 허용한다는 의미는 파드 복제본이 한 노드에만 여러개 실행될때는 마운트가 되지만 각각 다른 노드에 실행될 때는 한 파드만 마운트가 되고 다른 파드는 마운트가 되지 않는다는 의미 입니다.

볼륨 반환 정책은 이미 실습한것처럼 Retain, Delete, Recycle이 있으며 기본값은 Retain입니다.
볼륨 모드는 스토리지를 마운트하는 방법으로 블록Block으로 마운트할 지 파일시스템Filesystem으로 마운트 할지를 지정합니다. 기본값은 Filesystem입니다. 블록으로 마운트 한다는 것은 스토리지를 파티션(예: D드라이브 전체) 통째로 마운트 한다는 의미이고 파일시스템으로 마운트 한다는 것은 파티션 내의 특정 디렉토리나 파일을 마운트 한다는 의미 입니다. 특수한 목적이 아니라면 대부분 파일 시스템으로 마운트 합니다.
❼ 스토리지 제품별로 물리적인 볼륨에 대한 정보를 정의 합니다.
아래 글의 제품별 볼륨 정의를 참고하여 작성 합니다.
https://kubernetes.io/ko/docs/concepts/storage/volumes/#volume-types


2) 퍼시스턴트 볼륨 클레임
퍼시스턴트 볼륨 클레임의 구조는 아래와 같습니다.
이중에 생략이 가능한 항목은 ❶ storageClassName과 ❹ 레이블 셀렉터입니다.

스토리지 클래스 네임은 바인딩 할 퍼시스턴트 볼륨 오브젝트의 값과 똑같아야 합니다.
볼륨 요청 크기는 바인딩 할 퍼시스턴트 볼륨 오브젝트에 지정한 용량보다 같거나 작아야 합니다. 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트는 반드시 1:1로 매핑되므로 보통 퍼시스턴트 볼륨 오브젝트의 볼륨 크기와 동일하게 지정 합니다.
접근모드는 볼륨 마운트를 한 노드에서만 하게 할지와 읽기/쓰기 권한을 정의하는 것으로 역시 바인딩 할 퍼시스턴트 볼륨과 동일해야 합니다.
❹ 바인딩하고 싶은 퍼시스턴트 볼륨 오브젝트의 레이블을 지정 합니다. 이 항목은 생략할 수 있습니다.

새로운 퍼시스턴트 볼륨 클레임 오브젝트가 생성되면 ❶ 스토리지 클래스 네임, ❷ 볼륨 요청 크기, ❸ 접근 모드, ❹ 퍼시스턴트 볼륨 오브젝트 레이블 조건이 맞는 퍼시스턴트 볼륨 오브젝트가 바인딩 됩니다.
만약 조건에 맞는 퍼시스턴트 볼륨 오브젝트가 한개 이상이면 무작위로 한개가 선정되어 바인딩 됩니다.

<팁>
볼륨을 사용하는 사람이 퍼시스턴트 볼륨 오브젝트를 정의할 때 스토리지 클래스를 신경 쓰지 않게 할 수 있습니다.
기본 스토리지 클래스를 지정하면 퍼시스턴트 볼륨 클레임 오브젝트에 스토리지 클래스가 정의되지 않았을 때 자동으로 기본 스토리지 클래스가 사용되게 합니다.
기본 스토리지 클래스를 지정하는 방법은 ‘11.7 자동으로 볼륨 생성하기'에서 설명 하겠습니다.
</>

3) 퍼시스턴트 볼륨 클레임 오브젝트 예약 하기
퍼시스턴트 볼륨 오브젝트를 만들면서 바인딩 할 퍼시스턴트 볼륨 클레임 오브젝트를 지정할 수 있습니다.
‘claimRef’라는 항목에 퍼시스턴트 볼륨 클레임 오브젝트를 아래와 같이 지정하면 됩니다.

kind: PersistentVolume
apiVersion: v1
metadata:
  name: ott
  labels:
    service: ott
spec:
  storageClassName: standard
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /data/ott
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: ott
    namespace: ott


퍼시스턴트 볼륨 클레임 오브젝트를 생성하기 전에 미리 바인딩을 예약하는 것입니다.
특히 데이터베이스를 파드로 실행할 때 각 파드에 마운트할 퍼시스턴트 볼륨을 고정하고 싶을때 사용하면 유용 합니다.

‘claimRef’로 퍼시스턴트 볼륨 클레임 오브젝트를 예약하면 퍼시스턴트 볼륨 클레임 오브젝트에 정의한 볼륨 요청 크기와 볼륨 접근 모드 조건만 맞으면 바인딩 됩니다. 스토리지 클래스와 레이블 셀렉터는 무시 됩니다.
기존 퍼시스턴트 볼륨 클레임 오브젝트와 퍼시스턴트 볼륨 오브젝트를 지우고 테스트 해 보겠습니다.

[root@osboxes yaml]# k delete -f sts-member.yaml
[root@osboxes yaml]# k delete pvc ott
[root@osboxes yaml]# k delete pv ott


‘pv-ott.yaml’에 ‘claimRef’항목을 추가 합니다.

‘pvc-ott.yaml’에서 스토리지 클래스 네임과 레이블 셀렉터를 엉뚱한 값으로 지정 합니다.


spec:
  storageClassName: mystandard
  volumeName: ott
  resources:
    requests:
      storage: 1Gi
  accessModes:
  - ReadWriteOnce
  selector:
    matchLabels:
      service: myott


퍼시스턴트 볼륨 오브젝트를 생성하고 퍼시스턴트 볼륨 클레임 오브젝트도 생성 합니다.

[root@osboxes yaml]# k delete -f sts-member.yaml
[root@osboxes yaml]# k delete pvc ott
[root@osboxes yaml]# k delete pv ott


예상대로 잘 바인딩이 될 겁니다.

❯ k get pvc
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ott    Bound    ott      1Gi        RWO            mystandard     3s







11.3 파드 안에 임시 볼륨 만들어 사용하기

파드 로컬 볼륨을 사용하는 목적은 아래와 같이 어떤 처리를 위한 임시 공간이 필요하거나 컨피그맵, 시크릿, 파드 정보를 참조하기 위해서입니다.
파드 볼륨의 특징은 파드와 생사를 같이 한다는 것입니다. 파드가 실행될때 만들어지고 파드가 삭제되면 같이 삭제 됩니다.

구분 사용 목적 파드 삭제시
볼륨 폐기
볼륨 정의 키
어플리케이션 어떤 처리를 위한 임시 공간 Y emptyDir: {}
컨피그맵, 시크릿, 파드 정보 참조 Y - 컨피그맵: configMap
- 시크릿: secret
- 파드정보 참조: downwardAPI
데이터베이스 컨피그맵, 시크릿, 파드 정보 참조 Y


각각의 방법을 예제와 같이 알아 보겠습니다.

1) 어떤 처리를 위한 임시 공간 emptyDir
파드 내에 어떤 처리를 위해 자유롭게 읽고 쓸 수 있는 공간이 필요할 수 있습니다. 그리고 그 임시 공간은 파드안에 있으므로 파드가 사라지면 자동으로 없어 집니다.
샘플 야믈을 다운로드하여 테스트 해 보겠습니다.

[root@osboxes yaml]# cd ~/k8s/yaml
[root@osboxes yaml]# wget https://hiondal.github.io/k8s-yaml/3.11/emptydir.yaml
[root@osboxes yaml]# k apply -f emptydir.yaml


이미지는 도커를 배울 때 Node.js로 만든 간단한 웹서버입니다.
emptyDir로 파드 임시 볼륨을 ‘/cache’디렉토리로 마운트 합니다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: emptydir
  namespace: ott
spec:
  selector:
    matchLabels:
      app: emptydir
  replicas: 1
  serviceName: emptydir
  template:
    metadata:
      labels:
        app: emptydir
    spec:
      containers:
      - name: emptydir
        image: hiondal/hello
        imagePullPolicy: IfNotPresent
        startupProbe:
          exec:
            command:
            - /bin/sh
            - -ec
            - |
              echo hello > /cache/hi
        volumeMounts:
        - mountPath: /cache
          name: cache
      volumes:
      - name: cache
        emptyDir: {}

<팁>
‘startupProbe’는 파드 시작 시 초기 수행을 할 수 있는 방법입니다.
위 예제에서는 임시 볼륨으로 마운트한 ‘/cache’디렉토리에 ‘hi’라는 파일을 만듭니다.
</>
마운트된 디렉토리에 ‘hi’라는 파일이 잘 생성 되었는지 체크 해 봅니다.

[root@osboxes yaml]# k exec -it emptydir-0 -- cat /cache/hi
hello


emptyDir은 리눅스에서 메모리를 파일 시스템처럼 사용할 수 있는 tmpfs 공간을 마운트하여 사용할 수 있습니다.
tmpfs는 메모리 공간이기 때문에 매우 처리 속도가 빨라 유용하게 사용할 수 있습니다.
아래와 같이 emptyDir.medium을 ‘Memory’로 지정 하면 됩니다.


      volumes:
      - name: cache
        emptyDir:
          medium: Memory



2) 컨피그맵과 시크릿을 파드내에 마운트
컨피그맵과 시크릿을 파드에 마운트 하는 방법은 이미 ‘busybox’ 이미지를 이용해서 배웠습니다.
아래와 같이 샘플 야믈을 내려 받고 그 내용을 확인해 보시기 바랍니다.

[root@osboxes yaml]# cd ~/k8s/yaml
[root@osboxes yaml]# wget https://hiondal.github.io/k8s-yaml/3.10/sts-busybox-final.yaml

 


        volumeMounts:
        - name: myconfig
          mountPath: /home/config
        - name: mysecret
          mountPath: /home/secret/secret.conf
          subPath: secret.conf
        - name: projected
          mountPath: /home/projected
      volumes:
      - name: myconfig
        configMap:
          name: cm3
      - name: mysecret
        secret:
          secretName: secret3
      - name: projected
        projected:
          sources:
          - configMap:
              name: cm3
              items:
              - key: cm.conf
                path: cm/cm.conf
              - key: imgreg.conf
                path: cm/imgreg.conf
          - secret:
              name: secret3
              items:
              - key: secret.conf
                path: secret/secret.conf



3) 파드 정보 참조를 위한 downwardAPI
파드 명세에 정의한 내용을 볼륨으로 마운트하여 사용할 수 있습니다.
예를 들어 파드 안의 어플리케이션에서 파드의 이름이나 네임스페이스를 알아야 할 때 별도의 컨피그맵으로 만들면 이중 관리가 되어 비효율적입니다.
이 문제를 downwardAPI 볼륨을 이용하여 해결할 수 있습니다.
downwardAPI 볼륨과 환경변수를 이용하여 아래와 같은 정보를 참조할 수 있습니다.

구분 참조값 참조 방법 참조 경로
파드 노드명 환경변수 spec.nodeName
노드IP 환경변수 status.hostIP
네임스페이스 볼륨 metadata.namespace
파드명 볼륨 metadata.name
파드IP 환경변수 status.podIP
파드 유니크 아이디 볼륨 metadata.uid
서비스 어카운트 환경변수 spec.serviceAccountName
파드 레이블 볼륨 metadata.labels
metadata.labels[‘{key}’]
파드 어노테이션 볼륨 metadata.annotations
metadata.annotations[‘{key}’]
컨테이너 CPU 요청 크기 볼륨 requests.cpu
CPU 최대 크기 볼륨 limits.cpu
메모리 요청 크기 볼륨 requests.memory
메모리 최대 크기 볼륨 limits.memory


예제 야믈을 다운로드하여 실행하여 테스트 해 보시기 바랍니다.

[root@osboxes yaml]# cd ~/k8s/yaml
[root@osboxes yaml]# wget https://hiondal.github.io/k8s-yaml/3.11/downwardapi.yaml

 

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: downwardapi
  namespace: ott
spec:
  selector:
    matchLabels:
      app: downwardapi
  replicas: 1
  serviceName: downwardapi
  template:
    metadata:
      labels:
        app: downwardapi
    spec:
      serviceAccount: sa-ott
      containers:
      - name: downwardapi
        image: hiondal/hello
        imagePullPolicy: IfNotPresent
        resources:
          requests:
            cpu: 128m
            memory: 256Mi
          limits:
            cpu: 256m
            memory: 512Mi

        env:
        - name: THIS_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: THIS_NODE_IP
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        - name: THIS_POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: THIS_SERVICE_ACCOUNT
          valueFrom:
            fieldRef:
              fieldPath: spec.serviceAccountName

        volumeMounts:
        - mountPath: /info/pod
          name: podinfo
        - mountPath: /info/container
          name: containerinfo
      volumes:
      - name: podinfo
        downwardAPI:
          items:
          - path: namespace
            fieldRef:
              fieldPath: metadata.namespace
          - path: podname
            fieldRef:
              fieldPath: metadata.name
          - path: poduid
            fieldRef:
              fieldPath: metadata.uid
          - path: labels
            fieldRef:
              fieldPath: metadata.labels['app']
          - path: annotations
            fieldRef:
              fieldPath: metadata.annotations

      - name: containerinfo
        downwardAPI:
          items:
          - path: "cpu_limit"
            resourceFieldRef:
              containerName: downwardapi
              resource: limits.cpu
              divisor: 1m
          - path: "cpu_request"
            resourceFieldRef:
              containerName: downwardapi
              resource: requests.cpu
              divisor: 1m
          - path: "mem_limit"
            resourceFieldRef:
              containerName: downwardapi
              resource: limits.memory
              divisor: 1Mi
          - path: "mem_request"
            resourceFieldRef:
              containerName: downwardapi
              resource: requests.memory
              divisor: 1Mi

컨테이너 정보를 얻기 위한 downwardAPI 볼륨에서 ‘divisor’는 값을 표시할 단위입니다. 예를 들어 메모리를 1기가 단위로 표시하고 싶으면 1024Mi 또는 1Gi로 지정하시면 됩니다.

파드를 실행하고 파드 안으로 진입하여 ‘/info/podinfo’와 ‘/info/containerinfo’에 생성된 파일을 확인해 보십시오.
또한 환경 변수로 생성된 정보는 ‘env | grep THIS’로 확인해 볼 수 있습니다.

[root@osboxes yaml]# k apply -f downwardapi.yaml
[root@osboxes yaml]# k exec -it downwardapi-0 -- sh



11.4 노드 로컬 스토리지의 볼륨 사용하기

노드 로컬 스토리지는 클러스터를 구성하는 노드의 볼륨을 사용하는 방식입니다.
노드 로컬 스토리지 볼륨에는 hostPath와 local의 두가지가 있습니다.
hostPath 볼륨은 파드가 실행되는 노드의 볼륨을 의미하고 local볼륨은 파드가 실행될 노드를 지정하여 정의하는 볼륨을 의미 합니다.

그럼 각 볼륨을 예제를 통해 배워 보도록 하겠습니다.

1) hostPath 볼륨
여러분은 ‘member’와 ‘recommend’파드를 실행하기 위해 hostPath 볼륨을 사용해 봤습니다.
‘volume-ott.yaml’의 퍼시스턴트 볼륨 오브젝트 정의를 보면 ‘path’에 데이터가 있는 디렉토리를 지정하였습니다.

[root@osboxes]# cd ~/k8s/yaml
[root@osboxes yaml]# wget https://hiondal.github.io/k8s-yaml/3.4/volume-ott.yaml

 

kind: PersistentVolume
apiVersion: v1
metadata:
  name: ott
  labels:
    service: ott
spec:
  storageClassName: standard
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  hostPath:
    path: /data/ott
    type: Directory


hostPath볼륨을 사용하려면 파드가 실행될 모든 노드에 ‘path’에 지정한 디렉토리나 파일이 있어야 합니다.
hostPath는 정의한 볼륨이 어떤 유형인지 명확히 나타내기 위해 ‘type’을 지정할 수 있습니다.
hostPath에서 지정할 수 있는 볼륨 유형은 아래와 같습니다.

유형 설명
File 파일을 의미하며 지정된 파일이 반드시 존재해야 마운트됨
FileOrCreate 파일을 의미하여 지정된 파일이 없으면 0644 권한으로 생성함
kubelet이 생성하므로 보통 오너는 root로 파일이 생성됨
Directory 디렉토리를 의미하며 지정된 디렉토리가 반드시 존재해야 마운트됨
DirectoryOrCreate 디렉토리를 의미하며 지정된 디렉토리가 없으면 0755권한으로 생성함
kubelet이 생성하므로 보통 오너는 root로 디렉토리가 생성됨
Socket 지정된 경로에 유닉스/리눅스 소켓이 있어야 함
CharDevice 지정된 경로에 문자 디바이스가 있어야 함
BlockDevice 지정된 경로에 블럭 디바이스가 있어야 함

<팁>
0644나 0755와 같은 파일 권한의 의미에 대해서는 아래 글을 참고하십시오.
https://happycloud-lee.tistory.com/132
</>

그런데 어떤 경우에 hostPath볼륨을 쓸까요 ? 우리가 실습한 예제에서는 hostPath볼륨은 적합하지 않습니다.
보통 사용하는 경우는 쿠버네티스의 컨테이너 실행 엔진인 도커(/var/lib/docker)나 크라이오(/var/lib/crio)의 파일을 를 참조하거나 파드가 실행되기 위해서 사전에 있어야 하는 노드의 볼륨을 체크하기 위해서 사용 됩니다.
hostPath볼륨은 호스트 노드의 파일 시스템을 접근하기 때문에 보안적으로 매우 위험할 수 있습니다.
따라서 특별한 용도가 아니라면 사용하지 않는 것이 좋고 만약 꼭 사용해야 한다면 읽기 전용으로 마운트 하셔야 합니다.
읽기 전용으로 마운트 하는 방법은 아래 ‘member’워크로드 컨트롤러 명세 처럼 ‘volumeMounts’와 ‘persistentVolumeClaim’에 ‘readOnly: true’를 추가하시면 됩니다.


            memory: 128Mi
        volumeMounts:
        - name: data
          mountPath: /home/docker/data
          readOnly: true
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: ott
          readOnly: true

<팁>
읽기 전용으로 마운트 하여도 퍼시스턴트 볼륨 오브젝트의 볼륨 타입이 ‘FileOrCreate’나 ‘DirectoryOrCreate’이면 지정된 경로에 그 파일이나 디렉토리가 없으면 생성 합니다.
단, 파드 안에서 그 디렉토리나 파일을 수정하거나 삭제할 수는 없습니다.
</>

hostPath볼륨의 유형에 따른 테스트는 직접 해 보시기 바랍니다.
실습은 읽기 전용으로 마운트 하여 실제로 파드 안에서 파일 시스템을 수정할 수 없는지 해 보겠습니다.
우선 기존의 오브젝트들 정리 부터 합니다.
‘member’파드, 퍼시스턴트 볼륨 오브젝트, 퍼시스턴트 볼륨 클레임 오브젝트를 모두 지웁니다.

[root@osboxes]# cd ~/k8s/yaml
[root@osboxes yaml]# k delete sts member
[root@osboxes yaml]# k delete deploy member  
[root@osboxes yaml]# k delete pvc ott
[root@osboxes yaml]# k delete pv ott


‘volume-ott.yaml’파일을 이용하여 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트를 만듭니다.
‘sts-member.yaml’파일을 새로 다운로드 하고 배포 하십시오.

[root@osboxes yaml]# k apply -f volume-ott.yaml
[root@osboxes yaml]# rm -f sts-member.yaml
[root@osboxes yaml]# wget https://hiondal.github.io/k8s-yaml/3.11/sts-member.yaml


‘sts-member.yaml’의 내용을 잠깐 봐 주십시오.
파드는 2개이고 ‘volumeMounts’와 ‘persistentVolumeClaim’에 ‘readOnly: true’항목을 추가했습니다.
‘spec.template.spec.tolerations’는 컨트롤 플레인에도 배포가 되게 하는 정의 입니다.


spec:
  …
  replicas: 2
  …
  template:
    …
    spec:
      serviceAccount: sa-ott
      tolerations:
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: ""
      containers:
        …
        volumeMounts:
        - name: data
          mountPath: /home/docker/data
          readOnly: true
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: ott
          readOnly: tru


‘member’파드를 배포합니다.

[root@osboxes yaml]# k apply -f sts-member.yaml
[root@osboxes yaml]# k get po -o wide
NAME   …     NODE
member-0  …  worker1
member-1  …  master


컨트롤 플레인에 배포한 파드( 위 예에서는 ‘member-1’)의 로그를 보면 파일을 못 찾아 에러가 났을 겁니다.
컨트롤 플레인에는 퍼시스턴트 볼륨 오브젝트에 지정한 ‘/data/ott’디렉토리가 없기 때문입니다.

[root@osboxes yaml]# k logs -f member-1
… 
PATH==>/home/docker/data/members.properties
java.io.FileNotFoundException: /home/docker/data/members.properties (No such file or directory)


워커 노드에 배포한 파드를 진입하여 마운트된 디렉토리로 이동하여 파일을 생성해 보십시오.
아래와 같이 읽기 전용 파일 시스템이라는 에러 메시지를 날 겁니다.

[root@osboxes yaml]# k exec -it member-0 -- sh
$ cd /home/docker/data
$ ls -al
total 24
drwxr-xr-x. 3 docker root   4096 Jan 24 07:19 .
drwxr-xr-x. 1 docker docker 4096 Jan 24 07:59 ..
-rwxr-xr-x. 1 root   root    117 Jan  7 09:27 bestott.properties
-rwxr-xr-x. 1 root   root    116 Jan  7 09:27 members.properties
$ touch hello
touch: cannot touch 'hello': Read-only file system



2) local 볼륨
local볼륨은 볼륨을 프로비저닝할 특정 노드를 지정하여 그 노드에 파드가 배포되게 합니다.

local볼륨은 마운트 할 볼륨이 특정 노드(들)에 있는 경우 파드가 그 특정 노드(들)에 배포 되도록 할 때 유용 합니다.
노드를 지정하는 방식은 파드 스케줄링때 배운 노드 어피니티와 유사합니다.

물론 우리가 이미 배운 노드셀렉터, 노드 어피니티, 파드 어피니티, 파드 안티 어피니티를 이용해도 되겠지만 반드시 볼륨이 있는 노드에 배포해야 한다면 local볼륨이 가장 확실한 방법입니다.
아래 그림을 보면 좀 더 명확히 이해가 되실 겁니다.


<주의>
파드 스케줄링 방식 중 노드네임을 사용하면 무조건 그 노드에 할당 하므로 local볼륨의 nodeAffinity는 의미가 없어 집니다.
</>

local볼륨을 사용할 때는 볼륨 바인딩 모드가 ‘Immediate’가 아닌 ‘WaitForFirstConsumer’인 스토리지 클래스를 사용하는게 좋습니다. ‘WaitForFirstConsumer’모드는 볼륨을 마운트하는 파드가 실행 되기 전까지 바인딩과 볼륨 프로비저닝을 유보하는 옵션입니다.
단, 이 볼륨 바인딩 모드를 지원하는 스토리지 제품은 3개밖에 없습니다. local볼륨도 지원된다고 공식문서에는 있지만 제대로 되지 않습니다.
지원되는 3개 제품은 AWS Elastic Block Store, GCE Persistent Disk, Azure Disk입니다.

그럼 예제를 통해 local볼륨 사용법을 배워 보겠습니다.
먼저 기존 파드, 퍼시스턴트 볼륨 오브젝트, 퍼시스턴트 볼륨 클레임 오브젝트를 모두 지웁니다.

[root@osboxes yaml]# k delete -f sts-member.yaml
[root@osboxes yaml]# k delete -f volume-ott.yaml


local볼륨으로 정의된 야믈 파일을 다운로드 합니다.


‘localvol.yaml’의 퍼시스턴트 볼륨 오브젝트를 정의를 보면 ‘local’항목에 볼륨의 경로를 지정하였고 ‘nodeAffinity’에 배포할 노드의 조건을 지정하였습니다.
아래 노드 셀렉터 조건은 노드 레이블 ‘node-role.kubernetes.io/control-plane’이 존재하는 노드에 배포하라는 것입니다.


  persistentVolumeReclaimPolicy: Retain
  local:
    path: /data/ott
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: node-role.kubernetes.io/control-plane
          operator: Exists


퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트를 생성한 후 ‘member’파드를 배포합니다.

[root@osboxes yaml]# k apply -f localvol.yaml
[root@osboxes yaml]# k apply -f sts-member.yaml


파드가 컨트롤 플레인에 2개 배포 됩니다. local볼륨의 nodeAffinity 조건이 없었다면 각 노드에 1개씩 배포 되었을 것입니다.

[root@osboxes yaml]# k get po -o wide
NAME   …     NODE
member-0  …  master
member-1  …  master

 

11.5 네트워크 스토리지의 볼륨 사용하기

이제 가장 많이 사용하는 네트워크 스토리지 볼륨을 배워 볼 차례입니다.
다시 한번 쿠버네티스가 지원하는 네트워크 스토리지 볼륨을 정리하면 아래와 같습니다.

벤더 제품명 쿠버네티스 사용명 볼륨
확장
RWO ROX RWX
아마존 AWS AWS EBS(Elastic Block Store) awsElasticBlockStore O O    
MS Azure Azure Disk azureDisk O O    
Azure File azureFile   O O O
구글 GCP GCE PD(Persistent Disk) gcePersistentDisk O O O  
레드햇RedHat GlusterFS GlusterFS O O O O
포트웍스Portworx Portworx Volume portworxVolume O O   O
VMWare vSphere Volume vsphereVolume   O    
Ceph Ceph FS  cephfs   O O O
Ceph RBD rbd O O O  
기타 CSI csi O
NFS nfs   O O O
FlexVolume flexVolume O O O  
FC fc   O O  
iSCSI iscsi   O O  


이중에 실습에서는 NFSNetwork File System 볼륨을 사용하겠습니다.

먼저 NFS 서버를 구성 하겠습니다.
그리고 NFS볼륨을 퍼시스턴트 볼륨 오브젝트에 정의하여 파드에 마운트 하는걸 실습해 보겠습니다.

1) NFS 서버 구성
인그레스 학습할 때 웹 서버로 구매한 VM에 NFS서버를 설치 하겠습니다.

제일 먼저 SSH설정을 하겠습니다. 계속 암호 입력해서 로그인하기 귀찮기 때문입니다.
SSH key를 NFS서버로 복사 합니다. 당연히 NFS서버의 IP는 본인 걸로 바꾸셔야 합니다.

[root@osboxes yaml]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@169.56.70.205

root@169.56.70.205's password:
Number of key(s) added: 1


NFS서버 정보를 ‘~/.ssh/config’파일에 추가 합니다.
호스트 ID는 ‘nfs’로 합니다. ‘HostName’은 본인 NFS 서버의 퍼블릭 IP로 바꾸 십시오.

[root@osboxes yaml]# vim ~/.ssh/config

Host nfs
HostName 169.56.70.205
User root
IdentityFile ~/.ssh/id_rsa


잘 로그인이 되는지 테스트 합니다.

[root@osboxes yaml]# ssh nfs
Last login: Mon Jan 24 09:39:18 2022 from 223.38.21.113
[root@web ~]#


굳이 안해도 되지만 호스트명도 ‘nfs’로 바꿉니다. 변경한 후에는 빠져 나갔다가 다시 들어와야 합니다.

[root@web]# hostnamectl set-hostname nfs
Last login: Mon Jan 24 09:39:18 2022 from 223.38.21.113
[root@web ~]# exit
[root@osboxes yaml]# ssh nfs
[root@nfs ~]#


NFS 서버를 로그인한 후 아래와 같이 설치 하십시오.

NFS 서버를 설치하고 OS 시작 시 프로그램으로 추가하면서 시작 합니다.

[root@nfs]# dnf install nfs-utils
[root@nfs]# systemctl enable nfs-server.service --now


볼륨 디렉토리 ‘/data’를 작성 합니다.

[root@nfs]# mkdir /data


NFS 서버를 사용할 클라이언트 VM의 사설 IP를 등록 합니다.
컨트롤 플레인과 워커노드의 프라이빗 IP를 등록 하면 됩니다.
프라이빗 IP는 각 VM에서 아래와 같이 구하시면 됩니다. ‘eth0’의 IP가 프라이빗 IP입니다.
아래 예에서 컨트롤 플레인의 프라이빗 IP는 10.178.189.46 입니다.

[root@master]# ip a | grep 10.
[root@master ~]# ip a | grep 10.
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 10.178.189.46/26 brd 10.178.189.63 scope global noprefixroute eth0


각 VM의 프라이빗 IP를 구했으면 ‘/etc/exports’파일에 자신 VM의 프라이빗 IP를 아래와 같이 등록 하십시오.

[root@nfs]# vi /etc/exports
/data 10.178.189.19(rw,sync,no_subtree_check,no_root_squash)
/data 10.178.189.46(rw,sync,no_subtree_check,no_root_squash)


등록 된 설정을 적용 합니다.

[root@nfs]# exportfs -arv
exporting 10.178.189.19:/data
exporting 10.178.189.46:/data


NFS서버 설치를 완료 하였습니다.

이제 NFS서버를 사용할 클라이언트인 컨트롤 플레인과 워커 노드에서 아래 작업만 하시면 됩니다.
‘showmount’명령은 NFS서버의 볼륨 디렉토리인 ‘/data’를 현재 VM에 마운트 할 수 있는지 테스트 하는 겁니다.
이때 지정하는 IP는 NFS서버의 프라이빗 IP입니다.

[root@master]# dnf install -y nfs-utils nfs4-acl-tools
[root@master]# showmount -e 10.178.189.25
Export list for 10.178.189.25:
/data 10.178.189.46,10.178.189.19

 

[root@worker1]# dnf install -y nfs-utils nfs4-acl-tools
[root@worker1]# showmount -e 10.178.189.25
Export list for 10.178.189.25:
/data 10.178.189.46,10.178.189.19


NFS 서버 설치 및 구성을 모두 완료 하였습니다.

2) NFS 볼륨 사용 실습
이제는 NFS볼륨을 파드 안에 마운트 해 보겠습니다.
파드에 볼륨을 마운트 해야 하니까 먼저 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트를 만들어야 합니다.

기존 파드, 퍼시스턴트 볼륨 오브젝트, 퍼시스턴트 볼륨 클레임 오브젝트들을 모두 지웁니다.

[root@osboxes yaml]# cd ~/k8s/yaml
[root@osboxes yaml]# k delete -f sts-member.yaml
[root@osboxes yaml]# k delete -f localvol.yaml


NFS볼륨을 사용하기 위한 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트 정의 야믈 파일을 다운로드 합니다.


퍼시스턴트 볼륨 오브젝트 정의 부분을 보시면 ‘nfs’항목에 NFS서버의 IP와 볼륨 디렉토리 경로가 있습니다.
본인의 NFS서버 프라이빗 IP로 바꾸 십시오.


  persistentVolumeReclaimPolicy: Retain
 
  nfs:
    server: 10.178.189.25
    path: /data/ott


NFS서버에 ‘/data/ott’디렉토리를 만들어야 겠죠 ? 그리고 그 디렉토리에 ‘members.properties’와 ‘bestott.properties’파일도 만들어야 합니다.
배천 노드에서 필요한 파일들을 워커 노드에서 NFS서버로 복사 하십시오.

[root@osboxes yaml]# scp -r w1:/data/ott .

[root@osboxes yaml]# scp -r ./ott nfs:/data

[root@osboxes yaml]# ssh nfs ls -al /data/ott
합계 16
drwxr-xr-x. 2 root root 4096  1월 24 09:53 .
drwxr-xr-x. 3 root root 4096  1월 24 09:52 ..
-rwxr-xr-x. 1 root root  117  1월 24 09:54 bestott.properties
-rwxr-xr-x. 1 root root  116  1월 24 09:54 members.properties


‘nfsvol.yaml’파일을 이용하여 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트를 생성 합니다.

[root@osboxes yaml]# k apply -f nfsvol.yaml
[root@osboxes yaml]# k get pvc
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ott    Bound    ott      1Gi        RWO            standard       9s


‘sts-member.yaml’파일로 ‘member’ 파드를 실행 합니다.
이 파일은 퍼시스턴트 볼륨 클레임 오브젝트의 이름이 그대로이므로 수정할 필요가 없습니다.
다만 퍼시스턴트 볼륨 클레임 오브젝트와 바인딩된 퍼시스턴트 볼륨 클레임 오브젝트가 NFS서버의 볼륨으로 프로비저닝 되었다는게 바뀐 겁니다.

[root@osboxes yaml]# k apply -f sts-member.yaml
[root@osboxes yaml]# k get po -o wide


‘member’ 파드의 로그를 보고 파드가 실행될때가지 기다립니다.
아래와 같이 NFS서버의 ‘/data/ott’ 볼륨이 파드 내에 ‘/home/docker/data’로 잘 마운트 되어 ‘members.properties’파일을 읽는 것을 확인할 수 있습니다.

[root@osboxes yaml]# k logs -f member-0

2022-01-24 16:03:32.332  INFO 8 --- [           main] sConfig$$EnhancerBySpringCGLIB$$17b9a9fd : FILE PATH==>/home/docker/data/members.properties

2022-01-24 16:03:32.430  INFO 8 --- [           main] sConfig$$EnhancerBySpringCGLIB$$17b9a9fd : ondal=온달,남자,hiondal@gmail.com
2022-01-24 16:03:32.529  INFO 8 --- [           main] sConfig$$EnhancerBySpringCGLIB$$17b9a9fd : user1=유저1,여자,user1@gmail.com
2022-01-24 16:03:32.530  INFO 8 --- [           main] sConfig$$EnhancerBySpringCGLIB$$17b9a9fd : user2=유저2,여자,user2@gmail.com


다른 ‘member’ 파드도 로그를 확인해 봅시다.
그 파드도 볼륨이 잘 마운트 되어 정상 동작할 겁니다.

11.6 워크로드 컨트롤러에 퍼시스턴트 볼륨 클레임 오브젝트 정의하기

이제까지는 퍼시스턴트 볼륨 클레임 오브젝트를 별도로 생성 하고 워크로드 컨트롤러의 ‘volumes’에서는 ‘volumes.persistentVolumeClaim’에 그 퍼시스턴트 볼륨 클레임 오브젝트의 이름을 지정 하였습니다.
어플리케이션을 배포할 때는 보통 이렇게 합니다.
그런데 데이터베이스를 파드로 배포할때는 조금 다릅니다.
데이터베이스 파드는 각 파드가 자기 자신만의 데이터 저장소가 필요 합니다.
DB는 아래 아키텍처와 같이 각 파드가 고유의 볼륨을 갖고 있고 그 볼륨 간 복제를 통해 데이터를 동기화 합니다.

따라서 각 파드의 볼륨 마운트를 위한 퍼시스턴트 볼륨 클레임 오브젝트를 별도로 만드는 건 비효율적입니다.
쿠버네티스는 워크로드 컨트롤러를 정의하면서 퍼시스턴트 볼륨 클레임 오브젝트를 같이 정의하는 방법을 제공 합니다.
이를 실습하기 위해 실무에서 많이 사용하는 MySQL을 배포해 보겠습니다.

먼저 워크로드 컨트롤러에서 퍼시스턴트 볼륨 클레임 오브젝트를 정의하는 방법을 알아 보겠습니다.
그리고 퍼시스턴트 볼륨 오브젝트를 생성하면서 바인딩할 퍼시스턴트 볼륨 클레임 오브젝트를 예약하겠습니다.
마지막으로 MySQL 파드를 배포하겠습니다.
MySQL파드는 프라이머리 파드 1개와 세컨더리 파드 2개를 배포하겠습니다.

1) 워크로드 컨트롤러에 퍼시스턴트 볼륨 클레임 오브젝트 정의하기
MySQL을 배포하는 야믈 파일부터 다운로드 해 주십시오.


‘member-primary.yaml’을 열고 스테이트풀셋 ‘member-primary’의 맨 아래 부분을 보면 ‘volumeClaimTemplate’을 보십시오.
조금 위 쪽의 ‘volumeMounts’에서 ‘data’라는 이름의 볼륨을 ‘/bitnami/mysql’에 마운트 하도록 정의하고 있습니다.
퍼시스턴트 볼륨 클레임 오브젝트를 별도로 생성한다면 바로 밑의 ‘volumes’에 ‘persistentVolumeClaim’으로 별도 생성한 오브젝트로 지정했을 겁니다.
여기서는 그 대신에 ‘volumeClaimTemplate’이라는 항목 밑에 퍼시스턴트 볼륨 클레임 오브젝트를 바로 정의 하였습니다.
이렇게 각 파드가 고유의 데이터 볼륨이 필요한 경우는 워크로드 컨트롤러에 바로 퍼시스턴트 볼륨 클레임 오브젝트를 정의할 수 있습니다.
‘volumeClaimTemplate’으로 퍼시스턴트 볼륨 클레임 오브젝트를 정의하면 워크로드 컨트롤러가 배포될때 자동으로 지정한 명세대로 퍼시스턴트 볼륨 클레임 오브젝트가 생성 됩니다.
생성되는 퍼시스턴트 볼륨 클레임 오브젝트의 이름은 ‘{퍼시스턴트 볼륨 클레임 오브젝트명}-{워크로드 컨트롤러 오브젝트명}-{일련번호}’으로 생성 됩니다.
따라서 아래 퍼시스턴트 볼륨 클레임 오브젝트는 ‘data-member-primary-0’으로 생성 됩니다.


      volumes:
      - configMap:
          defaultMode: 420
          name: mysql
        name: config
      - configMap:
          defaultMode: 420
          name: member-dbinit
        name: initdb
  volumeClaimTemplates:
  - apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      labels:
        app.kubernetes.io/component: primary
        app.kubernetes.io/instance: member
        app.kubernetes.io/name: mysql
      name: data
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
      storageClassName: standard
      volumeMode: Filesystem


생성되는 퍼시스턴트 볼륨 클레임 오브젝트는 파드를 삭제해도 자동으로 삭제 되지 않습니다.
만약 임시로 사용하는 볼륨이라 파드가 삭제되면 자동으로 퍼시스턴트 볼륨 클레임 오브젝트를 삭제하고 싶으면 에페메랄ephemeral 볼륨을 사용할 수 있습니다.
에페메랄 볼륨은 단어 뜻 그대로 임시 볼륨으로 파드 로컬 볼륨처럼 파드와 라이프 사이클을 같이 하는 볼륨 입니다.
‘member-secondary.yaml’을 ‘ephemeral.yaml’로 복사하고 에페메랄 볼륨으로 바꿔 보겠습니다.
아래와 같이 ‘volumes’에 만들고 ‘volumes.ephemeral’ 밑에 퍼시스턴트 볼륨 오브젝트 명세를 정의하면 됩니다.
기존의 volumeClaimTemplates와 다른 점은 아래와 같습니다.

  • volumeClaimTemplates에서 단수형인 volumeClaimTemplate으로 변경
  • apiVersion, kind, name, volumeMode는 삭제 해야 함
  • metadata, spec.accessModes, spec.resources만 정의
  • 생성되는 퍼시스턴트 볼륨 클레임 오브젝트의 이름은 ‘{퍼시스턴트 볼륨 클레임 오브젝트명}-{워크로드 컨트롤러 오브젝트명}-{일련번호}’에서 ‘{워크로드 컨트롤러 오브젝트명}-{일련번호}-{볼륨명}’으로 달라짐

      volumes:
      - configMap:
          defaultMode: 420
          name: mysql
        name: config
      - name: data
        ephemeral:
          volumeClaimTemplate:
            metadata:
              labels:
                app.kubernetes.io/component: secondary
                app.kubernetes.io/instance: member
                app.kubernetes.io/name: mysql
            spec:
              accessModes:
              - ReadWriteOnce
              resources:
                requests:
                  storage: 1Gi


기존 ‘member-secondary’파드를 지우고 ‘ephemeral.yaml’을 이용하여 다시 배포 합니다.

[root@osboxes yaml]# k delete -f member-secondary.yaml
[root@osboxes yaml]# k apply -f ephemeral.yaml


자동으로 생성된 퍼시스턴트 볼륨 클레임 오브젝트를 확인해 보십시오.

[root@osboxes yaml]# k get pvc
NAME                         STATUS   VOLUME  …
…  
member-secondary-0-data      Bound    pvc-d45e44b3-b313-4a16-b17e-63144935edc8   
member-secondary-1-data      Bound    pvc-1c164f17-d79e-43e9-b0b9-9d1e4b2acd37


이제 ‘member-secondary’파드를 삭제해 보십시오.

[root@osboxes yaml]# k delete -f ephemeral.yaml
[root@osboxes yaml]# k get po


파드가 다 삭제된 후 다시 한번 퍼시스턴트 볼륨 클레임 오브젝트 목록을 보면 자동으로 삭제된 것을 확인할 수 있습니다.



2) 퍼시스턴트 볼륨 오브젝트에서 퍼시스턴트 볼륨 클레임 오브젝트 예약 하기
우리가 생성할 파드는 프라이머리 DB 파드 ‘member-primary-0’과 세컨더리 DB 파드 ‘member-secondary-0’과 ‘member-secondary-1’입니다.
따라서 퍼시스턴트 볼륨 클레임 오브젝트는 ‘data-member-primary-0’, ‘data-member-secondary-0’, ‘data-member-secondary-1’가 됩니다.
각 오브젝트는 퍼시스턴트 볼륨 오브젝트와 1:1로 바인딩 되야 합니다.
우리가 그 동안 했던 방식으로 퍼시스턴트 볼륨 오브젝트 3개를 만든다면 바인딩이 엉뚱하게 될 수 있습니다.
예를 들어 퍼시스턴트 볼륨 오브젝트를 ‘primary’, ‘secondary-0’, ‘secondary-1’로 만든다면 ‘primary’ 퍼시스턴트 볼륨 오브젝트가 ‘data-member-secondary-0’과 바인딩 될 수 있습니다.
그렇게 되면 세컨더리 DB 파드의 데이터가 프라이머리 DB 파드 용 볼륨에 저장되기 때문에 문제가 발생 합니다.
쿠버네티스는 퍼시스턴트 볼륨 오브젝트를 생성할 때 바인딩 될 퍼시스턴트 볼륨 클레임 오브젝트를 예약할 수 있게 하여 이러한 문제를 방지 합니다.
‘member-pv.yaml’파일의 내용을 봐주십시오.
이 파일에는 퍼시스턴트 볼륨 오브젝트 3개를 정의하고 있습니다.
각 오브젝트 정의 부분에 보면 아래와 같이 ‘claimRef’라는 항목이 있습니다.
그 내용을 보면 바인딩할 퍼시스턴트 볼륨 클레임 오브젝트의 이름을 지정하고 있습니다.
이렇게 퍼시스턴트 볼륨 클레임 오브젝트를 예약하고 퍼시스턴트 볼륨 오브젝트를 생성하면 나중에 워크로드 컨트롤러가 배포되면서 지정된 퍼시스턴트 볼륨 클레임 오브젝트가 제대로 바인딩 됩니다.

kind: PersistentVolume
apiVersion: v1

spec:
  …
  nfs:
    server: 10.178.189.25
    path: /data/ott/member/primary
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: data-member-primary-0
    namespace: ott

<팁>
‘claimRef’로 정의한 퍼시스턴트 볼륨 클레임 오브젝트와 바인딩 될때 접근 모드와 볼륨 용량만 맞으면 바인딩 됩니다.
그 외 퍼시스턴트 볼륨 클레임 오브젝트에 정의한 storageClassName과 레이블 셀렉터는 틀려도 됩니다.
</>

3) MySQL 파드 배포하기
이제 MySQL 파드들을 배포해 보겠습니다.
‘member-primary.yaml’과 ‘member-secondary.yaml’에 정의된 내용을 보면 ‘livenessProbe’, ‘readinessProbe’, ‘securityContext’외에는 모두 배웠던 것들입니다.
야믈의 정의 내용들이 어느 정도 이해가 되신다면 지금까지 잘 해오신 겁니다.
내용을 보면서 이해가 안되는 항목이 있다면 그 항목을 설명한 곳을 찾아 다시 한번 읽어 보시고 이해해 주십시오.
라이브니스 프로브와 레디니스 프로브는 ‘12. 헬스 체크를 위한 라이브니스 프로브와 레디니스 프로브’에서 배울테니 일단 넘어가십시오.
‘securityContext’는 조금 후에 설명 하겠습니다. 의외로 중요한 항목입니다.
<팁>
MySQL파드를 실행하면서 자동으로 데이터베이스, 테이블, 테스트 데이터등을 넣는 SQL을 실행할 수 있습니다.
컨피그맵 ‘member-dbinit’에 SQL을 만들고 파드의 ‘/docker-entrypoint-initdb.d’디렉토리에 마운트 하면 됩니다.
</>

제일 먼저 공통 오브젝트들부터 생성 합니다.
‘common-dbobj.yaml’의 내용을 보면 서비스 어카운트, 롤바인딩, MySQL 공통 컨피그맵 오브젝트들이 정의 되어 있습니다.

[root@osboxes yaml]# k apply -f common-dbobj.yaml
serviceaccount/sa-ott-mysql created
clusterrolebinding.rbac.authorization.k8s.io/crb_ott_sa-ott-mysql created
rolebinding.rbac.authorization.k8s.io/rb_sa-ott-mysql created
configmap/mysql created




다음으로 퍼시스턴트 볼륨 오브젝트를 생성합니다.
‘meber-pv.yaml’을 여십시오. 각 오브젝트는 NFS서버의 특정 디렉토리로 프로비저닝하도록 되어 있습니다.
일단 NFS서버의 IP는 여러분걸로 바꾸십시오.
프로비저닝할 디렉토리를 NFS서버에 만들어야겠죠 ?
NFS서버를 로그인 하고 각 디렉토리 볼륨을 만듭니다.

[root@osboxes ~]# ssh nfs

[root@nfs ~]# mkdir -p /data/ott/member/primary
[root@nfs ~]# mkdir -p /data/ott/member/secondary-0
[root@nfs ~]# mkdir -p /data/ott/member/secondary-1


‘/data/ott’디렉토리로 이동하여 하위에 생성된 디렉토리들을 확인 합니다.

[root@nfs ~]# cd /data/member/ott
[root@nfs ~]# ll
-rwxr-xr-x. 1 root root  117  1월 24 09:54 bestott.properties
-rwxr-xr-x. 1 root root  116  1월 24 09:54 members.properties
drwxr-xr-x. 2 root root 4096  1월 26 09:44 primary
drwxr-xr-x. 2 root root 4096  1월 26 09:44 secondary-0
drwxr-xr-x. 2 root root 4096  1월 26 09:44 secondary-1


위 디렉토리의 소유자를 보면 유저 ‘root’와 그룹 ‘root’로 되어 있습니다.
소유자가 이렇게 되어 있으면 파드가 배포될 때 각 디렉토리 볼륨에 데이터를 쓸 수 없습니다.
파드를 실행하는 OS유저가 ‘root’가 아니기 때문입니다.
이제 ‘securityContext’를 설명해야겠네요.
프라이머리 DB파드와 세컨더리 DB 파드의 컨테이너 명세에 보면 아래와 같이 ‘securityContext’항목이 있고 ‘runAsUser’에 ‘1001’로 정의 되어 있습니다.
이 의미는 ‘1001’이라는 OS유저로 파드를 실행한다는 것입니다.


    spec:
      … 
      containers:
      - name: mysql
        ports:
        …
        securityContext:
          runAsUser: 1001
        volumeMounts:

<팁>
파드를 실행할 OS유저는 컨테이너 이미지를 만들때 정의합니다.
‘member’와 ‘recommend’의 컨테이너 이미지를 만들때 ‘docker’라는 유저로 실행한 것을 기억하실 겁니다.
</>

‘1001’ 유저로 ‘root’에게만 쓰기 권한을 허용한 디렉토리에 쓸 수 없기 때문에 제대로 배포가 안됩니다.
방법은 2개가 있습니다. 첫째는 디렉토리의 쓰기 권한을 다른 유저에게도 허용하는 거고 둘째는 디렉토리의 쓰기 권한자를 ‘1001’로 바꾸는 겁니다.
첫번째 방법은 보안상 좋은 방법이 아니니 당연히 두번째 방법을 써야 합니다.
아래와 같이 각 디렉토리의 소유자를 ‘1001’로 바꿉니다.

[root@nfs ~]# chown 1001 primary
[root@nfs ~]# chown 1001 secondary-0
[root@nfs ~]# chown 1001 secondary-1
[root@nfs ~]# ll
-rwxr-xr-x. 1 root root  117  1월 24 09:54 bestott.properties
-rwxr-xr-x. 1 root root  116  1월 24 09:54 members.properties
drwxr-xr-x. 2 1001 root 4096  1월 26 09:44 primary
drwxr-xr-x. 2 1001 root 4096  1월 26 09:44 secondary-0
drwxr-xr-x. 2 1001 root 4096  1월 26 09:44 secondary-1


자 이제 배포할 준비가 끝났습니다.
‘member-pv.yaml’에서 NFS서버 IP를 본인걸로 잘 바꿨는지 한번 더 확인하시고 배포를 시작해 주십시오.

퍼시스턴트 볼륨 오브젝트 3개를 ‘member-pv.yaml’파일을 이용하여 생성 합니다.

[root@osboxes yaml]# k apply -f member-pv.yaml
[root@osboxes yaml]# k get pv
NAME              … RECLAIM POLICY   STATUS      CLAIM …

member-primary       … Retain        Available   ott/data-member-primary-0 …   
member-secondary-0   … Retain        Available   ott/data-member-secondary-0 …
member-secondary-1   … Retain        Available   ott/data-member-secondary-1 …


프라이머리 DB파드와 관련된 오브젝트들을 ‘member-primary.yaml’파일을 이용하여 생성 합니다.

[root@osboxes yaml]# k apply -f member-primary.yaml
configmap/member-dbinit created
secret/member-dbsecret created
statefulset.apps/member-primary created
service/member-primary created


퍼시스턴트 볼륨 클레임 오브젝트가 잘 생성되고 바인딩 되었는지 확인 합니다.

[root@osboxes yaml]# k get pvc
NAME                    STATUS   VOLUME        CAPACITY   ACCESS MODES …
data-member-primary-0   Bound    member-primary   1Gi        RWO          …


파드가 잘 실행되었는지 확인 합니다. 시간이 몇분정도 걸릴 수 있습니다.

[root@osboxes yaml]# k get po
NAME               READY   STATUS    RESTARTS        AGE

member-primary-0   1/1     Running   0               2m19s


세컨더리 파드들을 ‘member-secondary.yaml’파일을 이용하여 실행 합니다.

[root@osboxes yaml]# k apply -f ott-mysql-secondary.yaml
statefulset.apps/member-secondary created
service/member-secondary created


파드가 모두 정상적으로 실행될때까지 기다립니다. 몇분정도 걸립니다.
스테이트풀셋으로 배포되기 때문에 첫번째 세컨더리 파드가 실행되야 두번째 파드가 실행 됩니다.

[root@osboxes yaml]# watch k get po


퍼시스턴트 볼륨 클레임 오브젝트들이 잘 생성되고 바인딩 되었는지 확인 합니다.

[root@osboxes yaml]# k get pvc
NAME                    STATUS   VOLUME             …
data-member-primary-0   Bound    member-primary     …
data-member-secondary-0 Bound    member-secondary-0 …
data-member-secondary-1 Bound    member-secondary-1 …


아래와 같이 모든 파드들이 실행되면 잘 배포된 겁니다.

[root@osboxes yaml]# k get po
NAME                 READY   STATUS    RESTARTS        AGE

member-primary-0     1/1     Running   0               9m3s
member-secondary-0   1/1     Running   0               5m13s
member-secondary-1   1/1     Running   0               3m51s


SQL클라이언트로 DB가 연결이 되는지 확인해 보겠습니다.
‘DBeaver’라는 SQL클라이언트를 먼저 설치 하십시오. ‘https://dbeaver.io/’에서 설치할 수 있습니다.
프로그램을 실행하면 커넥션을 만드는 창이 뜰겁니다. ‘MySQL’을 선택하면 아래와 같이 접속 정보를 묻는 창이 나타납니다.
❶ Server Host는 여러분의 컨트롤 플레인이나 워커노드의 IP를 입력 하십시오.
❷ Port는 어떻게 구할 까요 ? 생성된 서비스 오브젝트를 보면 NodePort로 배포된 ‘member-primary’서비스가 있을 겁니다.
외부에 노출된 포트번호를 입력하면 됩니다. ‘member-primary.yaml’에서 NodePort를 고정했기 때문에 똑같이 ‘32001’번으로 나올 겁니다.

[root@osboxes yaml]# k get svc
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S) …
member-primary     NodePort    10.105.193.173   <none>        3306:32001/TCP …
member-secondary   ClusterIP   10.103.40.111    <none>        3306/TCP       …


❸ Database는 member입니다. ❹ Username은 ‘root’입니다. ❺ 암호는 ‘happy@cloud’입니다.
이 값들은 스테이트풀셋 ‘member-primary’의 환경 변수로 정의 되어 있습니다.
‘member-primary.yaml’파일을 열고 찾아 보십시오.


아래와 같이 연결이 되면 성공입니다.



11.7 자동으로 볼륨 생성하기Dynamic Provisioning

퍼시스턴트 볼륨 오브젝트를 수동으로 생성하는 것은 때로 번거로운 일입니다.
쿠버네티스는 퍼시스턴트 볼륨 클레임 오브젝트를 생성하면 자동으로 볼륨 디렉토리와 퍼시스턴트 볼륨 오브젝트를 생성하는 방법을 제공 합니다.
이렇게 자동으로 볼륨 디렉토리와 퍼시스턴트 볼륨 오브젝트를 생성하는 것을 동적 프로비저닝Dynamic provisioning이라고 합니다.
동적 프로비저닝의 동작 원리는 아래와 같습니다.

❶ 동적 프로비저닝을 위한 동적 프로비저너를 설치합니다. 이 프로비저너도 파드로 생성이 됩니다.
❷ 관리자는 동적 프로비저닝을 지원하는 스토리지 클래스를 미리 생성해야 합니다.
볼륨 사용자가 퍼시스턴트 볼륨 클레임 오브젝트에 스토리지 클래스명을 지정하지 않았을때 자동으로 동적 프로비저닝이 되게 하려면 생성한 스토리지 클래스를 기본 클래스로 만듭니다.
❸ 볼륨 사용자가 퍼시스턴트 볼륨 클레임 오브젝트를 생성 합니다.
❹ 동적 프로비저너는 퍼시스턴트 볼륨 클레임 오브젝트에 정의되어 있는 스토리지 클래스의 내용을 참조 합니다.
만약 퍼시스턴트 볼륨 클레임 오브젝트에 스토리지 클래스가 정의되어 있지 않으면 기본 스토리지 클래스를 참조 합니다. 스토리지 볼륨에 볼륨을 생성하고 퍼시스턴트 볼륨 오브젝트도 생성 합니다.
❺ 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트가 바인딩 됩니다.
❻ 볼륨 사용자가 파드를 실행 합니다.
❼ 퍼시스턴트 볼륨 클레임 오브젝트에 바인딩된 퍼시스턴트 볼륨 오브젝트의 스토리지 볼륨이 파드안에 마운트 됩니다.

동적 프로비저닝을 사용하려면 각 스토리지 제품에 맞는 CSI 드라이버가 설치되어야 합니다.
쿠버네티스 커뮤니티에서는 각 스토리지 제품별 CSI 드라이버를 아래 GitHub에서 제공하고 있습니다.
https://github.com/orgs/kubernetes-sigs/repositories?q=csi

우리는 바로 실습할 수 있는 NSF볼륨을 이용하여 동적 프로비저닝을 경험해 보겠습니다.

아래와 같은 순서로 NFS볼륨을 동적 프로비저닝하는 방법을 실습 하겠습니다.
동적 프로비저닝을 위해서 먼저 새로운 스토리지 클래스를 생성하고 기본 스토리지 클래스로 지정 하겠습니다.
그리고 NFS볼륨을 위한 동적 프로비저너를 설치 하겠습니다.
마지막으로 MySQL 파드를 동적 프로비저너를 이용하여 다시 배포 하겠습니다.

1) 스토리지 클래스 생성 및 기본 스토리지 클래스로 지정
스토리지 클래스 생성을 위한 야믈 파일을 다운로드 하십시오.


NFS볼륨의 ‘provisioner’명은 아무 이름이나 지정하면 됩니다.
동적 프로비저너 설치 시 이 이름으로 프로비저너를 지정해주면 됩니다.
‘annotations’에 ‘storageclass.kubernetes.io/is-default-class: "true"’로 정의하면 이 스토리지 클래스가 기본 스토리지 클래스가 됩니다.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
  name: nfs-dynamic
provisioner: nfs-dynamic
reclaimPolicy: Retain
volumeBindingMode: Immediate
allowVolumeExpansion: true


스토리지 클래스를 생성하고 결과를 확인 하십시오.
기본 스토리지 클래스로 지정했기 때문에 아래와 같이 이름 옆에 ‘(default)’로 표시됩니다.

[root@osboxes yaml]# k apply -f sc-nfs-dynamic.yaml
[root@osboxes yaml]# k get sc
NAME                    PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-dynamic (default)   nfs-dynamic                    Retain          Immediate           true                   4m50s
standard                kubernetes.io/no-provisioner   Delete          Immediate           false                  111m



2) 동적 프로비저너 설치

동적 프로비저너는 별도의 네임스페이스에 설치 합니다.
아래와 같이 ‘nfs’라는 네임 스페이스를 만들고 ‘nfs’로 네임스페이스를 변경 합니다.

[root@osboxes yaml]# k create ns nfs
[root@osboxes yaml]# kubens nfs

아래 글을 참고하여 만드십시오.
https://happycloud-lee.tistory.com/178

 

NFS서버 설치와 NFS Dynamic Provisioning 설정

NFS서버 설치는 아래 글을 참고하세요 . happycloud-lee.tistory.com/46?category=832247 NFS서버 만들기 1. ubuntu https://hiondal.blog.me/221624709742 NFS서버 만들기 k8s에서 Volume으로 사용할 수 있는 종류는 아래와 같이

happycloud-lee.tistory.com


3) MySQL파드를 동적 프로비저닝 하기
MySQL 파드를 동적 프로비저닝으로 다시 배포해 보겠습니다.

기존 파드, 퍼시스턴트 볼륨 클레임 오브젝트, 퍼시스턴트 볼륨 오브젝트를 모두 지웁니다.

[root@osboxes nfs-client]# cd ~/k8s/yaml
[root@osboxes nfs-client]# kubens ott
[root@osboxes yaml]# k delete -f member-primary.yaml
[root@osboxes yaml]# k delete -f member-secondary.yaml
[root@osboxes yaml]# k get pvc

[root@osboxes yaml]# k delete pvc data-member-primary-0 data-member-secondary-0 data-member-secondary-1
[root@osboxes yaml]# k delete -f member-pv.yaml


‘member-primary.yaml’과 ‘member-secondary.yaml’을 열고 스토리지 클래스명을 삭제 하거나 리마크 하십시오.
기본 스토리지 클래스인 ‘nfs-dynamic’이 자동으로 적용 됩니다.


  volumeClaimTemplates:
  - apiVersion: v1
    …
    spec:
      …
      #storageClassName: standard
      volumeMode: Filesystem


MySQL 프라이머리 파드를 실행 합니다.

[root@osboxes yaml]# k apply -f member-primary.yaml


퍼시스턴트 볼륨 클레임 오브젝트의 정보를 보면 자동으로 퍼시스턴트 볼륨 오브젝트가 만들어지고 바인딩된걸 확인할 수 있습니다.

[root@osboxes yaml]# k get pvc
NAME                 STATUS   VOLUME         
data-member-primary-0   Bound    pvc-1774dc89-921d-49b0-869d-1bbe2610e987


NFS 서버로 로그인하여 볼륨 디렉토리도 자동으로 생성되었는지 확인 합니다.
‘/data’밑에 이상한 긴 이름의 디렉토리가 생겼습니다.
동적 프로비저너는 ‘{네임스페이스}-{PVC명}-{PV명}’으로 볼륨 디렉토리를 만듭니다.

[root@osboxes yaml]# ssh nfs

[root@nfs ~]# ll /data
drwxr-xr-x. 5 root root 4096  1월 26 09:44 ott
drwxrwxrwx. 3 root root 4096  1월 26 13:51 ott-data-member-primary-0-pvc-1774dc89-921d-49b0-869d-1bbe2610e987


프라이머리 파드가 잘 실행 되었으면 세컨더리 파드도 실행 합니다.
자동으로 생성된 퍼시스턴트 볼륨 클레임 오브젝트와 볼륨 디렉토리도 확인해 보십시오.

[root@osboxes yaml]# k apply -f member-secondary.yaml


모든 파드가 잘 실행 되셨나요 ?
어떠십니까 ? 훨씬 편해졌죠 ?
기본 스토리지 클래스를 동적 프로비저닝을 지원하는 스토리지 클래스로 지정하면 볼륨 사용자는 볼륨의 크기와 접근 모드만 정의해 주면 되니 매우 편합니다.

연습삼아 ‘recommend’ 서비스를 위한 MySQL 파드도 설치해 보시기 바랍니다.
기존의 ‘member-primary.yaml’과 ‘member-secondary.yaml’을 복사하시고 내용을 보면서 바꾸시면 됩니다.
하다가 잘 안되시면 아래 페이지에 있는 야믈 파일을 참조 하십시오.
https://github.com/hiondal/k8s-yaml/tree/main/3.11/mysql

 

GitHub - hiondal/k8s-yaml: Kubernetes yamls

Kubernetes yamls. Contribute to hiondal/k8s-yaml development by creating an account on GitHub.

github.com

 

쿠버네티스 쉽게 이해하기 시리즈 목차

[쿠버네티스 쉽게 이해하기 1] 쿠버네티스 설치하기
[쿠버네티스 쉽게 이해하기 2] 쿠버네티스 아키텍처
[쿠버네티스 쉽게 이해하기 3] 한장으로 이해하는 쿠버네티스 리소스
[쿠버네티스 쉽게 이해하기 4] 쿠버네티스 개발에서 배포까지 실습
[쿠버네티스 쉽게 이해하기 5] 쿠버네티스 오브젝트 정의 파일 쉽게 만들기
[쿠버네티스 쉽게 이해하기 6] 꼭 알아야 할 쿠버네티스 주요 명령어
[쿠버네티스 쉽게 이해하기 7] 파드 실행 및 통제를 위한 워크로드 컨트롤러
[쿠버네티스 쉽게 이해하기 8] 파드 로드 밸런서 서비스
[쿠버네티스 쉽게 이해하기 9] 서비스 로드 밸런서 인그레스
[쿠버네티스 쉽게 이해하기 10] 환경변수 컨피그맵과 시크릿
[쿠버네티스 쉽게 이해하기 11] 데이터 저장소 사용을 위한 PV/PVC
[쿠버네티스 쉽게 이해하기 12] 헬스 체크를 위한 스타트업 프로브, 라이브니스 프로브, 레디니스 프로브
[쿠버네티스 쉽게 이해하기 13] 통합 로깅을 위한 EFK 스택
[쿠버네티스 쉽게 이해하기 14] 인증Authentication과 알백RBAC 방식의 인가Authorization
[쿠버네티스 쉽게 이해하기 15] 더 알면 좋을 주제들: 무중단 배포, 모니터링, HPA

댓글

전자책 출간 알림 [마이크로서비스패턴 쉽게 개발하기]