[k8s] Kubernetes 초급편 정리


쿠버네티스 Study 및 실습한 내용 정리한 페이지 입니다. (참고로 클러스터는 3개의 Node를 VBox Ubuntu 가상환경으로 구성하였습니다.)


Node(노드)

  • Kubernetes는 Container를 Pod 내에 배치하고 Node에서 실행함으로 워크로드를 구동함.
  • Node는 구성한 Cluster에 따라 가상 또는 물리적 머신일 수 있음.
  • 각 노드는 control-plane(node 중 하나)에 의해 관리되며 Pod를 실행하는 데 필요한 Service를 포함한다.
  • Node의 구성 방법에 대해서는 따로 기재하지 않음.

실습

1
kubectl get node %namespace%


image

1
kubectl describe node %node_name%

image


Pod(파드)


Pod

  • Pod의 안에는 Container들이 존재
  • 각각의 Container들은 Service가 연결될 수 있도록 Port를 가지고 있다.
  • 한 Cotainer는 하나 이상의 Port를 가질 수 있지만, Container간에 중복되는 Port는 가질 수 없다.
  • Pod내의 Container들은 하나의 Host로 묶여있다, 그래서 다른 Container에 접근할 때 localhost를 사용할 수 있다.
  • Pod가 생성 될 때 고유한 IP가 자동으로 할당 되는데, 해당 IP는 클러스터 내부에서만 접근 가능하다. 그리고 Pod가 재생성 될 경우 IP 주소는 변경된다.

Label

  • Label은 Pod 뿐만아니라 모든 오브젝트에 추가할 수 있음 (Pod에서 가장 많이 사용)
  • 오브젝트들을 목적에 따라 분류하고 분류한 오브젝트들만 따로 연결하기 위해서 사용
  • Label은 key/value가 한쌍 ex) type:wep, lo:dev, type:db, lo:prod

Node Scheldule

  • Pod는 특정 Node에 할당되어야 하는데, 자동으로 할당 되는 것과 직접 스케쥴링하는 방법이 있음.
  • 직접 Node를 할당하는 경우, Node에 Label을 달아주고, Pod를 생성할 때 nodeSelector 항목에 Node의 Label과 매칭되는 key value를 넣어주면 됨.
  • 자동으로 Node를 할당하는 경우 yaml에 memory 등을 제한하는 항목을 추가하면 자원 상태에 따라 스케줄러가 판단하여 자동으로 Node에 할당한다.

yaml 예시

1) Pod 생성

  • container1/container2라는 pod를 생성한다.
  • image는 각각 kubetm/p8000와 kubetm/p8080을 사용한다.
  • containerPort는 각각 8000과 8080을 사용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
spec:
  containers:
  - name: container1
    image: kubetm/p8000
    ports:
    - containerPort: 8000
  - name: container2
    image: kubetm/p8080
    ports:
    - containerPort: 8080

2) label 추가하여 Pod 생성

  • type: web, lo: dev로 label 추가하여 pod 생성
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Pod
metadata:
  name: pod-2
  labels:
    type: web
    lo: dev
spec:
  containers:
  - name: container
    image: kubetm/init

3) Node Schedule 사용하여 Pod 생성

  • worker-1 node에 pod 생성
  • worker-1에 pod를 생성할 자원이 충분하지 않으면, pending 상태에서 넘어가지 못함.
  • request는 Container가 생성될 때 노드에 요청하는 리소스의 양, limit은 해당 컨테이너가 생성된 후에 사용할 수 있는 리소스의 최대치
  • Container 가동 중, 메모리 사용량이 limit을 넘어가면 재구동됨 (Cpu 사용량의 경우 limit을 넘으면 Pod를 재가동 시키진 않고, request까지 낮추어서 퍼포먼스 저하시킴)
1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
  name: pod-3
spec:
  nodeSelector:
    kubernetes.io/hostname: worker-1
  containers:
  - name: container
    image: kubetm/init
1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Pod
metadata:
  name: pod-4
spec:
  containers:
  - name: container
    image: kubetm/init
    resources:
      requests:
        memory: 2Gi
      limits:
        memory: 3Gi

Command

1
2
3
4
5
6
# 둘다 자원을 생성할때 사용할 수 있지만
# create는 기존에 같은 이름의 Pod가 존재하면 생성이 안되고,  
# apply는 기존에 같은 이름의 Pod가 존재하면 업데이트됨.
kubectl create -f %yaml_file%
kubectl apply -f %yaml_file%
kubectl delete -f %yaml_file%
1
2
kubectl describe pod %pod_name% -n %namespace%
kubectl describe -f %yaml_file%
1
2
3
4
5
kubectl get pods -n %namespace% -o wide
kubectl get pod %pod_name% (default)
kubectl get pod %pod_name% -n %namespace% (specific namespace)
kubectl get pod %pod_name% -A (all namespace)
kubectl get pod %pod_name% --all-namespaces=true (all namespace)
1
2
3
# -i: --stdin 컨테이너에 표준 입력을 연결, 컨테이너 내부에서 사용자의 입력을 받을 수 있음.
# it: --tty 컨테이너에 터미널을 할당, 컨테이너 내부에서 터미널과 상호작용할 수 있음.
kubectl exec -i -t %pod_name% -c %container_name% -- /bin/bash


Service(서비스)


