티스토리 뷰
VM, 컨테이너, 멀티호스트 컨테이너 플랫폼, 컨테이너 오케스트레이션까지의 발전과정에 대한 포스팅이다.
'가상화' 개념의 등장
가상화 개념이 처음 등장했던 1960년대에, 무어의 법칙에 의해 HW의 성능이 빠르게 발전하는데 SW는 이만큼 발전을 하지 못했던 상황이 발생했다. 즉, HW는 빠르게 발전하는데 SW가 이를 제대로 활용하지 못하는 상황이 발생한 것이다. 또한 그 당시 컴퓨터 HW 자원의 가격은 매우 비싼 편이었다. 여러 대의 비싼 컴퓨터를 사용해서 애플리케이션을 띄우는 것은 매우 비효율적이라는 문제가 있었던 것이다.
이러한 문제점을 해결하고자 등장한 것이 '가상화'이다. 한 대의 컴퓨터의 자원을 가상화해 여러 대인 것처럼 보이게 하자는 것이다. 하나의 물리적인 컴퓨터 위에 여러 대의 OS가 구동되는 구조이다. 이러한 구조로 HW 자원의 효율을 높일 수 있었다.
cf. 하이퍼바이저란? : CPU, 메모리, NIC, 스토리지 등의 컴퓨터 리소스를 분리해서 가상머신을 만들어주는 소프트웨어
[가상화의 장점]
1) HW 자원을 보다 효율적으로 사용할 수 있다.(근본적인 해결책)
2) 네트워크 가상화를 통해 가상의 '격리된' 네트워크 제공함으로써 데이터를 안전하게 다룰 수 있다.
3) 여러개의 다양한 OS를 하나의 컴퓨터에서 구동할 수 있다.
[가상화의 단점]
- 무거운 게스트OS가 구동되는 형태이다 보니 여러 개의 VM이 구동된다면 성능상 이슈가 발생하기 쉽다.
'컨테이너'의 등장
VM은 게스트OS를 따로 포함하기 때문에 VM하나를 구동하는 데에도 시간이 오래 걸리며 VM을 구동하는 것 자체가 무거운 작업이 된다.
이러한 무거운 VM의 가볍게 만들고자 OS를 공유하자는 개념이 등장한다. 초기에는 리눅스의 chroot라는 root 디렉토리를 변경해주는 시스템 콜을 기반으로 루트 디렉토리를 변경해가며 가상화를 하는 개념이 등장했다. 하지만 이러한 방식은 디렉토리를 변경할 때마다 필요한 작업이 많았고 복잡했다.
이러한 이유로 인해 리눅스 커널을 보다 활용하는 LXC(Linux kernel container) 개념이 등장했다. 하드웨어 자원들을 cgroups을 통해 할당하고 namespace를 활용하여 프로세스를 격리시켜 분리된 공간을 만드는 방식이다.
컨테이너 개념은 계속해서 발전했으며 OS 커널을 공유하면서 애플리케이션 단위로 추상화하여 격리하는 형태가 되었다.
가볍게 가볍게,,,
위와 같이 컨테이너는 애플리케이션 단위로 이미지를 만들고 이들이 층을 구성하는 개념으로 컨테이너 사이즈를 최적화했다. 또한 OS 커널을 공유하기 때문에 OS를 구동하지 않고도 컨테이너를 띄울 수 있게 되었다. (OS 오버헤드 최소화)
컨테이너를 가볍게 만들 수 있었던 이유
1) 컨테이너를 구성하는 레이어들을 컨테이너 간 공유
2) VM과 다르게 HW의 가상화 개념이 아닌 OS의 가상화 개념
[컨테이너의 장점]
- OS 공유로 가벼운 가상환경 제공
- 컨테이너 간 완전히 독립된 환경 제공
- 컨테이너 구동이 빠르고 가볍기 때문에 트래픽에 따른 스케일링이 용이
- 컨테이너는 단 몇초만에 확장하고 축소 가능(scale-in 또는 scale-out)
[컨테이너의 단점]
- 보안 이슈 : 커널을 공유하기 때문에 보안 이슈가 발생할 가능성은 항상 존재
- 무조건 적인 컨테이너 구성은 오히려 좋지 않다. : 컨테이너는 MSA환경에서 최적화되어 있기 때문에 기존의 레거시(모놀리틱) 구조를 컨테이너로만 이전했다고 해서 컨테이너를 제대로 활용했다고 할 수 없음.
- 보통의 기업에서는 클라우드에서 컨테이너를 관리하는데, 클라우드는 베어메탈 시스템이 아닌 VM 환경이다.
VM과 컨테이너의 차이
VM | 컨테이너 |
- 하이퍼바이저가 HW 레벨에서 가상화 - 다양한 OS 탑재 가능 - 매우 무거운 이미지, 매우 긴 구동시간 - 호스트OS와 게스트OS는 완전히 분리됨 - 비효율적인 컴퓨팅 리소스 활용 |
- OS 레벨에서 가상화 - 호스트PC와 같은 OS 사용 - 가벼운 이미지, 빠른 구동시간 - 호스트OS를 가상화했기 때문에 호스트OS와 자원 공유 가능 - 컨테이너 간 레이어 이미지 공유를 통해 효율적인 자원 활용 |
* 가장 중요한 차이점 : 요구에 따라 scale-out, scale-in 해서 클라이언트의 요구에 따라 자유롭게 확장, 축소할 수 있게 된다. 이것이 단순 가상화인 VM과의 차이점이다. VM 역시 컨테이너와 마찬가지로 각각이 격리된 공간을 갖지만 컨테이너보다 무거운 사이즈를 갖기 때문에 자유로운 확장, 축소가 불가능했다.
+) 컨테이너와 VM의 차이 - 자원 활용
컨테이너는 필요한 이미지를 서로 공유하며 최소한의 자원만을 사용할 수 있다. 따라서 VM보다 컴퓨팅 리소스를 contiguous 하게 사용한다는 장점이 있다.
컨테이너가 리눅스를 기반으로 하는 이유
: 컨테이너를 만드는데에는 리눅스 커널의 기능이 필요하기 때문
- chroot : 독립된 공간을 만들어 줌
- namespace : 독립된 공간 안에 6가지의 isolated 된 기능을 지원함 따라서 마치 독립된 가상의 시스템인 것처럼 만들 수 있음(각 컨테이너들끼리 독립되도록)
- cgroup : 필요한 만큼의 하드웨어를 지원
* 윈도우나 맥에서도 컨테이너를 실행할 수 있지만, 하이퍼바이저 기능을 활성화시켜서 '리눅스 커널의 기능을 활용'할 수 있도록 해야지만 가능하다.
컨테이너 엔진 중 하나인 '도커'
1) 우수한 유연성과 이동성 : 컨테이너는 단 몇 초 만에 확장하고 축소 가능
2) 컨테이너는 애플리케이션을 구동하기 위한 환경 정보를 포함하기 때문에 실행 환경이 변하지 않는다.
3) 코드를 통해 실행 환경을 만들 수 있다.
4) 실행 환경이 곧 앱이 되기 때문에 배포가 간단해진다. (컨테이너 자체를 바꿔서 버전을 업데이트할 수 있다.)
cf. '개발환경 == 운영환경'의 예시
만약 위 그림에서 컨테이너 기반으로 프로그램을 만든 게 아니라면, 개발자는 개발을 하고 제품을 고객사에 판매할 때, 고객사의 운영환경 컴퓨터에 해당 프로그램이 실행될 수 있는 환경을 미리 동일하게 구축했어야 했다. 즉, 개발환경과 운영환경이 다를 수밖에 없었다.
하지만 컨테이너 기반으로 개발을 하면, 운영환경 자체를 컨테이너 안에 넣은 형태가 되어버리기 때문에 개발자가 만든 소프트웨어의 운영환경이 고객사에서 실행될 운영환경과 같아지는 효과가 있다.
따라서 고객사가 많더라도 다양한 고객사에게 항상 똑같은 환경으로 SW를 제공해 줄 수 있다. 컨테이너는 만들어진 시점과 동일한 형태로 지원할 수 있고 환경에 영향받지 않고 실행할 수 있다는 아주 큰 장점이 있다. 또한 운영환경에 애플리케이션을 구동하기 위한 환경 설정 과정이 필요하지 않기 때문에 빠른 배포가 가능해진다.
멀티호스트 컨테이너 플랫폼의 등장
하나의 호스트에 여러 개의 컨테이너를 올려 실행하는 구조가 될 경우 호스트에 문제가 생긴다면 모든 컨테이너에게도 문제가 생길 것이다. 즉, 호스트 하나에 컨테이너를 올리는 방식은 불안하니 여러 개의 호스트를 두고 컨테이너들을 '분산'시키는 멀티호스트 방식이 등장한다.
여러 호스트에 동일한 컨테이너를 실행하는 방식으로 멀티호스트 컨테이너 플랫폼을 활용할 수 있다. 특정 호스트에 문제가 생기더라도 나머지 호스트에서 '동일한' 컨테이너를 실행하고 있기 때문에 문제가 되지 않는다. 하지만 여러 개의 호스트를 개발자가 직접 관리하는 것은 어려운 일이다. 예를 들어 2개의 호스트에 다수의 백엔드 애플리케이션을 띄울 때 어떻게 호스트에 배치해서 실행시킬지에 대한 방법, 호스트가 죽었을 때 컨테이너들을 다시 수동으로 재시작해야 하는 등의 번거로움이 있다. 실제로 MSA 환경에서 하나의 서비스를 운영하는데에도 컨테이너는 수십개에서 수백개까지 이른다고 한다. 이렇게 많은 컨테이너를 사람이 직접 다루기는 힘들 것이다.
컨테이너 오케스트레이션의 등장
오케스트레이션은 지휘자라는 의미를 갖는다. 지휘자는 다양한 악기들을 지휘하며 음악이 가장 아름답게 들리도록 지휘한다.
즉, 오케스트레이션은 멀티호스트 컨테이너 플랫폼에서 발생할 수 있는, 수많은 컨테이너를 수동으로 관리하면서 발생하는 복잡함을 자동화하고자 등장했다. MSA 환경을 예로 들면 수많은 서비스와 컨테이너들이 있고 이들이 서로 네트워킹 하는 상황에서 동시에 관리하기 어려운 상황이 발생할 것이다.
위 그림과 같이 master 노드가 지휘자 역할(orchestration)을 하며 여러개의 worker 노드에 컨테이너들을 적절하게 분산하여 안정적으로 운영할 수 있게 한다.
개괄적인 오케스트레이션의 역할
- 수많은 컨테이너들을 worker 노드에 분산, 배치 (같은 컨테이너는 최대한 다르 노드에 분산)
- 특정 worker 노드가 다운되면 해당 노드에서 실행중이던 컨테이너를 다른 노드에서 재시작
- 필요에 따라 컨테이너 수를 scale-out, scale-in
- etc,
cf. Layer별 분리
쿠버네티스(k8s) 특징
1) 워크로드 분리
여러 개의 호스트 노드에 컨테이너를 분리시켜 운영한다.
2) 선언적 API (자동화의 핵심)
쿠버네티스에 요청을 하기만 하면 내부적으로 알아서 처리한다. 이러한 방식은 쿠버네티스 내부적으로 '추구하는 상태 값'을 지정해주는 것인데, 현재 상태가 어떻든지 간에 쿠버네티스가 알아서 상태를 맞춰준다. 예를 들어 웹 서버를 3개 실행해달라는 요청을 했을 때, 쿠버네티스가 현재 worker 노드들의 상태를 고려해서 알아서 적절하게 배치시킨다. 또한 운영중에 특정 노드에 문제가 생길 경우 해당 노드에 있던 컨테이너를 다른 노드로 옮김으로써 추구하는 상태를 항상 일치시킨다. 이러한 특징 때문에 DevOps, NoOps 등이 가능해진다. 또한 이러한 특징은 마치 운영체제와 비슷한데, 운영체제는 애플리케이션들이 하드웨어 위에서 적절하게 실행될 수 있도록 관리하기 때문이다.
3) vendor-neutral 오픈소스 (어디에서나 실행가능)
여러 가지 오케스트레이션 툴이 있지만 쿠버네티스는 CNCF 재단에서 운영된다는 점이 가장 큰 장점이다. CNCF 재단에서 운영되는 오픈소스이기 때문에 벤더의 종속성이 없다. 벤더사의 종속성이 없다 보니 비용적 측면에서 유리하고 특정 벤더사와의 의존성이 없어 확장성이 좋다. 예를 들어 쿠버네티스는 리눅스와 마찬가지로 온프레미스에서든, public 클라우드(AKS, EKS, GKE 등)든지 간에 상관없이 기존에 작성해둔 yml 파일을 기반으로 동일하게 실행할 수 있다.
cf. 쿠버네티스는 리눅스와 유사하게 다양한 배포판이 존재한다.
1) 관리형 쿠버네티스 : 사용자가 직접 관리하지 않고 AWS, Azure, GCP 등에서 관리해준다.
2) 설치형 쿠버네티스 : rancher, OpenShift 등에서 제공하며 설치할 수 있도록 패키지를 제공(필요한 여러 기능들이 추가된 형태)
3) 구성형 쿠버네티스 : 자유롭게 쿠버네티스를 구성하고 싶을 때 사용(kubeadm)
Reference
- 가상화 이해, https://www.redhat.com/ko/topics/virtualization
'[ DevOps ] > [ k8s ]' 카테고리의 다른 글
[k8s] 쿠버네티스에서 컨테이너 동작 flow (0) | 2022.09.04 |
---|---|
[k8s] containerd, runC, CNI플러그인 설치하기(without Docker, cgroup 활성화) (0) | 2022.08.31 |
[container] 컨테이너 런타임 표준화(OCI 표준) (1) | 2022.08.26 |
[k8s] k8s설치를 위한 VM 구축하기 (feat. Virtual Box) (0) | 2022.08.22 |
[k8s] VM에 쿠버네티스 클러스터 구축하기 (0) | 2022.08.22 |
- Total
- Today
- Yesterday
- LFCS
- GitOps
- 코틀린
- 카프카
- golang
- K8s
- db
- github actions
- Kotlin
- Linux
- 우분투
- rolling update
- jvm
- CICD
- container
- Stream
- Java
- Controller
- argocd
- kafka
- spring
- Non-Blocking
- RDB
- Kubernetes
- ci/cd
- 컨트롤러
- 쿠버네티스
- ubuntu
- go
- docker
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |