Liveness 살아있나??를 확인한다.

Readiness 준비됐나??를 확인한다.

 

Liveness 

살아있나??를 왜 확인할까

 

Kubernetes에서 한 개 이상의 Container를 포함하는 최소단위로 Pod라고 한다.

k8s의 각노드에는 kubelet이라는 노드별 관리자가 있고 kubelet은 각 Pod별로 설정된 값에 따라 내부의 Container를 관리한다.

따라서 Container에 문제가 생긴다면 다시 시작하여 해결한다.

그런데

정상상태임을 확인하고 문제로 감지 하는 것이 완벽할 수는 없다.

예를 들면, Java 어플리케이션의 경우 OutOfMemory에러가 발생하는 경우 JVM 프로세스는 계속 실행 중 일 수 있다. 또는 무한루프, 무한대기와 같은 교착 상태가 발생 했을 때

이를 감지 하지 못하고 따라서 Container의 재시작이 일어나지 않아 어플리케이션에 문제가 지속될 수 있다.

 

장애에 대한 케이스는 너무나 무궁무진하고 우리 모두 각자의 케이스에 맞는 대응, 대비가 필요하다.

그래서 추가적으로 이 Pod가 잘 돌아 가고 있는지를 체크하는 kubernetes의 api가 있는데 그것이 Liveness 이다.

 

[예제 추가 예정]

 

Readiness 

준비됐나를 왜 확인할까

뭔가 막연하다. 예를 들어 보면,

Pod의 Container가 image를 통해 올라가면 끝이 아니다.

만약 서버를 위한 Pod라면 프로그램들이 구동되고 하기 까지 어느 정도의 시간이 걸릴  것이다.

 

kubernetes에서 yaml파일을 통해 pod를 생성하고 조회를 했다.

상태가 1/1로 올라와있음을 확인했지만

당장 서버를 접속하거나 했을때 바로 되지 않고 잠시 기다려야 했던 상황이 있었을 것이다.

 

이럴 때 Readiness를 통해서 준비가 완료 되었는지를 확인하고

서비스에 사용할 수 있도록 하는 것이다.

보통 준비 완료를 확인하는 파일의 유무를 확인한다.

Readiness는 지속적으로 파일의 유무를 확인할 것이고,

파일이 없는 경우에는 해당 Container에 대한 service의 endpoint를 제거하는 것으로 새 트래픽을 받을 수 없게 한다.

 

Readiness는 올라가 있는 Container에 대한 지속적인 체크이다. Liveness와 같이 container를 재시작 하는 방식은 아니다. 단지 client와의 연결을 끊는다고 보면 될 것 같다.

 

[예제 추가 예정]

Kubernetes에서의 배포는 아무래도 기존과는 조금 다르다.

왜 필요한지 어떤식으로 해야하는지에 대해

약간의 서론과 함께 시작하고

대표적인 배포 방법을 이론적으로 기록하는 글이 되겠다.

 

일반 배포랑 어떻게 다를까?

 

가장 먼저 컨테이너 환경의 시작은

Container Image 파일에서 시작된다. 중요한것은 Image는 변경이 되지 않는다는 점이다.

이미 실행되고 있는 Image 변경은 불가능하다.

새로운 이미지를 만들고 이를 통해 새 컨테이너를 시작해야하는 점을 베이스로 가지고 있자.

 

Kubernetes의 최소 단위는 Pod 라고 한다.

Kubernetes는 Container Orchestration 도구이다.

즉 관리의 최소 단위라고 생각하면 될 것 같다.

 

목적을 위해 하나의 기능으로 컨테이너 이미지를 만들었다면

kubernetes에서는 이 이미지를 관리하는 용도의 Pod라는 기본 요소를 제공한다.

1개의 Pod는 꼭 한개가 아닌, 여러개의 container를 관리할 수 있다.

 

Pod는 스케줄링, 배포의 최소 단위이다.

컨테이너를 실행하기 위해서는 Pod를 통해야 하며 Pod가 죽으면 해당 Pod에게 관리 되는 컨테이너도 사라진다.

 

그렇다면 수정된 사항, 업드레이드 등의 새로운 버전으로의 배포는 어떻게 진행이 될까.

 

kubernetes의 배포 기본 절차

- 이전 버전 파드 제거

- 새로운 버전 파드 생성

- 생성된 파드 상태 확인

- 파드 생성 실패 시 기존 Pod로 롤백

 

가장 쉬운방법은 수동 방법이다.