ClusterIP (Default)

  • Service는 본인의 ClusterIP를 가지고 있다.
  • Service의 ClusterIP를 사용하여 Service에 연결된 Pod에 접근할 수 있다. (Pod는 재생성 가능하기 때문에 Cluster 내부에서 접근가능한 Pod의 IP는 변경 될 수 있음)
  • Service는 사용자가 조작하지 않는 이상 클러스터가 스스로 삭제하거나 재생성하지 않는다. 그러므로 Service의 ClusterIP는 불변하다.
  • Service의 ClusterIP도 Pod와 마찬가지로 Cluster 내부에서만 접근 가능하다.
  • Service에는 여러 개의 Pod를 연결할 수 있다.
  • Service에 여러 개의 Pod가 연결된 경우, Service가 트래픽을 분산시킨다.
  • 인가된 사용자, 내부 대시보드, Pod의 서비스상태 디버깅 등에 사용.

실습

1) Service 정보

1
2
kubectl get services -o wide
kubectl get service %service_nam% -n %namespace%

image

2) Service 실행

  • worker-1 node에 kubetm/app image로 containerPort 8080, 8081을 가지는 container 생성
  • 생성한 pod는 label에 key/value 값 app: pod을 가짐.
  • 실행한 service는 selector 사용하여 label key/value에 app: pod를 가지는 pod에 대해 적용
  • 이 서비스의 9000번 포트로 들어온 요청은 백엔드 파드의 8080번 포트로 전달 됨.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
  labels:
     app: pod
spec:
  nodeSelector:
    kubernetes.io/hostname: worker-1
  containers:
  - name: container
    image: kubetm/app
    ports:
    - containerPort: 8080
    - containerPort: 8081
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
  name: svc-1
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080
  - port: 9090
    targetPort: 8080

3) Service ClusterIP 사용하여 Pod에 Request 보내기

1
curl {ClusterIP}:{port}/hostname

image

NodePort

  • NodePort로 생성된 Service에는 기본적으로 ClusterIP를 가진다.
  • NodePort로 Service를 생성하면, Cluster에 생성된 모든 노드에서 동일한 NodePort 1개로 접근할 수 있다.
  • 참고로 Service와 연결된 Pod가 존재하는 Node에만 NodePort가 할당되는 것이 아니라 모든 Node에 Port가 할당 된다.
  • NodePort로 생성된 서비스는 노드에 상관 없이 트래픽을 분산 시킨다.
  • externalTrafficPolicy라는 옵션을 사용하면, 특정 Node에서 받은 Traffic은 해당 Node로만 전달하도록 할 수 있다.
  • 내부망 연결, 데모/임시 연결용.

실습

externalTrafficPolicy 옵션

  • Cluster (Default): 트래픽이 전달된 노드 내부의 Pod외에 다른 노드의 Pod로도 전달될 수 있음. (Node 단위의 로드 밸런싱 O)
  • Local: 트래픽이 전달된 노드 내부의 Pod로만 전달될 수 있음(Node 단위의 로드 밸런싱 X)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# port 30000은 Node의 모든 Pod에 할당 됩니다.
# Node의 IP (Internal 혹은 External)를 사용하여 Port에 접근 가능합니다.

apiVersion: v1
kind: Service
metadata:
  name: svc-2
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080
    nodePort: 30000
  type: NodePort
  externalTrafficPolicy: Local

NodePort로 curl 요청 보내기

  • pod가 실행 중인 node의 IP로 nodePort 사용하여 요청

image


Load Balancer

  • Load Balancer 생성된 Service에는 기본적으로 ClusterIP를 가진다.
  • Load Balancer로 생성된 Service의 외부 접속 IP는 자동으로 생성되지 않으므로 외부 접속을 위한 플러그인을 설치해주어야 한다. (클라우드 서비스 제외)
  • 외부에 시스템 노출용.

실습

  • 해당하는 label로 load balancing 자동 수행
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
  name: svc-3
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080
  type: LoadBalancer


Volume(볼륨)


emptyDir

  • 컨테이너들끼리 데이터를 공유하기 위해서 Volume을 사용하는 것, 최초 Volume이 생성 될 때는 비어있기 때문에 emptyDir이라고 명명.
  • Pod안의 Container들은 Volume 공간의 데이터에 자유롭게 접근할 수 있음.
  • Volume은 Pod안에 생성되기 때문에, Pod 생성 시에 만들어지고 삭제시에 없어짐, 그러므로 영속성이 필요하지 않은 임시 데이터에 대해서 사용해야 함.

실습

  • container1 접속시 mount2는 확인 할 수 없음. volume은 리소스는 공유하지만 격리 되어 있음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Pod
metadata:
  name: pod-volume-1
spec:
  containers:
  - name: container1
    image: kubetm/init
    volumeMounts:
    - name: empty-dir
      mountPath: /mount1
  - name: container2
    image: kubetm/init
    volumeMounts:
    - name: empty-dir
      mountPath: /mount2
  volumes:
  - name : empty-dir
    emptyDir: {}

image


hostPath

  • emptyDir와 달리 경로를 Pod가 아닌 Node에서 공유함.
  • Pod가 재생성 될 때, 혹은 Node에 문제가 생겨 Pod가 옮겨질 때 본래의 Node에서 Pod가 재생성되리라는 보장이 없으므로 고려해야 함.
  • 사용자가 직접 hostPath의 경로를 Node 추가시마다 Mount를 걸어줌으로서, Pod가 다른 Node로 옮겨지더라도 문제가 발생하지 않도록 처리할 수 있음. (추천 X)
  • hostPath는 Pod가 생성 되기 전에, 경로가 생성되어 있어야 오류가 발생하지 않음.
  • Pod의 Data를 저장하기 위함이 아니라, Pod가 할당 되어 있는 host(Node)의 Data를 사용해야할 때 적절할 수 있음.

