쿠버네티스 - 파드, 리플리카셋, 디플로이먼트, 스케일러빌리티!

파드 (Pod)

Pod : 고래의 떼(pod of whales)

파드는 쿠버네티스 애플리케이션의 기본 실행 단위, 쿠버네티스 객체 모델 중 만들고 배포할 수 있는 가장 작고 간단한 단위.

특성

  • 파드에는 하나 이상의 컨테이너가 들어있다.
  • 파드안의 컨테이너는 반드시 동일한 노드에 배치된다.
  • 어플리케이션 스케일 아웃은 파드단위로 이루어진다.
  • 파드안의 컨테이너는 네트워크와 스토리지를 공유한다.
  • 각 파드에는 고유한 IP 주소가 할당되며 파드 내부의 컨테이너는 해당 IP 를 공유한다.
  • 파드는 컨테이너뿐 아니라 스토리지도 가지고 있으며 공유 볼륨을 통행 컨테이너끼리 스토리지를 통해 데이터를 주고받을 수 있다.

kube2

생명주기

  1. Pending - 파드 생성중(이미지 다운, 컨테이너 생성중)
  2. Running - 파드안 모든 컨테이너가 실행중, 시자, 재시작 중
  3. Succeeded - 파드안 모든 컨테이너가 정상 종료 완료
  4. Failed - 파드안 컨테이너중 비정상 종료
  5. Unknown - 파드의 상태 확인 불가, 노드 통신 불가시 발생

생명주기는 kubelet 이 컨테이너를 주기적으로 진단한다.

매니페스트

아래 명령으로 파드 매니페스트 속성 종류 및 설명 검생 가능

$ kubectl explain pods
$ kubectl explain pods.metadata
$ kubectl explain pods --recursive

pods.spec

필드 타입 설명
pods.spec.containers Container[] 파드에 속하는 컨테이너 목록
pods.spec.imagePullSecrets LocalObjectReference[] 컨테이너 이미지 취득을 위한 인증정보
pods.spec.initContainers Container[] 초기화 처리를 하는 컨테이너
pods.spec.nodeName String 해당 라벨의 노드에 파드를 배치(스케줄링)
pods.spec.nodeSelector Object 해당 라벨의 노드에 파드를 배치(스케줄링)
pods.spec.priority Integer 파드의 우선순위 지정, 클수록 높음
pods.spec.restartPolicy String 재시작 정책(Always, OnFailure, Never), 기본값은 Always
pods.spec.volumes Volume[] 파드의 마운트할 볼륨 지정

pods.spec.containers

파드 매니페스트 속성의 containers 에 들어가는 객체 배열 Container 에 어떤 속성이 있는지 알아보자.

필드 타입 설명
pods.spec.containers.args String[] 컨테이너에 송신할 인수
pods.spec.containers.env EnvVar[] 컨테이너에 설정한 환경변수
pods.spec.containers.image String 컨테이너 이미지와 해당 경로
pods.spec.containers.imagePullPolicy String 컨테이너 이미지 취득시 규칙(Always, ifNotPresent, Never). 기본값은 pods.spec.containers.ifNotPresent 기존 이미지가 있으면 새로 취득하지 않는다. Always 설정시 항상 이미지 갱신
pods.spec.containers.name String 컨테이너 이름, 컨테이너 내부간에 통신할때 사용(DNS_LABEL)
pods.spec.containers.ports ContainerPort 배열 컨테이너 공개파드
pods.spec.containers.resources ResourceRequirements 컨테이너에 CPU, Memory 같은 리소스 할당
pods.spec.containers.volumeMounts VolumeMount 배열 컨테이너 마운트 볼륨 지정
pods.spec.containers.workingDir String 작업 디렉토리
pods.spec.containers.livenessProbe Probe 컨테이너 감시
pods.spec.containers.readlinessProbe Probe 컨테이너 감시

pods.spec.initContainers

초기화 컨테이너

앱 컨테이너가 실행되기 전 파드를 초기화,

apiVersion: v1
kind: Pod
metadata:
  name: kubernetes-simple-pod
  labels:
    app: kubernetes-simple-pod
spec:
  initContainers:
  - name: init-myservice
    image: arisu1000/simple-container-app:latest
    command: ['sh', '-c', 'sleep 2; echo helloworld01;']
  - name: init-mydb
    image: arisu1000/simple-container-app:latest
    command: ['sh', '-c', 'sleep 2; echo helloworld02;']
  containers:
  - name: kubernetes-simple-pod
    image: arisu1000/simple-container-app:latest
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']

pods.spec.containers.livenessProbe

파드가 제대로 동작하는지, 파드 내부의 서비스가 제대로 동작하는지 감시 하기 위해
메니페스트에서 livenessProbe 속성을 추가한다.

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http

spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/liveness
    args:
    - /server
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: X-Custom-Header
          value: Awesome
      initialDelaySeconds: 10
      periodSeconds: 5

