Computing

[jhKube][1] Kubernetes와 Linux Container 간단 정리 본문

Cloud/jhVM

[jhKube][1] Kubernetes와 Linux Container 간단 정리

jhson989 2022. 11. 21. 21:52

전글

- [jhVM][1] virt-manager, CentOS 7 qcow2 image (root password, 용량 설정 등)

- [jhVM][2] CentOS 7 user 추가(sudo 권한 부여), 가상머신 네트워크 설정 및 virbr0(static internal IP 부여)

- [jhVM][3] ssh 로그인 설정(비번 없이 로그인), qcow2 복사(VM 복제)

 

이전 글에 이어 CentOS 7 가상머신들을 이용한 쿠버네티스 환경 구축 과정에서 배운 내용을 정리하고자고 한다. jhVM 시리즈에서 가상머신 환경 구축은 끝났으니, 본격적으로 쿠버네티스를 설치해보려 한다. 공부 중인 단계에서 정리하는 글이기에 부족하거나 정확하지 않은 내용도 있을 수도 있다. 자세한 내용은 추후 다시 한번 정리해볼 예정이다.

Fig 1. 쿠버네티스 로고 [1]

 

 

Kubernetes와 Linux Container

쿠버네티스(Kubernetes, Kube, K8S)는 컨테이너화된 애플리케이션(혹은 워크로드, 서비스)을 관리하기 위한 컨테이너 오케스트레이션(Container Orchestration)[1]이다.

 

쿠버네티스는 컨테이너를 관리하는 시스템이라는 것인데, 이 문장을 이해하기 위해서는 컨테이너(Linux Container, 리눅스 컨테이너)가 무엇인지, 컨테이너를 관리한다는 게 무엇인지를 이해해야 한다. 그것을 이해하면 "컨테이너 오케스트레이션(Container Orchestration)"이라는 말이 어느정도 이해될 것이다.

 

두괄식으로 결론부터 말하자면, 컨테이너는 새로운 애플리케이션(앱) 배포 방식이다. 그리고 개발자가 자기가 만든 앱 컨테이너를 쿠버네티스에 등록하면 => 쿠버네티스는 자동으로 그 앱을 배포하고 문제 없이 운영해준다. (운영에 필요한 모든 것을 해준다. 자동 스케일링, 에러 시 재실행(fail over), 네트워크 관리, 로드 밸런싱, 중단 없는 업데이트(Rolling update) 등등)

 

왜 이런 앱 운영 시스템이 필요할까? 쿠버네티스가 앱 배포 및 관리를 해줌에 따라 이제 개발자는 단순히 앱 서비스(앱이 무엇을 할 지)만 잘 만들면 된다. 쿠버네티스 시스템이 충분히 잘 설치되어 있다면, 앱은 배포 및 운영 과정에서 아무 문제 없이 동작할 것이다.

 

정리하자면 컨테이너 오케스트레이션이라는 말은 결국 컨테이너가 잘 운영되도록 조율하는 행위를 의미하며, 쿠버네티스는 컨테이너들을 잘 운영하는 시스템 소프트웨어를 의미한다. 

 

 

 

애플리케이션 배포 방식의 변화

앞서 말했듯, 컨테이너는 새로운 애플리케이션 배포 방식이다. 전통적으로 애플리케이션 배포 방식에는 가장 단순한 exe 파일 형태로의 배포, makefile 등 빌드 과정을 포함한 배포, 애플리케이션이 설치된 가상머신 배포 등이 있다. 앱의 개발 환경과 실제 운영 환경이 복잡해지고 서로 다른 경우가 많아지면서 앱 배포 자체도 큰 일거리가 된다고 한다. (컴파일러 버전, 라이브러리 버전, 파일 시스템 상 파일 경로 등등)

 

밑의 Fig 2.은 이러한 앱 배포 방식의 진화를 보여주는 것이다. 크게 3개의 방식, 전통적 배포 방식(Traditional Deployment), 가상머신 배포 방식(Virtualized Deployment), 컨테이너 배포 방식(Container Deployment)이 있다. 이러한 배포방식은 앱 개발 환경과 운영 환경의 차이를 극복하여 더욱 쉽게 앱을 개발&배포할 수 있도록 진화되었다. (개인적으로는 3가지 방식 모두 각각의 장단점이 있기에 어느것이 좋다고 말하기 힘들지 않나 싶다. 사용목적이 다른 것이지)

 

