티스토리 뷰

프로그래밍/Kubernetes

쿠버네티스 개요

국윤창 2023. 1. 17. 00:30

쿠버네티스를 사용하는 이유

기존 대부분의 애플리케이션은 모놀리스(monolith) 형태로 이루어져있었다. 모놀리스 애플리케이션을 운영할 때 장애가 나거나 서버를 확장할 때는 새로운 서버에 동일한 환경을 직접 구성하여 마이그레이션했다.
이런 부분을 개선하기 위해 마이크로서비스 형태로 개발하고 있지만 애플리케이션을 구성하는 요소의 수가 많아지고 규모가 커지면 시스템을 원활하게 구성, 관리, 유지하기가 어려워진다.

쿠버네티스를 사용하면 마이크로서비스의 구성, 관리, 장애 처리를 자동화할 수 있고 서버 배포를 자동으로 스케줄링할 수 있다.

쿠버네티스를 사용하면 하드웨어 인프라를 추상화하여 데이터 센터 전체를 하나의 컴퓨팅 리소스로 제공한다. 따라서 사용하는 서버의 정보를 자세히 알 필요 없이 애플리케이션 구성요소를 배포하고 실행할 수 있다.

모놀리스 대신 마이크로서비스

모놀리스 애플리케이션을 사용하는 서버를 확장할 때는 서버의 성능을 늘리거나(수직확장), 서버를 늘려서 확장(수평확장)해야 한다. 수직확장은 비용이 많이 들며, 수평확장은 모놀리스 애플리케이션에선 일부분만 수평확장하는 것이 어렵거나 불가능하다.

마이크로서비스로 애플리케이션을 분할하면 위와 같은 문제를 해결할 수 있다. 마이크로서비스는 독립적으로 배포할 수 있는 작은 구성 요소의 집합이다. 각 마이크로서비스는 독립적인 프로세스로 실행되며 HTTP, gRPC와 같은 프로토콜로 서로 통신한다. 이와같이 API 형태로 통신하므로 이들 중 하나를 변경해도 다른 서비스를 변경하거나 재배포하지 않아도 된다.

모놀리스 애플리케이션과 독립 실행형 마이크로서비스의 구성 요소 비교

마이크로서비스는 각각의 서비스별로 확장되므로 다른 서비스는 건드릴 필요가 없다. 따라서 모놀리스 애플리케이션과 달리 일부분만 수평확장하는 것이 쉽다.

각 마이크로서비스는 개별적으로 확장 가능하다.

마이크로서비스의 단점은 구성 요소가 많아지면 배포 조합과 구성 요소간 상호 종속성 수가 많아져서 배포 관련 결정이 어려워진다는 것이다. 쿠버네티스를 사용하면 배포할 때 하나의 시스템처럼 동작할 수 있도록 구성해줘서 이런 단점을 극복할 수 있다.

애플리케이션에 동일한 환경 제공

쿠버네티스를 사용하면 개발환경과 프로덕션 환경을 동일하게 만들 수 있어서 프로덕션 환경에서만 발생하는 문제를 줄일 수 있다. 쿠버네티스는 컨테이너를 이용해 운영체제, 라이브러리, 시스템 구성, 네트워킹 환경 등을 개발, 운영환경에 상관없이 동일하게 구성할 수 있다.

DevOps

개발자가 배포와 운영까지 담당하여 신규 애플리케이션을 더 쉽고 빠르게 사용자에게 제공하는 것을 DevOps라고 한다.
DevOps를 하기 위해선 배포 프로세스를 간소화해야 한다. 보통 배포를 하기 위해선 인프라와 데이터 센터의 하드웨어 구성에 대한 이해가 필요하지만 쿠버네티스는 하드웨어를 추상화하기 때문에 이런 세부 정보를 몰라도 배포를 할 수 있다. 따라서 운영 담당자를 기다리지 않고 배포할 수 있기때문에 애플리케이션을 더 자주 릴리즈할 수 있다.

컨테이너 기술

쿠버네티스는 애플리케이션을 격리하기 위해 리눅스 컨테이너 기술을 사용한다.

컨테이너 이해

컨테이너는 호스트 내에서 프로세스처럼 실행되지만 다른 프로세스와 격리돼 있다.

가상머신과 달리 컨테이너는 오버헤드가 적은데, 가상머신은 시스템 프로세스를 실행해야 하기 때문에 추가 컴퓨팅 리소스가 필요하고 컨테이너는 격리된 프로세스에 지나지 않는다.
애플리케이션 그룹이 여러개 있을 경우 가상머신을 사용하면 시스템 프로세스도 같이 많아지므로 여러개의 애플리케이션 그룹을 배포해야한다면 컨테이너를 이용하는 것이 좋다.