livenessProbe 를 통해 컨테이너에 /healthz URI 에 5초주기(periodSeconds)로 요청을 날리고 200 ~ 400 사이의 값이 반환될 경우 정상으로 간주한다.
그 이외의 값이 반환될 경우 kublet 에 의해 컨테이너가 재시작 된다.

서비스가 실행될 때 까지의 텀(initialDelaySeconds)을 10초로 설정한다.

k8s.gcr.io/liveness 이미지에는 10초동안만 status code 200 을 반환하고 그 이후로는 status code 500을 반환하도록 설정되어있다.

10초 후 아래 명령어를 실행하면

$ kubectl get pods --output wide
$ kubectl describe pod liveness-http

CrashLoopBackOff 상태값과 로그에 Liveness probe failed: HTTP probe failed with statuscode: 500 가 찍혀있는걸 확인 가능하다.

http 를 통한 파드 상태확인 외에도 tcp소켓, 명령 실행 등을 통해서도 상태확인이 가능하다. https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/#컨테이너-프로브-probe

pods.spec.containers.readinessProbe

컨테이너가 실행된 후 실제 서비스 요청에 응답할 수 있을지 설정.

자바 어플리케이션 처럼 실행하는데 시간이 걸릴 경우 유용함.

파드 CRUD

먼저 간단한 이미지를 빌드하고 private registry 에 등록

$ docker build -t photo-view:v2.0 .
$ docker image tag photo-view:v2.0 mydomain:5000/photo-view:v2.0

$ docker images
REPOSITORY                        TAG                 IMAGE ID            CREATED              SIZE
mydomain:5000/photo-view   v2.0                05e6c8ef4559        About a minute ago   924MB
photo-view                        v2.0                05e6c8ef4559        About a minute ago   924MB

$ docker image push mydomain:5000/photo-view:v2.0

https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/

해당 private registrykubectl 로 사용할 수 있도록 secret 쿠버네티스 리소스 생성

docker login 을 통해 $HOME/.docker/config.json 파일에 인증데이터를 업데이트 후 해당 파일로 secret 리소스를 생성하자.

$ kubectl create secret generic regcred \
--from-file=.dockerconfigjson=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfigjson

맥의 경우 key 정보가 config.json 에 저장되는 것이 아닌 별도의 키체인에 저장되어 있어 위의 명령을 사용해봤자 auth faild 오류가 발생할것이다.
맥의 경우 바로 kubectlsecret 생성하는 아래의 명령 사용

$ kubectl create secret docker-registry regcred \
--docker-server=mydomain:5000 \
--docker-username=admin \
--docker-password=admin

--namespace='' 옵션을 생략했기에 기본적으로 default 에 적용된다.

해당 이미지로 파드 create

# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: photoview-pod
  labels:
    app: photo-view
    env: stage
spec:
  containers:
  - image: mydomain:5000/photo-view:v2.0
    name: photoview-container
    ports:
    - containerPort: 80
  imagePullSecrets:
    - name: regcred # 생성한 secret name 설정 
$ kubectl apply -f Pod/pod.yaml
pod/photoview-pod created

$ kubectl get pods --show-labels
NAME            READY   STATUS    RESTARTS   AGE     LABELS
photoview-pod   1/1     Running   0          2m13s   app=photo-view,env=stage

$ kubectl describe pods photoview-pod
// 상세정보 확인 가능

항상 imagePullSecrets를 매니페스트 파일에 적용해야만 다운이 가능한데 이를 service account 에 포함하여 생략할 수 있다.

$ kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "regcred"}]}'

새로운 이미지 photo-view:v1.0 을 빌드, 태그, private-registrypush

$ docker build -t photo-view:v1.0 .
$ docker image tag photo-view:v1.0 mydomain:5000/photo-view:v1.0
$ docker image push mydomain:5000/photo-view:v1.0

위에 생성한 photoview-pod의 이미지를 photo-view:v1.0 로 변경해보자.

매니페스트 파일의 image 속성을 변경

# pod.yaml
apiVersion: v1
kind: Pod
...
spec:
  containers:
  - image: mydomain:5000/photo-view:v1.0
  ...
...
$ kubectl apply -f Pod/pod.yaml
pod/photoview-pod configured

apply 명령으로 생성/수정이 가능하다.

파드 삭제

$ kubectl delete -f Pod/pod.yaml

파드 스케줄링 구조

스케줄링은 쿠버네티스 마스터 서버 API Server 에서 관리한다.
파드가 마스터 서버에 의해 어떤 노드에 전개(스케줄링)될지 알아보자.

API Server는 클러스터 안의 쿠버네티스 리소스를 관리(CRUD), etcd 에 접근지원 하기 위해 Restfule 인터페이스를 지원한다.