Fig 2. 애플리케이션 배포 방식의 변화 [2]

 

전통적 배포 방식을 앱을 운영 환경에서 바로 실행되도록 한다. 앱은 운영 환경에 설치된 OS와 하드웨어, 라이브러리/Bin 파일을 사용하여 동작할 것이다. 일반적으로 앱의 개발하는 환경과 앱이 운영되는 환경은 다를 것이기에(게임을 예로 들면 게임을 실행하는 모든 컴퓨터가 동일한 환경일 수는 없을 것이다) 다양한 운영 환경에서 앱이 잘 동작하는 지를 개발자(혹은 운영관리자/QA)가 잘 검수해야 한다. 이 경우 설치 환경에 제한이 있을 뿐만 아니라, 앱이 사용하는 라이브러리/Bin 또한 유연하게 동작해야 한다. (게임 설치를 예로 들면 하드웨어 사양(메모리 몇GB, GPU유무, 여유 저장공간 크기), OS, 라이브러리(DirectX 11 or 12) 등을 고려해야 한다)

 

가상머신 배포 방식은 개발 환경과 운영 환경과의 차이를 아예 없애기 위한 배포 방식으로, 개발 환경과 완벽히 동일한 가상머신을 생성하고 가상머신 안에 앱을 포함시켜 함께 배포한다. 운영 환경에서는 가상머신을 운영하기 위한 하이퍼바이저만 설치되어 있으면 된다. 가상머신은 독립적인 OS/라이브러리/Bin/파일시스템을 가지기에 개발 환경과 완벽히 똑같은 환경에서 앱이 운영될 수 있도록 한다. (하드웨어의 경우 여전히 문제가 되겠지만 emulation 기법등을 통해 어느정도 극복가능하지 않나 싶다.)

 

하지만 가상머신은 각각이 운영체제와 라이브러리 등을 가지기에 무겁다. 무겁다는 것은 차지하는 용량도 크고, 앱 실행이 느려진다는 것이다. 가상머신 하나마다 독립된 운영체제를 저장해야 하기에 용량을 매우 잡아먹는다. 또한 앱이 가상머신에서 실행되는 과정을 보면 앱 코드 -> 가상머신의 커널코드 -> 하이퍼바이저 -> 실제 컴퓨터(Host)의 커널 코드로 여러 단계를 거쳐 실행되기에 명령어 실행자체도 느려진다. 컨테이너 방식은 이를 극복하고자 한다.

 

 

 

Linux Container

가상머신은 하드웨어 레벨 가상화라고 하고, 컨테이너는 OS 레벨 가상화[3]라고 말할 수 있다. 가상머신 기술은 동일한 하드웨어 위에 여러 가상머신들을 실행시키는 것이라면, 컨테이너 기술은 동일한 OS 위에 여러 컨테이너들을 실행시킨다. 즉 한 컴퓨터에서 실행되는 모든 컨테이너는 OS까지는 동일하다.

 

가상머신들은 개별적으로 운영체제를 가지고 있다면, 컨테이너는 호스트 컴퓨터의 운영체제(리눅스 커널)을 공유한다. 운영체제를 공유하기에 컨테이너 하나가 차지하는 용량이 작을 뿐만 아니라, 컨테이너가 실행되는 과정도 앱 코드(+컨테이너 런타임) -> Host의 커널 코드로 매우 단순화된다. 

 

Fig 3. 리눅스 컨테이너의 구성 기술[4]

 

