본문 바로가기

Docker & Kubernetes

쿠버네티스(Kubernetes) - 오브젝트

오브젝트란?

쿠버네티스 시스템에서 영속성을 가지는 오브젝트이다. 하나의 의도를 담은 레코드이며, 영속성의 특징에 따라 오브젝트 생성을 보장하기 위해 지속적으로 작동한다. 이 오브젝트를 생성함으로써 클러스터의 워크로드를 어떤 형태로 보이고자 하는지에 대해 효과적으로 쿠버네티스 시스템에 전한다.

 

- 컨테이너화된 애플리케이션이 동작중인지 (그리고 어느 노드에서 동작 중인지)

- 애플리케이션이 이용할 수 있는 리소스

- 애플리케이션이 어떻게 재구동, 업그레이드, 내고장성(시스템의 일부가 고장이 나도 전체에는 영향을 주지 않고, 항상 시스템의 정상 작동을 유지하는 능력)과 같은 부분들을 동작해야 하는지에 대한 정책

 

즉, 오브젝트는 가장 기본적인 구성 단위가 된다. 그리고 이 오브젝트를 생성,수정,삭제 동작을 입력받아 전달해줄 때, 지금껏 사용했던 kubectl 커멘드라인 인터페이스를 이용할 수 있다.

이때, kubectl은 대부분의 경우 정보를 .yaml 파일을 받아서 Json형태로 포맷을 전환하여 쿠버네티스 API를 호출해준다.

 

1] 데몬셋(DaemonSet)

데몬셋은 클러스터 전체에 pod를 띄울때 사용하는 컨트롤러이다. 데몬셋을 이용하여 pod를 실행하면 항상 그 pod가 클러스터 전체 node에 떠있게 된다. 그리고 클러스터내에 새롭게 node가 추가되었을때 자동으로 그 node에 데몬셋으로 띄운 포드가 실행된다. 반대로 node가 클러스터에서 빠졌을때는 node에 있는 pod는 그대로 사라지며, 다른 곳으로 옮겨가서 실행되지 않는다. 그렇기 때문에 데몬셋은 보통 로그수집기를 실행하거나 node를 모니터링 하는 모니터링용 데몬 등. 클러스터 전체에 항상 실행시켜 두어야 하는 pod를 실행하는데 사용한다.

 

사용예)

= Calico 네트워크 플러그인과 kube-proxy를 생성

= MetalLB의 speaker

 

데몬셋 생성해보기

= https://xggames.tistory.com/69 => 인그레스와 로드밸런서 내용중 metallb.yaml 배포했던 내용을 가지고 계속 진행한다.

# MetalLB의 스피커가 각 노드에 분포되어 있는 상태 확인
[root@m-k8s-ys vagrant]# kubectl get pods -n metallb-system -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
controller-5f98465b6b-j4q5p   1/1     Running   1          27d   172.16.138.83    w3-k8s-ys   <none>           <none>
speaker-6z9q7                 1/1     Running   1          27d   192.168.56.101   w1-k8s-ys   <none>           <none>
speaker-k9vwj                 1/1     Running   1          27d   192.168.56.103   w3-k8s-ys   <none>           <none>
speaker-v2rh7                 1/1     Running   1          27d   192.168.56.10    m-k8s-ys    <none>           <none>
speaker-w8wgp                 1/1     Running   1          27d   192.168.56.102   w2-k8s-ys   <none>           <none>

 

VagrantFile에  "N = 3 # 워커노드 수" 를 4로 변경한다. 그리고 vagrant up 명령어로 w4-k8s-ys-config 워커 노드를 추가해주자. 그리고 다시 마스터노드로 들어가 "kubectl get pods -n metallb-system -o wide -w" (w는 watch의 약어)를 실행시키면 (linux의 tail -f와 비슷) 변경내용을 실시간으로 확인할 수 있다.

command + c 를눌러 취소하고, -w 명령어를빼고 추가된 워커노드에 demonset인 speaker가 설치되었는지 확인해보자.

[이후 생략...]

2] 컨피그맵(ConfigMap)

설정을 목적으로 key-value 쌍인 데이터를 저장하는데 사용하는 API 오브젝트이다. pod는 볼륨에서 환경 변수, 커맨드-라인 인수 또는 구성 파일로 컨피그맵을 사용할 수 있다. 컨피그맵을 사용하면 컨테이너 이미지에서 환경별 구성을 분리하여, 애플리케이션을 쉽게 이식할 수 있다.

컨피그맵으로 MetalLB IP 설정 변경해보기

