-
10. 쿠버네티스 핵심 개념 (5)24년 11월 이전/데브옵스(DevOps)를 위한 쿠버네티스 마스터 2021. 8. 14. 18:30반응형
이 문서는 인프런 강의 "데브옵스를 위한 쿠버네티스 마스터"을 듣고 작성되었습니다. 최대한 요약해서 강의 내용을 최소로 하는데 목표를 두고 있어서, 더 친절하고 정확한 내용을 원하신다면 강의를 구매하시는 것을 추천드립니다. => 강의 링크
네트워크 볼륨 (NFS)
Kubernetes
는 스토리지로 네트워크 파일 시스템(NFS
,GlusterFS
)을 이용할 수 있다. 이 절에서는NFS
를 볼륨으로 이용하는 것에 대해서 다룬다. 이 절은 "VM"에서 진행한다. 먼저 모든 노드에NFS
를 설치한다.$ sudo -i # apt-get install nfs-common nfs-kernel-server portmap -y
그리고 노드 1개를 선택해서 다음 작업을 진행한다. 나는 "슬레이브2"에서 진행했다.
## nfs용 디렉토리 생성 # mkdir /home/nfs ## 권한 부여 # chmod 777 /home/nfs ## 모든 노드의 ip nfs 디렉토리 접근할 수 있도록 권한 부여 # tee /etc/exports <<EOF /home/nfs 10.0.2.15(rw,sync,no_root_squash) 10.0.2.4(rw,sync,no_root_squash) 10.0.2.5(rw,sync,no_root_squash) EOF ## nfs 서버 재시작 # systemctl restart nfs-server ## 현재 마운트된 디렉토리 접근 가능 호스트 목록 확인 # showmount -e 127.0.0.1 Export list for 127.0.0.1: /home/nfs 10.0.2.5,10.0.2.4,10.0.2.15 ## /mnt 를 nfs 디렉토리에 마운트, 다음 형식을 따름 ## mount -t nfs <자신의 노드>:<NFS 디렉토리> <마운트 디렉토리> # mount -t nfs 10.0.2.5:/home/nfs /mnt ## 테스트 파일 생성 # echo test >> /home/nfs/test.txt ## /mnt에 공유되는지 확인 # cat /mnt/test.txt test
그 후 다음과 같이
volume-nfs.yaml
파일을 만든다.apiVersion: v1 kind: Pod metadata: name: mongodb spec: containers: - image: mongo name: mongodb volumeMounts: - mountPath: /data/db name: mongodb ports: - containerPort: 27017 volumes: - name: mongodb nfs: server: 10.0.2.5 path: /home/nfs
이제 리소스를 생성한다.
$ kubectl create -f volume-nfs.yaml
생성이 끝나면
mongodb
포드에 접속해서mongo
명령어를 실행한다.$ kubectl exec -it mongodb mongo ... >
이제 다음과 같이
mongodb
명령어를 사용해보자. 데이터베이스를 생성하고, 객체를 하나 저장하고 쿼리하는 내용이다.# 데이터베이스 생성 및 선택 > use mydb switched to db mydb # 데이터 추가 > db.foo.insert({name: "test", value: 1234}) WriteResult({ "nInserted" : 1 }) # 데이터 쿼리 > db.foo.find() { "_id" : ObjectId("611280e2a9c5bd71d0b71690"), "name" : "test", "value" : 1234 } # 종료 > exit
이제 포드를 제거해보자.
$ kubectl delete -f volume-nfs.yaml
그 후 다시 생성한다.
$ kubectl create -f volume-nfs.yaml
정상적으로 영구 디스크를 볼륨으로 사용하고 있었다면, 포드를 삭제했더라도 데이터가 남아 있을 것이다.
mongodb
에 접속해서 데이터베이스 선택, 데이터 쿼리를 진행해보자.$ kubectl exec -it mongodb mongo ... # 데이터베이스 선택 > use mydb switched to db mydb # 데이터 쿼리 db.foo.find() { "_id" : ObjectId("611280e2a9c5bd71d0b71690"), "name" : "test", "value" : 1234 } # 종료 > exit
잘 수행이 된다 굳!
클라우드 네트워크 볼륨 (gcePersistentDisk)
이 절은 "GCP"에서 진행한다. 이전 절에서 했던 작업을
GCP
같은 클라우드엣거는 미리 제공을 한다. 여기서는NFS
역할을 하는 영구 디스크인gcePersistentDisk
를 볼륨으로 사용하는 것을 다룬다. 먼저 영구 디스크인gcePersistentDisk
를 생성한다.$ gcloud compute disks create --size=10GB --zone=asia-northeast3-a mongodb
그 후 다음과 같이
volume-nfs-gce.yaml
파일을 만든다.src/ch10/k8s/volume-nfs-gce.yaml
apiVersion: v1 kind: Pod metadata: name: mongodb spec: containers: - image: mongo name: mongodb volumeMounts: - mountPath: /data/db name: mongodb ports: - containerPort: 27017 volumes: - name: mongodb gcePersistentDisk: pdName: mongodb fsType: ext4
이제 리소스를 생성한다.
$ kubectl create -f volume-nfs-gce.yaml
생성이 끝나면
mongodb
포드에 접속해서mongo
명령어를 실행한다.$ kubectl exec -it mongodb mongo ... >
이제 다음과 같이
mongodb
명령어를 사용해보자. 데이터베이스를 생성하고, 객체를 하나 저장하고 쿼리하는 내용이다.# 데이터베이스 생성 및 선택 > use mydb switched to db mydb # 데이터 추가 > db.foo.insert({name: "test", value: 1234}) WriteResult({ "nInserted" : 1 }) # 데이터 쿼리 > db.foo.find() { "_id" : ObjectId("611280e2a9c5bd71d0b71690"), "name" : "test", "value" : 1234 } # 종료 > exit
이제 포드를 제거해보자.
$ kubectl delete -f volume-nfs-gce.yaml
그 후 다시 생성한다.
$ kubectl create -f volume-nfs-gce.yaml
정상적으로 영구 디스크를 볼륨으로 사용하고 있었다면, 포드를 삭제했더라도 데이터가 남아 있을 것이다.
mongodb
에 접속해서 데이터베이스 선택, 데이터 쿼리를 진행해보자.$ kubectl exec -it mongodb mongo ... # 데이터베이스 선택 > use mydb switched to db mydb # 데이터 쿼리 db.foo.find() { "_id" : ObjectId("611280e2a9c5bd71d0b71690"), "name" : "test", "value" : 1234 } # 종료 > exit
잘 수행이 된다 굳!
PV와 PVC (1) 정적 프로비저닝
이 절은 "GCP"에서 진행된다. 그리고 이전 절 "클라우드 네트워크 볼륨 (gcePersistentDisk)"을 진행하고 오길 바란다.
PersistentVolume(이하 pv)
는Kubernetes
에서 유일하게 운영자가 관리하는 리소스이다. 실제적으로 스토리지 연결을 이 리소스로 한다고 생각하면 된다.PersistentVolumeClaim(이하 pvc)
는 추상 계층으로써 개발자가Kubernetes
에서 스토리지 작업을 하지 않고도 작업된 스토리지 볼륨을 사용하는데 쓰이는 리소스이다. 대충 이런 느낌이랄까?이제 다음과 같이
volume-pv.yaml
파일을 만든다.apiVersion: v1 kind: PersistentVolume metadata: name: mongo-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce - ReadOnlyMany persistentVolumeReclaimPolicy: Retain gcePersistentDisk: pdName: mongodb fsType: ext4 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mongo-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: "" --- apiVersion: v1 kind: Pod metadata: name: volume-pv spec: containers: - image: mongo name: mongodb volumeMounts: - mountPath: /data/db name: mongodb ports: - containerPort: 27017 volumes: - name: mongodb persistentVolumeClaim: claimName: mongo-pvc
pod
에서 볼륨은 이제pvc
로 지정하는 것을 볼 수 있다. 이 때claimName
은pvc
의 이름이어야 한다. 또한pvc
에 작성된spec
을 토대로 알맞는pv
가 있다면 그것을 사용하게 된다. 그리고pv
는 이전 절과 같이gcePersistentDisk
를 사용한다. 이제 리소스를 생성한다.$ kubectl create -f volume-pv.yaml
생성이 끝나면 다음 명령어들을 확인해보자.
$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mongo-pv 10Gi RWO,ROX Retain Bound default/mongo-pvc 25s $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mongo-pvc Bound mongo-pv 10Gi RWO,ROX 28s
이때
pv
에서CLAIM
에서pvc
가 보이는지STATUS
는 "Bound"인지 확인한다. 마찬가지로pvc
에서는STATUS
가 "Bound"인지VOLUME
이pv
의 이름이 설정됐는지 확인하면 된다. 이제mongodb
포드에 접속해서mongo
명령어를 실행한다.$ kubectl exec -it mongodb mongo ... >
이제 다음과 같이
mongodb
명령어를 사용해보자. 이전 절에서 진행했다면 데이터베이스를 선택하고 바로 저장한 객체를 다음과 같이 불러올 수 있을 것이다.# 데이터베이스 선택 > use mydb switched to db mydb # 데이터 쿼리 db.foo.find() { "_id" : ObjectId("611280e2a9c5bd71d0b71690"), "name" : "test", "value" : 1234 } # 종료 > exit
PV와 PVC (2) 동적 프로비저닝 StorageClass
이 절은 "GCP"에서 진행한다.
pv
는 몇 가지 고려 사항이 몇 가지 있다.- 개발 팀에 스토리지를 관리할 수 있는 자원이 있는가
- 디스크의 양이 충분한가
결국
pv
는 스토리지 영역을 컨트롤 할 수 있는 운영자가 절대적으로 필요하다. 만약 이런 부분이 미흡하다면 어떻게 해야 할까?StorageClass
를 이용하면 이 문제를 손쉽게 해결할 수 있다.StorageClass
는pv
를 만들지 않고도 동적으로pvc
가 요청한 크기만큼 스토리지를 볼륨으로 프로비저닝할 수가 있다. 다만 클라우드 프로바이더GCP
,AWS
,Azure
등의 환경에서 사용하는 것이 권장된다.다음과 같이 코드를 작성해보자. (이 때
pv
,pvc
는 모두 삭제해두어야 한다.)src/ch10/k8s/volume-storage-class.yaml
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: mongo-stroage-class provisioner: kubernetes.io/gce-pd parameters: type: pd-ssd --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mongo-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: mongo-stroage-class --- apiVersion: v1 kind: Pod metadata: name: mongodb spec: containers: - image: mongo name: mongodb volumeMounts: - mountPath: /data/db name: mongodb ports: - containerPort: 27017 volumes: - name: mongodb persistentVolumeClaim: claimName: mongo-pvc
이전 절에서 진행했던 코드에서 다음이 변경되었다.
- pv는 storageClass로 대체한다.
- pvc의 storageClassName 필드에 storageClass의 이름을 할당한다.
이제 리소스를 생성한 후 다음 명령어들을 확인해보자.
# 리소스 생성 $ kubectl create -f volume-storage-class.yaml # pv 확인 $ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mongo-pv 10Gi RWO,ROX Retain Released default/mongo-pvc 34m pvc-9a48f495-1af2-4174-824b-20c28d177615 1Gi RWO Delete Bound default/mongo-pvc mongo-stroage-class 4m18s # pvc 확인 $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mongo-pvc Bound pvc-9a48f495-1af2-4174-824b-20c28d177615 1Gi RWO mongo-stroage-class 4m39s
pvc
에서 요청했던대로 1Gi 만큼의 볼륨이 생긴 것을 확인할 수 있다. 디스크를 확인해보면 ssd 형 디스크가 하나 생성한 것을 확인할 수 있다.StatefulSet
StatefulSet
은 애플리케이션의 상태를 저장하고 관리하는데 사용되는 리소스이다.Deployment
와 상당히 유사한데, 차이점이라면Deployment
는 포드가 무작위로 생성되고 배치되는 반면,StatefulSet
은 포드의 순서와 배치를 결정할 수 있다.StatefulSet
은 다음과 같은 경우에 사용할 수 있다.- 안정적이고 고유한 네티워크 식별자가 필요한 경우
- 안정적이고 지속적인 스토리지를 사용해야 하는 경우
- 질서 정연한 포드의 배치와 확장을 원하는 경우
- 포드의 자동 롤링 업데이트를 사용하기 원하는 경우
각 포드의 상태를 유지할 수 있는 장점이 생기는 반면 다음과 같은 단점도 생긴다.
- StatefulSet 관련된 볼륨이 자동으로 삭제되지 않는다.
- Pod의 Storage는 PV 혹은 StorageClass로 프로비저닝을 해주어야 한다.
- 롤링 업데이트 수행 시 수동으로 복구해야 하는 경우가 생긴다.
- Pod 네트워크 ID를 유지하기 위해서 Headless Service가 필요하게 된다.
즉 상태를 유지할 수 있는 장점과 동시에 수동으로 관리의 필요성이 생긴다는 단점이 생긴다. 한 번
StatefulSet
을 만들어보자. 이 절은 "GCP"에서 진행한다. (로컬도 상관은 없다.) 다음과 같이 파일을 작성한다.apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None # Headless selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx serviceName: "nginx" replicas: 3 template: metadata: labels: app: nginx spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: k8s.gcr.io/nginx-slim:0.8 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "stateful-set-storage-class" resources: requests: storage: 1Gi --- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: stateful-set-storage-class provisioner: kubernetes.io/gce-pd parameters: type: pd-ssd
작성 요령은
Deployment
와 거의 동일하다. 가장 먼저 차이점은Service
작성 요령에 있다.apiVersion: v1 kind: Service # ... spec: # ... clusterIP: None # Headless
spec.clusterIP
의 값이 "None"이다. 이렇게 작성된 리소스를Headless Service
라고 한다.StatefulSet
이 관리하는Pod
를Service
로 연결해주려면 반드시 이렇게 만들어주어야 한다.# ... apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: # ... spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: k8s.gcr.io/nginx-slim:0.8 ports: - containerPort: 80 name: web # ...
StatefulSet
관련해서Deployment
와 가장 큰 차이점은Pod
에 대해 작성할 때 다음 데이터가 반드시 필요하다.- spec.terminationGracePeriodSeconds
- spec.containers[].ports.ports[].name
terminationGracePeriodSeconds
는 리소스를 종료할 때 대기해주는 시간을 의미한다. 순서대로 배치시키기 때문에 이 값은 필수적으로 들어간다. 또한,ports
관련 작성 시 이름이 필수적으로 들어가게 된다.# ... apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: # ... volumeClaimTemplates: - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "stateful-set-storage-class" resources: requests: storage: 1Gi
또한
volumeClaimTemplates
에서pvc
와 연결해주어야 한다. 작성 요령은Pod
의volumes
와 유사하다. 이제 터미널에 다음을 입력하여 리소스를 생성한다.$ kubectl create -f statefulset.yaml service/nginx created statefulset.apps/web created storageclass.storage.k8s.io/stateful-set-stroage-class created
리소스가 다 생성된다면 다음 명령어로 만들어진 리소스들을 확인해보자.
$ kubectl get pod -w # 순서대로 web-n (0, 1, 2...) 로 만들어지는 것을 확인할 수 있다. NAME READY STATUS RESTARTS AGE web-0 0/1 ContainerCreating 0 26s web-0 1/1 Running 0 32s web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 7s web-1 0/1 ContainerCreating 0 7s web-1 1/1 Running 0 22s web-2 0/1 Pending 0 0s web-2 0/1 Pending 0 0s web-2 0/1 Pending 0 7s web-2 0/1 ContainerCreating 0 7s web-2 1/1 Running 0 17s $ kubectl get pvc # 역시 www-web-n (0, 1, 2..) 형식으로 출력된다. NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE www-web-0 Bound pvc-fc161b94-5c7d-4367-b15d-c148eab6cdea 1Gi RWO stateful-set-storage-class 2m16s www-web-1 Bound pvc-a49ba9cf-2b6d-48e7-b8c8-d78ec259d554 1Gi RWO stateful-set-storage-class 104s www-web-2 Bound pvc-7e940025-e320-4da5-a3ef-500b4e5134a3 1Gi RWO stateful-set-storage-class 82s $ kubectl get statefulset NAME READY AGE web 3/3 2m55s
이제
StatefulSet
을 스케일 아웃해보자. 3개에서 5개로Pod
를 늘린다.$ kubectl scale statefulset web --replicas=5 statefulset.apps/web scaled $ kubectl get pod -w NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 12m web-1 1/1 Running 0 11m web-2 1/1 Running 0 11m # 여기서부터 확인 가능하다. 역시 오름차순 형태로 pod가 생성된다. web-3 0/1 Pending 0 5s web-3 0/1 Pending 0 7s web-3 0/1 ContainerCreating 0 7s web-3 1/1 Running 0 17s web-4 0/1 Pending 0 0s web-4 0/1 Pending 0 0s web-4 0/1 Pending 0 7s web-4 0/1 ContainerCreating 0 7s web-4 1/1 Running 0 17s $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE www-web-0 Bound pvc-fc161b94-5c7d-4367-b15d-c148eab6cdea 1Gi RWO stateful-set-storage-class 13m www-web-1 Bound pvc-a49ba9cf-2b6d-48e7-b8c8-d78ec259d554 1Gi RWO stateful-set-storage-class 13m www-web-2 Bound pvc-7e940025-e320-4da5-a3ef-500b4e5134a3 1Gi RWO stateful-set-storage-class 12m www-web-3 Bound pvc-7565e8f0-7c9a-4f9f-b38f-e6f582e33187 1Gi RWO stateful-set-storage-class 86s www-web-4 Bound pvc-0ddd0bae-7aa9-4543-9dd0-0e176970ba09 1Gi RWO stateful-set-storage-class 69s
이제는 스케일 인해보자. 5개에서 1개로 줄인다.
$ kubectl scale statefulset web --replicas=1 $ kubectl get pod -w NAME READY STATUS RESTARTS AGE NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 14m web-1 1/1 Running 0 13m web-2 1/1 Running 0 13m # web-4는 순식간에 삭제되었다.. 역순으로 삭제된다. web-3 0/1 Terminating 0 118s web-3 0/1 Terminating 0 2m3s web-3 0/1 Terminating 0 2m3s web-2 1/1 Terminating 0 13m web-2 0/1 Terminating 0 13m web-2 0/1 Terminating 0 13m web-2 0/1 Terminating 0 13m web-1 1/1 Terminating 0 14m web-1 0/1 Terminating 0 14m web-1 0/1 Terminating 0 14m web-1 0/1 Terminating 0 14m $ kubectl get pvc www-web-0 Bound pvc-fc161b94-5c7d-4367-b15d-c148eab6cdea 1Gi RWO stateful-set-storage-class 15m www-web-1 Bound pvc-a49ba9cf-2b6d-48e7-b8c8-d78ec259d554 1Gi RWO stateful-set-storage-class 14m www-web-2 Bound pvc-7e940025-e320-4da5-a3ef-500b4e5134a3 1Gi RWO stateful-set-storage-class 14m www-web-3 Bound pvc-7565e8f0-7c9a-4f9f-b38f-e6f582e33187 1Gi RWO stateful-set-storage-class 3m5s www-web-4 Bound pvc-0ddd0bae-7aa9-4543-9dd0-0e176970ba09 1Gi RWO stateful-set-storage-class 2m48s
리소스가 오름차순으로 순차적으로 늘어나는것과 반대로 내림차순으로 삭제되는 것을 확인할 수 있다. 한 가지 이상한 점이 눈에 띈다.
pvc
는 삭제되지 않았다는 것이다. 스토리지 볼륨의 경우 삭제하고 싶다면 수동으로 삭제를 진행해야 한다. 이번엔 롤링 업데이트를 해보자.StatefulSet
의 업데이트 전략은 2가지가 있다.- OnDelete : 모든 Pod를 수동으로 삭제 후 새로운 Pod가 업데이트 된다.
- RollingUpdate : Pod가 내림차순으로 삭제 후
$ kubectl edit statefulset web
다음 처럼 수정한다. (replicas = 1 -> 3, image = 0.8 -> 0.9)
그 후 리소스 변화를 관찰해보자.
$ kubectl get pod -w NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 20m web-1 0/1 ContainerCreating 0 3s web-1 1/1 Running 0 24s web-2 0/1 Pending 0 0s web-2 0/1 Pending 0 0s web-2 0/1 ContainerCreating 0 0s web-2 1/1 Running 0 17s web-0 1/1 Terminating 0 21m web-0 0/1 Terminating 0 21m web-0 0/1 Terminating 0 21m web-0 0/1 Terminating 0 21m web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s web-0 0/1 ContainerCreating 0 0s web-0 1/1 Running 0 10s
먼저
web-0
가 실행되는 상황에서Pod
가 2개 더 필요하다. 그럼web-1
,web-2
는 최신 버전인 "0.9"로 컨테이너가 실행된다. 그 후web-0
가 삭제 후 다시 만들어진다. 다시 버전을 0.8로 복귀시켜보자.$ kubectl edit statefulset web statefulset.apps/web edited $ kubectl get pod -w NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 2m28s web-1 1/1 Running 0 3m11s web-2 0/1 Terminating 0 2m47s web-2 0/1 Terminating 0 2m50s web-2 0/1 Terminating 0 2m50s web-2 0/1 Pending 0 0s web-2 0/1 Pending 0 0s web-2 0/1 ContainerCreating 0 0s web-2 1/1 Running 0 10s web-1 1/1 Terminating 0 3m24s web-1 0/1 Terminating 0 3m25s web-1 0/1 Terminating 0 3m34s web-1 0/1 Terminating 0 3m34s web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 10s web-0 1/1 Terminating 0 3m1s web-0 0/1 Terminating 0 3m2s web-0 0/1 Terminating 0 3m11s web-0 0/1 Terminating 0 3m11s web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s web-0 0/1 ContainerCreating 0 0s web-0 1/1 Running 0 10s
역순으로 업데이트되는 것을 확인할 수 있다. 즉 레플리카 수에서 부족한 번호부터 채우되 기본적으로는 역순으로 업데이트하는 것을 확인할 수 있다.
728x90'레거시 > 데브옵스(DevOps)를 위한 쿠버네티스 마스터' 카테고리의 다른 글
12. 애플리케이션 스케줄링과 라이프사이클 관리 (2) (0) 2021.08.20 11. 애플리케이션 스케줄링과 라이프사이클 관리 (1) (0) 2021.08.17 09. 쿠버네티스 핵심 개념 (4) (0) 2021.08.05 08. 쿠버네티스 핵심 개념 (3) (0) 2021.07.25 07. 쿠버네티스 핵심 개념 (2) (0) 2021.07.14