1. 쿠버네티스의 3가지 주요 특징과 네이티브 vs 매니지드 쿠버네티스 비교
필자는 현업 DevOps로 네이티브 쿠버네티스와 매니지드 쿠버네티스(EKS) 모두 경험하였습니다. 실제 운영하는 입장에서 쿠버네티스의 3가지 주요 특징과 네이티브와 매니지드 쿠버네티스의 차이점을 알아봅니다.
1. 의도한 상태(Desired State) 관리
주요 특징으로 먼저, 쿠버네티스는 ‘의도한 상태’라는 핵심 개념으로 클러스터를 관리합니다. 의도한 상태란 단어에서 유추할 수 있듯이 클러스터 내의 애플리케이션과 리소스를 어떻게 동작해야 하는지를 명시(의도한대로)적으로 정의하고, 현재 상태가 사전에 정의한 의도한 상태와 일치하도록 유지하는 프로세스를 의미합니다. 이 개념은 쿠버네티스가 애플리케이션 및 인프라 스트럭처를 자동으로 관리하고 유지하기 위한 핵심 원칙 중 하나입니다. 예를 들어, 예기치 않게 실행 중인 프로세스 중 하나가 다운되면 사용자 개입없이도 쿠버네티스가 자동으로 해당 프로세스를 시작하여 사전에 정의한 의도한 상태를 일관되게 유지하여 장애 대응력이 매우 뛰어납니다.
필자는 유닉스 시스템의 솔라리스 관리자였습니다. 장애가 발생하면 새벽이라도 관제팀에서 전화를 받아 일일이 콘솔에 접속하여 명령어로 해당 프로세스를 다시 실행하였습니다. 하지만 이제 쿠버네티스가 그일을 대신합니다. 새벽에 잠을 깨는 일이 줄었습니다. 의도한 상태 관리는 DevOps 문화와 더불어 클라우드 네이티브 환경에서 자주 사용되는 개념입니다. 이를 통해 시스템 관리의 효율성과 신뢰성을 극적으로 향상시킬 수 있습니다.
예제로 알아봅니다. 아래와 같이 NGINX ‘디플로이먼트’를 실행합니다. 디플로이먼트(Deployment)는 애플리케이션의 인스턴스를 관리하고 배포하기 위한 쿠버네티스 리소스입니다. 아래에 kubectl 명령어를 사용하였습니다. kubectl 명령어 사용법 등 자세한 사용법은 앞으로 이어지는 연재에서 다루겠습니다. 지금은 일단 핵심 개념에만 집중하면 도움이 됩니다.
$ (⎈ |switch-singapore-test:default) kubectl create deployment nginx –image=nginx deployment.apps/nginx created
해당 명령어로 NGINX 파드가 실행됩니다. ‘k get pod’ 명령어로 파드의 현재 현황을 확인할 수 있습니다. 파드란 하나 이상의 컨테이너를 포함한 쿠버네티스에서 사용하는 가장 작은 배포 단위입니다. 파드는 컨테이너의 논리적인 호스트이며, 같은 파드 내의 컨테이너는 동일한 네트워크 네임스페이스, IP 주소, 포트 범위, 스토리지 등을 공유합니다.
$ (⎈ |switch-singapore-test:default) k get pod NAME READY STATUS RESTARTS AGE nginx-748c667d99-d6bb5 1/1 Running 0 2m17s
임의로 장애 상황을 만들어 보겠습니다. 실시간 변화 상태를 확인하기 위해서 터미널 창을 2개로 나누고 위 창은 파드를 삭제하고 아래 창은 파드의 상태 변화를 -w(watch) 옵션을 사용하여 실시간으로 확인합니다. 파드를 삭제하는 명령어는 ‘k delete pod’ 입니다.
$ (⎈ |switch-singapore-test:default) k delete pod nginx-748c667d99-d6bb5 pod "nginx-748c667d99-d6bb5" deleted
아래 창에서 삭제된 파드가 자동으로 생성되는 것을 확인할 수 있습니다.
$ (⎈ |switch-singapore-test:nginx) k get pod -w NAME READY STATUS RESTARTS AGE nginx-748c667d99-d6bb5 1/1 Running 0 4m19s nginx-748c667d99-d6bb5 1/1 Terminating 0 4m30s nginx-748c667d99-jmb7z 0/1 Pending 0 0s nginx-748c667d99-jmb7z 0/1 ContainerCreating 0 0s nginx-748c667d99-d6bb5 0/1 Terminating 0 4m31s nginx-748c667d99-jmb7z 1/1 Running 0 3s
‘nginx-748c667d99-d6bb5’ 이름을 가진 파드가 종료(Terminating)되고 새로운 ‘nginx-748c667d99-jmb7z’ 이름의 파드가 실행(Running)됩니다. 쿠버네티스가 이전 파드가 종료된 것을 확인하고 자동으로 새로운 파드를 실행하였습니다. 즉, 쿠버네티스가 프로세스 다운을 감지하고 자동으로 처음의 ‘의도한 상태’로 복구한 것입니다. 참고로 ‘nginx-748c667d99-d6bb5’ 이름은 쿠버네티스 디플로이먼트 리소스가 nginx 디플로이먼트 이름에 자동으로 임의의 해쉬값을 붙여서 만들었습니다.
처음 ‘kubectl create deployment’ 명령어로 파드를 실행하였습니다. 그러면 쿠버네티스 디플로이먼트는 ‘의도한 상태’를 파드가 실행되는 상태로 정의합니다. 따라서 우리가 임의로(혹은 시스템의 예기치 않은 장애로) 파드를 삭제하여도 쿠버네티스는 의도한 상태인 하나의 파드가 실행되는 상태를 자동으로 유지하기 위하여 파드를 재시작합니다. 내부적으로 Deployment 리소스는 ReplicaSet Controller 이름의 컨트롤러를 이용하여 항상 의도한 상태로 유지합니다. 만약 파드의 수량을 3개로 선언하면 역시 항상 3개의 상태를 ReplicaSet Controller를 통하여 유지합니다. 이와 유사하게 쿠버네티스는 다양한 컨트롤러를 사용하여 항상 의도한 상태로 유지합니다. 담당자는 사전에 ‘의도한 상태’를 정의하고 쿠버네티스는 다양한 ‘컨트롤러’ 리소스를 이용하여 의도한 상태로 자동으로 유지합니다. 자가치유(Self-Healing)가 가능하고 개발자, 운영자 간 커뮤니케이션까지 원활하게 합니다.
2. 코드를 이용한 리소스 관리
쿠버네티스의 모든 리소스는 코드로 관리합니다. 예를 들어 애플리케이션을 설치한다면 이전 VM 환경에서는 아래와 같이 yum 명령어를 사용하였습니다.
yum install -y nginx
명령어를 사용하여 단계별로 수행하고 절차를 나열하여 원하는 결과를 달성하려고 합니다. 특히, 특정 명령어를 순차적으로 실행해야 정상으로 동작합니다. 하지만 시간이 지나감에 따라 시스템 상태가 변화되어 변경 사항을 추적하고 관리하기가 매우 어렵습니다. 흔히 매뉴얼로 관리하지만 현재 시스템 상태가 기존의 매뉴얼 문서와 일치(현행화)한다고 보장하기 어렵습니다.
쿠버네티스 환경 역시 이전 예제와 같이 kubectl create deployment 명령어를 사용할수도 있지만 거의 모든 리소스를 아래와 같이 코드 파일을 이용하여 생성합니다.
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
쿠버네티스 리소스를 명령어가 아닌 코드로 관리하는 것은 선언형 방식의 관리 접근 방법을 사용하는 것을 의미합니다. 쿠버네티스는 선언형 방식을 강력하게 채택한 플랫폼으로, ‘선언형 형식’이란 최종 상태를 명시적으로 정의하고 시스템이 그 상태로 수렴하도록 하는 접근 방식입니다. 선언형 방식에서는 작업을 수행하는 과정이나 단계를 직접 명시하지 않고, 원하는 결과물의 최종 상태를 정의하여 시스템이 해당 결과물을 달성하도록 유도합니다.
코드로 리소스를 정의하면 어떤 리소스들이 필요하고 어떤 설정을 가져야 하는지 명확하게 정의됩니다. 이를 통해 클러스터 내의 리소스가 일관성 있게 생성되고 구성되며, 예상치 못한 설정 오류나 충돌을 방지하여 시스템 안정성을 높입니다. 실제 리소스를 배포하기 전에 코드로 구현하여 사전에 동료들과 검토를 하여(PR Review) 작업 중 발생할 수 있는 장애를 예방할 수 있습니다. 그리고 동일한 코드를 사용할 수 있어 인프라스트럭처를 재현하는 데에 매우 유용합니다. 어느 환경에서든 동일한 코드를 실행하면 동일한 리소스가 배포되므로 개발, 테스트, 프로덕션 등 다양한 환경에서 일관된 환경을 유지할 수 있습니다. 그리고 버전 관리 시스템 (예: Git)을 통해 변경 사항을 추적하고 관리할 수 있습니다. 이를 통해 변경 내역을 추적하고 협업자들과 함께 작업하면서 변경 사항을 조율하는 것이 쉬워집니다.
개발자와 다르게 운영자들은 코드를 사용하는 것에 거부감을 느낄 수 있습니다. 하지만 쿠버네티스에서 사용하는 코드는 일반 프로그래밍 언어와 다르게 복잡하지 않아 배우기에 부담감이 적습니다. 간단한 YAML 파일 문법 정도만 알고 있으면 사용하는데 불편함이 없습니다. 또한 VSCode 등 도구를 사용하면 자동 완성, 문법 자동 체크 기능을 활용할 수 있어 편리합니다.
3. 고가용성 구성(Pet vs Cattle)
먼저 애완동물과 가축(Pet vs Cattle) 개념을 알아봅니다. 애완 동물과 가축은 인프라 관리와 관련된 2가지 접근 방식의 비유입니다. 애완 동물은 개별적이고 특별한 관리가 필요합니다. 일일이 이름을 부여하고 특별한 관심을 받습니다. 이에 비하여 가축은 특별한 이름을 가지지 않고 일반적인 태그나 번호로 사용합니다. 이전 예제에서 파드 이름(nginx-748c667d99-d6bb5)에 임의의 해쉬값을 사용하였습니다. 대규모로 관리하여 대체 가능하도록 확장성과 유연성을 필요합니다.
컨테이너 기반의 오케스트레이션 도구인 쿠버네티스는 가축(Cattle) 관리 방식을 채택합니다. 쿠버네티스는 컨테이너화된 애플리케이션을 표준화된 방식으로 관리하고, 인프라스트럭처를 자동화하며, 확장 가능하게 구축합니다. 이를 통해 애플리케이션의 배포, 확장, 롤링 업데이트, 자동 복구 등을 효율적으로 수행할 수 있습니다.
예를 들어 쿠버네티스는 애플리케이션(웹서버)과 애플리케이션(DB서버) 연결 시 기존 VM 환경에서 사용하는 IP 방식이 아닌 도메인 이름 방식의 서비스(Service) 리소스를 사용합니다. 기존에 사용하던 IP 방식은 고정된(Static) 값을 사용하여 DB 서버가 변경되면 IP가 변경되어 웹서버 환경 변수 등에 설정된 IP도 같이 변경해야 합니다. 하지만 쿠버네티스는 동적인(Dynamic) 도메인 방식을 사용하여 IP가 변경되면 자동으로 변경된 IP로 연결됩니다.
이와 유사하게 쿠버네티스는 언제든지 장애가 발생할 수 있다고 가정하고 장애가 발생하여도 자동으로 복구 및 서비스가 지속되도록 로드밸런서, Advanced 스케쥴링, Readiness/Liveness Probe 등 다양한 기능을 제공합니다.
아래는 쿠버네티스 서비스 리소스 예제입니다.
$ (⎈ |switch-singapore-test:nginx) k get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP 172.20.14.84 <none> 80/TCP,9113/TCP 23h # 첫번째 endpoint $ (⎈ |switch-singapore-test:nginx) k get endpoints NAME ENDPOINTS AGE nginx 10.110.1.118:9113,10.110.1.118:8080 23h # 두번째 endpoint $ (⎈ |switch-singapore-test:nginx) k get ep NAME ENDPOINTS AGE nginx 10.110.23.249:9113,10.110.23.249:8080 23h
파드 간 연결 시 nginx란 이름의 서비스를 이용합니다. 해당 서비스는 자동으로 ‘endpoints(종점)’를 생성하여 파드의 IP가 변경되면 자동으로 해당 서비스에 매핑된 IP를 업데이트합니다. 따라서 IP가 변경되어도 서비스 이름은 변경이 없어 기존 nginx 서비스 이름 그대로 파드 간 연결에 사용할 수 있습니다.
4. 네이티브 vs 매니지드 쿠버네티스 솔루션 비교
온프레미스 환경에서 쿠버네티스를 사용하면 공식 배포 버전의 네이티브 쿠버네티스를 사용하거나 OpenShift, Tanzu 등의 벤더 솔루션을 사용합니다. 클라우드 환경은 각 CSP(Cloud Service Provider)에서 제공하는 매니지드 쿠버네티스 EKS(Amazon Elastic Kubernetes Service), AKS(Azure Kubernetes Service), GKE(Google Kubernetes Engine)를 주로 사용합니다.
네이티브 쿠버네티스를 바닐라 쿠버네티스라고 부르기도 합니다. ‘바닐라 쿠버네티스’라는 용어는 쿠버네티스의 공식 배포 버전을 의미합니다. 바닐라는 일반적이고 원래의 상태를 의미하는 용어로, 여기서는 쿠버네티스의 공식 배포 버전을 구별하기 위해 사용됩니다. 쿠버네티스는 오픈소스 프로젝트로서 CNCF(클라우드 네이티브 컴퓨팅 재단)에 의해 관리됩니다. CNCF는 쿠버네티스의 개발과 유지 보수를 담당하며, 쿠버네티스의 공식 배포 버전을 제공합니다. 이 공식 배포 버전을 바닐라 쿠버네티스라고 부르는 것은, 이 버전이 쿠버네티스의 기본 구성 요소와 기능을 포함하고 있으며, CNCF에서 제공하는 원래의 상태를 나타낸다는 의미입니다.
네이티브와 매니지드 쿠버네티스의 주요한 차이점은 네이티브는 쿠버네티스 설치, 업그레이드 및 컨트롤 플레인 관리가 필요하다는 것입니다. 하지만 매니지드 쿠버네티스는 설치 등에 관련된 일련의 가이드를 제공하고 컨트롤 플레인은 직접 관리합니다. 그리고 자사의 다른 리소스와 통합이 되어 쿠버네티스 환경의 스토리지, 네트워크 구성이 네이티브 환경에 비하여 좀 더 용이합니다.
하지만 애플리케이션을 배포하고 서비스를 안정적으로 운영해야 하는 입장에서는 2가지 서비스가 크게 차이가 없습니다. 모두 쿠버네티스 기반의 시스템이라 쿠버네티스에 대한 이해가 필요하고 헬름, ArgoCD, Ingress 등 쿠버네티스 뿐만 아니라 다양한 다른 오픈소스 소프트웨어를 잘 연계하는 작업이 중요합니다. 개인적인 의견으로 2가지 서비스 모두 매일 수행하는 작업의 80% ~ 90%는 동일합니다. 매니지드 쿠버네티스 서비스를 사용한다고 업무량이 줄어들거나 난이도가 극적으로 낮아지는 일은 없습니다
간단히 예를 들어 보겠습니다. 네이티브 쿠버네티스는 kube-system 네임스페이스에 다양한 파드를 확인할 수 있습니다.
$ (⎈ |alooo:kube-system) k get pod NAME READY STATUS RESTARTS AGE calico-kube-controllers-7b9cddc446-clpc4 1/1 Running 1 (15d ago) 117d calico-node-2brvj 1/1 Running 0 117d (생략) coredns-68868dc95b-6mj9l 1/1 Running 0 117d coredns-68868dc95b-znpdb 1/1 Running 0 117d dns-autoscaler-7ccd65764f-546k4 1/1 Running 0 117d kube-apiserver-master1 1/1 Running 2 (117d ago) 117d kube-apiserver-master2 1/1 Running 1 117d kube-apiserver-master3 1/1 Running 1 117d kube-controller-manager-master1 1/1 Running 44 (65m ago) 117d kube-controller-manager-master2 1/1 Running 64 (64m ago) 117d kube-controller-manager-master3 1/1 Running 62 (2d1h ago) 117d kube-proxy-92rpp 1/1 Running 0 117d (생략) kube-scheduler-master1 1/1 Running 48 (25h ago) 117d kube-scheduler-master2 1/1 Running 68 (65m ago) 117d kube-scheduler-master3 1/1 Running 75 (64m ago) 117d metrics-server-6db6c9dd4-gtz55 1/1 Running 0 111d nginx-proxy-node1 1/1 Running 0 117d nginx-proxy-node2 1/1 Running 0 117d nginx-proxy-node3 1/1 Running 0 117d nodelocaldns-4gttk 1/1 Running 4 (32d ago) 117d (생략)
etcd, controller manager, scheduler, api-server 등 컨트롤 플레인을 구성하는 다양한 파드를 확인할 수 있습니다.
하지만 EKS는 컨트롤 플레인을 AWS에서 직접 관리하므로 해당 파드를 확인할 수 없습니다. 실행되는 파드 리스트를 확인하면 비교적 단순합니다.
$ (⎈ |switch-singapore-test:kube-system) k get pod NAME READY STATUS RESTARTS AGE aws-load-balancer-controller-7d96db6884-dh8rc 1/1 Running 0 34d aws-load-balancer-controller-7d96db6884-vwttg 1/1 Running 0 34d aws-node-kwqkb 1/1 Running 0 17d aws-node-xvgxm 1/1 Running 0 20d coredns-d9bc8f875-8wgjp 1/1 Running 0 20d coredns-d9bc8f875-ml4f6 1/1 Running 0 20d ebs-csi-controller-b995956fb-nbxqg 6/6 Running 0 45d ebs-csi-controller-b995956fb-t2jnk 6/6 Running 0 45d ebs-csi-node-47trz 3/3 Running 0 45d ebs-csi-node-5ffxg 3/3 Running 0 17d external-dns-5555f6796f-jtrgf 1/1 Running 0 2d17h kube-proxy-6gqfl 1/1 Running 0 17d kube-proxy-l95v9
그러나 컨트롤 플레인 관리 이 외의 작업들, 즉 다양한 오픈 소스 관리 작업은 동일합니다. 쿠버네티스 운영에 필수인 다양한 오픈소스 프로젝트 리스트는 CNCF 사이트에서 확인할 수 있습니다.
위와 같이 아주 많은 오픈소스 프로젝트를 확인할 수 있습니다. 각 기업마다 환경에 따라 위 오픈소스 소프트웨어를 적절히 조합하여 사용합니다. 쿠버네티스를 운영한다는 것은 쿠버네티스를 포함하여 위와 같이 다양한 오픈 소스 소프트웨어를 관리한다는 것과 동일합니다. 쿠버네티스 뿐만 아니라 다양한 오픈소스에 대한 이해가 반드시 필요합니다. 다행히 쿠버네티스는 많은 회사에서 이미 표준에 가깝게 사용 중이라 많은 사례가 있고 문서도 풍부하여 비교적 어렵지 않게 실 서비스에 적용할 수 있습니다.
이상 쿠버네티스의 특징과 네이티브, 매니지드 서비스를 비교해 보았습니다.
해당 기술 블로그에 질문이 있으시면 언제든지 문의해 주세요. 직접 답변해 드립니다.
k8sqna@jennifersoft.com
1.kubectl 명령어는 이와 같이 kubectl create{동사} deployment{리소스} 형식입니다.
2. ‘k get pod’ 현재 파드의 현황을 확인하는 명령어입니다. kubectl를 축약하여 k를 사용할 수 있습니다. 자세한 Kubectl 명령어 사용법은 앞으로 다룹니다.
3. 쿠버네티스 디플로이먼트 설명, https://kubernetes.io/ko/docs/concepts/workloads/controllers/deployment
4.물론 VM 환경에서도 Ansible, Terraform 등으로 코드로 인프라를 관리할 수 있습니다. 하지만 명령어로도 가능하여 대부분의 회사에서 아직 VM 환경에서는 명령어를 사용하는 것이 일반적입니다.