2. Resource Policies
2.1 Request / Limit (최소요구사항/최대 사용량)
쿠버네티스에서 파드를 어느 노드에 배포할지 스케쥴링 할 때, 스케쥴링이 될 노드에 해당 파드가 동작할 수 있는 충분한 자원이 확보가 되어야 합니다.
쿠버네티스에서 파드(컨테이너)에 필요한 리소스 양을 명시 할 수 있도록 설정을 지원합니다.
cpu/memory와 같은 컴퓨트 리소스 외에도 gpu/storage 리소스에 대한 쿼터도 지정 할 수 있습니다.
CPU는 m(밀리코어, 1코어=1000밀리코어) 단위로 지정하며, 해당 컨테이너에 어느정도의 CPU를 할당할 것인지를 지정합니다.
메모리는 Mi(Mib)를 사용합니다.
--- apiVersion: v1 kind: Pod metadata: name: frontend spec: containers: - name: app image: images.my-company.example/app:v4 resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m" - name: log-aggregator image: images.my-company.example/log-aggregator:v6 resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m"
metrics-server를 이용한 노드 별 리소스 모니터링
root@k8s-master01:~# kubectl top nodes | sort -n -k 2 NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% k8s-worker02 114m 1% 4030Mi 25% k8s-worker01 176m 2% 3196Mi 20% k8s-master03 279m 3% 4727Mi 29% k8s-master02 347m 4% 4144Mi 26% k8s-master01 414m 5% 4557Mi 28%
metrics-server를 이용한 파드 별 리소스 모니터링
root@k8s-master01:~# kubectl -n kube-system top pod | sort -n -k 2 NAME CPU(cores) MEMORY(bytes) nginx-proxy-k8s-worker01 1m 16Mi nginx-proxy-k8s-worker02 1m 17Mi dns-autoscaler-59b8867c86-hjkvs 2m 7Mi kube-controller-manager-k8s-master02 4m 19Mi kube-controller-manager-k8s-master03 4m 19Mi nodelocaldns-rdkbl 4m 15Mi coredns-588bb58b94-9qcvw 5m 16Mi kube-scheduler-k8s-master02 5m 20Mi nodelocaldns-sd99v 5m 10Mi coredns-588bb58b94-zcnvc 6m 14Mi kube-proxy-h584h 7m 22Mi kube-scheduler-k8s-master03 7m 19Mi nodelocaldns-9vlvr 7m 9Mi nodelocaldns-b8gpm 7m 9Mi metrics-server-6f77f96b88-v5jjs 8m 17Mi nodelocaldns-r4sjf 8m 16Mi kube-scheduler-k8s-master01 9m 21Mi kube-proxy-x8gcq 12m 22Mi calico-kube-controllers-75748cc9fd-gqdzw 13m 21Mi kube-proxy-w87v4 13m 15Mi kube-proxy-96tsm 20m 15Mi kube-proxy-tj8pv 24m 14Mi kube-controller-manager-k8s-master01 36m 52Mi calico-node-87g22 42m 85Mi calico-node-kk5vn 51m 84Mi calico-node-wckv7 51m 85Mi calico-node-8278d 64m 91Mi etcd-k8s-master02 70m 89Mi calico-node-4hzx4 71m 109Mi kube-apiserver-k8s-master02 77m 303Mi etcd-k8s-master03 81m 84Mi kube-apiserver-k8s-master01 94m 349Mi etcd-k8s-master01 99m 95Mi kube-apiserver-k8s-master03 111m 310Mi
2.2 ResourceQuota
쿠버네티스 운영 시 특정 팀에서 많은 리소스를 요구할 경우 ResourceQuota를 이용하여 네임스페이스별로 사용할 수 있는 리소스의 양을 정하고, 컨테이너 마다 사용 할 수 있는 양을 지정할 수 있습니다.
Resource Name | Description |
---|---|
| Across all pods in a non-terminal state, the sum of CPU limits cannot exceed this value. |
| Across all pods in a non-terminal state, the sum of memory limits cannot exceed this value. |
| Across all pods in a non-terminal state, the sum of CPU requests cannot exceed this value. |
| Across all pods in a non-terminal state, the sum of memory requests cannot exceed this value. |
| Across all pods in a non-terminal state, the number of huge page requests of the specified size cannot exceed this value. |
| Same as |
| Same as |
쿼터 오브젝트를 생성하여 특정 우선 순위의 파드와 일치 시키며, "low(낮음)", "medium(중간)", "high(높음)"의 세 가지 우선 순위 클래스 중 하나를 가질 수도 있습니다.
# quota-test.yaml --- apiVersion: v1 kind: ResourceQuota metadata: name: default spec: hard: cpu: "1000" memory: 200Gi pods: "10" # scopeSelector: # matchExpressions: # - operator : In # scopeName: PriorityClass # values: ["high"]
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19 ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m"
root@k8s-master01:~# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-deployment-5bccc488d-bqkvz 1/1 Running 0 18h nginx-deployment-5bccc488d-r4s5d 1/1 Running 0 18h nginx-deployment-5bccc488d-z29wp 1/1 Running 0 18h root@k8s-master01:~# kubectl get quota NAME AGE REQUEST LIMIT default 32s cpu: 750m/1k, memory: 192Mi/200Gi, pods: 3/10
2.3 LimitRange
ResourceQuota를 사용하면 네임스페이스의 리소스를 제한하고, LimitRange는 네임스페이스 내 파드(컨테이너)의 리소스를 제한합니다.
사용자가 컨테이너 리소스를 너무 크게 사용하면 특정 컨테이너가 많은 리소스를 점유하는 것을 방지할 수 있기 때문에 LimitRange를 사용합니다.
root@k8s-master01:~# cat LimitRange.yaml apiVersion: v1 kind: LimitRange metadata: name: cpu-min-max-demo-lr namespace: default spec: limits: - max: cpu: "800m" min: cpu: "200m" type: Pod #Container
root@k8s-master01:~# cat LimitRange.yaml apiVersion: v1 kind: LimitRange metadata: name: cpu-min-max-demo-lr namespace: default spec: limits: - max: cpu: "800m" min: cpu: "200m" type: Pod #Container root@k8s-master01:~# more nginx-deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19 ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "1000m" limits: memory: "128Mi" cpu: "1500m"
root@k8s-master01:~# kubectl get event --sort-by='lastTimestamp'
LAST SEEN TYPE REASON OBJECT MESSAGE
78s Warning FailedCreate replicaset/nginx-deployment-8579d7f98c Error creating: pods "nginx-deployment-8579d7f98c-mxw8q" is forbidden: maximum cpu usage per Pod is 800m, but limit is 1500m
2. Label & Selector
Label
Label은 Pod와 같은 객체에 연결된 키/값 쌍입니다.
리소스를 논리적인 그룹으로 나누거나, 식별의 편의를 위해 붙이는 이름표입니다.
Label은 생성 시 객체에 첨부할 수 있으며 나중에 언제든지 추가 및 수정할 수 있습니다.
Selector
특정 Label에 해당하는 객체를 식별하고 검색할 수 있습니다.
2.1 Node Label
# Node Label 확인 kubectl get nodes --show-labels # Node Label 추가 kubectl label nodes k8s-worker01 svc=web
2.2 Pod Selector
pod-label.yml
apiVersion: v1 kind: Pod metadata: name: nginx labels: env: test spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent nodeSelector: svc: web
3. 쿠버네티스 볼륨
PV(PersistentVolume): PV는 관리자가 프로비저닝했거나 스토리지 클래스를 사용해 동적으로 프로비저닝한 클러스터의 스토리지입니다. PV는 볼륨과 같은 볼륨 플러그인이지만 PV를 사용하는 개별 Pod와 독립적인 수명 주기를 가집니다.
PVC(PersistentVolumeClaim): PVC는 사용자가 볼륨을 사용하기 위해 PV에 하는 스토리지 요청입니다. Pod와 유사하게 Pod는 노드 리소스를 소비하고, PVC는 PV 리소스를 소비합니다.
3.1 PV의 Lifecycle
3.1.1 Provisioning
PV를 생성하는 단계로 프로비저닝 방법에는 두 가지가 있습니다.
정적 프로비저닝
정적 프로비저닝은 클러스터 관리자가 미리 적정 용량의 PV를 만들어 두고 사용자의 요청이 있을 시 미리 만들어 둔 PV를 할당하는 방식입니다.
사용할 수 있는 스토리지 용량에 제한이 있을 때 유용합니다.
동적 프로비저닝
동적 프로비저닝은 사용자가 PVC를 거쳐서 PV를 요청했을 때 생성해 제공합니다.
클러스터에 사용자가 원하는 만큼의 스토리지 용량이 있다면, 원하는 용량만큼을 생성해서 사용할 수 있습니다.
3.1.2 Binding
바인딩은 프로비저닝으로 생성된 PV를 PVC와 연결하는 단계입니다. PVC에서 원하는 스토리지 용량과 접근방법을 명시해서 용청하면 거기에 맞는 PV가 할당됩니다. PV와 PVC의 매핑은 1대1 관계입니다.
3.1.3 Using
PVC는 Pod에 설정되고, Pod는 PVC를 볼륨으로 인식해서 사용합니다. 클러스터는 PVC를 확인하여 바인딩된 PV를 찾고 해당 볼륨을 Pod에서 사용할 수 있도록 해줍니다. 할당된 PVC는 파드를 유지하는 동안 계속 사용되며, 시스템에서 임의로 삭제할 수 없습니다.
3.1.4 Reclaiming
사용이 끝난 PVC는 삭제되고, PV를 초기화(reclaim)하는 과정을 거칩니다. PV는 기존에 사용했던 PVC가 아니더라도 다른 PVC로 재활용이 가능합니다.
PV 초기화 정책
Retain: PV의 데이터를 그대로 보존합니다.
Recycle: 재사용하게 될 경우 기존의 PV 데이터들을 모두 삭제 후 재사용합니다.
Delete: 사용이 종료되면 해당 볼륨을 삭제합니다.
3.2 PV 생성
apiVersion: v1 kind: PersistentVolume metadata: name: test-pv labels: name: test-pv spec: capacity: storage: 1Gi accessModes: - ReadWriteMany hostPath: path: "/test/volume" # Value - capacity: 사용할 용량을 설정합니다. - accessModes:특정 접근 모드를 선택합니다. - hostPath: 노드에 저장되는 디렉토리를 설정합니다. # 적용하기 kubectl apply -f test-pv.yaml # PV 조회 kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE test-pv 1Gi RWX Retain Available 15s
3.3 PVC 생성
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi kubectl apply -f test-pvc.yaml # PV, PVC 조회 kubectl get pv,pvc NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/test-pv 1Gi RWX Retain Bound default/test-pvc 2m22s NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/test-pvc Bound test-pv 1Gi RWX 18s => PV와 PVC가 연결되어 PV가 Bound 상태로 변경된 것을 확인할 수 있습니다.
3.4 PVC를 사용할 Pod 생성
apiVersion: v1 kind: Pod metadata: name: test-nginx2 spec: containers: - name: test-nginx2 image: nginx:1.19 ports: - containerPort: 80 volumeMounts: - mountPath: "/test/volume" name: test-pv volumes: - name: test-pv persistentVolumeClaim: claimName: test-pvc # 옵션 - volumeMounts.mountPath: 볼륨 마운트할 컨테이너 안의 경로를 작성합니다. - volumes:.persistentVolumeClaim: 컨테이너에서 사용할 PV의 이름을 가져오고, PV와 연결되어 있으며 요청을 보낼 PVC를 지정합니다. # 적용하기 kubectl apply -f test-nginx2.yaml # 확인해보기 # 외부에서 확인 # kubectl describe pod test-nginx2 | grep -A1 Mounts Mounts: /test/volume from test-pv (rw) # 컨테이너 내부에서 확인 kubectl exec -it test-nginx2 -- bash root@test-nginx2:/# df -Th | grep volume /dev/vda1 xfs 50G 3.7G 47G 8% /test/volume => 지정한 경로에 볼륨이 마운트된 것을 확인할 수 있습니다. # 컨테이너 내부에서 test용 파일 생성 root@test-nginx2:/# touch /test/volume/test.txt # PV 생성 시 설정한 노드의 경로에서도 확인이 가능합니다. [root@worker-node ~]# ls -al /test/volume/ total 0 drwxr-xr-x 2 root root 22 Mar 10 06:22 . drwxr-xr-x 3 root root 20 Mar 10 06:18 .. -rw-r--r-- 1 root root 0 Mar 10 06:22 test.txt
4. 컨피그맵
Key-Value 쌍으로 기밀이 아닌 데이터를 저장하는 데 사용하는 API 오브젝트입니다.
컨테이너 이미지에서 환경 별 구성을 분리하여, 애플리케이션을 쉽게 이식할 수 있습니다.
개발/운영 환경의 컨테이너는 동일하게 구성하고, 컨피그맵 설정을 다르게 적용하여 서비스를 관리할 수 있습니다.
파드와 컨피그맵은 동일한 네임스페이스에 있어야 합니다.
4.1 컨피그맵 사용
4.1.1 컨피그맵을 생성합니다.
apiVersion: v1 kind: ConfigMap metadata: name: prod-account namespace: default data: ID: prod-user PASSWORD: prod-pass LOG_LEVEL: info
4.1.2 컨테이너에서 prod-account 컨피그맵의 LOG_LEVEL값을 가지고 오도록 설정합니다.
piVersion: apps/v1 kind: Deployment metadata: name: configmap-test labels: app: prod spec: replicas: 1 selector: matchLabels: app: prod template: metadata: labels: app: prod spec: containers: - name: testapp image: nginx:1.19 ports: - containerPort: 8080 env: - name: LOG_LEVEL valueFrom: configMapKeyRef: name: prod-account key: LOG_LEVEL
4.1.3 설정이 제대로 되었는지 파드 안에서 확인합니다.
root@k8s-master01:~/kb# kubectl get pod NAME READY STATUS RESTARTS AGE configmap-test-779ff45747-f4969 1/1 Running 0 80s root@k8s-master01:~/kb# kubectl exec -it configmap-test-779ff45747-f4969 -- bash root@configmap-test-779ff45747-f4969:/# env | grep LOG_LEVEL LOG_LEVEL=info
5. 시크릿
비밀번호, OAuth 토큰, ssh 키와 같은 민감한 정보를 저장하는 용도로 사용됩니다.
시크릿 생성 시 데이터는 base64로 인코딩되어 저장됩니다.
컨피그맵은 보안/암호화를 제공하지 않기 때문에, 저장하려는 데이터가 기밀인 경우, Secret을 사용하여 데이터를 비공개로 유지합니다.
시크릿은 ETCD에 암호화되지 않은 상태로 저장되기 때문에, API 접근 권한이 있는 모든 사용자는 시크릿을 조회/수정 할 수 있습니다.
TLS 인증서를 시크릿으로 저장하여 사용하는 경우도 많습니다.
secret 리소스의 type 필드로 타입을 명시 할 수 있습니다.
빌트인 타입 | 사용처 |
---|---|
| 임의의 사용자 정의 데이터 |
| 서비스 어카운트 토큰 |
| 직렬화 된(serialized) |
| 직렬화 된 |
| 기본 인증을 위한 자격 증명(credential) |
| SSH를 위한 자격 증명 |
| TLS 클라이언트나 서버를 위한 데이터 |
| 부트스트랩 토큰 데이터 |
5.1 불투명(Opaque) 시크릿 사용
5.1.1 명령어로 시크릿 생성
root@k8s-master01:~/kb# cat prod-user.txt prod-user root@k8s-master01:~/kb# cat prod-pass.txt prod-pass root@k8s-master01:~/kb# kubectl create secret generic prod-user --from-file=./prod-user.txt --from-file=./prod-pass.txt secret/prod-user-secret created root@k8s-master01:~/kb# kubectl get secrets NAME TYPE DATA AGE prod-user-secret Opaque 2 4s root@k8s-master01:~/kb# kubectl get secrets prod-user-secret -o yaml apiVersion: v1 data: prod-pass.txt: cHJvZC1wYXNzCg== prod-user.txt: cHJvZC11c2VyCg== kind: Secret metadata: creationTimestamp: "2023-03-13T02:35:54Z" name: prod-user-secret namespace: default resourceVersion: "1226226" uid: 41a2cb2d-97f2-41bc-824f-c0c2783ec678 type: Opaque *원래 값 확인방 root@k8s-master01:~/kb# echo cHJvZC11c2VyCg== | base64 --decode prod-user
5.1.2 yaml 파일로 시크릿 생성
yaml 파일로 생성시 필요 값들을 base64로 인코딩된 값을 넣어야 합니다.
root@k8s-master01:~/kb# echo -n "prod-user" | base64 cHJvZC11c2Vy root@k8s-master01:~/kb# echo -n "prod-pass" | base64 cHJvZC1wYXNz
시크릿을 생성합니다.
apiVersion: v1 kind: Secret metadata: name: prod-user type: Opaque data: username: cHJvZC11c2Vy password: cHJvZC1wYXNz
생성된 시크릿을 확인합니다.
root@k8s-master01:~/kb# kubectl apply -f prod-user-secret.yaml root@k8s-master01:~/kb# kubectl get secrets NAME TYPE DATA AGE prod-user Opaque 2 5s root@k8s-master01:~/kb# kubectl get secrets prod-user -o yaml apiVersion: v1 data: password: cHJvZC1wYXNz username: cHJvZC11c2Vy kind: Secret metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","data":{"password":"cHJvZC1wYXNz","username":"cHJvZC11c2Vy"},"kind":"Secret","metadata":{"annotations":{},"name":"prod-user","namespace":"default"},"type":"Opaque"} creationTimestamp: "2023-03-13T02:49:45Z" name: prod-user namespace: default resourceVersion: "1228228" uid: a5eff12c-2329-4697-92f7-f252a4f724ba type: Opaque
5.1.3 시크릿 사용
apiVersion: apps/v1 kind: Deployment metadata: name: secretapp labels: app: secretapp spec: replicas: 1 selector: matchLabels: app: secretapp template: metadata: labels: app: secretapp spec: containers: - name: testapp image: nginx:1.19 ports: - containerPort: 8080 env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: prod-user key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: prod-user key: password
root@k8s-master01:~/kb# kubectl exec -it secretapp-69d4797f86-7r95g -- bash root@secretapp-69d4797f86-7r95g:/# env | grep SECRET SECRET_USERNAME=prod-user SECRET_PASSWORD=prod-pass