들어가며…

현대 사회에서 웹 애플리케이션은 우리 일상에서 빠질 수 없는 중요한 서비스로 자리 잡았습니다. 소셜 미디어, 온라인 쇼핑, 금융 거래 등 우리가 사용하는 수많은 온라인 서비스들이 웹 애플리케이션을 기반으로 동작하고 있지요.

그러나 이런 웹 애플리케이션들을 개발하고 운영하는 것은 결코 간단한 일이 아닌데요, 이러한 도전적인 상황에서 등장한 쿠버네티스는 웹 애플리케이션의 배포, 관리, 확장과 같은 작업들을 간소화하고 효율화합니다.

이번 글에서는 쿠버네티스가 왜 등장하게 되었고, 어떤 특징을 가지고 있는지 함께 알아보겠습니다.

쿠버네티스의 등장 배경

웹 애플리케이션의 복잡성 증가

과거에 비해 현대의 웹 애플리케이션은 단순한 정보 제공 기능을 넘어 다양한 기능을 수행하고 있습니다. 이에 따라 웹 애플리케이션은 더욱 더 복잡해지고 있지요. 예전에는 단순한 웹 페이지들로 구성된 애플리케이션도, 현대에는 사용자 인증, 데이터베이스 연동, 보안 기능, 실시간 업데이트 등 다양한 기능들을 통합해야 하는 경우가 많습니다. 이로 인해 개발자들은 복잡한 코드와 다양한 종속성을 관리하며 애플리케이션을 구축해야 합니다.

뿐만 아니라, 다양한 기능을 제공하기 위해서는 애플리케이션을 지속적으로 업데이트하고 배포해야 하는데, 기존의 개발 및 배포 방식으로는 이에 대응하기 어려워졌습니다. 서로 다른 환경에서 실행되어야 하는 웹 애플리케이션은 환경 일관성의 부재로 인해 호환성 문제를 야기하고, 빠른 개발과 배포가 어려워지는 문제가 발생했습니다.

컨테이너 기술 도입

이러한 문제들을 해결하고자, 컨테이너 기술이 등장하게 되었습니다. 컨테이너는 애플리케이션과 그 실행에 필요한 모든 라이브러리, 설정, 종속성을 격리된 환경에 담아 패키징하는 혁신적인 방식을 제공합니다. 이를 통해 각각의 컨테이너는 독립적인 실행 환경을 가지면서 가볍고 빠르게 실행될 수 있습니다.

컨테이너는 환경 일관성과 이식성을 제공하며, MSA의 기반을 이루는데 큰 도움을 주기도 합니다. 최근 MSA의 도입으로, 이전에는 큰 단일 애플리케이션이었던 것들이 기능 단위로 세분화되고 있는 추세입니다. 이때 컨테이너는 각 서비스의 실행을 격리시켜 서로 영향을 주지 않고 운영할 수 있도록 돕습니다.

컨테이너 오케스트레이션 도구의 필요성

서비스의 수가 증가하고 다양한 환경에서 실행되어야 하는 MSA의 경우, 수동으로 많은 컨테이너를 관리하고 배포하기는 복잡한 일입니다. 이에 따라 컨테이너의 효율적인 활용과 관리를 위해 컨테이너 오케스트레이션 도구가 등장하게 되었습니다.

컨테이너 오케스트레이션은 컨테이너들을 여러 노드(서버)에 분산시키고, 컨테이너들의 상태를 모니터링하며, 필요에 따라 자동으로 컨테이너를 생성하거나 제거하여 애플리케이션을 항상 원하는 상태로 유지할 수 있도록 하는 일을 합니다. 마치 여러 악기들이 서로의 파트와 조화롭게 어우러져 아름다운 음악을 창조하는 것처럼, 컨테이너 오케스트레이션은 여러 컨테이너들이 협력하여 복잡한 애플리케이션을 원활하게 실행하고 관리하는 과정을 나타냅니다.

그동안 시장에서는 여러 컨테이너 오케스트레이션이 등장했는데, 대표적으로 Docker Swarm, Apache Mesos, Kubernetes가 있습니다. 이중에 현재 가장 널리 사용되고 컨테이너 오케스트레이션의 표준으로 자리잡은 도구가 바로 쿠버네티스입니다.

쿠버네티스란 무엇인가요?