실습

  • container 접근 시 mount1 경로 확인 됨.
  • worker-1 노드 접근 시 node-v 경로 확인 됨.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Pod
metadata:
  name: pod-volume-3
spec:
  nodeSelector:
    kubernetes.io/hostname: worker-1
  containers:
  - name: container
    image: kubetm/init
    volumeMounts:
    - name: host-path
      mountPath: /mount1
  volumes:
  - name : host-path
    hostPath:
      path: /node-v
      type: DirectoryOrCreate

image

image


PVC(Persistent Volue Claim) / PV(Persistent Volume)

  • Local Storage 혹은 NFS, AWS, git 등의 PV와 연결하여 Pod에 영속성이 있는 Data 영역을 제공하기 위함.
  • Kubernetes에서는 PVC / PV 를 사용할 때 User영역과 Admin 영역으로 분류하였음.
  • Admin이 PV를 생성한 후에, User가 PVC를 생성하면 Kubernetes가 PVC에 맞는 적절한 PV를 연결함. 이후 Pod를 만들 때 PVC를 마운팅하여 사용.

image

실습

1) PV-PVC 연결하기

  • PersistentVolume을 local로 생성, Node 경로에 /node-v 생성 됨.
  • PersistentVolumeClaim을 생성하면 k8s가 적절한 PV를 연결함, 아래에서는 PVC가 요청하는 storage 사이즈가 1G이므로 이미 생성되어져있던 pv-03의 storage 2G에 할당됨.
  • 이후, Pod 생성시 pvc-pv라는 이름으로 volume mount를 해주고 해당 이름에 대한 persistentVolumeClaim을 연결해주면 됨.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-03
spec:
  capacity:
    storage: 2G
  accessModes:
  - ReadWriteOnce
  local:
    path: /node-v
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - {key: kubernetes.io/hostname, operator: In, values: [worker-1]}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-01
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1G
  storageClassName: ""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
  name: pod-volume-3
spec:
  containers:
  - name: container
    image: kubetm/init
    volumeMounts:
    - name: pvc-pv
      mountPath: /mount3
  volumes:
  - name : pvc-pv
    persistentVolumeClaim:
      claimName: pvc-01

image

image

2) PV-PVC를 label과 selector를 이용해 연결하기

  • PVC를 label을 사용하여 특정 PV를 명시적으로 지정하여 연결하는 방법.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-04
  labels:
    pv: pv-04
spec:
  capacity:
    storage: 2G
  accessModes:
  - ReadWriteOnce
  local:
    path: /node-v
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - {key: kubernetes.io/hostname, operator: In, values: [worker-1]}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-04
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 2G
  storageClassName: ""
  selector:
    matchLabels:
      pv: pv-04

ConfigMap(컨피그맵) / Secret(시크릿)


ConfigMap, Secret

  • 외부에서 관리할 수 있는 간단한 값의 차이만 존재하는 두 개의 이미지를 하나의 이미지로 관리하기 위한 기능
  • ConfigMap과 Secret을 생성하여 Pod 생성 시 연결할 수 있음, Pod 생성 시 해당 값들은 환경 변수에 추가 됨.
  • ConfigMap과 Secret의 차이는 Secret은 보안 데이터를 저장하는데 사용. (Dashboard는 보안상의 이유로 실제로 잘 사용하지 않음.)

실습

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-dev
data:
  SSH: 'false'
  User: dev
---
apiVersion: v1
kind: Secret
metadata:
  name: sec-dev
data:
  Key: MTIzNA==
1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
spec:
  containers:
  - name: container
    image: kubetm/init
    envFrom:
    - configMapRef:
        name: cm-dev
    - secretRef:
        name: sec-dev

image

Env (Literal)

  • 상수를 넣는 방법
  • Secret은 Base64 인코딩을한 값을 넣어야 함. (이것이 Secret의 보안 규칙은 아님, 단지 Secret의 Value 규칙)
  • Pod로 주입될 때는 자동으로 디코딩 되어서 환경변수에서는 본래의 값을 볼 수 있음.
  • Secret은 메모리에 저장되고, 최대 1Mbyte까지만 넣을 수 있음. (메모리 사용하므로 성능에 주의 필요)

실습

image

Env (File)

  • file로 configmap을 만드는 것은 dashboard에서 지원하지 않으므로 명령어로 수행해야 함.
  • 예시) kubectl createconfigmap cm-file –from-file=./file.txt, kubectl create secret generic sec-file –from-file=./file.txt

실습

1
2
3
4
5
6
7
8
# file-c.txt
--------------
Content
--------------
# file-s.txt
--------------
Content
--------------
1
2
kubectl create configmap cm-file --from-file=./file-c.txt
kubectl create secret generic sec-file --from-file=./file-s.txt

image

