0부터 시작하는 Kubernetes 공부 - StatefulSet & CronJob & DaemonSet

Jaehong Lee·2022년 9월 14일
2
post-thumbnail

1. StatefulSet

p. 198

StatefulSet 은 Pod 의 상태를 저장한다. 각 Pod 가 순서대로 생성되기 때문에 고정된 이름, 볼륨, 설정등을 가질 수 있다

StatefulSet & Headless Service

StatefulSet 은 일반적으로 Ip 를 가지지 않는 서비스 타입인 Headless Service로 노출한다. Headless Service 를 사용할 경우 ClusterIp 가 없다

  • 이를 통해 StatefulSet 과 같은 상태를 가지는 오브젝트를 선택적으로 외부에 노출할 수 있다. 만약, 전부 외부에 노출하고 싶다면, NodePort 나 LB 서비스를 사용해야 한다
  • 일반적으로 Pod 는 Cluster 내의 Pod 간 통신만을 위한 Cluster Ip 를 가지며, 외부와의 통신은 불가능하다

StatefulSet & Headless Service 구조

  • Cluster Ip 가 있다면, 다른 Pod 에서 Cluster Ip 로 접근하여 라운드 로빈 방식으로 Pod 에 요청을 전달하기에 접근할 때마다 요청을 전달받는 Pod 가 다르다. 따라서 전에 접근할 때 저장한 Data 를 다시 접근시 조회 못하는 상황이 발생한다. 이는 각 Pod 가 각각의 Volume 과 연결되며 Cluster Ip 가 라운드 로빈 방식으로 요청을 전달해주기 때문이다
  • Headless Service 에서는 Cluster Ip 를 없애고, CoreDNS 를 통해 Domain 이름으로 해당 Pod 에 접근할 수 있다. Domain 이름을 통해 해당 Pod 에 접근하기 때문에, Cluster Ip 와 같이 라운드 로빈을 통해 접근할 때마다 요청을 전달 받는 Pod 가 달라지는 상황이 생기지 않는다

StatefulSet yaml 작성

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  replicas: 3
  serviceName: nginx # cluster-ip: none
  selector:
    matchLabels:
      app: nginx
  template:    # Pod
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - name: nfs-vol
          mountPath: /usr/share/nginx/html
      volumes:
      - name: nfs-vol
        persistentVolumeClaim:
          claimName: nfs-pvc  
  • 우리는 지금까지 Service 에서 label 을 통해 요청을 넘길 Pod 를 지정하였다. 허나, StatefulSet 에서는 연결하고자 하는 Headless Service 를 지정해야 한다. 따라서 연결하고자 하는 Service 의 Name 을 지정해야 한다

    이때, Cluster Ip 가 없으므로 CoreDNS 를 통해 도메인 이름을 통해 Cluster 내에서 통신이 가능하게 한다

PVC yaml 작성

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Mi
  • 위와 같이 작성한다

PV yaml 작성

root@manager:~/k8slab/etc# showmount -e localhost
Export list for localhost:
/shared                      211.183.3.0/24
/root/k8slab/rapalab/news    211.183.3.0/24
/root/k8slab/rapalab/shop    211.183.3.0/24
/root/k8slab/rapalab/default 211.183.3.0/24
  • nfs-server 에서 외부에 공유되는 디렉토리 확인
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 100Mi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 211.183.3.100
    path: /shared
  • 위와 같이 작성하자

Headless Service yaml 작성

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
    - port: 80
  clusterIP: None
  • Headless Service 이므로 cluster Ip 는 None 으로 해야 한다!!!

배포 및 확인

root@manager:~/k8slab/etc# k apply -f pv.yaml 
persistentvolume/nfs-pv created
root@manager:~/k8slab/etc# k apply -f nfs-pvc.yaml 
persistentvolumeclaim/nfs-pvc created
root@manager:~/k8slab/etc# k get pv,pvc
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                  STORAGECLASS       REASON   AGE
persistentvolume/nfs-pv                                     100Mi      RWX            Retain           Bound      default/nfs-pvc                                    4m16s
persistentvolume/pvc-0823d965-9a82-44aa-bc31-8023e3e4548d   50Mi       RWX            Delete           Released   default/nfs-pvc-test   nfs-storageclass            5d22h

NAME                            STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/nfs-pvc   Bound    nfs-pv   100Mi      RWX                           4m10s
  • 먼저, PV & PVC 를 배포해주자. Bound 되었는지 확인하자
root@manager:~/k8slab/etc# k apply -f sfs.yaml 
statefulset.apps/web created
root@manager:~/k8slab/etc# k apply -f svc.yaml
  • StatefulSet 과 Service 를 배포해주자
root@manager:~/k8slab/etc# k get pod,svc
NAME        READY   STATUS              RESTARTS   AGE
pod/web-0   1/1     Running             0          40s
pod/web-1   1/1     Running             0          27s
pod/web-2   0/1     ContainerCreating   0          1s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   6d23h
service/nginx        ClusterIP   None         <none>        80/TCP    4m4s
  • Pod 의 이름이 hash 값으로 랜덤으로 지정되지 않으며, ClusterIP 가 Node 인 것을 확인할 수 있다