쿠버네티스(Kubernetes)는 컨테이너 오케스트레이션 플랫폼으로, 컨테이너화된 애플리케이션의 배포, 확장 및 관리를 자동화하는 오픈소스 도구입니다. 약식으로는 K8s라고 표기하기도 하는데, 이는 "K"와 "s"와 그 사이에 있는 8글자를 나타냅니다. Google에서 개발한 Borg 시스템을 기반으로 하여, 쿠버네티스는 2014년에 공개되었고, 현재는 Cloud Native Computing Foundation(CNCF)에 의해 관리되고 있습니다.

쿠버네티스 특징

자동화된 컨테이너 배포 및 스케일링

쿠버네티스는 컨테이너 기반의 애플리케이션을 손쉽게 배포하고, 필요에 따라 자동으로 스케일링하는 기능을 제공합니다.
애플리케이션을 새로 업데이트하거나 변경 사항을 적용할 때, 쿠버네티스는 기존 버전과 새 버전을 서서히 교체하면서, 이전 버전의 컨테이너를 자동으로 중지시키고 새 버전을 시작시킵니다. 애플리케이션을 중단시키지 않고 안정적으로 업데이트할 수 있죠.
또한, 쿠버네티스는 애플리케이션의 부하가 늘어나거나 줄어들 때, 이를 감지하고 자동으로 인프라 확장 또는 축소를 수행할 수 있습니다. 이를 “오토스케일링”이라고 하는데, 이를 통해 서버 자원의 효율적인 사용과 트래픽에 따른 유연한 대응이 가능합니다.
쿠버네티스의 자동화된 컨테이너 배포 및 스케일링 기능은 개발자와 운영자의 작업을 간소화하고, 애플리케이션의 안정성과 성능을 향상시키는 데에 매우 유용합니다.

서비스 디스커버리와 로드 밸런싱

쿠버네티스는 애플리케이션을 여러 개의 컨테이너로 실행할 때, 각 컨테이너에 고유한 DNS(Domain Name System) 이름을 부여하여 “서비스”를 찾을 수 있도록 합니다. 이를 통해 동적으로 변하는 컨테이너 IP 주소와 상관없이 항상 일관된 방법으로 애플리케이션에 접근할 수 있습니다.
로드 밸런싱은 하나의 서비스에 여러 개의 컨테이너 인스턴스가 있을 때, 들어오는 요청을 이 컨테이너들 사이에 균등하게 분배하여 부하를 공평하게 분산시킵니다. 이를 통해 애플리케이션은 더 많은 사용자 또는 요청에 대해 효율적으로 대응하며, 전체적인 안정성과 성능을 향상시킬 수 있습니다.

스토리지 오케스트레이션

스토리지 오케스트레이션은 쿠버네티스에서 애플리케이션의 데이터를 관리하고 보존하기 위한 기능을 말합니다. 컨테이너는 일시적인 존재이기 때문에, 데이터를 컨테이너에 영구적으로 저장하기 어렵습니다. 하지만 쿠버네티스의 "볼륨"이라는 데이터 저장소를 사용하면, 호스트 머신의 디렉토리, 네트워크 스토리지, 클라우드 스토리지 등의 다양한 백엔드를 컨테이너에 마운트하여 데이터를 영구적으로 저장할 수 있습니다. 컨테이너가 종료되거나 재시작되더라도 데이터의 지속성을 보장할 수 있죠.

자동화된 롤아웃과 롤백

쿠버네티스는 애플리케이션의 새 버전을 롤아웃하고 문제가 발생하면 이전 버전으로 롤백하는 기능을 제공합니다. 이를 통해 애플리케이션의 업데이트를 안전하게 진행할 수 있습니다.

자동화된 빈 패킹

자동화된 빈 패킹은 쿠버네티스의 컨테이너 스케줄링 기능 중 하나로, 컨테이너를 클러스터의 노드에 효율적으로 배포하는 기능을 말합니다. 쿠버네티스는 여러 대의 컴퓨터(노드)에서 컨테이너를 실행하는데, 각 노드에는 자원(예: CPU, 메모리)이 제한적이기 때문에 컨테이너를 효율적으로 배치하는 것이 중요합니다. 이때 자동화된 빈 패킹은 컨테이너를 노드에 최대한 적절하게 배치하여 자원을 효율적으로 사용합니다.

자동복구