Fig 3.에서 보듯, 컨테이너 기술은 다양한 기술로 구현되지만 크게 두 가지, 리눅스 네임스페이스(Linux Namespace)와 리눅스 컨트롤 그룹(Linux Cgroups)이 대표적이다. 리눅스 네임스페이스는 각 프로세스가 독립적인 파일(파일 시스템), 프로세스, 네트워크 인터페이스 등의 뷰를 가질 수 있도록 하는 기술이고, 리눅스 컨트롤 그룹은 프로세스가 사용하는 하드웨어 양(CPU, 메모리, 네트워크 대역폭 등)을 제한하는 기술이다. (아직은 어려운 개념이라 추후 깊게 공부해 볼 예정이다)

 

리눅스 컨테이너는 이러한 기술을 통해 개발 환경과 운영 환경의 차이에 상관없는(OS는 상관있음) 높은 이식성(Portability)을 달성할 수 있다. 리눅스 컨테이너 안의 앱은 독립적인 파일시스템과 library, bin을 가지고 실행되므로, library/bin 버전을 개발 환경과 운영 환경 모두 완전히 동일하게 설정할 수 있다. 또한 앱이 호스트 커널 코드를 공유하여 곧바로 시스템콜을 날릴 수 있기에 성능 하락 또한 매우 적다고 한다. (다만 프로세스 격리를 위한 오버헤드가 추가되기에 일반 프로세스보다는 성능이 떨어질 수 밖에 없지만, 찾아보면 무시할 수준인 것 같다)

 

리눅스 컨테이너 기술은 앞에 리눅스라는 단어가 붙은 만큼 리눅스 커널을 사용하는 운영체제(CentOS, Ubuntu 등)에서 사용되는 기술이다. 즉 컨테이너 그리고 그것을 사용하는 도커(docker)나 쿠버네티스는 리눅스 운영체제에서만 동작한다. 특이한 점은 CentOS 기반 컨테이너를 Ubuntu 호스트 컴퓨터에서도 실행시킬 수 있는데, 이는 CentOS와 Ubuntu가 같은 리눅스 커널을 기반으로 만들어졌기 때문이다. 다만 운영체제의 버전에 따라서 리눅스 커널 버전도 달라지기에 호환이 안되는 경우도 있을 수 있다. 리눅스 커널을 사용하지 않는 맥OS나 윈도우즈OS에서는 기본적으로 리눅스 가상머신을 만들고 그 위에서 실행된다. 

 

 

 

Kubernetes에서의 애플리케이션 배포 방법 : 선연형

쿠버네티스에서는 애플리케이션을 컨테이너 형태로 배포한다. 개발자는 앱 서비스를 개발하고 이를 컨테이너에 형태로 구현하기만 하면 된다. 그 이후 쿠버네티스에게 이 컨테이너를 실행시켜 달라고 요청하면 된다. 쿠버네티스 앱 실행을 요청하기 위해서는 명령형(Imperative) 방식과 선언형(Imperative) 방식이 존재하는데, 일반적인 프로덕션 환경에서는 선연형 방식이 권장된다.

 

선언형 방식은 "앱 A가 이런 구성으로 3개 서비스됨"이라고 적혀있는 yaml 파일을 쿠버네티스에게 전달한다. 쿠버네티스는 전달된 yaml 파일들을 분석하여 앱 A가 3개 실행되는 지 계속 확인하며, 만약 실행되고 있지 않다면 3개를 실행시킨다. 이후에 앱 A 1개에 에러가 발생해 죽게 되더라도, 쿠버네티스가 자동으로 하나 더 새롭게 실행시켜 "3개"라는 조건을 만족시킨다. 개발자가 원하는 바를 선언만 해두면 그 선언대로 쿠버네티스 시스템이 자동으로 실행해주고, 실행 이후에 계속 조건이 만족됨을 체크한다.

 

명령형 방식은 우리가 일반적으로 사용하는 방식으로 "앱 A를 3개 실행시켜달라"는 명령을 쿠버네티스에게 전달한다. 쿠버네티스는 전달 받은 명령에 따라 앱 A를 3개 실행시킨다.

 

 

 

Reference

[1] https://kubernetes.io/ko/

[2] https://kubernetes.io/ko/docs/concepts/overview/what-is-kubernetes/

[3] https://ko.wikipedia.org/wiki/LXC

[4] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/overview_of_containers_in_red_hat_systems/introduction_to_linux_containers