kubectl delete pod {pod이름}
kubectl apply -f {변경된 image를 사용하는 pod}.yaml
kubectl describe pods {pod이름}

하지만 시스템이 복잡해지고 관리되어야할 pod가 많아짐에 따라 수동방식은 부담이 된다.

 

또한 이전 서비스와 새로운 서비스 사이의 다운타임과 같이

서비스의 배포 방식에 따라 다양한 배포 시나리오를 고려해야 한다.

 

k8s에는 디플로이먼트(deployment)라는 자원이 있다.

이 디플로이먼트를 통해

Pod들의 업그레이드 부터 롤백까지의 절차를 반복,자동화 할 수 있게 된다.

 

서론이 너무 길었다...

이제 원래 정리하고 싶었던 대표적인 배포 시나리오를 적어본다.

 

1. 롤링 배포

우선 kubectl 커맨드를 통한 롤링배포 방식은 더 이상 지원되지 않는다.

deployment의 yaml파일에 원하는 배포방식을 설정하고 적용한다.

 

장점으로는 무중단(zero downtime)이다. 어떻게 무중단이 될까?

업그레이드 Pod를 1개 만들고 이전버전 Pod를 1개 내린다. 이렇게 한세트씩 진행하는 방식이라고 보면된다.

때문에 기본적으로 대상 Pod는 replicas 2개 이상이 되어야 한다.

 

주의 사항

무중단을 제공하는 점에서 오는 문제이다.

이전 버전과 새 버전의 컨테이너가 동시에 존재하고 서비스된다는 점이다.

두 버전 차이로 인해 발생하게 되는 상황을 고려하고 배포를 진행해야 한다.

 

버전차이에 대한 문제는 당연하게도 무중단방식으로 배포하지 않으면 된다.

디플로이먼트의 yaml 파일에 설정값을 통해 이전버전 Pod를 다 죽이고 새 버전으로 올리게 할 수 있다.

 

2. 블루-그린 배포

블루는 이전버전, 그린은 새 버전을 뜻한다.

방법은 간단하다.

기존에 사용중인 deployment는 그대로 서비스 중인 상태에서

새 이미지를 사용한 다른 deployment를 만든다.

새 deployment가 문제없이 올라왔음을 확인하면

기존 사용사던 서비스가 새 deployment로 트래픽을 돌리는 것이다.

간단하게 service selector를 새 deployment로 변경하면 된다.

 

주의 사항

일시적이지만 2개의 deployment가 동시에 올라와 있는 상태라는 점에서 

그동안 어플리케이션 리소스는 2배가 사용된다는 점이 있다.

 

3. 카나리아 배포

카나리아는 새다. 유독 가스에 민감한 새다. 옛날에 광산에서 작은 새를 통해 미리 감지하는 목적으로 썼다고 한다.

즉, 미리 위험을 감지하기 위한 소수의 Pod를 생성하는 방법이다.

새 이미지를 사용한 deployment를 만든다. replicas는 시범 용으로 작은 수를 설정한다.

그리고 서비스를 통해 일부 트래픽을 작은 deployment로 흘리도록 하는 방법이다.

이 후 신규 버전이 정상임을 확인한다면 replica를 늘리고 기존 pod를 0으로 줄인다.

트래픽을 분산하는데 랜덤으로 하기도 특정 사용자로 분류 하기도 한다.

 

Kubernetes 에서 잘돌아가던 몇몇 Pod 에 문제가 생겼다

 

Pod의 상태는 Pending 이 걸려있고

Pod 들을 죽였다 다시 살려봐도 같은 증상을 보였다.

 

Deployment, Statefulset 과 같은 Controller를 통해 생성된 pod의 경우에는

Pod를 delete하면 자동 생성 되지도 않는 경우도 보였다.

 

문제가 생긴 pod들을 describe해보니

taint에 관련된 문제였다.

 

shell> kubectl describe pod "Pod이름"
Events:
  Type          Reason             Age     From               Message
  ----            ------               ----     ----               -------
  Warning  FailedScheduling    40s     ~~~      0/1 nodes are available: 1 node(s) had taint node.kubernetes.io/disk-pressure:NoSchedule, that the pod didn't tolerate.

빨간색의 node.kubernetes.io/disk-pressure:NoSchedule

로 보아 disk-pressure 디스크 용량이 부족하다는 것이다.

 

taint, toleration 의 문제의 경우 

>> kubernetes taint nodes "노드이름" node.kubernetes.io/disk-pressure:NoSchedule-

 

위의 커맨드 처럼 해당 taint를 빼면 문제가 해결되는 경우 (커맨드 끝의 " - "(대쉬)까지 넣어준다.)