파드가 생성되는 루틴은 대략적으로 아래와 같다.

  1. kubectl 명령 실행 - API ServerRestAPI 요청.
  2. 클러스터 구성 정보 갱신 - kubectl 로 인해 변경된 매니페스트 내용을 etcd 에 저장.
  3. 클러스터 구성 변경 - 젼달받은 매니페스트와 etcd의 데이터간 변화가 있다면 API Server에게 통지.
  4. 파드의 작성 - API Server가 통지받은 내용이 있다면 워커노드에 파드 업데이트 하도록 명령 송신, 노드내의 kubelet 은 전달받은 명령을 수행한다(새로운 파드 생성).

3번과 4번 과정 사이에서 파드를 어떤 노드에 스케줄링할지 결정한다.

스케줄링은 아래 2가지 규칙에 의해 결정된다.

  1. 노드의 필터링
    • 파드에 NodeSelector 를 설정하고 있는지 검사
    • 파드에 설정된 리소스 요구에 매칭되는 노드 필터링
  2. 노드의 우선순위
    • CPU, Memory 사용량에 따라 노드의 우선순위 결정
    • 우선순위별로 파드를 배치

파드 스케줄링 제어

위의 nodeSelector 속성을 정의해 명시적으로 노드를 정해주지 않고도 스케줄링할 수있는 방법이 여럿 있다.

Affinity

https://kubernetes.io/ko/docs/concepts/configuration/assign-pod-node/#어피니티-affinity-와-안티-어피니티-anti-affinity

Affinity 는 친밀감이란 뜻으로 서로다른 2개의 파드를 왠만하면 같은노드에 배치시키고 싶을때(podAffinity)
혹은 다른노드에 배치시키고 싶을때(podAntiAffinity) 사용한다.

또한 특정 조건을 갖춘 노드에서만 동작하도록 하는 nodeAffinity 도 있다.

Taints, Tolerations

https://kubernetes.io/ko/docs/concepts/configuration/taint-and-toleration/

Taints: 오염시키다 Tolerations: 용인,관용

서로 상반되는 역할을 하는 명령

Taints는 노드에 설정하는 것으로 파드를 스케줄링 하거나 조건에 맞는 파드만 스케줄링 하도록 할 수 있다.
Taints가 설정된 노드에 파드를 배치하고 싶다면 Tolerations 설정이 필요하다.

파드 리소스 설정

CPU, Memory 리소스는 매니페스트 파일에서 설정 가능하다.

apiVersion: v1
kind: Pod
metadata:
  name: requests-pod

spec:
  containers:
  - image: busybox
    command: ["dd", "if=/dev/zero", "of=/dev/null"]
    name: main
    resources:
      requests:
        cpu: 50m
        memory: 300Mi # (K M G T P), (Ki Mi Gi Ti Pi) 사용 가능

Minikube 에서 생성된 nodeCPU Limits100m, Memory Limits390Mi남아있다. 위의 매니페스트 설정대로 파드를 생성하고 줄어드는 Limits 를 확인

requests 속성을 파드의 최소 리소스 요청 단위를 뜻한다.

$ kubectl create -f Pod/pod-request.yaml
pod/requests-pod created 

$ kubectl get pods --output wide
NAME           READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
requests-pod   1/1     Running   0          39s   172.18.0.2   minikube-m03   <none>           <none>

$ kubectl describe node minikube-m03 명령으로 남은 리소스를 확인해보면 정확인 CPU 50m, Memory 300Mi 만큼 Limits 가 줄어있다.

쿠버네티스에서 파드를 스케줄링할때 실제 노드의 리소스사용량이 아닌 메니페스트에 설정된 리소스 설정으로 스케줄링 됨을 알 수 있다.
파드에 많은 리소스를 할당하게 되면 그만큼 다른 파드를 노드에 설정할 수 없다.

만약 파드에 설정한 resources 사용량을 넘게되면 쿠버네티스에서 어떻게 처리하는지 알아보자.

apiVersion: v1
kind: Pod
metadata:
  name: limits-pod
spec:
  containers:
  - name: main
    image: polinux/stress
    resources:
      limits:
        cpu: 90m
        memory: 300Mi
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "500M", "--vm-hang", "1"]

stress 프로그램으로 Memory300M를 넘는 500M 를 설정하여 실행

limits 속성은 파드 요청 제한 단위를 뜻한다.

$ kubectl get pods --output wide
NAME         READY   STATUS              RESTARTS   AGE   IP       NODE           NOMINATED NODE   READINESS GATES
limits-pod   0/1     ContainerCreating   0          6s    <none>   minikube-m03   <none>           <none>

$ kubectl get pods --output wide
NAME         READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
limits-pod   1/1     Running   0          9s    172.18.0.2   minikube-m03   <none>           <none>

$ kubectl get pods --output wide
NAME         READY   STATUS      RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
limits-pod   0/1     OOMKilled   0          9s    172.18.0.2   minikube-m03   <none>           <none>

