왜 K8S?
[Kubernetes] 마이크로서비스 애플리케이션의 분할과 확장에 따른 인프라 관리 에서도 언급했듯이, 기존의 모놀리스 애플리케이션에서 마이크로서비스로 변함에 따라 데브옵스의 중요성은 더욱 두각되고 있습니다. 시스템의 배포 가능한 애플리케이션 구성 요소의 수가 많아짐에 따라 모든 구성 요소의 관리가 더 어려워지고있죠. 구글은 10년 동안 보그와 오메가를 비밀로 유지하다가 오픈소스 시스템인 쿠버네티스를 출시하게 됩니다.
쿠버네티스의 메인기능
쿠버네티스는 리눅스 컨테이너의 기능에 의존해 애플리케이션의 내부 세부 상항을 알 필요없이, 각 호스트에 애플리케이션을 수동으로 배포하지 않고도 여러 애플리케이션을 실행할 수 있게합니다. 애플리케이션은 컨테이너에서 실행되므로 동일한 서버에서 실행되는 다른 애플리케이션에 영향을 미치지 않습니다.
마치 클러스터 운영체제와 같다
쿠버네티스는 클러스터의 운영체제로 이해하면 쉽습니다. 서비스 디스커버리(서비스 보존), 스케일링, 로드밸런싱, 자가 치유, 리더 선출 등의 다양한 기능을 제공받을 수 있습니다.
쿠버네티스 클러스터의 아키텍처
지금부터 쿠버네티스 클러스터가 어떻게 구성돼있는지 자세히 살펴봅시다. 쿠버네티스 클러스터는 2종류의 여러 노드로 구성되어 있습니다.
마스터 & 워커 노드
- 마스터 노드 : 전체 쿠버네티스 시스템을 제어하고 관리하는 쿠버네티스 컨트롤 플레인을 실행합니다.
- 워커 노드 : 실제 배포되는 컨테이너 애플리케이션을 실행합니다.
위와같은 두 종류의 노드의 구성요소를 자세히 살펴보면 아래와 같습니다. 이들에 대해서도 알아봅시다.
컨트롤 플레인(Control Plane)
컨트롤 플레인은 클러스터(Cluster)를 제어하고 작동시킵니다. 하나의 마스터 노드에서 실행하거나 여러 노드로 분할되고 복재돼 고가용성을 보장할 수 있는 여러 구성 요소로 구성됩니다. 그에 대한 구성요소는 다음과 같습니다.
- 쿠버네티스 API 서버 : 사용자, 컨트롤 플레인 구성요소와 통신합니다.
- 스캐줄러 : 애플리케이션의 배포를 담당합니다.
- 컨트롤러 매너저 : 구성요소 복제본, 워커노드 추적, 노드 장애처리와 같은 클러스터단의 기능을 수행합니다.
- Etcd : 클러스터 구성을 저장하는 분산 데이터 저장소입니다.
워커 노드
워커 노드는 컨테이너화된 애플리케이션을 실행하는 시스템입니다. 애플리케이션을 실행하고 모너터링하며 애플리케이션에 서비스를 제공하는 작업은 다음 구성요소들에 의해 수행됩니다.
- 컨테이너 런타임 : 컨테이너를 실행하는 도커, rkt 등이 해당됩니다.
- Kubelet : API 서버와 통신하고 노드의 컨테이너를 관리합니다.
- kube-proxy : 로드밸런싱 역할을 수행하는 쿠버네티스 서비스 프록시입니다.
애플리케이션 실행 메커니즘
디스크립션
애플리케이션을 실행하려면, 애플리케이션을 이미지로 패키징하고 이미지 레지스트리 (ex. DockerHub) 에 푸시하고 쿠버네티스 API 서버에다 애플리케이션 디스크립션을 게시해야 합니다. 게시하면 API 서버는 작성된 디스크립션 내용에 기반하여 컨테이너를 실행하고 인프라 환경을 구축합니다.
이 디스크립션에는 컨테이너 이미지, 애플리케이션 구성요소가 포함된 이미지, 해당 구성요소들이 서로 통신하는 방법, 동일 서버에 함께 배치되야하는 구성요소와 같은 정보가 포함됩니다. 추가적으로 실행할 각 구성 요소의 복제본 수도 지정할 수도 있습니다.
아키텍처와 애플리케이션 실행 메커니즘
API 서버가 애플리케이션 디스크립션을 처리할 때 스케줄러는 각 컨테이너에 필요한 리소스를 계산하고, 각 노드에 할당되지 않은 리소스를 기반으로 사용 가능한 워커 노드에 지정된 컨테이너를 할당합니다. 그 다음 해당 노드의 Kubelet 은 컨테이너 런타임(ex. 도커) 에 필요한 컨테이너 이미지를 가져와 컨테이너를 실행하도록 지시합니다.
위 예시를 보면 애플리케이션 디스크립터는 3개 세트(파드)로 그룹화된 4개의 컨테이너를 가지고 있습니다. 디스크립터에서 2개의 파드는 각각 하나의 컨테이너만 가지고, 마지막 파드는 2개의 컨테이너가 있습니다. 즉, 2개의 컨테이너를 함께 배치해야하며 서로 격리해서는 안됩니다. 또 파드 옆에는 실행해야하는 각 파드의 복제본 수도 지정되어 있습니다. 디스크립터를 쿠버네티스에 제출 후 각 파드의 지정된 복제본 수를 사용가능한 워커노드로 할당하는 방식입니다.
실행된 컨테이너 유지하기
애플리케이션이 실행되면 쿠버네티스는 애플리케이션의 배포 상태가 사용자가 제공한 디스크립션과 일치하는지 지속적으로 확인합니다. 예를들어 항상 4개의 인스턴스를 실행하도록 디스크립션에 지정했다면 항상 정확히 4개의 인스턴스가 실행되도록 합니다.
복제본 수 스캐일링
애플리케이션이 실행되는 동안 복제본 수를 늘릴지 줄일지 결정할 수 있습니다. 또는 최적의 복제본 수를 결정하는 작업을 쿠버네티스에 맡길 수도 있죠.
로드밸런싱
쿠버네티스는 클러스터 안에서 컨테이너를 이동시킬 수도 있다고 했었습니다. 애플리케이션 컨테이너가 이동이 어떻게 찾을 수 있을까요? 이는 kube-proxy 가 제공해주는 로드밸런싱 기능으로 해결됩니다. 하나의 고정 IP 주소로 모든 컨테이너라 로드밸런싱 되도록하며, 해당 IP 주소로 클러스터에서 실행중인 모든 애플리케이션을 노출시키는 방식입니다.
쿠버네티스의 강점
애플리케이션 배포의 단순화
쿠버네티스는 모든 워커 노드를 하나의 배포 플랫폼으로 제공합니다. 모든 노드는 이제 애플리케이션이 해당 노드를 사용하기를 기다리는 리소스 입장이 되었으며, 개발자는 애플리케이션이 어느 서버에서 실행 중인지 신경쓰지 않아도 됩니다.
상태확인 및 자가치유
쿠버네티스는 애플리케이견 구성요소와 애플리케이션이 구동중인 노드를 모니터링하다가 노드에 장애가 발생시 자동으로 애플리케이션을 다른 노드로 스캐줄링합니다. 이로써 애플리케이션을 재배치하는 대신 즉시 노드 자체를 수정해 사용 가능한 하드웨어 리소스 풀에 반환하는데 집중할 수 있습니다.
오토 스캐일링
급격한 부하 증가시 각 애플리케이션에서 사용하는 리소르를 모니터링하고, 각 애플리케이션의 실행중인 인스턴스 수를 계속 조정하도록 지시할 수 있습니다. 즉, 배포된 애플리케이션의 부하에 따라 전체 클러스터 크기를 자동으로 확장 또는 축소할 수 있습니다.
K8S가 개발자에게도 제공하는 이점이 있을까?
애플리케이션이 개발과 프로덕션 환경이 모두 동일한 환경에서 실행된다는 사실로 돌아가보면 버그가 발견됐을 때 큰 효과가 있습니다. 버그를 해결하고 수정해야하는 개발자의 작업이 줄어들죠.
또한 새로운 버전의 애플리케이션을 출시할 때 쿠버네티스가 새로운 버전이 잘못됐는지 자동으로 감지하고 즉시 롤아웃을 중지하기 때문에, 개발자들의 신뢰성을 증사킬 수 있죠. 이로 매번 버전 업데이트를 자주 할 수 있게되고, 지속적인 전달(CD) 작업 속도가 빨라져서 개발팀과 운영팀 모두에게 도움이 됩니다.