# 컨피그맵 deployment생성
[root@m-k8s-ys vagrant]# kubectl create deployment ys-configmap --image=sysnet4admin/echo-hname
deployment.apps/ys-configmap created

# 로드밸런서를 통해 노출
[root@m-k8s-ys vagrant]# kubectl expose deployment ys-configmap --type=LoadBalancer --name=ys-configmap-svc --port=80
service/ys-configmap-svc exposed

[root@m-k8s-ys vagrant]# kubectl get services
NAME               TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
kubernetes         ClusterIP      10.96.0.1      <none>          443/TCP        62d
ys-configmap-svc   LoadBalancer   10.97.193.64   192.168.56.11   80:31380/TCP   30s

# EXTERNAL-IP 192.168.56.11-13을 192.168.56.21-23 으로 변경하기
[root@m-k8s-ys vagrant]# sed -i 's/11/21/;s/13/23/' metallb-l2config.yaml

# 변경내용 적용
[root@m-k8s-ys vagrant]# kubectl apply -f metallb-l2config.yaml 
configmap/config configured

# 로드밸런서의 speaker pod 삭제
[root@m-k8s-ys vagrant]# kubectl delete pods --all -n metallb-system
pod "controller-5f98465b6b-j4q5p" deleted
pod "speaker-6z9q7" deleted
pod "speaker-k9vwj" deleted
pod "speaker-qlqrp" deleted
pod "speaker-v2rh7" deleted
pod "speaker-w8wgp" deleted

# speaker 확인시, 새로 pod가 생성되어있다.
[root@m-k8s-ys vagrant]# kubectl get pods -n metallb-system -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
controller-5f98465b6b-wzl5w   1/1     Running   0          19s   172.16.138.84    w3-k8s-ys   <none>           <none>
speaker-2ftzn                 1/1     Running   0          19s   192.168.56.102   w2-k8s-ys   <none>           <none>
speaker-9c86w                 1/1     Running   0          19s   192.168.56.101   w1-k8s-ys   <none>           <none>
speaker-9xjsp                 1/1     Running   0          19s   192.168.56.10    m-k8s-ys    <none>           <none>
speaker-sxjg8                 1/1     Running   0          19s   192.168.56.103   w3-k8s-ys   <none>           <none>
speaker-wm2jr                 1/1     Running   0          19s   192.168.56.104   w4-k8s-ys   <none>           <none>

# EXTERNAL-IP가 변경되어있는 모습 확인
[root@m-k8s-ys vagrant]# kubectl get services
NAME               TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
kubernetes         ClusterIP      10.96.0.1      <none>          443/TCP        62d
ys-configmap-svc   LoadBalancer   10.97.193.64   192.168.56.21   80:31380/TCP   5m26s

# 192.168.56.21로 접속확인

3] PV와 PVC

쿠버네티스에서는 의도적으로 pod가 언제든지 생성되고 삭제가 되도록 설계하였다. 하지만 파드에서 생성한 내용을 기록하고 보관하거나 모든 파드가 동일한 설정 값을 유지하고 관리하기 위해 볼륨으로부터 공통된 설정을 가지고 올 수 있도록 설계를 해야하는 경우도 있을 것이다. 이때 많은 쿠버네티스 볼륨 스토리지중에서 PV와 PVC에 대한 설명이다.

 

- PV: (=PersistentVolume) 지속적으로 사용 가능한 볼륨. 볼륨을 사용할 수 있게 준비하는 단계

- PVC: (=PersistentVolumeClaim) 지속적으로 사용 가능한 불륨 요청 준비된 볼륨에서 일정 공간을 할당받는다.

 

NFS 볼륨에 PV/PVC를 만들고 pod에 연결하기

= nfs-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity: # 사용하는 용량 제한이 아닌, 쓸 수 있는 용량
    storage: 100Mi
  accessModes: # PV를 어떤 방식으로 사용할지 정의
    - ReadWriteMany
    # ReadWriteMany: 여러개의 노드가 읽고 쓸 수 있도록 마운트
    # ReadWriteOnce: 하나의 노드에서만 불륨을 읽고 쓸 수 있도록 마운트
    # ReadWriteOnce: 여러 개의 노드가 읽도록 마운트
  persistentVolumeReclaimPolicy: Retain # PV가 제거됐을 때 작동하는 방법을 정의함. (Retain: 유지|Delete:삭제|Recycle:재활용)
  nfs: # NFS 서버 연결 위치 설정
    server: 192.168.56.10
    path: /home/vagrant/nfs_shared