$ kubectl get pods --output wide
NAME         READY   STATUS             RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
limits-pod   0/1     CrashLoopBackOff   2          43s   172.18.0.2   minikube-m03   <none>           <none>
$ kubectl describe pod limits-pod
# 상세 로그 확인.  

쿠버네티스에선 복구기능을 갖고 있기에 오류가 감지되면 기본적으로 재시작한다.
restartPolicy속성 에 따라 옵션이 다르며 기본값은 Always 이다.

$ kubectl get pods --output wide
NAME         READY   STATUS             RESTARTS   AGE     IP           NODE           NOMINATED NODE   READINESS GATES
limits-pod   0/1     CrashLoopBackOff   6          7m15s   172.18.0.2   minikube-m03   <none>           <none>

시간이 지남에 따라 RESTARTS 횟수가 계속 늘어나고 있다.

리플리카셋 (ReplicaSet)

파드가 자동으로 상태검사, 정상화(재시작) 하며 상태를 복구하는 것이라면 리플리카셋은 파드의 수를 유지, 자동으로 새로운 파드를 시작한다.

매니페스트

매니페스트 기본 구성은 파드와 같다.
spec 부분만 다른부분이 있는데 알아보자.

필드 타입 설명
replicaset.spec.replicas Integer 클러스터 안에서 가동시킬 파드의 수 (기본값 1)
replicaset.spec.selector LabelSelector 어떤 파드를 가동할지 정의, 파드의 template.metadata.label 에 설정된 값과 일치해야함
replicaset.spec.template PodTemplateSpec 실제 클러스터 내부 파드 수가 replicas 에 설정된 수보다 적을때 새로작성되는 파드의 템플릿
replicaset.spec.template.metadata Object 템플릿의 이름, Label과 같은 메타데이터
replicaset.spec.template.spec PodSpec 파드의 상세정보를 설정

즉 리플리카셋을 사용하려면 리플리카셋의 spec 과 파드의 spec 을 모두 정의해야한다.

리플리카셋 CRUD

# ReplicaSet/replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: photoview-rs
spec:
  replicas: 5
  selector:
    matchLabels:
      app: photoview
  template:
    metadata:
      labels:
        app: photoview
        env: prod
    spec:
      containers:
      - image: mydomain:5000/photo-view:v1.0
        name: photoview-container
        ports:
          - containerPort: 80
$ kubectl create -f ReplicaSet/replicaset.yaml
$ kubectl get pods --show-labels
NAME                 READY   STATUS    RESTARTS   AGE     LABELS
photoview-rs-466w6   1/1     Running   0          3h35m   app=photoview,env=prod
photoview-rs-fwv2f   1/1     Running   0          3h35m   app=photoview,env=prod
photoview-rs-j46rr   1/1     Running   0          3h40m   app=photoview,env=prod
photoview-rs-n64z2   1/1     Running   0          3h35m   app=photoview,env=prod
photoview-rs-zk4bz   1/1     Running   0          3h35m   app=photoview,env=prod

# 파일을 수정 후 apply 하면 기존 리플리카셋의 설정이 자동 수정/적용 된다.  
$ kubectl apply -f ReplicaSet/replicaset.yaml
$ kubectl delete -f ReplicaSet/replicaset.yaml

리플리카셋은 철저히 spec.template.metadata.labels.app 을 통해서 관리된다.

먼저 라벨명이 photo-view파드 를 하나 생성

$ kubectl apply -f ReplicaSet/pod-nginx.yaml
pod/nginx-pod created

$ kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
nginx-pod   1/1     Running   0          27s

그리고 리플리카셋으로 photo-view 라벨을 가진 파드 5개를 생성하도록한다.

$ kubectl apply -f ReplicaSet/replicaset-nginx.yaml
replicaset.apps/nginx-replicaset created

$ kubectl get pod
NAME                     READY   STATUS              RESTARTS   AGE
nginx-pod                1/1     Running             0          79s
nginx-replicaset-cg8l7   0/1     ContainerCreating   0          2s
nginx-replicaset-hgkkd   0/1     ContainerCreating   0          2s
nginx-replicaset-kg5ks   0/1     ContainerCreating   0          2s
nginx-replicaset-p2w5f   0/1     ContainerCreating   0          2s

기존에 파드 매니페스트로 생성했던 nginx-pod 파드와 함께 4개의 추가 파드가 생성된다.

디플로이먼트 (Deployment)

Deployment: 전개, 배치
https://kubernetes.io/ko/docs/concepts/workloads/controllers/deployment/

쿠버네티스에선 어플리케이션의 유연한 CI/CD(지속적인 통합/배포) 를 위해 Deployment 를 제공한다.

DeploymentReplicaSet의 상위개념이다.
똑같이 여러개의 파드를 생성하고 관리면서 업데이트 관련 기능을 추가 제공한다.