root@manager:~/k8slab/etc# k describe svc nginx
Name:              nginx
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                None
IPs:               None
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         192.168.182.52:80,192.168.189.67:80,192.168.235.132:80
Session Affinity:  None
Events:            <none>
  • Endpoints 가 설정되있다. 허나, ClusterIP 정보는 없다

Test 용 Pod 생성 및 확인

root@manager:~/k8slab/etc# k run -it --image busybox testdns --restart Never --rm /bin/sh
  • Pod 를 하나 배포해주자
    • it : 대화 창구를 열고 인터렉티브하게 통신하겠다
    • name 은 testdns 이다
    • restart Never 은 배포 실패시 더 이상 시도하지 말라는 옵션이다
    • rm 은 사용을 다 하고 나오면 삭제하라는 옵션
    • /bin/sh 는 it 를 통해 상호 통신을 하기 위하여 shell 을 실행하라는 명령어이다
/ # exit
pod "testdns" deleted
pod default/testdns terminated (Error)
  • 빠져나오지 Pod 가 삭제된다
root@manager:~/k8slab/etc# k run net --image=sysnet4admin/net-tools --restart Never --rm -it -- nslookup web-1.nginx
Server:		10.96.0.10 # CoreDNS 주소
Address:	10.96.0.10#53

Name:	web-1.nginx.default.svc.cluster.local
Address: 192.168.235.132

pod "net" deleted
  • 위 Pod 를 배포하고, 명령을 전달하자
    • Server 주소는 CoreDNS 주소이다
    • Domain 이름을 통해 web-1 Pod 의 Ip 를 확인할 수 있다
    • nslookup 할 때, 앞에는 Pod 이름, 뒤에는 연결된 Service 이름이다
root@manager:~/k8slab/etc# k run net --image=sysnet4admin/net-tools --restart Never --rm -it -- nslookup nginx
Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	nginx.default.svc.cluster.local
Address: 192.168.235.132
Name:	nginx.default.svc.cluster.local
Address: 192.168.182.52
Name:	nginx.default.svc.cluster.local
Address: 192.168.189.67
  • Service 에 대한 주소를 확인하면, Service 에 포함된 Pod 의 주소를 확인할 수 있다. 서비스는 Ip 를 None 으로 했기에 확인할 수 없다

2. CronJob

CronJob

주기적으로 실행하는 K8S 오브젝트이고, 특정 시간 간격으로 지정된 업무를 반복적으로 실행하게 해준다

CronJob yaml 작성

apiVersion: batch/v1
kind: CronJob
metadata:
  name: testcron
spec:
  schedule: "*/1 * * * * " # by 1min
  jobTemplate: #work
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: tesstcronctn
            image: busybox
            args: ["sh","-c","date"]
  • schedule 은 실행할 주기이다. */1 을 통해 1분마다 실행하게 설정했다
  • jobTemplate 은 설정한 주기마다 실행할 작업이다
    • 우리는 1 분마다 busybox 를 배포하여 시간을 출력하게 설정했다. -c 는 실행하라는 옵션이다

배포 및 확인

root@manager:~/k8slab/etc# k get pod,jobs
NAME                          READY   STATUS      RESTARTS   AGE
pod/testcron-27718752-qkwzz   0/1     Completed   0          21s

NAME                          COMPLETIONS   DURATION   AGE
job.batch/testcron-27718752   1/1           6s         21s
  • 배포 후 확인해보자
root@manager:~/k8slab/etc# k get jobs
NAME                COMPLETIONS   DURATION   AGE
testcron-27718752   1/1           6s         90s
testcron-27718753   1/1           4s         30s
root@manager:~/k8slab/etc# k get pod
NAME                      READY   STATUS      RESTARTS   AGE
testcron-27718752-qkwzz   0/1     Completed   0          100s
testcron-27718753-5sbvg   0/1     Completed   0          40s
  • 1 분 주기로 실행되는 것을 확인할 수 있다. 매 작업 주기마다 CronJob 이 생성된다
root@manager:~/k8slab/etc# k get jobs
NAME                COMPLETIONS   DURATION   AGE
testcron-27718753   1/1           4s         2m12s
testcron-27718754   1/1           5s         72s
testcron-27718755   1/1           4s         12s
  • CronJob 은 최대 3 개까지 기록된다

CronJob 은 모든 History 를 기록하지는 않는다. 성공한 Job 3 개와 실패한 Job 1 개만 기본적으로 기록한다

3. DaemonSet