Volume Mount (File)

  • Container 안에 mount path를 정의하고 path안에 configMap이 정의된 file을 mount 할 수 있음.
  • 환경 변수 타입은 한번 주입하고 나면 끝이고 Pod가 재생 되어야만 변경될 수 있음.
  • 하지만 Volume Mount 방식은 file이 변경될 경우 Pod의 값도 변경 됨. (1분 마다 refresh 됨.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
  name: pod-mount
spec:
  containers:
  - name: container
    image: kubetm/init
    volumeMounts:
    - name: file-volume
      mountPath: /mount
  volumes:
  - name: file-volume
    configMap:
      name: cm-file

image


Namespace / Resource Quota / LimitRange

  • Kubernetes Cluster 안에는 여러 개의 Namespace를 만들 수 있고, Namesapce에는 여러 Pod들을 생성할 수 있음.
  • 각 Pod들은 Cluster 자원을 공유해서 사용하는데, 하나의 Pod가 너무 많은 자원을 사용할 경우 나머지 Pod들은 자원 사용에 문제가 생김.
  • Resource Quota를 사용하여 Namespace마다 설정해줄 경우, Namespace마다 사용할 수 있는 최대 자원의 양을 제한할 수 있음.
  • Namespace 내부에서도 마찬가지로 하나의 Pod가 자원을 너무 많이 사용할 경우를 대비해, LimitRange 사용하여 설정된 값보다 많은 자원을 사용하는 Pod를 Namespace에 들어오지 못하게 할 수 있음.
  • Resource Quota / LimitRange는 Namespace 뿐만 아니라 Node에도 설정할 수 있음.

Namespace

  • 같은 Namespace 안에는 같은 이름의 Object를 생성할 수 없음.
  • Namespace들은 각자의 자원을 타 Namespace와 공유하지 않음.
  • Service는 타 Namespace의 Object의 label에는 연결하지 않음.
  • Node나 Persistency Volume 등은 Namespace와 상관 없이 공용으로 사용 됨.

실습

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Namespace
metadata:
  name: nm-1
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
  namespace: nm-1
  labels:
    app: pod
spec:
  containers:
  - name: container
    image: kubetm/app
    ports:
    - containerPort: 8080

image

Resource Quota

  • Namespace의 자원을 설정하는 Object
  • Resource Quota가 정의된 Namespace에 Pod를 생성할 때는 반드시 Pod에 requests / limits spec을 명시해야 한다. (defaultRequest 옵션 사용 시 예외 )
  • 현재 Resource Quota로 설정된 자원양을 초과하는 자원 양을 사용하는 Pod는 생성 될 수 없다.
  • 만약 다른 Pod가 자원을 일부 사용하고 있다면, 남은 자원 양을 초과하는 Pod는 생성 될 수 없다.
  • Kubernetes 버전마다 Resource Quota로 제한할 수 있는 Object 종류가 다르므로 확인 필요.

실습

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Namespace
metadata:
  name: nm-3
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: rq-1
  namespace: nm-3
spec:
  hard:
    requests.memory: 3Gi
    limits.memory: 5Gi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
spec:
  containers:
  - name: container
    image: kubetm/init
    resources:
      requests:
        memory: 2Gi
      limits:
        memory: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-2
  namespace: nm-3
spec:
  containers:
  - name: container
    image: kubetm/init
    resources:
      requests:
        memory: 2Gi
      limits:
        memory: 3Gi

image

LimitRange

  • ResourceQuota는 Namespace 뿐만 아니라 Cluster 전체에 부여할 수 있는 권한이지만, LimitRange의 경우 Namespace내에서만 사용 가능함.
  • maxLimitRequestRatio: request / limit의 비율 정의, 생성하는 Object의 비율이
  • defaultRequest : Objet 정의에 request / limit 을 설정하지 않을 경우, Default 값을 셋팅하는 기능.

실습

1) limit range 정의

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: v1
kind: Namespace
metadata:
  name: nm-5
---
apiVersion: v1
kind: LimitRange
metadata:
  name: lr-1
  namespace: nm-5
spec:
  limits:
  - type: Container
    min:
      memory: 0.1Gi
    max:
      memory: 0.5Gi
    maxLimitRequestRatio:
      memory: 1
    defaultRequest:
      memory: 0.1Gi
    default:
      memory: 0.5Gi

image

2) limit range에 위배되는 pod 생성

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
  namespace: nm-5
spec:
  containers:
  - name: container
    image: kubetm/app

image

3) limit range에 부합하는 pod 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
  namespace: nm-5
spec:
  containers:
  - name: container
    image: kubetm/app
    resources:
      requests:
        memory: 200Mi
      limits:
        memory: 200Mi

image


Controller

  • Auto Healing: Node에 문제가 생겼을 때, 정상 Node에 Pod를 재생성하여 자동으로 서비스를 복구함.
  • Auto Scaling: Pod에 부하가 몰릴 때, Pod를 추가 생성하여 부하를 분산.
  • SW Update: 여러 Pod에 대한 Version을 업데이트해야할 경우, Controller를 통해 한번에 쉽게할 수 있고 업데이트 도중 문제가 생기면 rollback도 가능함.
  • Job: 일시적인 작업을 해야하는 경우 일시적으로 Pod를 생성하여 작업을 수행하고, 수행을 마치면 Pod를 삭제함.
  • Replication Controller (Deprecated) –> ReplicaSet (New)

Template

  • Controller와 Pod는 Service와 Pod처럼 Label과 Selector로 연결 됨. (아래 그림에서는 Replication이 Controller)
  • 그리고 template에 Pod를 정의하게 되는데, Controller는 Pod가 죽으면 template에 정의된 내용을 사용하여 Pod를 재생성 함.
  • 이를 이용하여 template을 업데이트하고, 기존 Pod를 제거하므로서 Version Update를 수동으로 할 수 있음.

image

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Pod
metadata:
  name: pod1
  labels:
    type: web
spec:
  containers:
  - name: container
    image: kubetm/app:v1
  terminationGracePeriodSeconds: 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Controller의 selector에 연결할 label을 넣고
# 아래 template에 정의된 Pod에도 label을 정의해야 Controller에 정상 연결 됨.
apiVersion: apps/v1
kind: ReplicationController
metadata:
  name: replica1
spec:
  replicas: 1
  selector:
    matchLabels:
      type: web
  template:
    metadata:
      name: pod1
      labels:
        type: web
    spec:
      containers:
      - name: container
        image: kubetm/app:v1
      terminationGracePeriodSeconds: 0