Recreate
오래된 파드를 정지시키고 새로운 파드를 다시 작성하는 방식. 가장 심플하고 빠르지만 서버가 모두 내려가 버리기에 다운타임이 발생한다.

Rolling update
애플리케이션 버전업이 모두 한꺼번에 업데이트 되는것이 아닌
순서대로 조금씩 업데이트하는 방법
똑같은 애플리케이션이 여러 개 병렬로 움직이는 경우 가능하다.

blue/green Deployment
버전이 다른 두 애플리케이션을 동시에 가동하고 네트워크 설정을 사용해 별도의 공간에서 동작시킨다.
업데이트 버전의 애플리케이션 테스트 완료 후 서비스는 전환시켜 업데이트 완료.
블루(구버전), 그린(신버전) 을 전환하는 뜻에서 유래됨.
그린의 애플리케이션에서 장애 발생시 블루로 바로 복구 가능한 장점이 있다.

Roll out, Roll back
롤아웃(roll-out) 간단히 번역하면 신제품 또는 정책출시 또는 릴리즈라 할 수 있다.
Deployment는 컨테이너 이미지 버전업 등 업데이트가 있을 때 사로운 사양의 리플리카셋(매니페스트) 를 작성하고
그에 해당하는 새로운 파드로 이를 대체해 롤아웃을 수행한다.

매니페스트

# 기본항목
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
# 디플로이먼트 스팩
spec:
  replicas: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 50%
      maxSurge: 50%
  selector:
    matchLabels:
      app: nginx-pod # 템플릿 검색조건
  # 파드 템플릿
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.14 # 컨테이너 이미지
          ports:
            - containerPort: 80

Deployment의 매니페스트 또한 spec 속성이 좀 다를뿐 나머지는 비슷하다.

필드 설명
replicas 클러스터 안에서 가동시킬 파드의 수
selector 어떤 파드를 가동시킬지에 대한 셀렉터, 파드에 적용된 라벨을 사용한다.
template 클러스터 내부 파드 수가 리플리카수보다 작을때 새로 작성할 파드의 템플릿
strategy 업데이트 방식 결정 가능, RollingUpdate, Recreate 가 있으며 기본값은 RollingUpdate
maxUnavailable 롤링 업데이트중 항상 사용가능한 파드의 총수, 위의 경우 신버전, 구버전 합쳐서 리플리카수의 50%의 파드가 항상 동작중이어야 한다. 기본값은 25%
maxSurge 파드를 작성할 수 있는 최대 개수, 100%로 설정시 신버전의 파드수가 리플리카수만큼 실행되어 한번에 20개의 파드가 동작하게 된다. 기본값은 25%. 리소스 상황에 따라 특이사항이 발생할 수 있음으로 maxSurge 는 작성하는 것을 권장한다.
readinessProbe 실행한 파드가 정상인지 확인하는 속성 파드의 livenessProbe 와 비슷하다.
  • livenessProbe: 컨테이너가 동작 중인지 여부를 나타낸다. 만약 활성 프로브(liveness probe)에 실패한다면, kubelet은 컨테이너를 죽이고, 해당 컨테이너는 재시작 정책의 대상이 된다. 만약 컨테이너가 활성 프로브를 제공하지 않는 경우, 기본 상태는 Success이다.

  • readinessProbe: 컨테이너가 요청을 처리할 준비가 되었는지 여부를 나타낸다. 만약 준비성 프로브(readiness probe)가 실패한다면, 엔드포인트 컨트롤러는 파드에 연관된 모든 서비스들의 엔드포인트에서 파드의 IP주소를 제거한다. 준비성 프로브의 초기 지연 이전의 기본 상태는 Failure이다. 만약 컨테이너가 준비성 프로브를 지원하지 않는다면, 기본 상태는 Success이다.

Pod livenessProbe: https://kouzie.github.io/docker/kubernetes/쿠버네티스-파드,-리플리카셋,-스케일러빌리티/#파드-감시

디플로이먼트 CRUD

도커 허브에서 바로 이미지를 가져와 디플로이먼트 CRUD

# 생성
$ kubectl create deployment --image=nginx nginx-app
deployment.apps/nginx-app created

# 스케일 업
$ kubectl scale deploy nginx-app --replicas=2
deployment.apps/nginx-app scaled

$ kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
nginx-app-d6ff45774-m6frx   1/1     Running   0          113s
nginx-app-d6ff45774-q7r5v   1/1     Running   0          26s

$ kubectl get deployments
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
nginx-app   2/2     2            2           2m17s

# 서비스 생성
$ kubectl expose deployment nginx-app --type=NodePort --port=80
service/nginx-app exposed

$ kubectl get service nginx-app # localhost:30403 접속
NAME        TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx-app   NodePort   10.104.196.2   <none>        80:30403/TCP   6s

