75일차) 2025-04-16(RBAC, 3A, Dynamic Provisioner)
RBAC (Role Based Access Control, 역할기반접근제어)
AAA
- 인증(Authentication) - 내가 누구다(로그인, 사용자를 식별)
- 인가(authorization) - 나는 이러이러한 행동을 할 수 있다
- 어카운트(Accounting) - 계정 사용 기록
k8s
Role(AWS에서는 Policy와 비슷)을 생성 후 해당 Role을 SA(Service Account)한테 부여(RoleBinding)해줌
Role - RoleBinding - SA, 3개의 리소스를 만들어야한다.
AWS
Policy(정책)을 생성한 다음, 특정한 역할(Role)에 부여하여 해당 역할을 사용자나 리소스한테 부여
K8s Role의 종류
Role = 특정 네임스페이스에 대한 권한.
RoleBinding = Role를 SA와 묶어주기위한 리소스.
ClusterRole = 클러스터 전체에 대한 권한.
ClusterRoleBinding = ClusterRole를 SA와 묶어주기위한 리소스.
SA = Service Account, 사용자 계정. 주로 pod같은 리소스에 부여하여 해당 리소스가 특정한 Role(ClusterRole)을 수행할 수 있는 권한을 부여.
→ 결론 : SA를 생성해서 해당 SA에 RoleBinding으로 Role을 부여
사용자한테 권한 부여
root@master:~/mani# mkdir rbac
root@master:~/mani# cd rbac/
- SA 생성
vi sa.yml
apiVersion: v1
kind: ServiceAccount
metadata:
name: pod-reader-sa
kubectl apply -f sa.yml
- 위에서 생성한 SA를 인증하기 위한 secret 생성
vi sec.yml
apiVersion: v1
kind: Secret
metadata:
name: pod-reader-token
namespace: default
annotations:
kubernetes.io/service-account.name: pod-reader-sa
type: kubernetes.io/service-account-token
kubectl apply -f sec.yml
- 기본 apiGroups에 속한 pod를 get하거나 list만 할 수 있는 클러스터롤을 정의
vi cr.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-reader-crole
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
kubectl apply -f cr.yml
vi crb.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pod-reader-crolebinding
subjects:
- kind: ServiceAccount
name: pod-reader-sa #위에서 생성한 sa
namespace: default
roleRef:
kind: ClusterRole
name: pod-reader-crole #위에서 생성한 ClusterRole
apiGroup: rbac.authorization.k8s.io
kubectl apply -f crb.yml
- 시크릿의 토큰을 조회
kubectl get secret pod-reader-token -o jsonpath='{.data.token}' | base64 --decode
현재 kubectl 을 치면, ~/.kube/config 파일을 통해 나를 인증/인가하고, 클러스터에 요청
이 파일을 하나 복사해서 다른 config를 구성할 예정. ~/.kube/config.pod-reader라는 이름으로 만들자.
root@master:~/.kube# cp config config.pod-reader
- 아까 조회한 토큰을 복사한 후
vi config.pod-reader
- client-certificate-date 삭제
- client-key-date 삭제
- user: 밑이 token:이라는 항목을 추가후, 아까 복사한 토큰을 복붙
KUBECONFIG=/root/.kube/config.pod-reader
# 내가 기본 config 파일을 /root/.kube/config.pod-reader 이걸로 변경시키고 싶다면 위와같은 환경변수를 정의해주면 된다.
cp /etc/kubernetes/admin.conf ~/.kube/config
# 혹시 위처럼 config 파일을 수정한 경우엔 다시 복사하기
Dynamic Provisioner
PV나 그에 해당하는 디렉토리를 미리 생성하거나, 요청이 들어왔을때 수동으로 생성할 필요 없이 PVC가 들어오면 자동으로 PV 및 디렉토리를 생성해주는 기능
EKS 에서는 efs csi 드라이버라는걸 통해서 다이나믹 프로비저닝 기능을 구현할 수 있다.
https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
# 다이나믹 프로비저너가 있는 헬름 차트. 우리는 헬름으로 설치할게 아니라 안에 있는 매니페스트 파일들을 통해 설치할 예정
- 현재 디렉토리에 깃 클론
root@master:~/mani# mkdir dynamic
root@master:~/mani# cd dynamic
root@master:~/mani/dynamic# git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner .
- 매니페스트 파일이 들어있는 deploy 경로로 이동
root@master:~/mani/dynamic# cd deploy
vi deployment.yaml
- 스토리지 클래스 파일
vi class.yaml
# 스토리지클래스는 스토리지의 등급을 분류하는 리소스. 그렇다면, 내가 원하는 등급의 리소스를 만들어 주는애가 누구인가? 에 대한 정의가 필요함. 여기서는 k8s-sigs.io/nfs-subdir-external-provisioner 라는 이름을 갖는 프로비저너가 해당 등급의 pv를 만들어주는 프로비저너다.
kubectl apply -f class.yaml
- 다이나믹 프로비저닝 용도로 사용할 경로 생성. 이 경로는 나중에 deployment에서 수정해줄 예정
mkdir /shared/dynamic
- 권한부여
chmod 777 -R /shared/dynamic
- rbac.yaml
vi rbac.yaml
kubectl apply -f rbac.yaml
- deployment.yaml
vi deployment.yaml
kubectl apply -f deployment.yaml
- 기존 pod, pv, pvc 삭제
root@master:~/mani/dynamic/deploy# kubectl delete pod --all
root@master:~/mani/dynamic/deploy# kubectl delete pv,pvc --all
kubectl api-resources
# kind(리소스)와 리소스가 속한 apiVersion을 확인가능.
kubectl api-resources --namespaced=true
# 특정 네임스페이스에 종속된 리소스 확인
kubectl api-resources --namespaced=false
# 특정 네임스페이스에 종속되지 않은(=클러스터 공통 리소스) 확인.
kubectl api-resources --namespaced=true | grep -i serviceaccount
# sa가 네임스페이스에 종속된 리소스인지 확인
kubectl api-resources --namespaced=true | grep -i clusterrole
- 기존 내용 두고, 새로 test.yml 파일 생성
cp test-claim.yaml test.yml
kubectl apply -f test.yml
-
실습)
스토리지클래스의 이름 : test-sc , nfs공유폴더 /slow로 하여 기존의 프로비저너, RBAC은 지우고 새로 한번 만들어보세요.
쿠버네티스 클러스터의 /k8s/dynamic 은 두고 /k8s/dynamic-slow 라는 디렉토리로 복제해서 한번 해보세요!!
root@master:~/mani# cp -r dynamic/ dynamic-slow/
root@master:~/mani/dynamic-slow# cd deploy/
root@master:~/mani/dynamic-slow/deploy# kubectl delete pod --all
root@master:~/mani/dynamic-slow/deploy# kubectl delete pv,pvc --all
- 스토리지 클래스 이름 : test-sc
root@master:~/mani/dynamic-slow/deploy# vi class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: test-sc
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
# or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
archiveOnDelete: "false"
root@master:~/mani/dynamic-slow/deploy# kubectl apply -f class.yaml
- 다이나믹 프로비저닝 용도로 사용할 경로 생성. 이 경로는 나중에 deployment에서 수정해줄 예정
mkdir /shared/dynamic-slow
- 권한부여
chmod 777 -R /shared/dynamic-slow
- 위 경로로 dep 수정
root@master:~/mani/dynamic-slow/deploy# vi deployment.yaml
root@master:~/mani/dynamic-slow/deploy# kubectl apply -f deployment.yaml
- rbac.yml
root@master:~/mani/dynamic-slow/deploy# vi rbac.yaml
root@master:~/mani/dynamic-slow/deploy# kubectl apply -f rbac.yaml
- test.yml
root@master:~/mani/dynamic-slow/deploy# vi test.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
spec:
storageClassName: test-sc
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
root@master:~/mani/dynamic-slow/deploy# kubectl apply -f test.yml
자율과제)
동적 프로비저너를 구성해보세요.
네임스페이스 = kube-provisioner
두개의 프로비저너는 각각 fast, slow 라는 스토리지를 갖고있으며 요청(fast,slow)에 따라 각각 마스터노드의 /pv/fast , /pv/slow라는 디렉토리에 pv를 생성해야합니다.
- 경로 생성
sudo mkdir -p /pv/fast
sudo mkdir -p /pv/slow
- 권한 부여
chmod 777 -R /pv/fast
chmod 777 -R /pv/slow
- 권한 유지
root@master:~/mani/dynamic-pro/deploy# vi /etc/exports
/pv/fast *(rw,sync,no_root_squash,no_subtree_check)
/pv/slow *(rw,sync,no_root_squash,no_subtree_check)
root@master:~/mani/dynamic-pro/deploy# sudo exportfs -r
- 네임스페이스 생성
root@master:~/mani/dynamic-pro/deploy# kubectl create ns kube-provisioner
- 스토리지 클래스
root@master:~/mani/dynamic-pro/deploy# vi class.yaml
# class-fast.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: k8s-sigs.io/nfs-fast
parameters:
archiveOnDelete: "false"
---
# class-slow.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: k8s-sigs.io/nfs-slow
parameters:
archiveOnDelete: "false"
root@master:~/mani/dynamic-pro/deploy# kubectl apply -f class.yaml
- deployments.yml
root@master:~/mani/dynamic-pro/deploy# vi deployments.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner-fast
namespace: kube-provisioner
labels:
app: nfs-client-provisioner-fast
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner-fast
template:
metadata:
labels:
app: nfs-client-provisioner-fast
spec:
serviceAccountName: nfs-client-provisioner-fast
containers:
- name: nfs-client-provisioner
image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-fast
- name: NFS_SERVER
value: 211.183.3.100
- name: NFS_PATH
value: /pv/fast
volumes:
- name: nfs-client-root
nfs:
server: 211.183.3.100
path: /pv/fast
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner-slow
namespace: kube-provisioner
labels:
app: nfs-client-provisioner-slow
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner-slow
template:
metadata:
labels:
app: nfs-client-provisioner-slow
spec:
serviceAccountName: nfs-client-provisioner-slow
containers:
- name: nfs-client-provisioner
image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-slow
- name: NFS_SERVER
value: 211.183.3.100
- name: NFS_PATH
value: /pv/slow
volumes:
- name: nfs-client-root
nfs:
server: 211.183.3.100
path: /pv/slow
root@master:~/mani/dynamic-pro/deploy# kubectl apply -f deployments.yaml
- test.yml
root@master:~/mani/dynamic-pro/deploy# vi test.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim-fast
spec:
storageClassName: fast
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim-slow
spec:
storageClassName: slow
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
root@master:~/mani/dynamic-pro/deploy# kubectl apply -f test.yaml
- rbac
root@master:~/mani/dynamic-pro/deploy# vi rbac.yaml
# FAST
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner-fast
namespace: kube-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-fast-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner-fast
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner-fast
namespace: kube-provisioner
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-fast-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner-fast
namespace: kube-provisioner
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner-fast
namespace: kube-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner-fast
namespace: kube-provisioner
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner-fast
apiGroup: rbac.authorization.k8s.io
# SLOW
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner-slow
namespace: kube-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-slow-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner-slow
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner-slow
namespace: kube-provisioner
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-slow-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner-slow
namespace: kube-provisioner
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner-slow
namespace: kube-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner-slow
namespace: kube-provisioner
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner-slow
apiGroup: rbac.authorization.k8s.io
- 기존 리소스 삭제
root@master:~/mani/dynamic-pro/deploy# kubectl delete pod --all
root@master:~/mani/dynamic-pro/deploy# kubectl delete pv,pvc --all
- 기존 StorageClass 삭제
kubectl delete sc fast
kubectl delete sc slow
kubectl apply -f class.yaml
- PVC를 다시 생성하려면 기존 PVC도 삭제:
kubectl delete pvc test-claim-fast
kubectl delete pvc test-claim-slow
kubectl apply -f test.yml
- PVC/PV/SC 삭제
kubectl delete pvc test-claim-fast test-claim-slow
kubectl delete sc fast slow
- /pv/ 디렉토리 내 흔적 제거 (옵션)
rm -rf /pv/fast/*
rm -rf /pv/slow/*
- StorageClass 재배포
kubectl apply -f class.yaml
- PVC 재생성
kubectl apply -f test.yml
- 생성된 디렉토리 확인
ls /pv/fast/
ls /pv/slow/
풀이)
- 네임스페이스를 명시 = 네임스페이스에 종속된 리소스들의 네임스페이스를 변경해줘야 함
- 종속 - SA, Role, Pod, PVC
프로비저너를 두개 생성 → 하나의 pod에 두개의 컨테이너를 정의
- 필요한 매니페스트 파일만 복사
root@master:~/mani/dynamic/deploy# mkdir fast-slow
root@master:~/mani/dynamic/deploy# cp class.yaml fast-slow/
root@master:~/mani/dynamic/deploy# cp rbac.yaml fast-slow/
root@master:~/mani/dynamic/deploy# cp test-claim.yaml fast-slow/
root@master:~/mani/dynamic/deploy# cp deployment.yaml fast-slow/
root@master:~/mani/dynamic/deploy# cd fast-slow/
root@master:~/mani/dynamic/deploy/fast-slow# vi rbac.yaml
# ClusterRole이나 ClusterRoleBinding은 네임스페이스에 종속적이 않으나, SA가 네임스페이스에 종속적이기때문에 SA만 네임스페이스를 맞춰줘야한다.
# roleRef: 에서는 네임스페이스 명시안해도됨
vi rbac.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-provisioner --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-provisioner roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-provisioner rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-provisioner roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io |
kubectl apply -f rbac.yaml
- 스토리지클래스의 경우엔 sc-fast / sc-slow 두개 생성
vi class.yaml
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: sc-fast provisioner: provisioner-fast# or choose another name, must match deployment's env PROVISIONER_NAME' parameters: archiveOnDelete: "false" --- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: sc-slow provisioner: provisioner-slow# or choose another name, must match deployment's env PROVISIONER_NAME' parameters: archiveOnDelete: "false" |
# 프로비저너의 이름(provisioner-fast,provisioner-slow)을 나중에 컨테이너에서 명시해야한다.
kubectl apply -f class.yaml
vi deployment.yaml
# 프로비저너 컨테이너를 두개를 띄우더라도 serviceAccountName:을 pod의 spec에서 명시하기때문에 두개의 컨테이너 전부 같은 sa를 갖게 될 것
apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-provisioner spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: con-fast-provisioner image: 61.254.18.30:5000/provisioner:v4.0.2 volumeMounts: - name: vol-fast mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: provisioner-fast - name: NFS_SERVER value: 211.183.3.100 - name: NFS_PATH value: /fast - name: con-slow-provisioner image: 61.254.18.30:5000/provisioner:v4.0.2 volumeMounts: - name: vol-slow mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: provisioner-slow - name: NFS_SERVER value: 211.183.3.100 - name: NFS_PATH value: /slow volumes: - name: vol-fast nfs: server: 211.183.3.100 path: /fast - name: vol-slow nfs: server: 211.183.3.100 path: /slow |
mkdir /fast /slow
chmod 777 -R /fast
chmod 777 -R /slow
vi /etc/exports
# worker노드들에는 꼭 nfs-common 패키지가 설치되어있어야 함.
systemctl restart nfs-server
kubectl apply -f deployment.yaml
kubectl get pod -n kube-provisioner
- pvc 생성
vi test-claim.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-provisioner spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: con-fast-provisioner image: 61.254.18.30:5000/provisioner:v4.0.2 volumeMounts: - name: vol-fast mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: provisioner-fast - name: NFS_SERVER value: 211.183.3.100 - name: NFS_PATH value: /fast - name: con-slow-provisioner image: 61.254.18.30:5000/provisioner:v4.0.2 volumeMounts: - name: vol-slow mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: provisioner-slow - name: NFS_SERVER value: 211.183.3.100 - name: NFS_PATH value: /slow volumes: - name: vol-fast nfs: server: 211.183.3.100 path: /fast - name: vol-slow nfs: server: 211.183.3.100 path: /slow |