Replicas

  • replicas를 조절하여 Pod의 개수를 조절할 수 있음. (replicas를 증가시키면 scail out, 감소 시키면 scale in이라고 한다.)
  • Replication과 Template을 같이 만들어서 사용할 수 있음.

image

Selector

  • 위 2개의 기능과 달리, Selector는 Replicaset에만 있음.
  • Replication의 selector는 key와 value가 같은 Pod에 연결 됨.
  • 반면 ReplicaSet의 selector는 2가지 추가적인 속성이 있음. (matchLabels, matchExpressions)
  • matchLabels은 기존과 동일하게 key와 value가 모두 같은 경우 연결 됨.
  • matchExpressions은 key와 value는 좀 더 다양한 방법으로 컨트롤 할 수 있음.

image

Exists / DoesNotExist / In / NotIn

  • Exists: value에 상관 없이 key가 있으면 선택
  • DoesNotExist: value와 상관 없이 key가 없으면 선택
  • In: values라는 속성을 사용하여, 다수의 values에 있는 값들이 하나라도 있으면 선택.
  • NotIn: values라는 속성을 사용하여, 다수의 values에 있는 값들이 모두 없으면 선택.

image

실습

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Pod
metadata:
  name: pod1
  labels:
    type: web
spec:
  containers:
  - name: container
    image: kubetm/app:v1
  terminationGracePeriodSeconds: 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replica1
spec:
  replicas: 1
  selector:
    matchLabels:
      type: web
  template:
    metadata:
      name: pod1
      labels:
        type: web
    spec:
      containers:
      - name: container
        image: kubetm/app:v1
      terminationGracePeriodSeconds: 0

1) relicase 값 1->2로 변경 후 pod 개수 확인

image

2) 수동으로 Pod 업데이트 해보기

image

3) Controller 삭제 후, 연결 된 파드 모두 삭제되는 것 확인

  • 삭제 되는 것 확인할 수 없었습니다.아무래도 쿠버네티스 가비지 컬렉션이 동작하는데에 시간이 오래 걸려서 그런 것 같습니다. (–cascade=background 옵션 줘도 여전히 삭제 안됨.)

image

4) Selector - matchLabels

  • Selector에서는 template을 정의해서 사용하기 때문에 matchExpressions를 많이 사용하지 않으므로 굳이 실습 진행하지 않음 (Node 스케줄링에서 많이 다뤄볼 예정)
  • replicaset에서 selector 사용 시 주의할 점이 있는데, 아래 예시에서 template의 labels에 selector의 label이 포함되지 않을 경우 selector에서 에러를 반환 함.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replica1
spec:
  replicas: 1
  selector:
    matchLabels:
      type: web
      ver: v3
  template:
    metadata:
      labels:
        type: web
        ver: v1
        ver: v2
        location: dev
    spec:
      containers:
      - name: container
        image: kubetm/app:v1
      terminationGracePeriodSeconds: 0

image

Deployment

1) ReCreate

  • Deployment가 기존의 Pod를 중지시키고, 새로운 버전의 Pod를 생성합니다.
  • Downtime이 발생하므로, 일시적인 정지가 가능한 Service에 대해 사용 가능.

2) Rolling Update

  • Deployment가 기존의 Pod를 중지시키지 않고, 새로운 버전을 배포 함.
  • 업데이트를 하는 동안 사용자들의 일부는 이전 버전에, 일부는 최신 버전에 접근하게 됨.
  • 배포 중간에 추가적인 자원을 소모하는 대신 Downtime이 없다는 장점이 있음.

3) Blue/Green

  • selector를 사용하여 Service에 연결된 Pod들을 배포 한뒤, Service의 selector만 변경하여 기존의 Pod와의 연결을 끊음으로서 새로운 버전을 배포하는 방법
  • Rolling Updatge와 마찬가지로 추가적인 자원을 소모하는 대신 Downtime이 없음.
  • 만약 새로 배포한 버전에 문제가 생길 경우 Selector를 다시 되돌려서 이전 버전으로 roll back이 쉽게 가능함. (문제가 없을 경우 이전 버전을 제거하면 됨)

4) Canary

  • 카나리라는 새를 이용하여 광산의 일산화탄소량을 확인하던 방법에서 유래한 이름의 배포 방식.
  • 2개의 label을 사용하여 기존의 Pod들이 동작하는 상태에서 새로운 버전의 Pod를 Service에 연결 시킨 후, Service를 통해 일부의 Traffic만 새로 연결한 Pod에 전달 되도록 하면 더 안전하고 적은 자원으로 새로운 버전을 테스트 할 수 있음.

Deployment - Recreate 과정

1) Deployment 정의 시 yaml 파일에 replicaset과 동일한 값들을 정의합니다. 하지만 이 값들은 Deployment가 직접 Pod를 만들어 관리하기 위한 것들이 아니고, Replicaset을 정의하기 위한 용도입니다. Deployment를 통해 Replicaset이 생성 되고, Label을 통해 Service를 연결 시켜서 Pod에 접근할 수 있습니다.

image

2) 이후 업데이트를 진행하게 될 경우, template에 정의된 버전을 변경해주면, Deployment가 이전 Replicaset의 replicas 값을 0으로 변경시킵니다. (Pod가 제거 되고, Service와의 연결도 끊겨서 Downtime이 발생하게 됩니다.) 그리고 새로운 Replicaset이 생성 되는데 여기에는 새로운 버전의 Pod가 생성됩니다.

image