가상머신에 애플리케이션을 분리하는 것과 컨테이너로 각 애플리케이션을 격리하는 것의 차이점

가상머신에서 시스템 콜을 호출하면 하이퍼바이저를 통해 호스트의 CPU에서 명령을 수행하지만, 컨테이너는 호스트 OS의 커널에서 시스템 콜을 수행한다.
가상머신은 컨테이너에 비해 오버헤드가 많지만 호스트 OS의 커널과 분리되어 있어서 보안위험이 컨테이너에 비해 적다.

가상머신의 애플리케이션이 CPU를 사용하는 방식과 컨테이너에서 사용하는 방식의 차이점

컨테이너가 동일한 운영환경에서 프로세스를 격리하는 방법은 리눅스 네임스페이스와 리눅스 컨트롤 그룹이다.
리눅스 네임스페이스는 각 프로세스가 시스템(파일, 프로세스, 네트워크 인터페이스, 호스트 이름 등)에 대한 독립된 뷰만 볼 수 있도록 한다.
리눅스 컨트롤 그룹은 프로세스가 사용할 수 있는 리소스(CPU, 메모리, 네트워크 대역폭 등)의 양을 제한한다.

리눅스 네임스페이스는 초기 구동 시 하나만 있지만 추가로 네임스페이스를 생성하고 리소스를 구성할 수 있다. 프로세스를 생성할 때 네임스페이스 중 하나에서 프로세스를 실행한다. 서로 다른 네임스페이스에 존재하는 프로세스의 네트워크나 프로세스 간 통신 등을 격리할 수 있어서 이를 이용해 컨테이너 여러개를 네임스페이스 별로 격리할 수 있다.

컨테이너가 사용할 수 있는 시스템 리소스의 양을 제한하는 방법은 리눅스 커널 기능 중 cgroups을 이용하는 것이다. 프로세스는 설정된 양 이상의 CPUI, 메모리, 네트워크 대역폭 등을 사용할 수 없다.

도커 컨테이너 플랫폼

도커는 애플리케이션 뿐만 아니라 라이브러리, 여러 종속성, 운영체제 파일시스템까지도 패키징하여 다른 컴퓨터로 쉽게 프로비저닝할 수 있게 만들었다.

도커로 패키징된 애플리케이션을 실행하면 서로 다른 환경의 리눅스 운영체제에서도 동일한 파일을 볼 수 있다. 도커로 실행된 애플리케이션은 실행 중인 서버의 내용은 볼 수 없으므로 개발 컴퓨터와 다른 라이브러리가 설치돼 있는지는 중요하지 않다.

도커 컨테이너 이미지는 가상머신과 거의 동일한 수준의 격리를 제공하지만 훨씬 작은 컨테이너 이미지를 사용한다. 가장 큰 차이점은 도커 컨테이너 이미지가 여러 이미지에서 공유되고 재사용될 수 있는 레이어로 구성돼 있다는 것이다. 동일한 레이어를 포함하는 컨테이너 이미지를 다운로드 받을 때 이미 설치된 레이어는 건너뛴다.

도커의 주요 개념은 아래와 같다.

 

  • 이미지: 애플리케이션과 해당 환경을 패키지한 것이다. 애플리케이션에서 사용할 수 있는 파일시스템과 실행경로와 같은 메타데이터도 포함한다.
  • 레지스트리: 도커 이미지를 저장하고 공유할 수 있는 저장소이다.
  • 컨테이너: 도커 기반 컨테이너 이미지에서 생성된 리눅스 컨테이너다. 실행 중인 컨테이너는 호스트에서 실행되는 프로세스로 보이지만 다른 프로세스와는 완전히 격리돼 있다. 또한 프로세스는 할당된 리소스의 양만 엑세스하고 사용할 수 있다.

도커 이미지, 레지스트리, 컨테이너

도커 이미지는 레이어로 구성돼 있다. 모든 도커 이미지는 다른 이미지 위에 빌드되며 서로 다른 두개의 이미지가 같은 부모 이미지를 사용할 수 있으므로 정확히 동일한 레이어를 포함할 수 있다. 이 때문에 이미 전송한 레이어를 다른 이미지를 전송할 때 다시 전송할 필요가 없기 때문에 네트워크로 이미지를 배포하는 속도가 빨라진다.

