[Kubernetes in Action] Introducing Kubernetes

2021. 9. 21. 16:29DevOps/Docker & Kubernetes

Kubernetes in Action 2nd Edition 을 정리한 글입니다.

 

 

Overview

Introduction Chapter인 만큼, Kubernetes 이전의 서비스 구조와 배포방법과 그에 따른 쿠버네티스의 필요성을 안내합니다. 그리고 쿠버네티스의 구성, 쿠버네티스를 알기 위해 반드시 알아야 하는 리눅스 컨테이너 시스템에 대해 설명하며, 리눅스 컨테이너 시스템을 활용한 대표적인 컨테이너 플랫폼인 도커(Docker)에 대해 살펴봅니다.

 

 

Moving from monolithic apps to microservices

요즘, 거대한 monolithic application은 각각 그 도메인별로 나누어 작고 독립적인 단위로 배포가 됩니다. 이렇게 작게 나누어져 독립적으로 배포되고 기능하는 컴포넌트들을 마이크로서비스(microservice)라고 합니다. 뒤에서 조금 더 자세하게 살펴보겠지만, 쿠버네티스는 이렇게 하나의 커다란 애플리케이션(기능)을 마이크로서비스 단위로 나누어서 각각의 서비스들을 원하는 만큼 자주, 편리하게 배포하고 유지하는 방법을 제공합니다.

 

 

많은 레거시 애플리케이션들이, 그리고 새롭게 개발되는 여러 애플리케이션들이 Monolithic Application이 아닌 MicroService Application 구조를 선택하고 있는데 그 이유는 다음과 같습니다.

 

  1. 애플리케이션의 기능 일부만의 수정으로 인해 전체 애플리케이션을 다시 배포할 필요가 없다. 해당 기능이 구현되어 있는 도메인의 서비스만 다시 배포하면 된다.
  2. 서버의 요청량이 많아져 부하가 높아졌을 때, 이를 관리하기 위해서 전체 서버를 Scale up하거나 Scale out 할 필요가 없습니다. 요청이 많은 서버 노드들만 Scale out하는 식으로 간편하고 효율적인 대응이 가능하다.
  3. 각각의 마이크로서비스는 공통된 인터페이스(e.g HTTP)로 통신하기 떄문에 모든 서비스들이 공통된 언어(C, Java, Javascript...)로 개발될 필요가 없다. 해당 개발을 맡은 개발자나, 도메인의 특성에 따라 가장 적합한 언어로 개발한 뒤에 인터페이스만 맞춰주면 된다.

 

쿠버네티스는 컨테이너를 관리하는 컨테이너 오케스트레이션(Container Orchestration)을 제공하기 때문에 이런 다양한 마이크로 서비스의 장점을 살리면서 편리하게 각각의 컨테이너들을 관리할 수 있습니다.

 

 

Introducing container technologies

위에서 살펴본 것처럼, 마이크로 서비스를 구성하는 여러 애플리케이션 (e.g 검색 서버, 동영상 서버, 이미지 서버, 어카운트 서버, 멤버쉽 서버 등등)들은 각각 다른 언어로 개발될 수 있으며, 같은 언어로 개발되더라도 서로 다른 버전의 라이브러리를 사용해서 개발 될 수 있습니다. 따라서 각각의 서비스들을 같은 서버 노드(Worker)에 올려서 실행할 때는 (e.g 검색 서버와 동영상 서버를 같은 클라우드 컴퓨팅 노드에서 실행) 환경의 격리가 필수적입니다. 

 

 

 

Virtual Machine(VM)

 

환경을 격리하는 방법중 의 하나로 VM(Virtual Machine. 가상 머신)을 사용하는 방법이 있습니다. 가상 머신은 물리적 컴퓨팅 머신(호스트)의 Host OS위에 Hypervisor 프로세스를 실행하고 그 위에 Guest OS를 실행해서 완전히 격리된 환경을 제공해줍니다. Mac OS에서 ActiveX를 사용하기 위해 MacOS위에 Window OS를 설치해서 internet explorer를 사용하는 경우에, 이런 방법을 사용하게 됩니다.

 

 

VM을 사용할 경우, Guest OS(Host OS위에 설치된 OS)위에서 돌아가는 서비스(위의 예에서의 internet explorer)는 Guest OS에 자체적으로 할당된 커널 리소스를 사용하게 되며 하이퍼 바이저를 통해 실제 Host OS의 CPU를 사용하여 동작하게 됩니다.

 