3) 새로운 버전의 Pod에도 동일한 Label이 있기 때문에 Service에 자동으로 연결 됩니다.

image

Deployment - Recreate 실습

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-1
spec:
  selector:
    matchLabels:
      type: app
  replicas: 2
  strategy:
    type: Recreate
  revisionHistoryLimit: 1 # replicas가 0인된 replicaset을 1개만 남기겠다는 의미 (default는 10)
                          # 즉, 2번의 업데이트가 진행될 경우 가장 오래된 버전의 replicaset이 삭제 됨.
  template:
    metadata:
      labels:
        type: app
    spec:
      containers:
      - name: container
        image: kubetm/app:v1
      terminationGracePeriodSeconds: 10
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
  name: svc-1
spec:
  selector:
    type: app
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080

1) 먼저 v1으로 배포 후 오브젝트들의 상태를 확인합니다.

image

2) 1초마다 version을 확인하는 shell 명령어를 입력한 뒤, deploy의 image 버전을 변경한 후 apply 적용하여 재배포를 실행합니다.

image

3) 재배포 완료된 것을 확인할 수 있습니다.

image

4) v2로 롤백해보겠습니다, 먼저 rollback 가능한 history를 확인합니다. (revisionHistoryLimit이 1이므로 2개가 나옵니다.)

image

5) 아래의 명령어를 사용하여 rollback 가능 합니다.

image

Deployment - Rolling Update 과정

1) 기존의 replicaset의 replicas를 유지한채로 새로운 버전의 replicaset을 생성합니다. image

2) 이후, 기존 버전의 replicas를 하나씩 순차적으로 줄이면서 새로운 버전의 replicas를 증가시킵니다. 마찬가지로 기존 replicaset은 삭제되지 않고 남아 있습니다. (roll back 할 수 있게) image

3) 참고로, 새로운 replicaset이 생성 될 때 기존의 Pod와 새로운 Pod의 Label이 구분이 안되지 않을까? 하는 의문을 가질 수 있는데 쿠버네티스에서 자체적으로 추가적인 Label을 생성하여 구분할 수 있게 하고 있습니다. (이것은 실습에서 알아봅시다.)

Deployment - Rolling Update 실습

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-2
spec:
  selector:
    matchLabels:
      type: app2
  replicas: 2
  strategy:
    type: RollingUpdate
  minReadySeconds: 10 # 배포 간격을 10초로 둠으로서 실습간에 눈으로 보기 용이. 
  template:
    metadata:
      labels:
        type: app2
    spec:
      containers:
      - name: container
        image: kubetm/app:v1
      terminationGracePeriodSeconds: 0
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
  name: svc-2
spec:
  selector:
    type: app2
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080

1) Rolling Update 방식으로 Deployment 배포 후 확인합니다. (v1으로 배포된 것을 확인할 수 있습니다.)

image

2) 1초마다 version 확인하는 shell 명령어 입력 후, v1으로 yaml파일 변경 후 apply 입력하여 배포해줍니다. 이 때 v1과 v2가 섞여서 동작하는 것을 볼 수 있고 시간이 지난 후 v1이 완전히 삭제되어 v2로 동작하는 것을 확인할 수 있습니다.

image

3) v2로 재배포 된 것을 확인할 수 있습니다.

image

Deployment - Blue/Green 실습

1) 먼저 Replicaset과 Service를 사용하여 배포 및 Pod를 연결 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replica1
spec:
  replicas: 2
  selector:
    matchLabels:
      ver: v1
  template:
    metadata:
      name: pod1
      labels:
        ver: v1
    spec:
      containers:
      - name: container
        image: kubetm/app:v1
      terminationGracePeriodSeconds: 0
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
  name: svc-3
spec:
  selector:
    ver: v1
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080

3) 아래와 같이 label과 selector를 v2로 변경 후 replicaset을 배포 합니다. 이때 기존의 Service에는 Label이 v1이므로 새로 만든 Pod들이 연결되어 있지 않은 상태이고 새로운 replicaset은 이미 생성된 상태 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replica1
spec:
  replicas: 2
  selector:
    matchLabels:
      ver: v2
  template:
    metadata:
      name: pod1
      labels:
        ver: v2
    spec:
      containers:
      - name: container
        image: kubetm/app:v2
      terminationGracePeriodSeconds: 0

4) 이후 Service의 Selector를 v2로 변경하면, downtime없이 곧바로 동작하는 것을 확인할 수 있습니다.

Deployment - DaemonSet

  • 각각의 Node들이 존재하고 각각의 Node에 자원이 다르게 남아있는 상황에서, 이전에 배운 Replicaset의 경우 자원에 따라 Pod를 배치할 것 입니다. 반면 Daemonset은 Node의 자원 상태와 상관 없이 모든 Node에 Pod가 하나씩 생긴다는 특징이 있습니다.
  • 성능 수집을 위한 Monitoring하기 위한 용도(프로메테우스), 로깅 용도(Fluentd, LogStash), Storage 용도(GlusterFS를 활용한 NFS)
  • 참고로 쿠버네티스 자체적으로도 네트워크 관리를 하기 위해 각각의 node에 proxy 역할을 하는 Pod를 생성함.

image

