반응형
4장에서 다루는 내용
- 파드의 안정적인 유지
- 동일한 파드의 여러 인스턴스 실행
- 노드 장애 시 자동으로 파드 재스케줄링
- 파드의 수평 스케줄링
- 각 클러스터 노드에서 시스템 수준의 파드 실행
- 배치 잡 실행
- 잡을 주기적 또는 한 번만 실행하도록 스케줄링
- 실환경에서는 배포한 애플리케이션이 자동으로 실행되고 수동적인 개입 없이도 안정적인 상태로 유지하기 위해서 레플리케이션컨트롤러 또는 디플로이먼트와 같은 유형의 리소스를 생성해 파드를 생성하고 관리한다.
4.1 파드를 안정적으로 유지하기
- 파드가 노드에 스케줄링되는 즉시, 해당 노드의 Kubelet은 파드의 컨테이너를 실행하고 파드가 존재하는 한 컨테이너가 계속 실행되도록 할 것이다.
- 컨테이너의 주 프로세스에 크래시가 발생하면 Kubelet이 컨테이너를 다시 시작한다.
- 때때로 애플리케이션은 프로세스의 크래시 없이도 작동이 중단되는 경우가 있다.
- 일례로 자바 애플리케이션이 메모리 누수가 있어서 OOM을 발생해도 JVM 프로세스는 계속 실행된다.
- 이것처럼 실제로는 문제가 발생했는데도 불구하고 알려주지 못해 쿠버네티스가 애플리케이션을 다시 시작하도록 하는 방법이 있다면 좋을 것이다.
4.1.1 라이브니스 프로브 소개
- 쿠버네티스는 라이브니스 프로브를 통해 컨테이너가 살아 있는지 확인할 수 있다.
- 파드의 스펙에 각 컨테이너의 라이브니스 프로브를 지정할 수 있다.
- 주기적으로 프로브를 실행하고 프로브가 실패할 경우 컨테이너를 다시 시작한다.
- 쿠버네티스는 세 가지 매커니즘을 사용해 컨테이너에 프로브를 실행한다.
- HTTP GET 프로브는 지정한 IP 주소, 포트, 경로에 HTTP GET 요청을 수행한다.
프로브가 응답을 수신하고 응답 코드가 오류를 나타내지 않는 경우에 프로브가 성공했다고 간주된다.
오류 코드를 반환하거나 전혀 응답하지 않으면 프로브가 실패한 것으로 간주돼 컨테이너를 다시 시작한다. - TCP 소켓 프로브는 컨테이너의 지정된 포트에 TCP 연결을 시도한다. 연결에 성공하면 프로브가 성공한 것이고, 그렇지 않으면 컨테이너가 다시 시작된다.
- Exec 프로브는 컨테이너 내의 임의의 명령을 실행하고 명령의 종료 상태 코드를 확인하다. 상태 코드가 0이면 프로브가 성공한 것이다. 모든 다른 코드는 실패로 간주된다.
- HTTP GET 프로브는 지정한 IP 주소, 포트, 경로에 HTTP GET 요청을 수행한다.
4.1.2 HTTP 기반 라이브니스 프로브 생성
- 예제에서는 처음 다섯 번째까지는 적절히 처리하고 이후의 모든 요청은 오류를 반환하는 애플리케이션을 만들었다.
- 만약 라이브니스 프로브를 설정하게 되면 오류를 확인하고 컨테이너가 다시 시작돼 클라이언트의 요청을 다시 적절히 처리하게 된다.
apiVersion: v1
kind: Pod
metadata:
name: kubia-liveness
spec:
containers:
- image: luksa/kubia-unhealthy
name: kubia
livenessProbe: # 라이브니스 프로브
httpGet:
path: / # HTTP 요청 경로
port: 8080 # 프로브가 연결해야 하는 네트워크 포트
4.1.3 동작 중인 라이브니스 프로브 확인
$ kubectl get po kubia-liveness
NAME READY STATUS RESTARTS AGE
kubia-liveness 1/1 Running 1 2m
- RESTARTS 열을 보면 1이 있는 것을 볼 수 있다. 이미 라이브니스 프로브가 동작해서 컨테이너를 살렸다는 뜻
- 이를 확인해보려면 describe 명령어로 확인하면 된다.
$ kubectl describe po kubia-liveness
Name: kubia-liveness
...
Containers:
kubia:
Container ID: docker://480986f8
Image: luksa/kubia-unhealthy
Image ID: docker://sha256:2b208508
Port:
State: Running
Started: Sun, 14 May 2017 11:41:40 +0200
Last State: Terminated
Reason: Error
Exit Code: 137
Started: Mon, 01 Jan 0001 00:00:00 +0000
Finished: Sun, 14 May 2017 11:41:38 +0200
Ready: True
Restart Count: 1
Liveness: http-get http://:8080/ delay=0s timeout=1s period=10s #success=1 #failure=3
...
Events:
... Killing container with id docker://95246981:pod "kubia-liveness ..."
container "kubia" is unhealthy, it will be killed and re-created
- Exit Code는 137 으로 128+9 즉 SIGKILL 시그널 번호의 9번으로 인해 프로세스가 강제로 종료됐음을 의미한다.
- Events 항목을 보면 컨테이너가 unhealthy로 re created 되었다는 것을 알 수 있다.
4.1.4 라이브니스 프로브의 추가 속성 설정
- kubectl describe는 라이브니스 프로브에 관한 추가적인 정보도 표시된다.
Liveness: http-get http://:8080/ delay=0s timeout=1s period=10s #success=1 #failure=3
- delay : 컨테이너가 시작된 후 바로 프로브가 시작된다는 것을 나타낸다.
- timeout : 제한 시간을 나타낸다. 컨테이너가 1초 내로 응답해야한다는 뜻이다.
- period : 컨테이너는 10초마다 프로브를 수행하며
- failure : 프로브가 3번 연속 실패하면 컨테이너가 다시 시작된다.
- 위와 같은 추가적인 매개변수는 프로브를 정의할 때 지정할 수 있다.
- 초기 지연을 설정하려면 아래와 같이 initaildelaySeconds 속성을 라이브니스 프로브에 추가한다.
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 15
- 초기 지연을 설정하지 않으면 프로브는 컨테이너가 시작되자마자 프로브를 시작한다. 이 경우 대부분 애플리케이션이 요청을 받을 준비가 돼 있지 않기 때문에 프로브가 실패한다.
4.1.5 효과적인 라이브니스 프로브 생성
- 운영 환경에서는 반드시 라이브니스 프로브를 정의해야 한다.
- 더 나은 라이브니스 프로브를 위해 HTTP 요청만 하는 것이 아니라 특정 URL 경로 (예를들어 /health)에 요청하도록 프로브를 구성하는 게 좋을 수 있다.
- 라이브니스 프로브는 애플리케이션 내부만 체크하고, 외부 요인의 영향을 받지 않도록 해야 한다. 예를 들어 웹서버의 라이브니스 프로브는 웹서버가 백엔드 데이터베이스에 연결할 수 없을 때 실패를 반환해서는 안된다. 근본적인 원인이 데이터베이스 자체에 있는 경우, 웹 서버 컨테이너를 재시작한다 하더라도 문제가 해결되지 않는다.
- 라이브니스 프로브는 너무 많은 연산을 해서는 안되고, 완료하는 데 너무 오랜 시간이 걸리면 안된다. 기본적으로 프로브는 자주 실행되며 1초 내에 완료되어야 한다.
- 라이브니스 프로브를 너무 무겁게 만들면 메인 애플리케이션 프로세스에서 사용할 수 있는 CPU 시간이 줄어들게 된다.
- 노드 자체에 크래시가 발생한 경우 노드 크래시로로 중단된 모든 파드의 대체 파드를 생성해야 하는 것은 컨트롤 플레인의 몫이다.
4.2 레플리케이션컨트롤러 소개
- 레플리케이션컨트롤러는 쿠버네티스 리소스로서 파드가 항상 실행되도록 보장한다.
4.2.1 레플리케이션컨트롤러의 동작
- 레플리케이션컨트롤러는 실행 중인 파드 목록을 지속적으로 모니터링하고, 특정 유형의 실제 파드 수가 의도하는 수와 일치하는지 항상 확인한다.
- 의도하는 수의 복제본보다 많은 복제본을 가질 수 있는 경우
- 누군가 같은 유형의 파드를 수동으로 만든다.
- 누군가 기존 파드의 유형을 변경한다.
- 누군가 의도하는 파드 수를 줄인다.
- 레플리케이션컨트롤러는 정확히 말하면 특정 레이블 셀렉터와 일치하는 파드 세트에 작동한다.
- 정확한 수의 파드가 항상 레이블 셀렉터와 일치하는지 확인하는 것이다.
- 레플리케이션컨트롤러에는 세 가지 필수 요소가 있다.
- 레이블 셀렉터 : 레플리케이션컨트롤러의 범위에 있는 파드를 결정한다.
- 레플리카 수 : 실행할 파드의 의도하는 수를 지정한다.
- 파드 템플릿 : 새로운 파드 레플리카를 만들 때 사용된다.
- 레플리케이션컨트롤러의 레플리카 수, 레이블 셀렉터, 심지어 파드 템플릿은 언제든지 수정할 수 있지만 레플리카 수의 변경만 기존 파드에 영향을 미친다.
- 레이블 셀렉터를 변경하면 기존 파드가 레플리케이션컨트롤러의 범위를 벗어나므로 컨트롤러가 해당 파드에 대한 관리를 중지한다.
- 파드 템플릿은 레플리케이션컨트롤러로 새 파드를 생성할 때만 영향을 미친다. 템플릿은 쿠키 커터라고 생각할 수 있다.
- 레플리케이션컨트롤러 사용 시 이점
- 기존 파드가 사라지면 새 파드를 시작해 파드가 항상 실행되도록 한다.
- 클러스터 노드에 장애가 발생하면 장애가 발생한 노드에서 실행 중인 모든 파드(레플리케이션컨트롤러의 제어하에 있는 파드)에 관한 교체 복제본이 생성된다.
- 수동 또는 자동으로 파드를 쉽게 수평으로 확장할 수 있게 한다.
4.2.2 레플리케이션컨트롤러 생성
- 다른 오브젝트와 마찬가지로 쿠버네티스 API 서버에 JSON 또는 YAML 디스크립터를 게시해 레플리케이션컨트롤러를 만든다.
apiVersion: v1
kind: ReplicationController
metadata:
name: kubia
spec:
replicas: 3
selector:
app: kubia
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: luksa/kubia
ports:
- containerPort: 8080
- 템플릿의 파드 레이블은 레플리케이션컨트롤러의 레이블 셀렉터와 완전히 일치해야 한다. 그렇지 않으면 컨트롤러에서 새 파드를 무한정 생성할 수 있다.
- 이런 경우를 방지하기 위해 API 서버는 레플리케이션컨트롤러의 정의를 검증하고 잘못 구성된 경우 이를 받아들이지 않는다.
- 셀렉터를 지정하지 않는 것도 선택 가능한 옵션이다. 셀렉터를 지정하지 않으면 템플릿의 레이블로 자동 설정된다.
$ kubectl create -f kubia-rc.yaml
replicationcontroller "kubia" created
4.2.3 레플리케이션컨트롤러 작동 확인
- 삭제된 파드에 관한 레플리케이션컨트롤러의 반응 확인 내용 생략
$ kubectl get rc
NAME DESIRED CURRENT READY AGE
kubia 3 3 2 3m
- DESIRED : 의도하는 파드 수
- CURRENT : 현재 파드 수
- READY : 준비된 파드 수
$ kubectl describe rc kubia
Name: kubia
Namespace: default
Selector: app=kubia
Labels: app=kubia
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 4 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=kubia
Containers: ...
Volumes: <none>
Events:
From Type Reason Message
---- ------- ------ -------
replication-controller Normal SuccessfulCreate Created pod: kubia-53thy
replication-controller Normal SuccessfulCreate Created pod: kubia-k0xz6
replication-controller Normal SuccessfulCreate Created pod: kubia-q3vkg
replication-controller Normal SuccessfulCreate Created pod: kubia-oini2
- describe를 하게 되면 레플리케이션컨트롤러의 추가 정보를 볼 수 있다.
- 컨트롤러가 새 교체 파드를 만들어 파드 삭제에 대응한다. 엄밀히 말하면 이 것은 삭제 자체에 대한 대응이 아니라 부족한 파드 수라는 결과적인 상태에 대응하는 것이다.
- 레플리케이션컨트롤러는 삭제되는 파드에 대해 즉시 통지를 받지만, 이 통지 자체가 대체 파드를 생성하게 하는 것은 아니고, 통지는 컨트롤러가 실제 파드 수를 확인하고 적절한 조치를 취하도록 하는 트리거 역할을 한다.
- 쿠버네티스를 사용할 때는 노드에서 장애가 발생하면 레플리케이션컨트롤러는 노드의 파드가 다운됐음을 감지하자마자 파드를 대체하기 위해 새 파드를 기동한다.
- 예제에서는 임의로 노드에 장애를 내 새 파드가 기동되는 과정을 살펴봤다.
$ gcloud compute ssh gke-kubia-default-pool-b46381f1-zwko
Enter passphrase for key '/home/luksa/.ssh/google_compute_engine':
Welcome to Kubernetes v1.6.4!
...
luksa@gke-kubia-default-pool-b46381f1-zwko ~ $ sudo ifconfig eth0 down
- 네트워크 인터페이스를 강제로 종료한 상황이다.
- 새로운 노드에서 노드의 상태를 확인해보자
$ kubectl get node
NAME STATUS AGE
gke-kubia-default-pool-b46381f1-opc5 Ready 5h
gke-kubia-default-pool-b46381f1-s8gj Ready 5h
gke-kubia-default-pool-b46381f1-zwko NotReady 5h
- 노드 중 하나가 NotReady 상태로 변경됐음을 알 수 있다.
- 노드가 몇 분 동안 접속할 수 없는 상태로 유지될 경우 해당 노드에 스케줄된 파드는 Unknown으로 변경된다.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubia-oini2 1/1 Running 0 10m
kubia-k0xz6 1/1 Running 0 10m
kubia-q3vkg 1/1 Unknown 0 10m
kubia-dmdck 1/1 Running 0 5s
- 파드의 AGE를 보면 kubia-dmdck 파드가 새로 생성 됐음을 알 수 있다. 이는 레플리케이션컨트롤러가 시스템의 실제 상태를 의도하는 상태로 만드는 작업을 다시 수행했음을 의미한다.
- 노드에 장애가 발생한 경우도 마찬가지다. 즉각적인 인간의 개입이 필요하지 않고 시스템이 자동으로 스스로 치유한다.
4.2.4 레플리케이션컨트롤러의 범위 안팎으로 파드 이동하기
- 레플리케이션컨트롤러가 생성한 파드는 무조건 적으로 레플리케이션컨트롤러에 영속적이지는 않다. 레플리케이션컨트롤러는 레이블 셀렉터와 일치하는 파드만을 관리한다.
- 파드의 레이블을 변경하면 레플리케이션컨트롤러의 범위에서 제거되거나 추가될 수 있다. 한 레플리케이션컨트롤러에서 다른 레플리케이션컨트롤러로 이동할 수도 있다.
- 파드가 레플리케이션컨트롤러에 묶여 있지는 않지만, 파드는 metadata.ownerReferences 필드에서 레플리케이션컨트롤러를 참조한다.
$ kubectl label pod kubia-dmdck type=special
pod "kubia-dmdck" labeled
$ kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
kubia-oini2 1/1 Running 0 11m app=kubia
kubia-k0xz6 1/1 Running 0 11m app=kubia
kubia-dmdck 1/1 Running 0 1m app=kubia,type=special
$ kubectl label pod kubia-dmdck app=foo --overwrite
pod "kubia-dmdck" labeled
$ kubectl get pods -L app
NAME READY STATUS RESTARTS AGE APP
kubia-2qneh 0/1 ContainerCreating 0 2s kubia
kubia-oini2 1/1 Running 0 20m kubia
kubia-k0xz6 1/1 Running 0 20m kubia
kubia-dmdck 1/1 Running 0 10m foo
- 위는 레이블을 변경시켜 app=kubia 레이블을 가진 파드가 하나 생성된 상황이다. 이 처럼 기존에 있는 레이블을 변경하면 변경된 파드는 레플리케이션컨트롤러의 관리에서 벗어나고, app=kubia 레이블을 가진 새로운 파드가 생성된다.
4.2.5 파드 템플릿 변경
- 레플리케이션컨트롤러의 파드 템플릿은 언제든지 수정할 수 있다. 수정하게 된다면 기존의 파드에는 아무 영향을 끼치지 않고 앞으로 생성될 파드에만 영향을 끼친다.
- 기존 파드를 수정하려면 해당 파드를 삭제하고 레플리케이션컨트롤러가 새 템플릿을 기반으로 새 파드로 교체하도록 해야 한다.
$ kubectl edit rc kubia
- 위 명령을 사용해서 레플리케이션컨트롤러를 편집할 수 있다.
- 편집을 하게 되면 YAML 편집기가 열리게 되는데 파드 템플릿 섹션에서 레이블을 변경하면 kubectl이 레플리케이션컨트롤러를 업데이트한다.
4.2.6 수평 파드 스케일링
- 수평 파드 스케일링을 하려면 레플리케이션컨트롤러의 replicas 숫자만 늘려주거나 줄여주면 된다.
- 아래 두 가지 방식으로도 수정이 가능하다.
$ kubectl scale rc kubia --replicas=10
$ kubectl edit rc kubia # spec.replicas 의 값을 10으로 늘려주면 된다.
- kubectl scale 명령은 쿠버네티스에게 직접 파드를 늘리라는 것은 아니고 레플리케이션컨트롤러의 DESIRED를 선언적으로 변경한다는 것이 훨씬 명확해 보인다.
- 쿠버네티스에서 파드를 수평으로 확장한다는 것은 "x개의 인스턴스가 실행되게 하고 싶다"와 같이 의도하는 바를 언급하는 것이다.
- 쿠버네티스를 직접 컨트롤해서 파드를 늘리는 것이 아니라 의도하는 상태를 지정할 뿐
- 레플리케이션컨트롤러를 삭제할 때 --cascade=false 옵션을 사용하면 레플리케이션컨트롤러에 속해 있는 파드를 계속 실행 시킬 수 있다.
$ kubectl delete rc kubia --cascade=false
replicationcontroller "kubia" deleted
4.3 레플리케이션컨트롤러 대신 레플리카셋 사용하기
- 초기에는 레플리케이션컨트롤러가 유일한 재스케줄링 요소였다. 후에 레플리카셋이라는 유사한 리소스가 도입됐고, 완벽히 레플리카셋으로 대체될 것이다.
4.3.1 레플리카셋과 레플리케이션 컨트롤러 비교
- 레플리카셋은 레플리케이션컨트롤러와 똑같이 동작하지만 더 풍부한 표현식을 사용하는 파드 셀렉터를 갖고 있다.
- 레플리카셋의 셀렉터는 특정 레이블이 없는 파드나 레이블의 값과 상관없이 특정 레이블의 키를 갖는 파드를 매칭시킬 수 있다.
- 예를 들어 레플리카셋은 env=* 이렇게 매칭시킬 수 있는데 레플리케이션컨트롤러는 안된다.
4.3.2 레플리카셋 정의하기
apiVersion: apps/v1beta2
kind: ReplicaSet
metadata:
name: kubia
spec:
replicas: 3
selector:
matchLabels:
app: kubia
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: luksa/kubia
- 레플리케이션컨트롤러와 유일한 차이점은 셀렉터에 있다. 파드가 가져야 하는 레이블은 selector 속성 바로 아래 나열하는 대신 selector.matchLabels 아래에 지정한다.
4.3.3 레플리카셋 생성 및 검사
- kubectl create 명령을 사용해 YAML 파일로 레플리카셋을 생성하고 kubectl get 및 kubectl describe를 사용해 레플리카셋을 검사할 수 있다.
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
kubia 3 3 3 3s
$ kubectl describe rs
Name: kubia
Namespace: default
Selector: app=kubia
Labels: app=kubia
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=kubia
Containers: ...
Volumes: <none>
Events: <none>
- 보다시피 레플리케이션컨트롤러와 다르지 않다.
4.3.4 레플리카셋의 더욱 표현적인 레이블 셀렉터 사용하기
- matchExpressions를 사용하면 더 표현적이고 강력한 셀렉터를 사용 가능하다.
selector:
matchExpressions:
- key: app
operator: In
values:
- kubia
- 셀렉터에 표현식을 추가할 수 있다. 각 표현식은 키, 연산자, 가능한 값이 포함돼야 한다.
- 다음은 네 가지 유효한 연산자다.
- In은 레이블의 값이 지정된 값 중 하나와 일치해야 한다.
- NotIn은 레이블의 값이 지정된 값과 일치하지 않아야 한다.
- Exists는 파드는 지정된 키를 가진 레이블이 포함돼야 한다. 이 연산자를 사용할 때는 값 필드를 지정하지 않아야 한다.
- DoesNotExist는 파드에 지정된 키를 가진 레이블이 포함돼 있지 않아야 한다. 동일하게 값 필드를 지정하지 않아야 한다.
4.3.5 레플리카셋 정리
$ kubectl delete rs kubia
replicaset "kubia" deleted
4.4 데몬셋을 사용해 각 노드에서 정확히 한 개의 파드 실행하기
- 레플리카셋은 쿠버네티스 클러스터 내 어딘가에 지정된 수만큼의 파드를 실행하는 데 사용된다. 그러나 클러스터의 모든 노드에, 노드당 하나의 파드만 실행되길 원하는 경우가 있을 수 있다.
- 시스템 수준의 작업을 수행하는 인프라 관련 파드가 이런 경우다. 예를 들면 모든 노드에서 로그 수집기와 리소스 모니터를 실행하려는 경우가 좋은 예다.
- 또 다른 좋은 예는 쿠버네티스의 kube-proxy 프로세스이며, 서비스를 작동시키기 위해 모든 노드에서 실행돼야 한다.
4.4.1 데몬셋으로 모든 노드에 파드 실행하기
- 데몬셋은 모든 노드에 파드를 한 개씩 띄우기 위해서 사용한다.
- 데몬셋에는 원하는 복제본 수라는 개념이 없다. 파드 셀렉터와 일치하는 파드 하나가 각 노드에서 실행 중인지 확인하는 것이 데몬셋이 수행해야 하는 역할이기 때문에 복제본 개념이 필요 없다.
- 노드가 다운되면 데몬셋은 다른 곳에서 파드를 생성하지 않는다. 허나, 노드가 하나 추가되면 즉시 새로 생긴 노드에 파드를 하나 생성한다. 삭제의 경우도 동일하다.
4.4.2 데몬셋을 사용해 특정 노드에서만 파드를 실행하기
- 파드를 일부 노드에서만 실행되도록 설정하지 않는 이상 데몬셋은 클러스터의 모든 노드에 파드를 배포한다.
apiVersion: apps/v1beta2
kind: DaemonSet
metadata:
name: ssd-monitor
spec:
selector:
matchLabels:
app: ssd-monitor
template:
metadata:
labels:
app: ssd-monitor
spec:
nodeSelector:
disk: ssd
containers:
- name: main
image: luksa/ssd-monitor
- 위와 같은 형식일 때 spec.nodeSelector 를 정의하게 되면 disk=ssd 레이블이 있는 노드를 선택하는 노드 셀렉터를 갖는다.
$ kubectl create -f ssd-monitor-daemonset.yaml # yaml 파일 기반 생성
daemonset "ssd-monitor" created
$ kubectl get ds # 데몬셋 생성 확인
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE-SELECTOR
ssd-monitor 0 0 0 0 0 disk=ssd
$ kubectl get po # 파드 확인
No resources found.
- 위에서 설정한 nodeSelector에 따르면 레이블을 추가해야한다.
$ kubectl get node
NAME STATUS AGE VERSION
minikube Ready 4d v1.6.0
$ kubectl label node minikube disk=ssd # 노드에 레이블 추가
node "minikube" labeled
$ kubectl get po # 파드 재확인
NAME READY STATUS RESTARTS AGE
ssd-monitor-hgxwq 1/1 Running 0 35s
$ kubectl label node minikube disk=hdd --overwrite # 레이블 변경
node "minikube" labeled
$ kubectl get po # 레이블 변경 후 파드 삭제 중 상태
NAME READY STATUS RESTARTS AGE
ssd-monitor-hgxwq 1/1 Terminating 0 4m
4.5 완료 가능한 단일 태스크를 수행하는 파드 실행
- 지금까지는 계속 실행돼야 하는 파드에 관해서만 이야기했다.
- 작업을 완료한 후에는 종료되는 태스크를 실행하려는 경우를 소개해보자
4.5.1 잡 리소스 소개
- 쿠버네티스는 잡 리소스를 이용해서 한번 프로세스를 실행하고 종료한다.
- 만약 노드에 장애가 발생한 경우 해당 노드에 있던 잡이 관리하는 파드는 레플리카셋 파드와 같은 방식으로 다른 노드로 다시 스케줄링된다.
- 프로세스 자체에 장애가 발생한 경우, 잡에서 컨테이너를 다시 시작할 것인지 설정할 수 있다.
- 잡은 작업이 제대로 완료되는 것이 중요한 임시 작업에 유용하다.
4.5.2 잡 리소스 정의
apiVersion: batch/v1
kind: Job
metadata:
name: batch-job
spec:
template:
metadata:
labels:
app: batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job
- spec에는 restartPolicy를 이용해서 프로세스가 종료될 때 쿠버네티스가 수행할 작업을 지정할 수 있다.
- 기본값은 Always 이고 Onfailure나 Never도 있다. 잡 파드는 지속적으로 반복되지 않으므로 Onfailure나 Never를 명시해주어야 한다.
4.5.3 파드를 실행한 잡 보기
$ kubectl get jobs # job 확인
NAME DESIRED SUCCESSFUL AGE
batch-job 1 0 2s
$ kubectl get po # 잡으로 생성된 파드 확인
NAME READY STATUS RESTARTS AGE
batch-job-28qf4 1/1 Running 0 4s
$ kubectl get po -a # 잡으로 생성된 파드 완료된 상태 확인
NAME READY STATUS RESTARTS AGE
batch-job-28qf4 0/1 Completed 0 2m
$ kubectl logs batch-job-28qf4 # 성공적인 잡 완료 확인
Fri Apr 29 09:58:22 UTC 2016 Batch job starting
Fri Apr 29 10:00:22 UTC 2016 Finished succesfully
$ kubectl get job # 잡 확인
NAME DESIRED SUCCESSFUL AGE
batch-job 1 1 9m
4.5.4 잡에서 여러 파드 인스턴스 실행하기
- 잡은 두 개 이상의 파드 인스턴스를 생성해 병렬 또는 순차적으로 실행하도록 구성할 수 있다.
- 잡 스펙에 completions와 parallelism 속성을 설정해 수행한다.
- completions은 순차 parallelism은 병렬이다.
apiVersion: batch/v1
kind: Job
metadata:
name: multi-completion-batch-job
spec:
completions: 5 # 5개 순차 실행,
template:
<template is the same as in listing 4.11>
apiVersion: batch/v1
kind: Job
metadata:
name: multi-completion-batch-job
spec:
completions: 5 # 2개씩 5개 실행, 2 2 1 이렇게 실행이된다.
parallelism: 2
template:
<same as in listing 4.11>
$ kubectl scale job multi-completion-batch-job --replicas 3
job "multi-completion-batch-job" scaled
- 위와같이 scale하면 잡이 실행되는 동안 잡의 parallelism 속성을 변경할 수도 있다.
4.5.5 잡 파드가 완료되는 데 걸리는 시간 제한하기
- 파드 스펙에 activeDeadlineSeconds 속성을 설정해 파드의 실행 시간을 제한할 수 있다.
- 파드가 이보다 오래 실행되면 시스템이 종료를 시도하고 잡을 실패한 것으로 표시한다.
- 잡의 매니페스트에서 spec.backoffLimit 필드를 지정해 실패한 것으로 표시되기 전에 잡을 재시도할 수 있는 횟수를 설정할 수 있다. 명시적으로 지정하지 않으면 기본값은 6이다.
4.6 잡을 주기적으로 또는 한 번 실행되도록 스케줄링하기
- 잡 오브젝트는 생성하는 즉시 해당하는 파드를 실행한다. 특정 시간 또는 지정된 간격으로 반복 실행되어야 하는 경우 어떤가?
- 쿠버네티스에서는 크론잡 리소스를 만들어 구성한다.
- 쿠버네티스는 설정된 시간에 잡 리소스를 크론잡 오브젝트에 설정한 잡 템플릿에 따라 생성한다.
4.6.1 크론잡 생성하기
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: batch-job-every-fifteen-minutes
spec:
schedule: "0,15,30,45 * * * *"
jobTemplate:
spec:
template:
metadata:
labels:
app: periodic-batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job
- 크론잡 스케줄 형식은 아래와 같다.
- 분
- 시
- 일
- 월
- 요일
- 위 예제에서는 "0,15,30,45 * * * *" 이기 때문에 매 0,15,30,45 분 매시 매일 매월 매요일 반복해야한다. (*은 모든이라는 뜻이다.)
- 요일을 나타낼때는 0이 일요일이 기준이다. 토요일이 6
- 크론잡은 jobTemplate에 따라 잡 리소스를 생성한다.
4.6.2 스케줄된 잡의 실행방법 이해
- 잡 리소스는 대략 예정된 시간에 크론잡 리소스에서 생성된다. 그러면 잡은 파드를 생성한다.
- startingDeadlineSecondes 필드를 지정해 데드라인을 설정할 수 있다.
apiVersion: batch/v1beta1
kind: CronJob
spec:
schedule: "0,15,30,45 * * * *"
startingDeadlineSeconds: 15
...
- 설정된 시간에서 15초지난 시점까지 시작하지 않으면 잡이 실행되지 않고 실패로 표시된다.
- 예를 들어 9시 0분 에서 9시 0분 15초까지 시작하지 않으면 실패로 표시된다.
느낀 점
무난한 내용이었다고 생각이 든다.
라이브니스 프로브를 이용해서 운영 단에서 서비스에 대한 안정성을 보장해주었다.
레플리케이션컨트롤러 또는 레플리카셋으로 수평 확장을 하거나 데몬셋을 이용해서 노드 전체에 파드를 하나씩 띄우기도 했다.
잡이나 크론잡을 이용해서 배치 성 작업을 하기도 했다.
정리
라이브니스 프로브
- 라이브니스 프로브를 통해 컨테이너가 정상 상태인지 확인 가능하다.
- 주기적으로 프로브를 실행하고 프로브가 실패할 경우 컨테이너를 다시 시작한다.
- 세 가지 매커니즘이 있다.
- HTTP GET 프로브 : 지정한 IP 주소, 포트, 경로에 HTTP GET 요청을 수행한다.
- 소켓 프로브 : 컨테이너의 지정된 포트에 TCP 연결을 시도.
연결에 성공하면 프로브가 성공 아니면 실패 - Exec 프로브 : 컨테이너 안에서 명령어를 실행 후 실행이 완료되면 코드 0을 뱉고 성공으로 처리됨 그 외 전부 실패
- 라이브니스 프로브는 spec.containers.livenessProbe 에 정의된다.
- 라이브니스 프로브는 추가 속성 설정이 있다.
- 예시
Liveness: http-get http://example:8080/ delay=0s timeout=1s period=10s #success=1 #failure=3
- delay : 컨테이너가 시작된 뒤 라이브니스 프로브가 실행되기까지 걸리는 시간
- timeout : 제한 시간을 나타냄. 컨테이너가 1초 내로 응답해야한다.
- period : 컨테이너가 프로브를 수행하는 주기
- success : 컨테이너가 성공을 판단하는 회수
- failure : 프로브가 실패를 판단하는 회수, 실패라고 판단되면 컨테이너를 재시작한다.
- 초기 지연을 설정하려면 YAML에 initialdelaySeconds 속성을 추가한다. 초기 지연을 웬만하면 설정해야한다. 안그러면 컨테이너가 실행되자마자 프로브가 시작돼서 실패로 처리됨
- 예시
- 라이브니스 프로브는 HTTP 요청만하는 게 아니라 특정 URL 경로로 하는 것이 좋다. 예를 들면 /health 같은
- 라이브니스 프로브는 외부 요인의 영향을 받지 않도록 해야한다. 예를 들어 A 컨테이너 애플리케이션이 B DB에 접근한다고 했을 때 B DB와의 (A 컨테이너 안에서 발생한) 네트워크 설정으로 인해 프로브가 동작하는것을 방지해야한다.
- 왜냐하면 근본적인 원인인 A 컨테이너의 네트워크 설정은 재시작 한다고 달라질게 없기 때문
- 라이브니스 프로브를 너무 무겁게 만들면 메인 애플리케이션 프로세스가 사용할 CPU 용량이 줄어들기 때문에 가볍게 만들어야한다.
- 노드 자체에 크래시가 발생한 경우 라이브니스 프로브로 어떠한 동작을 하는 것 보다 컨트롤 플레인에게 맡겨야한다.
레플리케이션컨트롤러 & 레플리카셋
- 레플리케이션컨트롤러는 파드가 항상 실행되도록 보장한다.
- 레플리케이션컨트롤러는 실행 중인 파드 목록을 지속적으로 모니터링하고, 실제 파드 수가 의도하는 수와 일치하는지 항상 확인한다.
- 레플리케이션컨트롤러는 특정 레이블 셀렉터와 일치하는 파드 세트에 작동한다. 정확한 수의 파드가 항상 레이블 셀렉터와 일치하는 지 확인하는 것이다.
- 레플리케이션컨트롤러의 레플리카 수, 레이블 셀렉터, 파드 템플릿은 언제든지 수정할 수 있다.
- 기존 파드의 레이블 셀렉터를 변경하면 파드가 레플리케이션컨트롤러의 범위를 벗어나므로 컨트롤러가 해당 파드에 대한 관리를 중지한다. 그리고 레플리케이션컨트롤러의 입장에서는 DESIRED의 수보다 CURRENT의 수가 한 개 줄어들은 것으로 생각 돼 파드 하나를 띄운다.
- 레플리케이션컨트롤러 사용 시 이점
- 기존 파드가 사라지면 새 파드를 시작해 파드가 항상 실행되도록 함
- 파드가 위치한 클러스터 노드에 장애가 발생하면 장애가 발생한 노드에서 실행 중인 모든 파드에 관한 교체 복제본이 생성된다.
- 수동 또는 자동으로 파드를 쉽게 수평으로 확장할 수 있게 한다.
- 템플릿의 파드 레이블은 레플리케이션컨트롤러의 레이블 셀렉터와 완전히 일치해야 한다. 그렇지 않으면 컨트롤러에서 새 파드를 무한정 생성할 수 있다.
- 레이블 셀렉터를 지정하지 않으면 템플릿의 레이블로 자동 설정된다.
- 파드가 레플리케이션컨트롤러에 무조건적으로 영속적이지는 않다. 파드는 metadata.ownerReferences 필드에서 레플리케이션컨트롤러를 참조한다.
kubectl sclae rc kubia --replicas=10
- 명령어를 이용해 수동으로 수평 파드 스케일링을 할 수 있다.
kubectl delete rc kubia --cascade=false
- 레플리케이션컨트롤러를 삭제할 때 --cascade=false 옵션을 사용하면 레플리케이션컨트롤러에 속해 있는 파드를 삭제하지 않고 계속 실행 가능하다.
- 레플리케이션컨트롤러보다 레플리카셋이 사용되고 앞으로는 레플리카셋만 사용될 것이다.
- 레플리카셋은 더 풍부한 표현식을 사용하는 파드 셀렉터를 갖고 있다. 특정 레이블이 없는 파드나 레이블의 값과 상관없이 특정 레이블의 키를 갖는 파드를 매칭시킬 수 있다.
- 예를 들어 레플리카셋은 env=* 이렇게 매칭시킬 수 있는데 레플리케이션컨트롤러는 안된다.
- 레플리카셋의 셀렉터는 spec.selector.matchLabels에 지정한다.
- matchExpressions는 더 표현적이고 강력한 셀렉터를 사용하게 해준다.
selector:
matchExpressions:
- key: app
operator: In
values:
- kubia
- 셀렉터에 표현식을 추가할 수 있다. 각 표현식은 키, 연산자, 가능한 값이 포함돼야한다.
- 네 가지 유효한 연산자
- In : 레이블의 values 값이 지정된 값 중 하나와 일치해야 한다.
- NotIn : 레이블의 values 값이 지정된 값 중 하나와 불일치해야 한다.
- Exists : 파드는 지정된 key를 가진 레이블이 포함돼야 한다.
- DoesNotExist : 파드는 지정된 key를 가진 레이블이 포함돼 있지 않아야 한다.
- Exitsts 와 DoesNotExist는 values 필드가 없어야 한다.
데몬셋
- 데몬셋은 모든 노드에 파드를 한 개씩 띄우기 위해서 사용한다.
- 따로 replicas를 늘리거나 할 수 없이 노드의 개수에 따라서 파드의 개수가 정해진다.
- 파드 셀렉터와 일치하는 파드 하나가 각 노드에서 실행 중인지 확인하는 것이 데몬셋이 수행해야하는 역할
- 노드가 다운되면 데몬셋은 다른 곳에서 파드를 생성하지 않는다.
- 좋은 예는 kube-proxy 서비스를 작동시키기 위해서 모든 노드에서 실행돼야하는 역할을 하는 파드
apiVersion: apps/v1beta2
kind: DaemonSet
metadata:
name: ssd-monitor
spec:
selector:
matchLabels:
app: ssd-monitor
template:
metadata:
labels:
app: ssd-monitor
spec:
nodeSelector:
disk: ssd
containers:
- name: main
image: luksa/ssd-monitor
잡 & 크론잡
- 작업을 완료한 후에는 종료되는 태스크
- 한번 프로세스를 실행하고 종료한다.
- 만약 노드에 장애가 발생한 경우 해당 노드에 있던 잡 리소스가 관리하던 파드는 레플리카셋 파드와 같은 방식으로 다른 노드로 다시 스케줄링된다.
- 프로세스 자체에 문제가 생긴 경우, 잡에서 컨테이너를 다시 시작할 것인지 설정 가능
- 잡은 작업이 제대로 완료되는 것이 중요한 임시 작업에 유용
apiVersion: batch/v1
kind: Job
metadata:
name: batch-job
spec:
template:
metadata:
labels:
app: batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job
- spec.restartPolicy를 이용해서 프로세스가 종료될 때 쿠버네티스가 수행할 작업을 지정할 수 있다.
기본값은 Always 이고 OnFailure, Never가 있다. 잡 파드는 지속적으로 반복되지 않으므로 OnFailure이나 Never를 명시해주어야 한다. - 잡은 두개 이상의 파드 인스턴스를 생성해 병렬 또는 순차적으로 실행할 수 있다.
- 잡 스펙에 completions, parallelism 속성을 설정해 수행한다.
- completions 는 잡 파드를 해당 숫자만큼 실행 후 모두 성공하면 성공 처리
- parallelism 은 한번에 실행할 수 있는 파드의 개수
apiVersion: batch/v1
kind: Job
metadata:
name: multi-completion-batch-job
spec:
completions: 5 # 5개 순차 실행,
template:
<template is the same as in listing 4.11>
apiVersion: batch/v1
kind: Job
metadata:
name: multi-completion-batch-job
spec:
completions: 5 # 2개씩 5개 실행, 2 2 1 이렇게 실행이된다.
parallelism: 2
template:
<same as in listing 4.11>
# 실행 중인 잡의 parallerlism 속성을 수동으로 변경 가능하다.
$ kubectl scale job multi-completion-batch-job --replicas 3
job "multi-completion-batch-job" scaled
- 잡은 activeDeadlineSeconds 속성을 설정해 파드의 실행 시간을 제한할 수 있다.
- activeDeadlineSeconds를 지나게 되면 시스템이 종료를 시도하고 잡을 실패한 것으로 표시
- spec.backoffLimit 필드를 지정해 잡이 실패할 경우 다시 실행시킬 재시도 횟수를 설정할 수 있다. 명시적으로 지정하지 않으면 기본 값은 6이다.
backoffLimit은 지수적으로 증가한다. (10초, 20초, 40초, ...) - 파드를 특정 시간 또는 지정된 간격으로 반복 실행되어야하는 경우는 어떻게 하는가?
- 쿠버네티스의 크론잡 리소스를 만들어 구성하면된다.
- 설정된 시간에 잡 리소스를 크론잡 오브젝트에 설정한 잡 템플릿에 따라 생성한다.
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: batch-job-every-fifteen-minutes
spec:
schedule: "0,15,30,45 * * * *"
jobTemplate:
spec:
template:
metadata:
labels:
app: periodic-batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job
- 크론잡 스케줄의 표현식은 이렇다.
- 분
- 시
- 일
- 월
- 요일
- 다섯가지 항목으로 주기를 설정한다.
- 예시로 0 3 * * * 는 매요일 매월 매일 AM 03:00 에 실행하라는 의미
- 요일을 나타낼때는 0이 일요일 기준, 6이 토요일
- jobTemplate에 따라 잡 리소스를 생성한다.
- 잡에서 설정한 activeDeadlineSeconds와 비슷하게 startingDeadlineSeconds 설정을 해 데드라인을 설정할 수 있다.
참고 자료
쿠버네티스 인 액션
반응형
'책, 강의' 카테고리의 다른 글
[쿠버네티스 인 액션] 5장 - 서비스: 클라이언트가 파드를 검색하고 통신을 가능하게 함 (1) | 2023.11.21 |
---|---|
[쿠버네티스 인 액션] 3장 - 쿠버네티스에서 컨테이너 실행 (1) | 2023.10.30 |
[쿠버네티스 인 액션] 2장 - 도커와 쿠버네티스 첫걸음 (1) | 2023.10.29 |
[쿠버네티스 인 액션] 1장 - 쿠버네티스 소개 (1) | 2023.10.29 |