최근 IT 업계의 개발자나 운영자라면 쿠버네티스를 직접 사용하고 있거나, 사용하지 않더라도 쿠버네티스라는 단어를 한번 정도는 들어보았을텐데요. 오늘은 쿠버네티스가 왜 등장하게 되었고, 어떤 특징을 가지고 있는지 간단히 알아보겠습니다.
온프레미스 환경에서 새로운 웹 기반 서비스를 배포한다고 가정해 보겠습니다. 3-Tier 아키텍처 구성을 위해 각 용도에 맞는 서버 머신을 준비한 후에 데이터베이스, 애플리케이션 서버, 웹서버 소프트웨어를 각각 설치합니다. 설치가 끝나면 각 Tier 마다 소프트웨어의 상세 설정을 변경합니다. 만약 개발(Development) 환경이라면 소프트웨어가 제공하는 기본 설정을 사용해도 큰 문제 없겠지만, 운영(Production) 환경이라면 서비스 중에 문제가 발생하지 않도록 보안 요소를 포함한 많은 설정을 꼼꼼하게 점검해야 합니다. 어느 정도 설정 작업이 마무리되면 Tier간 연결 작업을 진행합니다. 애플리케이션에서 데이터베이스 연결을 위한 JDBC Connection 설정이 대표적인 예입니다. 이러한 기반 작업들을 마무리하고 나면 애플리케이션 코드와 각종 연관 라이브러리를 배포하고 데이터를 로드합니다.
하지만 아무리 신경써서 구성하더라도 어딘가에서 오류가 발생하곤 합니다. 같은 코드를 배포하더라도 개발자 로컬 환경, 개발 환경, 운영 환경마다 참조하는 라이브러리 버전이나 환경변수 값이 서로 다르게 설정되어 문제가 발생하는 경우도 있습니다.
그래서 꽤 오래전부터 많은 사람들은 반복적인 구성 작업을 자동화하고 실행 환경을 표준화하기 위한 노력을 기울여왔습니다. 그 가운데는 서버 단위의 표준화 방법도 있었습니다. 하지만 서버 머신을 이미지화하는 경우에는 운영체제(OS)를 포함해야 하므로 베이스 이미지의 크기가 커질 수 밖에 없습니다. 따라서 잦은 수정과 배포에 대응하기 어렵고, 서버 안에 존재하는 환경변수나 설정의 관리 및 주입이 어렵다는 단점이 존재합니다.
소프트웨어 설치와 구성 작업을 표준화, 자동화하는 방식도 사용되었습니다. 각 조직의 운영자가 자동화 스크립트를 작성하는 방법, 각종 프로비저닝 도구를 도입하는 방법 등이 대표적인 예입니다. 이를 통해 어느 정도 자동화는 실현할 수 있지만 모든 서버에 접속하여 배포를 수행하는 중앙 서버의 권한이 증가한다는 점, 도구를 통해 배포된 환경에서 수작업을 수행하는 순간 구성의 일관성이 깨진다는 점 등의 문제가 있습니다.
IT 업계에서 컨테이너라는 용어는 꽤 오래전부터 사용되었습니다. (예를 들어 서블릿 컨테이너가 있음) 그 중 지난 10년간 IT 업계를 뒤흔든 컨테이너라는 용어는 “애플리케이션과 애플리케이션 실행에 필요한 것들을 함께 패키징하여 실행"하는 의미를 가지고 있습니다. 물류업계의 컨테이너가 규격화된 박스 사용을 통해 수송의 혁명을 가져온 것처럼 IT의 컨테이너도 큰 변화를 가져왔습니다.
컨테이너는 미리 생성한 컨테이너 이미지를 기반으로 실행됩니다. 애플리케이션 컨테이너의 예를 들자면 이미지 안에 소스 코드 뿐만 아니라 소프트웨어 엔진, 각종 설정, 연관 라이브러리 등의 런타임 환경이 포함되어 있기 때문에 비교적 의존성에서 자유로운 상태로 애플리케이션을 실행할 수 있습니다. 물론 컨테이너 실행 시 필요한 환경변수를 주입할 수 있는 방법도 제공됩니다.
가상머신 이미지와 비교할 때 컨테이너 이미지는 운영체제를 포함하지 않기 때문에 훨씬 소형이라는 장점이 있습니다. 또 컨테이너는 내부적으로 Layer 방식을 사용하기 때문에 효율적인 용량 관리가 가능하고 컨테이너 이미지의 버전 관리가 용이합니다. 이에 따라 오랜 시간 고민이었던 자동화와 표준화에 대한 고민은 컨테이너 덕분에 많은 부분 해소되었고, 다양한 소프트웨어의 설치와 배포가 컨테이너 이미지 기반으로 활발히 이루어지고 있습니다.
최근 기업들은 IT 경쟁력 자체가 비즈니스 경쟁력이라는 이야기를 많이 합니다. 우리 일상의 전반이 상당부분 디지털화되었고 각종 트렌드와 소비자의 요구는 빠르게 변화하기 때문에 IT 역량에 따라 비즈니스의 성패가 달리는 경우가 많습니다. 빈번한 배포를 위한 CI/CD, 그리고 빈번한 배포에도 안정적인 서비스 유지를 위한 MSA(마이크로서비스 아키텍처)는 현대적인 IT의 핵심 요소가 된지 오래입니다.
특히 MSA 도입에 따라 과거의 커다란 애플리케이션은 목적에 따라 여러 서비스로 분리되고 각 서비스의 규모는 점점 작아지는 추세입니다. 그런데 소형화된 서비스마다 별도의 전용 서버 머신을 할당한다면 관리해야 할 서버의 수가 증가하고 전체적으로는 자원의 낭비가 발생할 가능성이 큽니다. 하지만 컨테이너는 서버 머신 리소스의 일부만을 사용하기 때문에 효율성을 높일 수 있습니다. 게다가 가상머신에 비해 훨씬 경량이기 때문에 빠르게 배포, 실행할 수 있다는 장점이 있습니다. 사실상 MSA를 가능하게 하는 것은 컨테이너라고 해도 과언이 아닙니다.
컨테이너는 서비스 구성 표준화, 실행 결과의 일관성, 배포 민첩성, MSA의 실현 등 다양한 장점을 제공하지만 한편으로는 새로운 고민을 가져왔습니다. 컨테이너 수 증가에 따라 컨테이너 관리를 위한 부하가 발생한 것은 물론이고, 컨테이너 기반의 서비스 아키텍처를 구성하기 위하여 새로운 컴포넌트들의 필요성이 나타났습니다. 이에 컨테이너를 잘 사용하고 관리하기 위한 컨테이너 오케스트레이션 도구가 출현했습니다.
대부분의 컨테이너 오케스트레이션 도구들은 컨테이너 배포, 그룹화된 컨테이너 관리, 컨테이너 간 또는 외부와의 연결 제공, 컨테이너 상태 추적 등의 기능을 제공합니다. 그동안 시장에 여러 컨테이너 오케스트레이션 도구가 출현했는데 의미있게 자리매김한 것은 Docker Swarm, Apache Mesos, 그리고 쿠버네티스(Kubernetes) 정도라고 할 수 있습니다. 그리고 현재는 쿠버네티스가 사실상 컨테이너 오케스트레이션 도구의 표준 역할을 하고 있습니다.
쿠버네티스는 과거 구글 내부에서 사용하던 Borg를 기반으로 발전한 도구입니다. 2015년에 버전 1.0이 발표되었고 이후 지금까지 CNCF(Cloud Native Computing Foundation)에서 관리하고 있습니다. CNCF는 리눅스 재단(Linux Foundation) 및 구글, IBM, 레드햇, 도커, 인텔, 시스코, 트위터, 이베이 등의 기업들이 설립한 비영리 단체로 컨테이너를 포함한 클라우드 네이티브 기술 발전을 목표로 합니다. 현재 CNCF 산하에는 100개가 넘는 프로젝트가 있는데, CNCF의 첫 프로젝트가 바로 쿠버네티스입니다. 또한 컨테이너 이미지 저장소인 하버(Harbor), 쿠버네티스 패키지 매니저인 헬름(Helm), 시스템 모니터링을 위한 프로메테우스(Prometheus) 등도 CNCF 프로젝트입니다.
쿠버네티스는 다음과 같은 특징을 지니고 있습니다.
컨테이너가 실행될 노드를 결정하는 스케줄링 작업을 쿠버네티스가 담당합니다. 사용자는 쿠버네티스에게 스케줄링을 일임하거나 스케줄링 시 반드시 지켜야하는 큰 원칙만 제시하면 됩니다. 예를 들어 A 애플리케이션은 a-node 라는 레이블을 가진 노드에서만 실행하거나, A와 B는 서로 다른 노드에 배포한다는 것 정도입니다.
이러한 스케줄링 시에 쿠버네티스는 파드(포드, Pod)라는 단위를 사용합니다. 파드 안에는 1개, 또는 1개 이상의 컨테이너가 포함되어 있습니다. 같은 파드 안의 컨테이너들은 함께 실행되며 파드의 로컬 볼륨을 공유할 수 있습니다. 특히 메인 컨테이너의 보조적인 역할을 수행하는 컨테이너를 배치하는 사이드카 패턴을 구성하기에 용이합니다. 이 외에도 파드의 집합인 ReplicaSet, 배포 관리를 위한 Deployment, 상태를 갖는 StatefulSet, 각 노드마다 하나씩 실행되는 DaemonSet, 반복 작업을 실행하기 위한 CronJob 등 다양한 형태의 Pod 실행 방법을 제공합니다.
한편 쿠버네티스는 사용자가 지정한 컨테이너의 상태를 지속적으로 관찰하여 만약 비정상적인 상태 감지를 감지하면 자동으로 재배포함으로써 정상 상태를 유지하려는 오토힐링 기능을 제공합니다. 예를 들어 A 파드가 실행 중인 어떠한 노드가 갑작스럽게 종료되면 쿠버네티스는 A 파드를 다른 노드에서 다시 실행합니다.
부하에 따라 규모가 자동 확장, 축소되는 오토스케일링도 쿠버네티스의 주요한 기능 중 하나입니다. CPU 사용률 임계치에 따른 파드 복제본 확장 규칙을 설정해 놓으면, 부하가 늘어나 파드의 CPU 사용률이 임계값을 넘어설 때 자동으로 파드 복제본이 추가로 실행되어 서비스 가용성을 확보할 수 있습니다.
그 외에도 로드밸런서를 포함한 네트워크 기능, 컨테이너가 사용하는 볼륨 스토리지, 컨테이너 실행에 필요한 각종 정보를 저장하기 위한 key-value 기반 저장소 등을 제공합니다. 참고로 쿠버네티스는 K8s 라는 약자로 불리우기도 하는데, 이는 K와 s 사이에 8개의 글자(ubernete)가 있기 때문입니다.
쿠버네티스의 단위는 클러스터입니다. 그리고 쿠버네티스 클러스터는 컨트롤 플레인과 흔히 워커 노드라고 불리우는 컴퓨팅 노드 컴포넌트로 구분됩니다. 컨트롤 플레인은 클러스터 전반의 정보 저장소인 etcd, 클러스터 전체적으로 발생하는 각종 요청을 처리하는 kube-apiserver, 파드 스케줄링을 담당하는 kube-scheduler 등으로 구성됩니다. 컨트롤 플레인은 클러스터 관리에 대한 임무만 수행하기 때문에 사용자 워크로드를 실행하지는 않습니다. 사용자 워크로드는 1개 이상의 컴퓨팅 노드로 구성된 노드 컴포넌트 영역에서 실행됩니다. 노드 컴포넌트를 구성하는 각 노드에는 컨테이너 실행에 필요한 컨테이너 런타임, 그리고 컨트롤 플레인과 통신하면서 컨테이너를 배포하고 상태를 관리하는 kubelet 등이 포함되어 있습니다.
하나의 클러스터 안에는 여러 네임스페이스(Namespace)를 만들 수 있습니다. 클러스터가 비교적 물리적인 단위라면 네임스페이스는 논리적인 격리 단위입니다. 네임스페이스 개념을 사용하여 객체들을 다양한 조건으로 그룹화할 수 있습니다. 예를 들어 조직별, 서비스별, 또는 개발/검증/운영과 같은 환경 등 사용자가 원하는 기준을 바탕으로 네임스페이스 구조를 설계할 수 있습니다. 한편 쿠버네티스 클러스터를 생성하면 kube-system, default 등의 기본적인 네임스페이스가 존재합니다.
쿠버네티스 자체는 오픈소스이기 때문에 리눅스, 윈도우, macOS 상에서 누구나 자유롭게 사용할 수 있습니다. 물론 쿠버네티스 설치부터 시작하여 지속적인 운영 관리까지 모두 사용자의 몫입니다. 이에 여러 소프트웨어 업체들은 차별화된 관리 기능과 사용자 지원이 포함된 쿠버네티스 버전을 제공하기도 합니다.
또한 AWS, Azure, Google Cloud 로 대표되는 퍼블릭 클라우드 제공자들은 관리형(Managed) 쿠버네티스를 제공합니다. 이러한 클라우드사의 쿠버네티스를 사용하면 컨트롤 플레인 영역의 관리에 신경 쓸 필요가 없고 워크로드를 실행하기 위한 컴퓨팅 노드도 클라우드사의 가상 머신 서비스를 사용할 수 있습니다. 사용자 입장에서는 원하는 시점에 빠르게 클러스터를 생성할 수 있고, 서버 자원을 전혀 보유하고 있지 않아도 쿠버네티스를 사용할 수 있다는 장점이 있습니다. 또 사용한 만큼만 요금을 지불하기 때문에 초기 도입 비용이 낮다고 할 수 있습니다.
이제까지 쿠버네티스의 등장 배경과 특징에 대해 간단히 알아보았습니다. 정리하자면 비즈니스와 IT 환경의 경쟁력 확보를 위해 컨테이너의 사용이 확대되고 있고, 이러한 컨테이너를 더욱 잘 사용하기 위해 쿠버네티스를 도입하는 기업이나 조직이 늘어나고 있다는 것입니다. 쿠버네티스에 대한 새로운 소식과 각종 기술 문서는 쿠버네티스 공식 홈페이지(https://kubernetes.io/)에서 확인할 수 있습니다.