Deployment - Job

  • 일반적인 방법으로 만들어진 Pod, Replicaset을 통해 만들어진 Pod 그리고 Job을 통해 만들어진 Pod가 있다고 할 때 이 3개의 Pod가 동작중인 Node가 Down 될 경우 일반적인 방법으로 만들어진 Pod는 Node와 함께 Down되어 복구될 수 없습니다. 하지만 Controller(Replicaset, Job)에 의해 만들어진 Pod들은 Controller에 의해 장애가 발생하게 되면 다른 Node에 재생성(Recreate)되기 때문에 서비스가 유지될 수 있습니다. 또한 Replicaset으로 생성된 Pod의 경우 일을 하지 않을 경우 재시작(Restart)시키기 때문에 어떤일이 있어도 서비스가 유지되어야하는 목적으로 사용할 수 있습니다.
  • 반면 Job의 경우 Pod가 제대로 동작하지 않는 경우 Pod를 종료(Finish)시킵니다. (이 때 종료라는 의미는 Pod를 삭제하는 것은 아니고 자원을 사용하지 않는 상태로 만듭니다.)
  • 참고로 재생성은 Pod를 재생성하기 때문에 IP와 자원같은 것들이 재할당 되고, 재시작 같은 경우는 Pod의 IP와 자원 등은 그대로 있고 재시작만 합니다.)
  • Job에 의해 료된 Pod에 사용자는 접속할 수 있고, 만약 정말 사용하지 않는다고 판단할 경우 직접 삭제해줄 수 있습니다.

Deployment - CronJob

  • 위에서 설명한 Job들을 주기적인 시간에 따라 생성하는 것을 의미합니다.
  • 용도로는 DB Backup, 주기적으로 무언가를 확인하는 작업(ex Update), 예약 메세지를 보내는 작업 등에 사용 됩니다.

DaemonSet 실습

Daemonset은 아래와 같이 selector와 template이 있어서 모든 Node에 template으로 pod를 만들고, selector와 label로 daemonset과 연결이 됩니다.

image

그런데 만약 Node들의 OS 정보가 달라서 아래처럼 Label이 정의되어 있다고 할 때, 만약 특정 서비스를 ubuntu에서는 실행할 수 없어서 Node3에는 설치를 하고 싶지 않다면 nodeSelector를 지정하여 nodeSelector가 없는 Node에는 설치하지 않도록 설정할 수 있습니다. 이처럼 Daemonset은 Pod를 Node에 2개이상 만들 순 없지만 특정 Node에 Pod를 만들지 않게 설정할 수 있습니다.

image

1) DaemonSet - HostPort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-1
spec:
  selector:
    matchLabels:
      type: app
  template:
    metadata:
      labels:
        type: app
    spec:
      containers:
      - name: container
        image: kubetm/app
        ports:
        - containerPort: 8080
          hostPort: 18080

데몬셋 실행 시, 클러스터의 모든 Node에 pod가 생성된 것을 확인할 수 있습니다.

image

Node의 Internal-IP:hostPort를 사용하여 hostname을 받아오는 것도 확인할 수 있습니다.

image

2) DaemonSet - 재배포

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-1
spec:
  selector:
    matchLabels:
      type: app
  template:
    metadata:
      labels:
        type: app
    spec:
      containers:
      - name: container
        image: kubetm/app:v1
        ports:
        - containerPort: 8080
1
2
3
4
5
...
...
        image: kubetm/app:v2
        ports:
        - containerPort: 8080

재배포 수행할 경우, 기존의 Pod가 삭제되고 재생성 되는 것을 확인할 수 있습니다.

image

image

image


3) DaemonSet - NodeSelector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-2
spec:
  selector:
    matchLabels:
      type: app
  template:
    metadata:
      labels:
        type: app
    spec:
      nodeSelector:
        nodetype: worker
      containers:
      - name: container
        image: kubetm/app
        ports:
        - containerPort: 8080

이번에는 nodeSelector 기능을 실습해보겠습니다. 먼저 node들에 label을 설정합니다.

1
2
3
4
5
6
kubectl label nodes master nodetype=master
kubectl label nodes worker-1 nodetype=worker
kubectl label nodes worker-2 nodetype=worker

kubectl get nodes --show-labels
kubectl get nodes -l nodetype=worker --show-labels

그리고 daemonset을 실행하면 worker-1 / worker-2 node에만 생성되는 것을 확인할 수 있습니다.

image

Job 실습

Job도 Daemonset과 마찬가지로 template과 selector가 존재합니다. Daemonset과 다른 점이 Job의 template에는 특정 일만하고 종료되는 Pod들을 담게 됩니다. (Selector는 Job이 알아서 만들어줍니다.)

image

그래서 이 template을 이용하여 일반적으로 하나의 Pod를 생성하고 Pod가 일을 다하고 나면 Job도 종료됩니다. 예외적으로 completions라는 옵션을 주어서 여러개의 Pod를 순차적으로 실행시켜서 모든 작업이 완료되어야만 Job도 종료되게 할 수 있습니다.

image

그리고 parallelism이라고 해서 Pod 생성을 동시에 여러개씩 할 수 있습니다. 또 activeDeadlineSeconds라고 해서 특정 시간을 주어 해당 시간이 지난 후에는 Job의 기능을 정지시킬 수 있습니다. 만약 해당 시간이 지나게 되면 실행 중인 Pod들은 모두 종료되고 아직 실행되지 않은 Pod들은 실행되지 않은채로 끝나게 됩니다. (사용자의 예측 범위를 벗어나도록 종료되지 않은 Pod들을 비정상동작으로 판단하고 종료하는 기능을 제공하기 위함.)

image

1) Job-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 20초간 수행되는 Job
apiVersion: batch/v1
kind: Job
metadata:
  name: job-1
spec:
  template:
    spec:
      restartPolicy: Never # Job을 만들 때 반드시 설정해줘야함.
                           # OnFailure 혹은 Never가 있음.
      containers:
      - name: container
        image: kubetm/init
        command: ["sh", "-c", "echo 'job start';sleep 20; echo 'job end'"]
      terminationGracePeriodSeconds: 0