각 레이어는 호스트에 한번만 저장되기 때문에 같은 이미지를 사용하는 컨테이너는 동일한 파일을 읽게된다. 하지만 그중 하나가 파일을 덮어써도 다른 컨테이너에서 이 변경사항을 볼 수 없는데, 컨테이너 이미지 레이어는 읽기 전용이고 컨테이너가 실행될 때마다 레이어 위에 쓰기 레이어가 새로 만들어지기 때문이다. 따라서 쓰기 레이어를 각 컨테이너가 가지고 있으므로 어떤 컨테이너가 쓰기 레이어에 쓰더라도 다른 컨테이너에선 볼 수가 없는 것이다.

컨테이너 이미지는 모든 리눅스 시스템에서 실행될 수 있지만, 컨테이너가 호스트의 리눅스 커널을 사용하기 때문에 애플리케이션이 특정 커널 버전이 필요하다면 이식성이 떨어진다.
커널 버전뿐만 아니라 특정 하드웨어 아키텍처용으로 만들어진 애플리케이션도 특정 하드웨어의 호스트에서만 동작하므로 이식성이 떨어진다.
이런 애플리케이션은 컨테이너 대신 가상머신을 사용해야 한다.

쿠버네티스

쿠버네티스를 사용하면 모든 노드가 하나의 컴퓨터인 것처럼 소프트웨어 애플리케이션을 실행할 수 있다. 쿠버네티스는 기본 인프라를 추상화하고 개발과 운영 팀 모두의 개발, 배포, 관리를 단순화한다.
클러스터에 노드가 얼마나 있든 쿠버네티스로 애플리케이션을 배포하는 것은 항상 동일하다. 클러스터에 노드를 추가하는 것은 단순히 리소스 양이 추가되는 것을 의미한다.

쿠버네티스 시스템은 마스터 노드와 여러 개의 워커 노드로 구성된다. 개발자가 애플리케이션 매니페스트를 마스터에 게시하면 쿠버네티스는 해당 애플리케이션을 워커 노드 클러스터에 배포한다.

쿠버네티스는 전체 데이터 센터를 하나의 배포 플랫폼으로 제공한다.

쿠버네티스를 사용하면 개발자가 특정 인프라 관련 서비스를 애플리케이션에 구현하지 않아도 된다. 쿠버네티스가 이런 서비스를 대신 제공한다. 서비스 디스커버리, 스케일링, 로드밸런싱, 자가 치유, 리더 선출 같은 것들이 이에 해당한다. 따라서 개발자는 애플리케이션의 실제 기능을 구현하는데 집중할 수 있다.

쿠버네티스 클러스터 아키텍처

쿠버네티스 클러스터의 노드는 두 가지 유형으로 나눌 수 있다.

 

  • 마스터 노드: 쿠버네티스 시스템을 제어하고 관리하는 쿠버네티스 컨트롤 플레인을 실행한다.
  • 워커 노드: 배포되는 컨테이너 애플리케이션을 실행한다.

쿠버네티스 클러스터를 구성하는 구성 요소

컨트롤 플레인은 클러스터를 제어하고 작동시킨다. 컨트롤 플레인의 구성요소는 아래와 같다.

 

  • 쿠버네티스 API는 사용자와 컨트롤 플레인 구성 요소와 통신한다.
  • 스케줄러는 애플리케이션의 배포는 담당한다. (애플리케이션의 배포 가능한 각 구성 요소를 워커 노드에 할당)
  • 컨트롤러 매니저는 구성 요소 복제본, 워커 노드 추적, 노드 장애 처리와 같은 클러스터단의 기능을 수행한다.
  • Etcd는 클러스터 구성을 지속적으로 저장하는 신뢰할 수 잇는 분산 데이터 저장소다.

워커 노드는 컨테이너화된 애플리케이션을 실행하는 시스템이다. 워커 노드는 아래의 구성 요소로 이루어진다.

 

  • 컨테이너를 실행하는 컨테이너 런타임 (도커, rkt 등)
  • 컨트롤 플레인의 API 서버와 통신하고 노드의 컨테이너를 관리하는 kubelet
  • 애플리케이션 구성 요소 간에 네트워크 트래픽을 로드밸린싱하는 쿠버네티스 서비스 프록시 (kube-proxy)

쿠버네티스에서 애플리케이션 실행

쿠버네티스에서 애플리케이션을 실행하려면 이미지로 애플리케이션을 패키징하고 레지스트리에 등록한 뒤 쿠버네티스 API 서버에 애플리케이션 디스크립션을 게시해야 한다.

 

디스크립션에는 컨테이너 이미지, 애플리케이션 구성 요소가 서로 통신하는 방법, 동일 서버에 함께 배치돼야 하는 구성 요소와 같은 정보가 포함된다. 각 구성 요소의 복제본 수를 지정할 수도 있다. 또한 IP 주소로 노출해 다른 구성 요소에서 검색 가능하게 하는 구성 요소도 포함될 수 있다.

 