Applications running inside those VMs perform system calls to the guest OS’ kernel in the VM, and the kernel then performs x86 instructions on the host’s physical CPU through the hypervisor.

 

 

이 방식은 Guest OS위에서 돌아가는 프로세스들이 Host OS의 커널이 아닌 Guest OS의 커널을 사용해서 동작하므로 완전히 격리된 환경을 제공해주지만, Guest 커널을 위한 리소스가 추가적으로 들어가야 하기 때문에 아래에서 설명할 Linux Container 방식보다 훨씬 더 많은 물리적 리소스를 사용하게 됩니다. 또한, 각각의 VM은 완전히 격리되어 있기 때문에 공통된 설정을 적용하기가 어려우므로 각각의 환경을 따로 관리해주어야 한다는 단점이 있습니다. 

 

 

하이퍼바이저는 가상 머신(Virtual Machine, VM)을 생성하고 구동하는 소프트웨어입니다. 가상 머신 모니터(Virtual Machine Monitor, VMM)라고도 불리는 하이퍼바이저는 하이퍼바이저 운영 체제와 가상 머신의 리소스를 분리해 VM의 생성과 관리를 지원합니다. 하이퍼바이저로 사용되는 물리 하드웨어를 호스트라고 하며 리소스를 사용하는 여러 VM을 게스트라고 합니다.

 

 

 Linux Container

 

리눅스 컨테이너 기술은 위의 VM방식과는 다른 방법으로 격리된 환경을 지원합니다.(컨테이너는 격리된 실행 환경을 의미합니다.) VM방식과는 다르게 Host OS 안에서 동작하며, 따라서 서로 다른 컨테이너들이 각각 다른 OS의 커널을 사용하는 것이 아닌 Host OS의 커널을 사용합니다. 하지만 여전히 각 컨테이너들은 격리된 별도의 환경에서 실행되는 것을 보장할 수 있으며, 이는 리눅스에서 제공하는 다음의 두 가지 메커니즘으로 인해서 가능하게 됩니다.

 

  • Linux Namespaces: 리눅스 시스템은 기본적으로 하나의 네임스페이스를 가지지만, 사용자가 추가적인 네임스페이스를 사용하는 것을 지원합니다. 새로운 프로세스를 시작할 때 사용자는 특정 프로세스가 특정한 네임스페이스 안에서 구동될 수 있도록 지정할 수 있으며, 해당 프로세스는 자신이 속한 네임스페이스의 리소스만을 바라보게 됩니다. 즉 "격리"가 가능한 것입니다.
  • Linux Control Groups: 리눅스 시스템은 특정 컨테이너가 사용할 수 있는 리소스를 "제한"할 수 있도록 허용하므로써 다른 컨테이너의 리소스를 접근하거나 사용하는 것을 막아줍니다. 즉 특정 컨테이너의 "격리"와 "제한"을 줄 수 있도록 하는 것입니다.

 

리눅스 컨테이너 기술은 위 두가지 메커니즘을 통해서 각각의 컨테이너가 독립된 환경에서 구동되는 것을 보장하며, VM방식과는 다르게 Host OS위에서 동작하기 때문에 다른 커널들을 위한 리소스, 하이퍼바이저를 위한 리소스 등이 필요하지 않게 됩니다. 따라서 훨씬더 가볍고 부담없이(lightweighted) 동작이 가능합니다. 도커가 바로 이 리눅스 컨테이너 위에서 동작하는 플랫폼입니다.

 

 

*VM과는 다르게 Container 방식은 동일한 Host OS의 커널을 사용하기 때문에 특정 컨테이너가 다른 버전의 커널을 이용하거나, 다른 시스템 아키텍쳐 (e.g x86, ARM)를 사용할 경우 제대로 동작하지 않을 수 있습니다.

 

 

Introducing Docker container platform

기본적으로 쿠버네티스에 대한 글이므로 도커 컨테이너에 대한 자세한 설명은 다루지 않도록 하겠습니다. 이후 쿠버네티스와 마이크로서비스를 이해하기 위해 필요한 부분만 다루도록 하겠습니다.

 

 

Docker Images

도커 컨테이너는 도커 이미지가 구동되는 환경을 의미하며, 도커 이미지는 여러 이미지들의 레이어로 구성됩니다. 도커 컨테이너를 사용해서 여러 개의 애플리케이션을 컨테이너에 배포하면, 아래 그림에서 보이는 것과 같이 서로 다른 컨테이너에서 공통된 Binaries & Libraries들에 접근해서 사용할 수 있는데, 이는 도커 이미지의 특징과, 도커 시스템이 이미지를 관리하는 독특한 방법 때문입니다.

 