쿠버네티스는 애플리케이션의 안정성을 위해 자동 복구 기능을 제공합니다. 쿠버네티스는 애플리케이션을 지속적으로 모니터링하며, 어떤 노드나 컨테이너가 장애가 발생하면, 자동으로 해당 컨테이너를 복구하거나 새로운 컨테이너를 생성하여 문제를 해결합니다.

쿠버네티스 클러스터와 네임스페이스

클러스터

쿠버네티스의 단위는 클러스터입니다. 그리고 쿠버네티스 클러스터는 컨트롤 플레인(Control Plane)과 워커 노드(Worker Node)로 나누어볼 수 있습니다. 컨트롤 플레인은 클러스터의 제어를 담당하며, 워커 노드는 애플리케이션 컨테이너를 실행하고 관리하는 데 사용됩니다.

네임스페이스

하나의 클러스터 안에는 여러 네임스페이스를 만들 수 있습니다. 클러스터가 비교적 물리적인 단위라면 네임스페이스는 논리적인 격리 단위입니다. 네임스페이스를 사용하여 다수의 팀이나 프로젝트가 동일한 클러스터 내에서 자원을 분리하여 사용할 수 있습니다. 각 네임스페이스는 해당 네임스페이스 내에서만 고유한 리소스 이름을 가질 수 있으므로, 리소스 간의 충돌을 방지하고 격리된 환경을 제공합니다.

쿠버네티스 동작 원리

쿠버네티스(Kubernetes)의 이름은 그리스어로 "조타수"를 의미하는 "κυβερνήτης(kubernḗtēs)"에서 유래하였습니다. 이것은 쿠버네티스가 컨테이너화된 애플리케이션을 관리하고 운영하는 역할을 수행하는데서 유래된 이름입니다.

쿠버네티스 컴포넌트를 크게 분류하면, 컨트롤 플레인(Control Plane)과 워커 노드(Worker Node)로 나누어볼 수 있습니다. 쿠버네티스를 배를 타는 크루와 관련하여 다음과 같이 비유를 들어 보겠습니다.

컨트롤 플레인(Control Plane)은 배의 선장과 같습니다. 선장은 항해 경로를 결정하고, 목표지점에 도착하기 위한 계획을 수립합니다. 마찬가지로, 컨트롤 플레인은 클러스터의 상태를 모니터링하고, 클러스터 전체의 조작을 수행하여 원하는 상태로 유지합니다.

워커 노드(Worker Node)는 배의 선원들입니다. 선원들은 선장의 명령에 따라 필요한 작업을 수행하며, 배가 안전하고 원활하게 항해하도록 도와줍니다. 워커 노드도 마찬가지로, 컨트롤 플레인에서 전달받은 지시에 따라 컨테이너를 실행하고, 애플리케이션을 관리하며, 리소스를 적절하게 사용하여 클러스터를 운영합니다.

이렇게 생각해보면, 쿠버네티스는 바다를 항해하는 큰 배처럼 컨테이너화된 애플리케이션을 운영하고, 리소스를 관리하여 원하는 목표 지점(상태)에 도달할 수 있도록 지원한다는 의미를 더욱 쉽게 이해할 수 있습니다.

아래 쿠버네티스 공식 홈페이지에서 소개하고 있는 쿠버네티스의 컴포넌트 그림을 보며 자세히 살펴보겠습니다.

컨트롤 플레인(Control Plane)