= nfs-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Mi

 

# nfs_shared 폴더 생성 (/home/vagrant 폴더내)
[root@m-k8s-ys vagrant]# mkdir nfs_shared

# NFS로 받아들일 IP영역 + 읽기/쓰기, 쓰기작업 동기화, root 계정 사용 등 옵션 적용
# 오류발생!! ip가 틀림. [root@m-k8s-ys vagrant]# echo '/home/vagrant/nfs_shared 192.168.50.0/24(rw,sync,no_root_squash)' >> /etc/exports
[root@m-k8s-ys vagrant]# echo '/home/vagrant/nfs_shared 192.168.56.0/24(rw,sync,no_root_squash)' >> /etc/exports

# NFS서버 활성화(다음에 시작할 때도 자동으로 적용)
[root@m-k8s-ys vagrant]# systemctl enable --now nfs
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.

# nfs-pv.yaml 오브젝트 생성 (PV)
[root@m-k8s-ys vagrant]# kubectl apply -f nfs-pv.yaml 
persistentvolume/nfs-pv created

# PV의 상태가 Available(사용 가능)임을 확인
[root@m-k8s-ys vagrant]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-pv   100Mi      RWX            Retain           Available                                   4m47s

# nfs-pvc.yaml 오브젝트 생성 (PVC)
[root@m-k8s-ys vagrant]# kubectl apply -f nfs-pvc.yaml 
persistentvolumeclaim/nfs-pvc created

# PVC 생성 확인
[root@m-k8s-ys vagrant]# kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc   Bound    nfs-pv   100Mi      RWX                           10s

# PVC 생성후, PV의 상태가 Bound(묶여짐)임을 확인
[root@m-k8s-ys vagrant]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
nfs-pv   100Mi      RWX            Retain           Bound    default/nfs-pvc                           10m

PVC는 PV와 구성이 거의 동일하지만, PV 사용자가 요청할 볼륨 공간을 관리자가 만들고, PVC 사용자(개발자)간 볼륨을 요청하는 데 사용한다는 차이가 있다.

 

= nfs-pvc-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-pvc-deploy
spec:
  replicas: 4
  selector:
    matchLabels:
      app: nfs-pvc-deploy
  template:
    metadata:
      labels:
        app: nfs-pvc-deploy
    spec:
      containers: # audit-trail 이미지를 가지고 온다. - 요청을 처리할 때마다 접속 정보를 로그로 기록
      - name: audit-trail
        image: sysnet4admin/audit-trail
        volumeMounts: # 볼륨이 마운트될 위치를 지정
        - name: nfs-vol
          mountPath: /audit
      volumes: # PVC로 생성된 볼륨을 마운트하기 위해서 nfs-pvc라는 이름을 사용하였다
      - name: nfs-vol
        persistentVolumeClaim:
          claimName: nfs-pvc

 

# nfs-pvc-deploy.yaml 배포 (pod생성)
[root@m-k8s-ys vagrant]# kubectl apply -f nfs-pvc-deploy.yaml 
deployment.apps/nfs-pvc-deploy created

# nfs pod확인
[root@m-k8s-ys vagrant]# kubectl get pods

............ 아무리 기다려봐도

ContainerCreating에서 Running 상태로 넘어가지 않고있는 이슈가 발생하였다. (이경우 .yaml파일이 잘못되었거나, 논리적으로 맞지

않다는 뜻이다) 이때

[root@m-k8s-ys vagrant]# kubectl describe pods # pod에 어떤 오류가 발생했는지 확인

를 쳐보면 어떤 오류가 발생했는지 확인할 수 있다.

폴더에 access denied!!!가 발생하고 있었다..

열심히 뭐지뭐지하고 열심히 삽질한 결과..

 

/etc/exports 파일에 192.168.50.0/24 ...로 잘못입력했다. 192.168.56.0/24 (노드들 포트범위)로 수정했다..ㅠㅠ

/etc/exports을 수정하고, [exportfs -r] 로 nfs서비스 동기화 실행

