0부터 시작하는 Kubernetes 공부 - 동적 프로비저닝

Jaehong Lee·2022년 9월 8일
1
post-thumbnail

1. Service Account

  • Service Account 를 확인하자
    • Namespace 마다 하나씩 존재하는 default 계정은 모든 명령을 사용할 수 있다

만약, 계정의 기능을 제한하고 싶으면, 별도의 SA 를 생성하고, 해당 SA 에 대한 Role 을 생성한다. 이 두가지는 오브젝트 이므로 Bind 하기 위한 Role Binding 이 필요하다

  • 만약, namespace / node / pv 와 같은 namespace 에 속하지 않는 것들에 대해서는 cluster role 이라고 하며, 이를 sa 와 연결하기 위해 cluster role binding 이 필요하다

2. 동적 프로비저닝 구조

동적 프로비저닝을 사용하지 않는 방법

  • 운영자는 볼륨을 직접 만들어 PV 에 넣어준다. 이를 개발자가 PVC 를 배포하면, 해당 요청 사항에 맞는 Volume 을 찾아 연결해준다. 이는 운영자가 수동적으로 PV 를 프로비저닝 해야 한다
    • 이때, 특정 사용자에게만 연결해줄려면, PVC 와 PV 에 storageClassName 을 붙여서 구분한다
  • 이를 Pod 에서는 Volume 부분에 PVC 를 넣어서 사용한다

PVC 배포시 해당 PV 가 있다면, PVC 는 PV 와 Bound 된다. 이를 사용하려면 Pod 에 PVC 를 넣어주면 된다. 이를 통해 Pod 는 PVC 에 Bound 된 PV 를 확인하여 PV 와 Mount / Bind 된다

동적 프로비저닝

동적 프로비저닝은 StorageClass와 프로비저너를 사용하여 자동으로 PV를 생성해서 PVC와 Bound 시키는 기능이다

storage class & pvc & 프로비저너

  • 위와 같이 Provisoner 에는 접속할 스토리지의 정보가 있으며, 이를 전담하는 SA 를 통해 접속한다. 이때, PVC 의 요청 사항이 전달되면, 프로비저너에서는 해당 요청 사항에 맞는 볼륨을 프로비저닝하여 Pool 에 넣고, 해당 PV 는 PVC 와 storageClassName 을 통해 자동으로 Bound 된다
  • Provisoner 는 실질적으로 Pod 이므로 ns 별로 따로 만들어서, ns 별로 다른 공간을 사용하게 할 수 있다

더 자세한 그림

  • Provisoner 는 사전에 등록한 서버 ( 주소, 디렉토리 ) 를 사용하여 볼륨을 프로비저닝 & 사용할 수 있게 해주는 Pod 이다. 이는 배포시 Pod 형태로 배포한다

  • 이 Provisioner 를 전담할 Service Account 가 필요하다. ROLE 을 통해 이 SA 가 할 수 있는 기능을 명세한다. 이 SA 와 ROLE 을 Binding 을 통해 연결한다. 이렇게 생성된 SA 는 오직 Provisoner 만 전담한다

    • Provisoner 는 스토리지와 Mount 되어 안에 물리 자원을 사용하여 볼륨을 생성해줄 수 있다. 이를 통해 사용자가 스토리지에서 직접 볼륨을 만들어 주는 것이 아닌, Provisioner 가 요청된 볼륨을 자동으로 만들어 Pool 에 담아준다
    • 이때, StorageClassName 도 넣어주어, StorageClass 를 통해 요청한 사용자에게만 제공해줄 수 있게 한다. 이를 통해 PVC 와 Bound 된다
    • Pod 에 해당 PVC 를 넣어 PV 와 연결해서 사용할 수 있다
    • 운영자가 PV 를 직접 프로비저닝 해줄 필요가 없다
  • PVC 만 작성하게 되면, 자동으로 요청을 처리할 수 없으므로 수동으로 처리해줘야 한다. 이때, StorageClass 를 사용하면, 요청을 자동으로 처리할 수 있는 프로비저너를 지정한다