# 상세 조회
$ kubectl describe service nginx-app
Name:                     nginx-app
Namespace:                default
Labels:                   app=nginx-app
Annotations:              <none>
Selector:                 app=nginx-app
Type:                     NodePort
IP Families:              <none>
IP:                       10.104.196.2
IPs:                      <none>
LoadBalancer Ingress:     localhost
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30403/TCP
Endpoints:                10.1.0.11:80,10.1.0.12:80 # 중요
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

# 삭제
$ kubectl delete deployment nginx-app
deployment.apps "nginx-app" deleted

매니페스트를 생성후 Deployment 리플리카셋과 파드가 생성되는지 확인

# 기본항목
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
# 디플로이먼트 스팩
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod # 템플릿 검색조건
  # 파드 템플릿
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.15 # 컨테이너 이미지
          ports:
            - containerPort: 80
$ kubectl apply -f Deployment/nginx-deployment.yaml
deployment.apps/nginx-deployment created

$ kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           24s

$ kubectl get replicaset,pod
NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-5bff7844cb   3         3         3       5m11s

NAME                                    READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-5bff7844cb-6n2xh   1/1     Running   0          5m11s
pod/nginx-deployment-5bff7844cb-9jmvt   1/1     Running   0          5m11s
pod/nginx-deployment-5bff7844cb-kc7ph   1/1     Running   0          5m11s

디플로이먼트는 내부에서 리플리카셋, 파드 이력을 갖고 있다. kubectl get replicaset 명령에도 조회가 가능하다.

리소스의 네이밍 규칙이 있다.

Deployment - nginx-deployment
ReplicaSet - nginx-deployment-5bff7844cb
Pod - nginx-deployment-5bff7844cb-kc7ph

뒤에 특정 해시값이 라벨로도 붙어있으며 이를 사용해 Deployment가 리소스를 관리한다.

기존의 nginx:1.14 버전의 이미지를 nginx:1.15 로 변경해보자.

$ kubectl apply -f Deployment/nginx-deployment.yaml
deployment.apps/nginx-deployment configured