(참고자료: https://ccambo.blogspot.com/2020/12/centos-nfs-centos-8-nfs.html)

두둥! 정상적으로 마운트되고, pod들이 Running상태로 되었다. 그럼 계속 예제를 진행해보자.

# NFS서버에 마운팅한 파드중 하나에 접속
[root@m-k8s-ys vagrant]# kubectl exec -it nfs-pvc-deploy-5fd9876c46-2r726 -- /bin/bash

# 192.168.56.10:/home/vagrant/nfs_shared가 /audit와 마운트 되어있는 모습.

root@nfs-pvc-deploy-5fd9876c46-2r726:/audit# df -h
Filesystem                              Size  Used Avail Use% Mounted on
overlay                                  37G  2.8G   35G   8% /
tmpfs                                   1.3G     0  1.3G   0% /dev
tmpfs                                   1.3G     0  1.3G   0% /sys/fs/cgroup
192.168.56.10:/home/vagrant/nfs_shared   37G  3.3G   34G   9% /audit
/dev/mapper/centos_k8s-root              37G  2.8G   35G   8% /etc/hosts
shm                                      64M     0   64M   0% /dev/shm
tmpfs                                   1.3G   12K  1.3G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                                   1.3G     0  1.3G   0% /proc/acpi
tmpfs                                   1.3G     0  1.3G   0% /proc/scsi
tmpfs                                   1.3G     0  1.3G   0% /sys/firmware

# 다시 master노드로 와서 LB 생성
[root@m-k8s-ys vagrant]# kubectl expose deployment nfs-pvc-deploy --type=LoadBalancer --name=nfs-pvc-deploy-svc --port=80
service/nfs-pvc-deploy-svc exposed

그리고 CURL명령어로 열심히 호출해주고..

master노드의 /home/vagrant/nfs_shared 폴더에도 pod에서 생성된 로그파일이 있는지 확인해보자!

 

# 테스트했던 deployment, pvc, pv 정리
[root@m-k8s-ys vagrant]# kubectl delete deployment nfs-pvc-deploy
deployment.apps "nfs-pvc-deploy" deleted

[root@m-k8s-ys vagrant]# kubectl delete pvc nfs-pvc
persistentvolumeclaim "nfs-pvc" deleted

[root@m-k8s-ys vagrant]# kubectl delete pv nfs-pv
persistentvolume "nfs-pv" deleted

 

그밖에 사용자가 관리자와 동일한 단일 시스템이라면 PV와 PVC를 사용할 필요가 없다. 이때 아래의 yaml파일을 실행시켜서도 사용이 가능하다.

= nfs-ip.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-ip
spec:
  replicas: 4
  selector:
    matchLabels:
      app: nfs-ip
  template:
    metadata:
      labels:
        app: nfs-ip
    spec:
      containers:
      - name: audit-trail
        image: sysnet4admin/audit-trail
        volumeMounts:
        - name: nfs-vol
          mountPath: /audit
      volumes:
      - name: nfs-vol
        nfs:
          server: 192.168.56.10
          path: /home/vagrant/nfs_shared

4] 스테이트풀셋

: 지금까지는 레플리카셋(spec의 replicas)을 통하여 이름과 순서 등 Random한 파드 생성을 진행하였다. 반대로 스테이트폴셋은 레플리카셋과는 반대로 고정된 이름, 볼륨, 설정등을 가지고 파드를 생성하는 방법을 말한다. 아래의 표로 비교해보자.

  레플리카셋 스테이트풀셋
파드 생성시 이름 설정 Random 이름으로 설정 Ordinal index 이름으로 생성
파드 생성시 순서 동시 생성 순차 생성
파드 Recreate시 파드 이름 변경 파드 이름 유지
파드 삭제시 순서 동시 삭제 인덱스 높은 순부터 순차 삭제
불륨 생성하는 방법 PVC를 직접 생성 volumeClainTemplates을 통한 동적 생성
파드의 수를 늘리면 PVC는? 1개의 PVC에 모두 연결 각각의 PV를 생성한 뒤 연결
PVC 연결된 특정 파드가 죽으면? NodeSelector가 설정 되어 있다면 해당 노드에 동일한 서비스로 랜덤한 파드이름 생성
(같은 노드에 PVC, 파드가 생성되지 않으면 연결되지 않음)
특정 파드와 동일한 파드를 생성 후 기존 PVC와 연결
PVC 연결된 파드 수를 0으로 하면? PVC도 삭제함 PVC는 삭제하지 않음

= 스테이트풀셋이 사용되는 경우

1) 안정적이고 고유한 네트워크 식별자가 필요한 경우

2) 안정적이고 지속적인 스토리지를 사용해야 하는 경우

3) 질서 정연한 파드의 배치와 확장을 원하는 경우

4) 파드의 자동 롤링 업데이트를 사용하기 원할때

주로 레디스(Redis), 주키퍼(Zookeeper), 카산드라(Cassandra), 몽고DB(MongoDB) 등의 마스터-슬레이브 구조 시스템에서 사용한다.

 