도커 컨테이너는 "도커 이미지가 실행되는 환경"을 의미하며 도커 이미지는 "애플리케이션을 사용하기 위한 환경들의 기술"을 의미합니다. 예를 들어서 다음 2가지 웹서버가 있다고 가정해보겠습니다.

 

  • A: node14, git, react 사용
  • B: node14, git, angular 사용

 

애플리케이션 A와 B를 실행하기 위해서 도커는 Dockerfile에 기술된 대로 A, B의 이미지를 만듭니다. (예를 들면 아래와 같은 포맷으로)

### Example
FROM node:fermium-alpine AS builder

RUN apk --no-cache add git

RUN yarn install --frozen-lockfile \
    && yarn cache clean

RUN yarn build

EXPOSE 3000
CMD ["sh", "yarn start"]​

 

이때 도커의 이미지는 여러 개의 레이어로 구성되며, 위의 예제에서 node layer(Layer 1), git layer(Layer 2), dependency install layer(Layer3), build layer(Layer4) 등으로 구성됩니다. 도커 이미지의 특성에 따라 각각의 이미지 레이어는 Read-only로 구성되며, 빌더의 설정에 따라 캐싱되어 재사용이 가능합니다. 이러한 이유들로 인해서 애플리케이션 A와 B의 이미지는 Layer 1과 Layer 2를 공유하게 되며, 이는 시스템 자원의 리소스를 아끼는 결과를 가져옵니다. 

 

 

결과적으로 도커 컨테이너 시스템은 Host OS에서 별도의 hypervisor나 Guest OS없이 리눅스 컨테이너 기술들을 사용하며, 도커 시스템이 가진 독특한 이미지 레이어 구성방식으로 인해 각각의 컨테이너를 격리된 환경에서 실행하면서도, 자원 낭비를 최소화하고 재사용 효율을 높이는 방법을 제공합니다. 

 

 

 

Introducing Kubernetes

쿠버네티스는 이렇게 도커와 같은 컨테이너 시스템 안에서 수많은 마이크로서비스 애플리케이션들이 제대로 구동될 수 있도록 관리하는 방법을 제공합니다. 간단한 동작방식은 다음과 같습니다.

 

개발자가 애플리케이션이 어떻게 구성되어야 하는지를 쿠버네티스 시스템에게 알려줍니다. 예를 들어서 1번 애플리케이션은 3개의 컨테이너로 구성되고, 2번 애플리케이션은 10개... , 3번과 4번은 같은 컨테이너 안에서 동작해야 하고... 

 

그러면 하나의 마스터 노드와 여러 개의 워커 노드들로 구성된 쿠버네티스 시스템은 이 명세대로 애플리케이션이 구동되는 것을 보장해줍니다. 하나의 컨테이너가 예상치 못한 이유로 죽었다면, 알아서 새로운 노드를 생성하고, 죽은 노드를 제거하는 식으로 작동하는 것입니다. 

 

Understanding the architecture of a Kubernetes cluster

쿠버네티스 시스템은 위에서 살펴보았든 마스터 노드(master node)와 워커 노드(worker node)로 구성됩니다.

 

마스터 노드

마스터 노드는 컨트롤 플레인(Kubernetes Control Plane)을 통해 쿠버네티스 시스템을 통제하고 관리합니다. 컨트롤 플레인은 워커노드의 클러스터를 관리하고 동작하도록 합니다. 다음의 4가지 요소로 구성되어 있습니다.

  • Kubernetes Api Server: 관리자와 다른 컨트롤 플레인 컴포넌트들이 Communication하는 곳입니다.
  • Scheduler: 워커노드를 할당하는 등 애플리케이션을 스케줄링하는 역할을 담당합니다.
  • Controller Manager: 클러스터 레벨의 함수들을 실행합니다. 컴포넌트 복제, 워커노트 추적, 워커노드 실패 에러 처리등의 기능을 담당합니다.
  • etcd: 클러스터 설정을 저장하는 곳입니다. 

 

워커 노드

워커 노드는 컨테이너화된 애플리케이션이 실제로 구동되는 곳입니다. 다음의 컴포넌트들을 통해 구동, 모니터링, 서비스를 제공합니다.

  • Docker (or other Container Runtime): 컨테이너를 구동합니다. 
  • Kubelet: API server와 워커노드 사이의 통신을 담당합니다. 
  • Kubernetes Service Proxy(kube-proxy): 네트워크 트래픽을 로드밸런싱 해줍니다. 

 

 

반응형