API 서버가 애플리케이션 디스크립션을 처리할 때 스케줄러는 각 컨테이너에 필요한 리소스를 계산하고 각 노드에 가용할 수 있는 리소스를 파악하여 사용 가능한 워커 노드에 지정된 컨테이너를 할당한다. 그 다음 워커 노드의 kubelet은 컨테이너 런타임에 필요한 이미지를 가져와 실행하도록 지시한다.

 

쿠버네티스 아키텍처와 그 위에서 실행되는 애플리케이션의 기본 개요

쿠버네티스는 애플리케이션의 배포 상태가 사용자가 제공한 디스크립션과 일치하는지 지속적으로 확인한다. 프로세스가 중단되거나 응답이 중지될 때와 같이 인스턴스가 제대로 작동하지 않으면 쿠버네티스가 자동으로 다시 시작한다.

마찬가지로 워커 노드가 종료되거나 엑세스할 수 없게되면 쿠버네티스는 이 노드에서 실행 중인 모든 컨테이너의 노드를 새로 스케줄링하고 새로 선택한 노드에서 실행한다.

 

애플리케이션의 복제본 수를 늘리거나 줄일 수 있다. 쿠버네티스는 추가 복제본을 기동하거나 초과 복제본을 정지시킨다. 최적의 복제본 수를 결정하는 작업을 쿠버네티스에게 맡길 수도 있따. CPU 부하, 메모리 사용량, 초당 요청 수와 같은 매트릭을 기반으로 복제본 수를 자동으로 조정할 수 있다.

 

쿠버네티스에 배포된 애플리케이션은 워커 노드 중 하나에 배포된다. 외부에서 애플리케이션에 접근하는 경우 배포된 노드는 매번 다를 수 있기 때문에 배포된 컨테이너를 찾아서 접근할 수 있는 방법이 필요하다.

쿠버네티스는 특정 컨테이너 그룹을 쉽게 찾을 수 있도록 하나의 고정 IP 주소로 컨테이너들을 노출하는 방법을 제공한다. (후에 쿠버네티스 서비스를 설명할 때 자세히 다룬다.)

 

이렇게 노출된 컨테이너 접근하면 kube-proxy가 요청을 로드밸런싱한다. 서비스의 IP 주소는 일정하게 유지되므로 클라이언트는 컨테이너가 어느 노드에 있더라도 항상 연결할 수 있다.

쿠버네티스 사용의 장점

쿠버네티스는 모든 워커 노드를 하나의 배포 플랫폼으로 제공하기 때문에 애플리케이션 개발자는 자체적으로 배포를 시작할 수 있으며 클러스터를 구성하는 서버에 관해 알 필요가 없다.

다만 특정 하드웨어나 특정 버전의 OS에서 실행해야만 하는 경우 애플리케이션이 특정 노드에 배포되어야만 한다. 쿠버네티스는 특정 노드 그룹에 배포하도록 선택하는 것이 가능하다. 이는 후에 설명한다.

 

쿠버네티스를 이용해 애플리케이션을 배포하면 노드의 리소스를 최대한 활용할 수 있다. 쿠버네티스가 리소스에 맞는 노드를 찾아 배포하기 때문이다. 노드와 컨테이너 수가 많을수록 사람이 하는 것보다 쿠버네티스가 하는 것이 유리하다.

 

쿠버네티스는 애플리케이션 구성 요소와 노드를 모니터링하다가 장애 발생 시 자동으로 다른 노드로 스케줄링한다. 이 과정을 자동으로 이루어지기 때문에 수동으로 마이그레이션할 필요가 없어지고 장애에 대응하느라 소모하는 시간이 적어진다.

 

또한 부하 급증에 대응하느라 모니터링할 필요가 적어진다. 쿠버네티스가 리소스를 모니터링하고 인스턴스 수를 조정하도록 지시할 수 있다.

 

쿠버네티스를 사용하면 애플리케이션 개발이 단순화된다. 쿠버네티스를 사용하면 개발과 프로덕션 환경을 동일하게 구성할 수 있기 때문에 버그를 미리 발견할 수 있다.

또한 일반적으로 구현해야 하는 기능을 구현할 필요가 없다. 예를 들면, 쿠버네티스 API 서버를 쿼리하면 개발자가 리더 선정과 같은 매커니즘을 구현하지 않아도 된다.

마지막으로 쿠버네티스를 사용하면 개발자들의 신뢰가 높아진다. 애플리케이션을 배포할 때 새로운 버전이 잘못됐는지 자동으로 감지하고 즉시 롤아웃을 중지하기때문에 CD가 가속화되어 조직 전체에 도움이 된다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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
글 보관함