Job이 완료된 후, Pod는 삭제되지 않고 남아있습니다. (이후, Job을 삭제하면 Pod도 같이 삭제 됩니다.)

image

2) Job-2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: batch/v1
kind: Job
metadata:
  name: job-2
spec:
  completions: 6
  parallelism: 2
  activeDeadlineSeconds: 30
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: container
        image: kubetm/init
        command: ["sh", "-c", "echo 'job start';sleep 20; echo 'job end'"]
      terminationGracePeriodSeconds: 0

위의 Job을 실행하면 총 6개의 Job을 준비했지만 첫번째 2개의 Pod 생성 후 30초가 지났을 때 아직 모든 Job에 지정된 deadline 시간을 초과하기 때문에 실행중이던 2번째 Pod쌍은 중지되고 3번째 Pod쌍은 실행되지 않은채로 Job이 종료됩니다.

image

3) Job-3

Job이 수행되고 난후, Pod가 Completed인 상태로 남아 있어서 이것이 정상인지 궁금하여 관련 내용을 조사 해보았습니다.

  • Job이 실행되고 난 후, Pod가 Completed 상태인 경우 해당 Pod를 삭제하거나 필요에 따라 유지할지 결정할 수 있음.
  • 만약 Pod를 유지할 경우 리소스를 차지하게 되므로 적절한 관리가 필요함. 일반적으로 더 이상 필요하지 않은 Completed 상태의 Pod는 정리하는 것이 좋음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: batch/v1
kind: Job
metadata:
  name: job-1
spec:
  ttlSecondsAfterFinished: 5 # Job 완료 후 5초 후에 삭제.
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: container
        image: kubetm/init
        command: ["sh", "-c", "echo 'job start';sleep 20; echo 'job end'"]
      terminationGracePeriodSeconds: 0

spec에 ttlSecondsAfterFinished를 정의하여 Job이 완료된 후 Pod를 자동으로 정리시킬 수 있습니다.

image

CronJob 실습

CronJob은 JobTemplate을 정의하여 Job을 생성하고 schedule을 정의하여 이 시간을 주기로 Job을 생성합니다. 아래와 같이 schedule을 정의할 경우 1분에 하나씩 Job을 생성한다는 의미입니다.

image

위와 같이 정의된 CronJob을 실행시키면 아래와 같이 1분 간격으로 Job이 생성되고, Job은 Pod를 생성하게 됩니다.

image

그리고, CronJob에는 concurrencyPolicy라는 기능이 있습니다. Allow / Forbid / Replace라는 3가지 기능을 제공합니다. (Default: Allow)

  • Allow: schedule 주기가 돌아왔을 때, 앞의 주기에 만들었던 Pod의 상태에 상관 없이 본래 계획된 대로 새로운 Job을 실행하여 Pod를 생성합니다.
  • Forbid: schedule 주기가 돌아왔을 때, 앞의 주기에 만들었던 Pod가 종료되지 않은 상태라면 Job 실행을 Skip하고 Pod가 종료되는 즉시 다음 Job이 실행 됩니다.
  • Replace: schedule 주기가 돌아왔을 때, 앞의 주기에 만들었던 Pod가 종료되지 않은 상태라면 이전 Job을 삭제하고 (기존 Pod도 함께 삭제), 새 Job이 실행 됩니다. (1.19버전 이후)

1) Allow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cron-job
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: container
            image: kubetm/init
            command: ["sh", "-c", "echo 'job start';sleep 20; echo 'job end'"]
          terminationGracePeriodSeconds: 0

CronJob을 생성한 후에 수동으로 job을 생성할 수 도 있습니다.

1
kubectl create job --from=cronjob/cron-job cron-job-manual-001

아래와 같이 1분 마다 job이 생성 되며, 수동으로 생성한 job도 확인할 수 있습니다.

image

그리고 아래와 같이 suspend 값을 true로 변경하여 cronjob이 job을 주기적으로 생성하는 것을 중단시킬 수 있습니다.

1
kubectl patch cronjobs cron-job -p '{"spec" : {"suspend" : true }}'

cronjob을 삭제하면 쿠버네티스 1.19버전 이후로는 수동으로 생성한 job도 삭제 됩니다. (이전 버전에서는 수동으로 생성한 job은 삭제되지 않음.)

image

2) Forbid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cron-job-1
spec:
  schedule: "*/1 * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: container
            image: kubetm/init
            command: ["sh", "-c", "echo 'job start';sleep 140; echo 'job end'"]
          terminationGracePeriodSeconds: 0

1분마다 Job을 생성하는 동일한 CronJob 입니다. 다른점은 concurrencyPolicy 옵션이 Forbid 입니다. sepc에 그런데 140초 동안 Job이 실행되므로 첫번째 Job 실행 후 두번째 Job의 실행은 Skip되고 3번째 Job이 생성되는 것을 확인할 수 있습니다. (Age를 보면 2번째 Job은 Skip 된 것을 알 수 있음)

image

2) Replace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cron-job-3
spec:
  schedule: "*/1 * * * *"
  concurrencyPolicy: Replace
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: container
            image: kubetm/init
            command: ["sh", "-c", "echo 'job start';sleep 140; echo 'job end'"]
          terminationGracePeriodSeconds: 0

이번에는 concurrencyPolicy 옵션이 Replace 입니다. 이전 Job이 삭제되고 새로 실행되는 것을 확인할 수 있습니다.

image

Updated:

Leave a comment