root@manager:~/k8slab/etc# k get daemonset
No resources found in default namespace.
root@manager:~/k8slab/etc# k get daemonset -n kube-system
NAME          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
calico-node   4         4         4       4            4           kubernetes.io/os=linux   7d
kube-proxy    4         4         4       4            4           kubernetes.io/os=linux   7d
  • default Namespace 에는 없다. kube-system Namespace 에는 calico 와 kube-proxy 가 있는 것을 확인할 수 있다

    • 우리는 이런 DaemonSet 을 만든 적이 없다. 이 DaemonSet 의 실체는 Pod 이다. 단, DaemonSet 으로 생성된 Pod 는 모든 Node 에 일괄적으로 하나씩 자동 배포가 된다. 주로, log 확인, 모니터링, 노드간 Network ( Overlay ) 등을 위한 Agent 로 활용된다
  • 대표적으로 kube-proxy, calico 등의 네트워크 플러그인을 들 수 있다

    • 각 Node 에 백업을 위한 볼륨 포드를 하나씩 배포하고 싶은 경우에도 사용할 수 있다

DaemonSet yaml 작성

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: test
spec:
  selector:
    matchLabels:
      name: test
  template:
    metadata:
     labels:
       name: test
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master # 마스터도 배포
        effect: NoSchedule
      containers:
      - name: test
        image: busybox
        args: ["tail", "-f", "/dev/null"] # 포드가 중지되지 않게 설정
        resources:
          limits:
            cpu: 100m # cpu 0.1 개
            memory: 200Mi
  • DaemonSet 에서 matchLabels 를 통해 해당 label 의 Pod 들을 DaemonSet 으로 동작하게 해준다

  • tolerations 는 Node 에 지정된 Taints 를 무시하고, 아래에 적용한 부분에 따라 Pod 가 배포된다. 즉, Master 에도 배포할 수 있는 것이다. 즉, tolerations 에 작성된 taints 를 무시해주는 것이다

    key 가 node-role.kubernetes.io/master 이고, effect 가 NoSchedule 인 Node 에 대해 Pod 배치를 용인해주는 것이다. 따라서 master Node 에도 Pod 가 배치된다

확인

root@manager:~/k8slab/etc# k get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP                NODE      NOMINATED NODE   READINESS GATES
test-7tl8p   1/1     Running   0          16s   192.168.235.133   worker1   <none>           <none>
test-jw86q   1/1     Running   0          16s   192.168.189.78    worker2   <none>           <none>
test-k69sv   1/1     Running   0          16s   192.168.102.67    manager   <none>           <none>
test-n9qp2   1/1     Running   0          16s   192.168.182.53    worker3   <none>           <none>
  • master 를 포함하여 모든 Node 에 하나씩 배포되었다

삭제를 한다면

root@manager:~/k8slab/etc# k delete pod test-k69sv
pod "test-k69sv" deleted
root@manager:~/k8slab/etc# k get pod -o wide
NAME         READY   STATUS              RESTARTS   AGE     IP                NODE      NOMINATED NODE   READINESS GATES
test-7tl8p   1/1     Running             0          7m25s   192.168.235.133   worker1   <none>           <none>
test-jkm9s   0/1     ContainerCreating   0          2s      <none>            manager   <none>           <none>
test-jw86q   1/1     Running             0          7m25s   192.168.189.78    worker2   <none>           <none>
test-n9qp2   1/1     Running             0          7m25s   192.168.182.53    worker3   <none>           <none>
  • DaemonSet 의 Pod 를 삭제하면, Pod 가 삭제된 Node 에 새로 Pod 가 배포된다

4. Node Taints

root@manager:~/k8slab/rapalab# k get node
NAME      STATUS   ROLES                  AGE     VERSION
manager   Ready    control-plane,master   7d1h    v1.21.0
worker1   Ready    <none>                 7d1h    v1.21.0
worker2   Ready    <none>                 7d1h    v1.21.0
worker3   Ready    <none>                 6d23h   v1.21.0
  • manager node 에는 master 와 control-plane 이라는 roles 가 정해져있다. 따라서 기본적으로 master node 라고 부른다. 이 manager node 를 자세히 보면
root@manager:~/k8slab/rapalab# k describe node manager
Name:               manager
Roles:              control-plane,master
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=manager
                    kubernetes.io/os=linux
                    node-role.kubernetes.io/control-plane=
                    node-role.kubernetes.io/master=
                    node.kubernetes.io/exclude-from-external-load-balancers=
Annotations:        kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
                    node.alpha.kubernetes.io/ttl: 0
                    projectcalico.org/IPv4Address: 211.183.3.100/24
                    projectcalico.org/IPv4IPIPTunnelAddr: 192.168.102.64
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Wed, 07 Sep 2022 11:43:53 +0900
Taints:             node-role.kubernetes.io/master:NoSchedule
  • master node 에는 master 와 control-plane 이라는 role 과 label 이 지정되어 있다
  • Taints 는 Pod 배포에 대한 스케쥴을 관리한다. 해당 Node 는 NoSchedule 이므로 Pod 가 배포되지 않는다
  • Taints 가 None 인 Node 는 Pod 가 무조건 배포된다
profile
멋진 엔지니어가 될 때까지

0개의 댓글