= 스테이트풀셋 사용시 유의해야할 점

1) 스테이트풀셋과 관련된 볼륨이 삭제되지 않기때문에, 별도의 관리가 필요하다.

2) 파드의 스토리지는 PV나 스토리지클래스로 프로비저닝을 수행해야 한다

3) 롤링업데이트를 수행하는 경우 수동으로 복구해야 할 수 있음 (롤링업데이트 수행시 기존의 스토리지와 충돌로 인한 애플리케이션 오류 발생 우려)

4) 파드 네트워크 ID를 유지하기 위해 headless서비스가 필요

 

(?) 롤링 업데이트란? https://kubernetes.io/ko/docs/tutorials/kubernetes-basics/update/update-intro/

=> 따라서, 레플리카셋을 사용할지, 스테이트풀셋을 사용할지는 프로젝트의 상황에따라 달라질 수 있다.

 

= 스테이트풀셋 사용해보기

= nfs-pvc-sts.yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nfs-pvc-sts
spec:
  replicas: 4
  serviceName: sts-svc-domain #statefulset need it
  selector:
    matchLabels:
      app: nfs-pvc-sts
  template:
    metadata:
      labels:
        app: nfs-pvc-sts
    spec:
      containers:
      - name: audit-trail
        image: sysnet4admin/audit-trail
        volumeMounts:
        - name: nfs-vol # same name of volumes's name 
          mountPath: /audit
      volumes:
      - name: nfs-vol
        persistentVolumeClaim:
          claimName: nfs-pvc
# nfs-pv와 nfs-pvc 먼저 실행하고나서 nfs-pvc-sts.yaml 실행할 것.

# 스테이트풀셋 LB적용
[root@m-k8s-ys vagrant]# kubectl expose statefulset nfs-pvc-sts --type=LoadBalancer --name=nfs-pvc-sts-svc --port=80
error: cannot expose a StatefulSet.apps
# ==> expose명령어는 스테이트풀셋을 지원하지 않는다!! 따라서 yaml파일을 통해 service를 실행해주자.

= nfs-pvc-sts-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: nfs-pvc-sts-svc
spec:
  selector:
    app: nfs-pvc-sts
  ports:
    - port: 80
  type: LoadBalancer
[root@m-k8s-ys vagrant]# kubectl apply -f nfs-pvc-sts-svc.yaml 
service/nfs-pvc-sts-svc created

[root@m-k8s-ys vagrant]# kubectl get services
NAME              TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
kubernetes        ClusterIP      10.96.0.1       <none>          443/TCP        64d
nfs-pvc-sts-svc   LoadBalancer   10.108.72.139   192.168.56.21   80:30913/TCP   29s

[root@m-k8s-ys nfs_shared]# ls -al
합계 24
drw-rw-r--. 2 vagrant vagrant  233  3월 27 22:37 .
drwx------. 5 vagrant vagrant 4096  3월 27 22:35 ..
-rw-r--r--. 1 root    root     240  3월 27 22:06 audit_nfs-pvc-deploy-5fd9876c46-2r726.log
-rw-r--r--. 1 root    root      48  3월 27 22:06 audit_nfs-pvc-deploy-5fd9876c46-lm99l.log
-rw-r--r--. 1 root    root     188  3월 27 22:06 audit_nfs-pvc-deploy-5fd9876c46-rnd2m.log
-rw-r--r--. 1 root    root      94  3월 27 22:06 audit_nfs-pvc-deploy-5fd9876c46-srkz8.log
-rw-r--r--. 1 root    root     376  3월 27 22:38 audit_nfs-pvc-sts-2.log

# 마찬가지로 스테이트풀셋을 사용해서 PV, PVC를 통해 - audit_nfs-pvc-sts-2.log 파일이 master node 마운트 폴더에 추가되어있다

# 외부노출 서비스 및 스테이트풀셋 삭제
[root@m-k8s-ys vagrant]# kubectl delete services nfs-pvc-sts-svc
service "nfs-pvc-sts-svc" deleted

# (!) 이때, 파드의 삭제가 생성의 역순으로 진행된다.
[root@m-k8s-ys vagrant]# kubectl delete statefulset nfs-pvc-sts
statefulset.apps "nfs-pvc-sts" deleted

참고자료

= 서적 - 컨테이너 인프라 환경 구축을 위한 쿠버네티스/도커, 길벗 - 제 3장

= https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/kubernetes-objects/

= https://arisu1000.tistory.com/27834

= https://nearhome.tistory.com/107