도 있지만 

 

disk-pressure의 경우엔 taint 제거로도 해결이 되지 않았다.

 

해결가능한

첫번째 방법은

디스크를 정리하는 것이다.

특히 Docker image 파일들이 많이 쌓여 생기는 경우가 보이는데

정리를 해주면 빠른 해결이 가능하다.

관련 커맨드
도커 이미지 리스트 docker images
도커 이미지 제거 docker rmi {이미지 id}
도커 컨테이너 조회 docker ps / docker ps -a
   

 

두번째 방법은

데이터 디렉토리를 바꿔주는 것이다.(더 여유있는 용량을 마운트한 디렉토리)

앞으로의 관리적인 측면을 보자면 이 방법이 더 좋을 것 같다.

 

도커의 기본 디렉토리는 /var/lib/docker 이다.

이 기본 디렉토리를 바꾸는 방법은

# /lib/systemd/system/docker.service 파일 수정

>> sudo vi /lib/systemd/system/docker.service

위의 파일에서

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

를 찾아서

--data-root={원하는 디렉토리}

를 추가하고 저장한다. 아래 예시

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --data-root={원하는 디렉토리}

 

그리고 docker를 재시작하면 적용이 된다.

>> sudo service docker restart (우분투) 

 

적용이 되었는지를 확인하는 가장 간단한 방법은

docker image를 새로 받아보고,

기존과의 용량 변화를 확인하는 것이다.

 

#스토리지 확인

df -h

#특정 디렉토리의 할당마운트와 사이즈 확인

df -h {디렉토리}

 

#예시

df -h /data

df -h /var

 

이미지 pull

docker pull {image이름:tag}

Micro
                   작은
Service
                   서비스
Architecture
                   설계방식

 

말그대로 아주 작은 서비스를 말한다.
큰 몸뚱이 하나를 잘게 쪼개는 것이다. 
단순하게 잘게 쪼개기만 하는것은 아니다.
각각 쪼개진 것들이 혼자서도 잘 돌아 가야한다.

모놀리틱(Monolithic) 아키텍처라고 하는게 기존 큰 몸뚱이 구조라고 할 수 있다.
이 구조에서는 보통 기능들이 서로서로 얽혀있어 결합력이 뛰어나기 때문에
로직,코드 등 무엇인가가 바뀐다면? 그에 영향을 받는것이 많아지게 된다.
당연히 몸뚱이가 크면 클수록 복잡성이 더 커질 것이고,
이 말은 작은 기능하나 추가하는 것도 어려운 상황이 될 수도 있다는 것이다.

잘 만들어진 마이크로 서비스 아키텍처에서는 어떨까?
앞에서 말한것처럼 각 쪼개진 서비스들은 혼자서 잘 돌아 간다는 것이 중요하다.
애초부터 다른 서비스 상관없이 잘 돌아가는 구조로 만들어져 있다면
어떤 기능이 추가되더라도 그 대상 서비스만 영향을 미치게 될 것이다.

먹는걸로 예를 들어볼까

----- 모놀리틱 아키텍처 식당 -----
코스가 나오는 식당이라고 해보겠다.

코스는
    에피타이저
    메인
    디저트
    음료
4개의 구성으로 되어있다.
하나의 코스안에 각 메뉴의 맛이 서로 얽혀 있는 구조.

 
코스의 모든 메뉴는 다 따로 노는 것이 아니다 쉐프가 원하는 맛의 흐름이 있다.
(헛소리 죄송합니다. 예를 들다보니..)

----- 마이크로 서비스 아키텍처 식당 -----
에피타이저 가게
메인메뉴 가게
디저트 가게
음료 가게

각각의 가게가 따로 잘 돌아간다.

 

개발자로 일하기 시작한지 만 3년이 조금 더 넘었다.

 

빅데이터에 꽂혀서 취업을 헤매다 좋은 회사에서 함께하고 있다.

많이 많이 배우는 중이다.

 

몇달전 MSA 프로젝트에 참여할 기회가 생겼고, 

나름 열심히 준비했고

현재 프로젝트 진행중에도 배울껀 산더미라는걸 느끼고 있다.

 

MSA는 굉장히 어렵다.

공부했던 것들 다시 봐야할 일이 많고

하면서도 내 머릿속에서 정리가 안되는 것 같다.

 

그래서

지난 3년넘도록 생각했던 블로그 좀 해야지해야지 생각하던걸

 

드디어 시작해본다.

 

 

+ Recent posts