$ kubectl describe deploy nginx-deployment
Name:                   nginx-deployment
Namespace:              default
...
...
OldReplicaSets:  <none>
NewReplicaSet:   nginx-deployment-f75fb748c (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  28m   deployment-controller  Scaled up replica set nginx-deployment-5bff7844cb to 3
  Normal  ScalingReplicaSet  18s   deployment-controller  Scaled up replica set nginx-deployment-f75fb748c to 1
  Normal  ScalingReplicaSet  4s    deployment-controller  Scaled down replica set nginx-deployment-5bff7844cb to 2
  Normal  ScalingReplicaSet  4s    deployment-controller  Scaled up replica set nginx-deployment-f75fb748c to 2
  Normal  ScalingReplicaSet  3s    deployment-controller  Scaled down replica set nginx-deployment-5bff7844cb to 1
  Normal  ScalingReplicaSet  3s    deployment-controller  Scaled up replica set nginx-deployment-f75fb748c to 3
  Normal  ScalingReplicaSet  2s    deployment-controller  Scaled down replica set nginx-deployment-5bff7844cb to 0

nginx-deployment-5bff7844cb 이름의 리플리카셋의 파드를 하나씩 줄이며
nginx-deployment-f75fb748c 이름의 새로운 리플리카셋의 파드를 하나씩 생성한다.

디플로이먼트 이력(history)을 확인하려면 rollout history 옵션을 사용한다.

$ kubectl rollout history deploy rollout-deployment --revision=3
deployment.apps/rollout-deployment with revision #3
Pod Template:
  Labels:	app=photo-view
	pod-template-hash=d8bf6cb58
  Containers:
   photoview-container:
    Image:	ai1.beyless.com:5005/photo-view:v1.0
    Port:	80/TCP
    Host Port:	0/TCP
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>

$ kubectl rollout history deploy rollout-deployment --revision=4
deployment.apps/rollout-deployment with revision #4
Pod Template:
  Labels:	app=photo-view
	pod-template-hash=6b5ddcb6b7
  Containers:
   photoview-container:
    Image:	ai1.beyless.com:5005/photo-view:v2.0
    Port:	80/TCP
    Host Port:	0/TCP
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>

Roll out, Roll back

디플로이먼트를 업데이트하고 문제가 생기면 다시 이전버전으로 돌릴 수 있는 기능(롤백) 을 사용해보자.

먼저 아래와 같은 디플로이먼트를 생성 후 실제 서비스까지 동작하는지 확인

apiVersion: apps/v1
kind: Deployment
metadata:
  name: rollout-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: photo-view
  template:
    metadata:
      labels:
        app: photo-view
    spec:
      containers:
        - image: ai1.beyless.com:5005/photo-view:v1.0
          name: photoview-container
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: rollout
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    app: photo-view
$ kubectl apply -f Deployment/rollout-depoyment.yaml
deployment.apps/rollout-deployment created
service/rollout created

$ kubectl get pod
NAME                                 READY   STATUS    RESTARTS   AGE
rollout-deployment-d8bf6cb58-2p5wz   1/1     Running   0          48s
rollout-deployment-d8bf6cb58-56mrf   1/1     Running   0          48s
rollout-deployment-d8bf6cb58-bscp8   1/1     Running   0          48s

현재 사용중인 이미지 photo-view:v1.0photo-view:v2.0 으로 수정 후 다시 적용(Roll out)

$ kubectl apply -f Deployment/rollout-depoyment.yaml
deployment.apps/rollout-deployment configured
service/rollout unchanged

$ kubectl describe deploy rollout-deployment
Name:                   rollout-deployment
Namespace:              default
...
Annotations:            deployment.kubernetes.io/revision: 2
...
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  41s   deployment-controller  Scaled up replica set rollout-deployment-d8bf6cb58 to 3
  Normal  ScalingReplicaSet  27s   deployment-controller  Scaled up replica set rollout-deployment-6b5ddcb6b7 to 1

describe 명령으로 출력된 Annotations 속성으로 revision 값 확인
해당 디플로이먼트가 몇번 업데이트 되었는지 확이 가능하다.

d8bf6cb58 -> 6b5ddcb6b7 해시의 변경값이다.

이제 photo-view:v2.0 으로 업데이트된 디플로이먼트를 다시 예전버전으로 롤 백해보자.

첫번째 방법으로 탬플릿 이미지를 photo-view:v1.0 로 다시 적용해보자.

kubectl apply -f Deployment/rollout-depoyment.yaml
deployment.apps/rollout-deployment configured
service/rollout unchanged

$ kubectl describe deploy rollout-deployment
...
Annotations:            deployment.kubernetes.io/revision: 3
...

$ kubectl get pod
NAME                                 READY   STATUS    RESTARTS   AGE
rollout-deployment-d8bf6cb58-9nwh5   1/1     Running   0          33s
rollout-deployment-d8bf6cb58-t2f4l   1/1     Running   0          34s
rollout-deployment-d8bf6cb58-tgg57   1/1     Running   0          31s

revision값은 3이 되었고 해시값이 새롭게 변하지 않고 다시 d8bf6cb58 로 돌아갔다.

디플로이먼트, 리플리카셋, 파드 모두 매니페스트 이력을 가지고 롤아웃/롤백을 진행하고 있기 때문

이 외에도 현재 사용중인 매니페스트 수정하거나 kubectl rollout 명령을 사용해 롤백이 가능하다.

$ kubectl edit deploy rollout-deployment
$ kubectl rollout undo deployment rollout-deployment --to-revision=2 

구성관리가 유지되지 않음으로 매니페스트 파일의 갱신(선언적 관리)으로 롤아웃/롤백 하는것을 권장한다.

블루/그린 디플로이먼트

블루/그린 이라고 별다른 기법이 있는건 아니다.

서로 다른 버전의 2개의 디플로이먼트를 각각 생성하고 이에 접근하는 Service 리소스를 변경하는 것이다.

# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: photo-view
  template:
    metadata:
      labels:
        app: photo-view
        ver: v1.0
    spec:
      containers:
        - image: ai1.beyless.com:5005/photo-view:v1.0
          name: photoview-container
          ports:
            - containerPort: 80
# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: green-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: photo-view
  template:
    metadata:
      labels:
        app: photo-view
        ver: v2.0
    spec:
      containers:
        - image: ai1.beyless.com:5005/photo-view:v2.0
          name: photoview-container
          ports:
            - containerPort: 80
$ kubectl apply -f Deployment/blue-deployment.yaml
deployment.apps/blue-deployment created

$ kubectl apply -f Deployment/green-deployment.yaml
deployment.apps/green-deployment created

$ kubectl get pod
NAME                                 READY   STATUS        RESTARTS   AGE
blue-deployment-58d5d4869b-kmn88     1/1     Running       0          19s
blue-deployment-58d5d4869b-vlx2c     1/1     Running       0          19s
blue-deployment-58d5d4869b-w4729     1/1     Running       0          19s
green-deployment-5466fc4568-7hxqp    1/1     Running       0          15s
green-deployment-5466fc4568-mvs2w    1/1     Running       0          15s
green-deployment-5466fc4568-t8hp2    1/1     Running       0          15s

그리고 이 DeploymentReplicaSetPod 에 접근하는 서비스를 작성하고 실행한다.

apiVersion: v1
kind: Service
metadata:
  name: webserver
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector: # 접근할 파드 수정
    app: photo-view
    ver: v1.0
$ kubectl apply -f Deployment/service.yaml
service/webserver created

이제 service.yml 매니페스트 파일만 수정해서 두 버전의 디플로이먼트에 접근할 수 있도록 설정하면 된다.

스케일러빌리티

순간적으로 많은양의 요청이 들어올 경우 시스템 처리능력을 높이는 방법
시스템 처리능력을 높이는 방법은 2가지가 있다.

  • 스케일 아웃(수평 스케일): 시스템 구성 서버 대수를 늘림으로 처리능력 향상, 로드밸런서를 추가해야 하며 시스템의 가용성이 높아진다.
  • 스케일 업(수직 스케일): 서버의 리소스(CPU, Memory) 를 증각 시켜 처리능령 향상

수직이던 수평이던 파드와 노드단위로 스케일(처리능령 향상) 가능하다.

처리량의 증가정도에 따라 파드를 스케일할지 노드를 스케일할지 결정한다.

파드 수동 수평 스케일 (kubectl scale)

kubectl scale 명령으로 파드 스케일을 늘릴 수 있다.

리플리카셋으로 nginx 파드를 3개 생성

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx-replicaset
spec:
  replicas: 3
  selector:
    matchLabels:
      app: photo-view
  template:
    metadata:
      labels:
        app: photo-view
    spec:
      containers:
      - image: nginx
        name: photoview-container
$ kubectl apply -f HPA/pod-scale.yaml
replicaset.apps/nginx-replicaset created

$ kubectl scale --replicas=8 rs/nginx-replicaset
replicaset.apps/nginx-replicaset scaled

$ kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-replicaset-4bv5g   1/1     Running   0          19s
nginx-replicaset-4cjjq   1/1     Running   0          19s
nginx-replicaset-5z9qk   1/1     Running   0          19s
nginx-replicaset-bt98h   1/1     Running   0          19s
nginx-replicaset-c5fkk   1/1     Running   0          2m29s
nginx-replicaset-hnv8w   1/1     Running   0          2m29s
nginx-replicaset-nxtcn   1/1     Running   0          19s
nginx-replicaset-zbsd6   1/1     Running   0          2m29s

파드 자동 수평 스케일 (HorizontalPodAutoscaler)

kubectl scale 명령으로 수동으로 스케일하였다면 HorizontalPodAutoscaler 쿠버네티으 리소스를 사용해 자동으로 수평 스케일 가능하다.
쿠버는 CPU 사용률, 기타 메트릭을 체크해 파드 스케일이 가능하다.

리플리카셋 외에도 Deployment, Relication Controller, StatefuleSet 등의 리소스에서 스케일링 가능하다.

먼저 스케일전의 리플리카셋을 생성한다.

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: busy-replicaset
spec:
  replicas: 2
  selector:
    matchLabels:
      app: busy
  template:
    metadata:
      labels:
        app: busy
    spec:
      containers:
      - image: busybox
        name: hpa-container
        command: ["dd", "if=/dev/zero", "of=/dev/null"]
        resources:
          requests:
            cpu: 100m
          limits:
            cpu: 100m

자동 스케일을 위해선 requests, limits 속성을 둘다 설정할 필요가 있다.
내부에서 dd 명령을 통해 limits100m 만큼의 코어가 되어있다.

$ kubectl apply -f HPA/replicaset-hpa.yaml
replicaset.apps/busy-replicaset created

$ kubectl get pod --show-labels
NAME                    READY   STATUS    RESTARTS   AGE   LABELS
busy-replicaset-w97wr   1/1     Running   0          35s   app=busy
busy-replicaset-z5sh8   1/1     Running   0          35s   app=busy

$ kubectl top pod
Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)

이 상태에서 자동 스케일 가능하도록 HorizontalPodAutoscaler 리소스를 작성

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: budy-hpa
spec:
  minReplicas: 1   # 최소 리플리카 수
  maxReplicas: 5   # 최대 리플리카 수
  metrics:
  - resource:
      name: cpu
      targetAverageUtilization: 30  # CPU 가 30% 되도록 조정
    type: Resource
  scaleTargetRef: # 자동스케일 대상 리소스(리플리카셋)를 결정
    apiVersion: apps/v1
    kind: ReplicaSet
    name: busy-replicaset

배치 잡

웹, DB 서버와 같은 상주 서비스는 파드를 통해 항시 관리되지만
기계학습, 배치처리는 Job, CronJob 을 통해 실행되고 정지(실행완료)된다.

Job

Job은 하나 이상의 파드에서 배치처리를 하기 위한 리소스.
DB 마이크레이션같은 한번의 실행으로 끝나는 것에 이용된다.

Job 의 실행 오류, 예외 발생시 Job 컨트롤러가 성공할 때까지 파드를 새로 생성해 실행시킨다.

CronJob

CronJob 은 정해진 시간에 Job 을 수행하기 위한 리소스.
백업, 메일 송신 등과 같은 배치처리에 사용된다.