프로비저너를 스토리지와 연결되어 스토리지의 물리 자원을 통해 볼륨을 프로비저닝 해준다

3. Public 환경의 동적 프로비저닝

동적 프로비저닝은 Nfs / iscsi / glusterfs, ebs 등에게 명령을 전달하여 볼륨을 생성할 수 있도록 지시하는 역활을 수행하는데 퍼블릭 환경은 해당 프로비저너가 이미 존재하고 있으므로 별도의 추가 작업 없이 개발자가 요청만 하면, 볼륨을 생성하여 제공할 수 있다

  • aws 의 경우 eks / gcp 의 경우 gke 에는 동적 프로비저너가 있다. 이는 aws 의 경우 aws-ebs 라고 한다. aws-ebs 는 K8S 에 속해있으며, ebs 에게 명령을 내린다. ebs 가 필요한 만큼의 볼륨을 만들어 Storage Class 를 붙여서 PV 에 저장한다. 이후, 요청 사항 비교를 통해 적합하면 해당 볼륨을 사용한다

aws, gcp, azure 의 경우에는 각 csp 에서 제공하는 블럭 스토리지를 제어할 수 있는 동적 프로비저너가 이미 존재하기 때문에 각 csp 에서 K8S 서비스를 제공하는 engine 을 이용하여 손쉽게 볼륨을 제공받을 수 있다

  • 허나, on-premise 에서 직접 클라우드 환경을 구성하여 운영한다면, 직접 프로비저너를 준비해야 한다. 우리는 nfs 를 이용하여 볼륨 ( 디렉토리 ) 를 제공하므로, nfs-provisioner 를 생성해야 한다
  • 이는 Pod 로 존재한다

4. 동적 프로비저닝 구현

동적 프로비저닝은 PV 를 직접 만들 필요가 없다. 따라서 Provisoner, SA, Rule, PVC, Pod, StorageClass 만 생성해주면 된다

  • 위와 같은 구조이다

kube-apiserver.yaml 설정

vi /etc/kubernetes/manifests/kube-apiserver.yaml 
  • kube-apiserver.yaml 파일을 편집기로 열자
  • 위 설정을 추가하자. 이는 동적 프로비저닝을 위해서 반드시 추가해야 하는 설정이다

Service Account & Rule & Cluster Rule 생성 및 연결

kind: ServiceAccount #서비스 계정
apiVersion: v1
metadata:
  name: nfs-pod-provisioner-sa
---
kind: ClusterRole # Role of kubernetes - 클러스터 룰
apiVersion: rbac.authorization.k8s.io/v1 # auth API
metadata:
  name: nfs-provisioner-clusterRole
rules:
  - apiGroups: [""] # rules on persistentvolumes
    resources: ["persistentvolumes"] # kind 지정, pv 라고 지정한 것
    verbs: ["get", "list", "watch", "create", "delete"] #허용할 명령
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"] # api 그룹은 있으면 지정
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding # rule 과 sa 를 연결
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-provisioner-rolebinding
subjects: # sa 지정
  - kind: ServiceAccount
    name: nfs-pod-provisioner-sa # defined on top of file
    namespace: default
roleRef: # binding cluster role to service account - 클러스터 rule 지정
  kind: ClusterRole
  name: nfs-provisioner-clusterRole # name defined in clusterRole
  apiGroup: rbac.authorization.k8s.io
---
kind: Role # 룰
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-pod-provisioner-otherRoles
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding # 룰 연결
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-pod-provisioner-otherRoles
subjects:
  - kind: ServiceAccount
    name: nfs-pod-provisioner-sa # same as top of the file
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: nfs-pod-provisioner-otherRoles
  apiGroup: rbac.authorization.k8s.io
  • Provisoner 를 전담하기 위한 Service Account 와 해당 계정에 대한 Rule 과 Cluster Rule 을 정의하고, 연결하기 위한 Binding 을 작성하여 배포해주자