컨트롤 플레인은 쿠버네티스 클러스터의 중앙 관리 및 제어 부분으로, 클러스터의 상태를 모니터링하고 관리하는 중요한 구성 요소들을 포함합니다. 컨트롤 플레인에 속해 있는 컴포넌트들은 다음과 같습니다.

  1. kube-apiserver:
    공식 문서에서는 kube-apiserver를 ‘쿠버네티스 컨트롤 플레인의 프론트엔드’ 라고 소개하고 있습니다. kube-apiserver는 쿠버네티스 클러스터로 들어오는 요청을 가장 앞에서 접수하는 “대문” 역할을 하죠. 쿠버네티스 명령어 도구인 kubectl을 사용해 수행되는 명령은 kube-apiserver로 전송됩니다.

  2. etcd:
    etcd는 클러스터가 동작하는 데 필요한 리소스의 구성 정보, 상태 및 명세 정보 등 모든 설정 데이터들을 key-value 형태로 저장하는 저장소입니다. api를 통해 전달받은 리소스 정보를 여기 etcd에 저장하죠. 안정적인 동작을 위해 자료를 분산해서 저장하여 쿠버네티스의 신뢰성과 안정성을 제공합니다.

  3. kube-scheduler:
    쿠버네티스 클러스터는 여러 노드로 구성되어 있고, 파드(Pod)는 여러 노드 중 특정 노드에 배치되어 동작하게 됩니다. 이때 새로 생성된 파드를 감지해 적절한 노드로 배치하는 작업을 스케줄링이라고 합니다. kube-scheduler는 이런 스케줄링을 담당하는 컴포넌트입니다. 새로운 파드를 적절하게 분산시키고, 리소스를 효율적으로 사용하여 클러스터의 성능과 안정성을 유지하는데 기여하지요.
    * 파드(Pod)는 쿠버네티스에서 가장 작은 배포 단위로서, 하나 이상의 컨테이너들을 묶어서 함께 실행하는 그룹입니다.

  4. kube-controller-manager:
    클러스터의 상태를 지속적으로 모니터링하고, 원하는 상태로 유지하기 위해 관리하는 것이 kube-controller-manager 입니다. 노드가 정상적으로 작동하는지, 파드가 의도한 복제본(replica) 개수를 유지하고 있는지, 서비스와 파드가 적절하게 연결되어 있는지 등의 역할을 하고 있습니다.

워커 노드(Worker Node)

  1. kubelet:
    kubelet(쿠블릿)은 마스터 노드로부터 받은 명령을 따라 컨테이너를 관리하고 노드 상태를 보고하는 역할을 합니다. kubectl 명령어를 사용하면, 파드를 관리하기 위해 작성하는 YAML이 kube-apiserver로 전송된 후 kubelet으로 전달됩니다. kubelet은 YAML을 통해 전달된 파드를 생성 또는 변경하고, YAML에 명시된 컨테이너가 정상적으로 실행되는지 확인하며 파드 안의 컨테이너들을 관리합니다.

  2. container runtime:
    컨테이너 런타임은 컨테이너를 시작하고 실행하는 역할을 합니다. 대표적으로 도커(docker)가 있고, 컨테이너디(containerd), 크리오(CRI-O) 등이 있습니다.

  3. kube-proxy:
    kube-proxy는 쿠버네티스 클러스터 내부에서 네트워크 요청을 전달하는 역할을 합니다. 파드 IP는 파드가 배포될 때마다 매번 변하지만, kube-proxy가 이 파드에 접근할 수 있는 방법을 갱신하고, 서비스 오브젝트는 이 정보를 통해 파드가 외부에서 접근할 수 있는 경로를 제공합니다.

마치며…

지금까지 쿠버네티스에 대해 함께 자세히 알아보았습니다. 이 글을 통해 쿠버네티스의 정확한 의미와 그 중요성을 명확하게 이해하시는 데 도움이 되었기를 바랍니다.

쿠버네티스는 현대적인 애플리케이션 개발과 배포를 위한 필수적인 도구로, 이제 기본적인 개념과 동작 원리를 잘 숙지하셨을 것입니다. 이 지식은 여러분이 복잡한 클러스터를 보다 효율적으로 관리하고, 애플리케이션을 원할하게 실행하며 확장하는 데 큰 도움이 될 것입니다.

더욱이, 쿠버네티스는 지속적으로 발전하며 새로운 기능과 개선 사항이 추가되고 있습니다. 커뮤니티에서는 다양한 학습 자료와 지원 리소스를 제공하고 있으므로, 여러분은 이를 활용하여 보다 심도 있는 학습을 진행할 수 있을 것입니다. 이론뿐만 아니라 실제 운영 경험을 통해 더 나은 애플리케이션 배포와 관리를 실현해보시기 바랍니다. 함께 해주셔서 감사합니다!

Camellia

참고 사이트 및 도서

https://kubernetes.io/ko/docs/concepts/overview/
https://www.samsungsds.com/kr/insights/220222_kubernetes1.html
https://www.sharedit.co.kr/posts/12040
https://www.whatap.io/ko/blog/142/

조훈, 심근우, 문성주 저, 컨테이너 인프라 환경 구축을 위한 쿠버네티스/도커 (길벗, 2021)
정원천, 홍석용, 정경록, 공용준 저, 쿠버네티스 입문 (동양북스, 2020)