Provisioner Pod 배포

Provisioner 는 Pod 이다

kind: Deployment
apiVersion: apps/v1
metadata:  #deployment 정의
  name: nfs-pod-provisioner
spec:  # replicaset 정의
  selector: 
    matchLabels: 
      app: nfs-pod-provisioner
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-pod-provisioner
    spec:
      serviceAccountName: nfs-pod-provisioner-sa # Provisoner 를 전담할 Service Account 이름
      containers:
        - name: nfs-pod-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest # 사용 이미지
          volumeMounts: # 아래 스토리지와 연결한 볼륨을 마운트하는 것
            - name: nfs-provisioner-v
              mountPath: /persistentvolumes # provisioner 컨테이너에 볼륨을 마운트 될 위치
          env: # 환경 변수 - Storage class 에 전달해줄
            - name: PROVISIONER_NAME # do not change
              value: nfs-test # SAME AS PROVISONER NAME VALUE IN STORAGECLASS
            - name: NFS_SERVER # do not change
              value: 211.183.3.100 # Ip of the NFS SERVER
            - name: NFS_PATH # do not change
              value: /shared # path to nfs directory setup
      volumes: # Provisoner 는 스토리지와 연결되므로 해당 연결 정보를 가져야 한다
       - name: nfs-provisioner-v # same as volumemouts name
         nfs:
           server: 211.183.3.100
           path: /shared
  • nfs 서버 주소, 공유할 디렉토리 경로에 주의하자. 또한, volumes 의 name 과 PROVISIONER_NAME 의 value 값을 기억하자. 이는 Pod 와 storageClass 에서 사용할 것이다
    • Provisoner 는 스토리지와 연결되므로 해당 연결 정보를 가져야 한다. 우리는 nfs 방식을 사용하며 211.183.3.100 nfs-server 의 /shared 디렉토리와 Bind 시킬 것이다

StorageClass 생성

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storageclass # PVC 에서는 이 이름으로 StorageClass 와 연결
provisioner: nfs-test # Provisioner 이름
parameters:
  archiveOnDelete: "false"
  • name 과 provisioner 값에 주의하자

PVC 배포 및 Bound 확인

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc-test
spec:
  storageClassName: nfs-storageclass # SAME NAME AS THE STORAGECLASS
  accessModes:
    - ReadWriteMany #  must be the same as PersistentVolume
  resources:
    requests:
      storage: 50Mi
  • pvc 를 배포하자
  • Bound 가 되었다! 우리는 해당 PV 를 만든 적이 없는데도 PV 가 프로비저닝 되어 Bound 되었다. 이는 Provisioner 가 PV 를 자동으로 프로비저닝 해줬기 때문이다
    • 이때, 프로비저너가 프로비저닝한 PV 에 storageClassName 을 요청한 사용자의 PVC 의 storageClassName 으로 자동으로 지정하여, 프로비저닝된 PV 와 요청한 사용자의 PVC 를 Bound 해준다

Deployment 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nfs-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      volumes:
      - name: nfs-test # 볼륨 이름
        persistentVolumeClaim:
          claimName: nfs-pvc-test  # same name of pvc that was created
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: nfs-test # name of volume should match claimName volume
          mountPath: /mydata2 # mount inside of contianer
  • PVC 의 이름을 volumes 에 넣어주면 된다

확인하기

  • nginx 와 Provisioner deploy 배포 확인
  • PV, PVC 연결 확인
  • StorageClass 확인
  • Service Account 확인

파일 확인

  • 지정한 공유 디렉토리 안에 생성된 default-nfs-pvc 디렉토리에 파일을 넣어야 한다
  • 파일을 하나 넣어준다
  • 배포된 Pod 에서 잘 확인된다. Bind 가 잘 되었다
profile
멋진 엔지니어가 될 때까지

0개의 댓글