구글 스터디잼/쿠버네티스 중급

[Coursera] Containers 및 Kubernetes 소개

남쪽마을밤송이 2022. 9. 1. 20:17

* Coursera, Getting Started with Google Kubernetes Engine 강의 내용입니다.

 

 Introduction to Containers and Kubernetes 

 컨테이너 소개 

얼마 전만 해도 애플리케이션을 배포하는 기본 방식은 실제 컴퓨터에 배포하는 것이었다.

  • 앱을 설치하려면 물리적 공간, 전원 냉각 장치, 네트워크 연결을 준비한 후 운영체제를 깔고 소프트웨어 종속 항목을 먼저 설치해야 했다.
  • 처리, 성능, 중복성, 보안, 확장성의 향상이 필요한 경우에는 컴퓨터를 추가해야 했다.
  • 이러한 방식은 리소스 낭비가 크고 대규모 배포와 유지보수에 많은 시간이 소요될 뿐만 아니라 이동하기가 매우 어렵다.
  • 또한 애플리케이션은 특정 운영체제에 맞게 빌드되었고 특정 하드웨어에 맞춰 빌드되는 경우도 있었다.

 

바로 이점에서 가상화가 필요하다.

  • 가상화를 통해 여러 가상 서버와 운영체제를 동일한 물리적 컴퓨터에서 실행할 수 있다.
  • 하이퍼바이저는 소프트웨어 레이어로서 기본 하드웨어에서 운영체제의 종속성을 해소하여 여러 가상 머신이 하드웨어 하나를 공유할 수 있도록 한다.
    • KVM이 유명한 하이퍼바이저이다.
  • 가상화를 채택하면 새 솔루션 배포 시간이 짧아지고 사용하는 물리적 컴퓨터의 리소스 낭비가 줄어든다.
  • 또 이동성이 향상되는데 가상 머신은 이미지를 만들어 이동할 수 있기 때문이다.
  • 하지만 애플리케이션, 모든 종속 항목과 운영체제는 여전히 번들로 묶여 있게 된다. VM을 하이퍼바이저 제품 간에 이동하는 것은 쉽지 않으며 VM을 시작할 때마다 운영체제를 부팅하는 시간이 소요되는 것이다.

 

단일 VM에서 여러 애플리케이션을 실행하면 또 다른 까다로운 문제가 발생한다.

  • 먼저 종속 항목을 공유하는 애플리케이션이 서로 격리되지 않는 문제가 있다.
  • 또한 특정 애플리케이션의 리소스 요구사항 때문에 다른 애플리케이션에서 필요한 리소스를 확보하지 못할 수 있다.
  • 그뿐만 아니라 특정 애플리케이션의 종속 항목 업그레이드로 인해 다른 애플리케이션이 실행 중지될 수 있다.

 

엄격한 소프트웨어 엔지니어링 정책으로 문제 해결을 시도해 볼 수도 있다.

  • 예를 들어 종속 항목을 잠그고 어느 애플리케이션에서도 이를 변경할 수 없도록 할 수 있지만 그러면 새 문제가 생긴다. 종속 항목은 종종 업그레이드가 필요하기 때문이다.
  • 애플리케이션 작동을 확인하는 통합 테스트는 효과적이지만 종속 항목 문제가 새 장애를 일으키고 해결이 어려울 수 있다. 그리고 애플리케이션 환경의 기본 무결성을 확인하기 위해 통합 테스트를 이용해야 하는 경우 개발 속도가 크게 저하된다.
  • VM 중심으로 이 문제를 해결하는 방법은 애플리케이션마다 전용 가상 머신을 실행하는 것이다. 각 애플리케이션에서 고유 종속 항목을 유지 관리하고 커널이 격리되어 있으므로 애플리케이션끼리 성능에 영향을 미치지 않는다.
    • 하지만 이 상황을 수십만 개 애플리케이션으로 확장하면 문제가 금방 드러난다. 간단한 커널 업데이트만 생각해도 대규모 시스템의 경우 전용 VM은 중복적이며 낭비이다. 또한 VM은 시작하는 속도가 비교적 느린데 전체 운영체제를 부팅해야 하기 때문이다.

 

종속 항목 문제를 더 효율적으로 해결하려면 애플리케이션과 종속 항목 수준에서 추상화를 구현하면 된다.

  • 이 때 전체 머신 또는 전체 운영체제가 아니라 사용자 공간만 가상화한다.
  • 다시 말해 사용자 공간은 커널 위에 있는 모든 코드이며 애플리케이션과 종속 항목을 포함하는데 이것이 컨테이너를 만든다는 의미이다. 컨테이너는 단일 애플리케이션 코드를 실행하는 격리된 사용자 공간이다.
  • 이렇게 하면 운영체제 전체를 실행하지 않으므로 가볍다. 또한 기본 시스템 위에서 예약하고 패키징하므로 매우 효율적이다.
  • 컨테이너는 아주 빠르게 만들고 종료할 수 있다. 애플리케이션을 구성하는 프로세스만 시작 또는 중지하고 전체 VM을 부팅하거나 각 애플리케이션의 운영체제를 초기화하지 않기 때문이다.
  • 개발자에게 이러한 추상화가 유용한 이유는 시스템의 나머지는 신경 쓰지 않아도 되기 때문이다. 코드 관리의 진화에서 다음 단계는 컨테이너화라 할 수 있다.

 

컨테이너는 가볍고 독립적이고 리소스 효율이 높으며 이동성이 우수한 실행 패키지이다.

  • 컨테이너를 사용하면 VM에서 최종 코드를 실행할 때 소프트웨어 종속 항목 즉 애플리케이션 런타임, 시스템 도구 시스템 라이브러리, 기타 설정에 신경 쓰지 않아도 된다.
  • 개발자가 컨테이너를 선호하는 것은 애플리케이션 중심으로 확장성 높은 고성능 애플리케이션을 제공하기 때문이다.
  • 또한 컨테이너를 사용하면 개발자가 기본 하드웨어와 소프트웨어를 전제로 작업할 수 있다.
    • 예를 들어 Linux 커널 기반 환경의 경우 노트북에서 작동하는 코드가 프로덕션 환경에선 실패하는 일이 없어진다.
    • 모든 환경에서 동일한 컨테이너가 동일하게 실행되는 것이다.
  • 그리고 프로덕션 이미지를 기반으로 컨테이너를 점진적으로 변경하고 파일 복사 한 번으로 이를 빠르게 배포할 수 있기 때문에 개발 프로세스가 빨라진다.
  • 마지막으로 컨테이너는 애플리케이션을 쉽게 빌드할 수 있는데 이 애플리케이션은 마이크로서비스 설계 패턴 즉, 느슨하게 결합되고 세분화된 구성요소를 사용한다. 이러한 모듈식 설계 패턴은 운영체제를 확장하고 애플리케이션의 구성요소를 업그레이드하면서도 전체 애플리케이션에는 영향을 주지 않는다.

 

 Why developers like containers 

애플리케이션과 종속 항목을 '이미지'라고 한다. 간단히 말해 컨테이너는 실행 중인 이미지 인스턴스인 것이다.

  • 소프트웨어를 컨테이너 이미지로 빌드하면 개발자는 손쉽게 애플리케이션을 패키징하고 제공할 수 있으며 앱이 실행될 시스템 걱정은 안 해도 된다.
  • 컨테이너 이미지를 빌드하고 실행하려면 소프트웨어가 필요한데 Docker라는 오픈소스 기술로 컨테이너에서 애플리케이션을 개발, 실행할 수 있다.
  • 하지만 Docker는 Kubernetes처럼 애플리케이션을 대규모로 조정하는 방법은 제공하지 않는다.

 

 Containers use a varied set of Linux technologies 

컨테이너는 Linux에 내장된 기본 기능이 아니고 워크로드를 격리하는 기능은 몇 가지 기술을 조합한 것인데 그 기반 기술 중 하나가 Linux 프로세스이다.

  • Linux 프로세스마다는 서로 분리된 고유의 가상 메모리 주소 공간이 있고 Linux 프로세스는 빠르게 생성하고 삭제할 수 있다.
  • 컨테이너는 Linux 네임스페이스를 사용하여 애플리케이션에 제공할 항목인 프로세스 ID 번호, 디렉터리 트리, IP 주소 등을 제어한다. 이때 Linux 네임스페이스와 Kubernetes 네임스페이스는 동일하지 않다.
  • 컨테이너는 Linux cgroup으로 애플리케이션이 사용할 수 있는 CPU 시간, 메모리, I/O 대역폭 기타 리소스의 최대 사용량을 제어한다.
  • 마지막으로 컨테이너는 유니온 파일 시스템을 사용하여 애플리케이션과 종속 항목을 간결한 최소 레이어 모음으로 효율적으로 캡슐화한다.

 

 Containers are structured in layers 

컨테이너 이미지는 여러 레이어로 구조화되어 있다.

  • 이미지 빌드에 사용하는 도구는 '컨테이너 매니페스트'라는 파일에서 안내를 읽어온다.
    • Docker 형식의 컨테이너 이미지의 경우 이를 Dockerfile이라고 한다.
    • Dockerfile의 안내에 따라 컨테이너 이미지 내부 레이어가 지정된다.
  • 각 레이어는 읽기 전용이다.
  • 이 이미지에서 컨테이너를 실행하는 경우 쓰기 가능한 임시 최상위 레이어도 생성된다.

 

간단한 Dockerfile을 살펴보자.

이 Dockerfile의 명령어 4개는 각각 하나의 레이어를 생성한다.

  • 먼저 FROM 문으로 기본 레이어를 공개 저장소에서 가져와 생성한다. 여기서는 특정 버전의 Ubuntu Linux 런타임 환경이 사용되었다.
  • COPY 명령어로 새 레이어를 추가하는데 여기에는 빌드 도구의 현재 디렉터리에서 복사한 파일이 포함되어 있다.
  • RUN 명령어는 make 명령어를 사용하여 애플리케이션을 빌드하고 빌드 결과를 세 번째 레이어에 배치한다.
  • 끝으로 마지막 레이어는 실행 시 컨테이너 내에 실행할 명령어를 지정한다.

 

각 레이어는 이전 레이어와 일정 부분만 다를 뿐이다.

  • 따라서 Dockerfile을 작성할 때는 변경할 가능성이 가장 낮은 레이어에서 변경할 가능성이 가장 높은 레이어로 구성해야 한다.
  • 하지만 요즘은 배포 및 실행하는 컨테이너에 애플리케이션을 빌드하는 것은 권장하지 않는다. 빌드 도구는 배포된 컨테이너를 혼잡하게 할 뿐이며 최악의 경우 추가 공격에 노출될 수 있기 때문이다.
  • 대신 요즘은 애플리케이션 패키징에 다단계 빌드 프로세스를 이용하는데 이 경우 한 컨테이너에서 최종 실행 가능한 이미지를 빌드하고 다른 컨테이너에는 애플리케이션 실행에 필요한 항목만 포함한다.

 

이미지에서 새 컨테이너를 만들면 컨테이너 런타임에서는 쓰기 가능한 레이어를 기본 레이어 위에 추가하는데 이 레이어를 보통 '컨테이너 레이어'라고 한다.

  • 실행 중인 컨테이너에 대한 새 파일 쓰기, 기존 파일 수정 및 파일 삭제와 같은 모든 변경사항은 쓰기 가능하고 얇은 컨테이너 레이어에 기록된다. 그런데 이는 모두 임시 변경사항이므로 컨테이너가 삭제되면 이 레이어의 내용도 영구 삭제된다. 반면 기본 컨테이너 이미지 자체는 변경되지 않은 상태로 유지된다.
  • 애플리케이션을 설계할 때 이러한 컨테이너의 특징을 고려해야 한다. 데이터를 영구적으로 저장하고 싶다면 실행 중인 컨테이너 이미지가 아닌 다른 곳에서 작업해야 하는 것이다.

 Containers promote smaller shared images 

각 컨테이너에는 쓰기 가능한 고유의 컨테이너 레이어가 있고 모든 변경사항이 이 레이어에 저장되므로 여러 컨테이너가 동일한 기본 이미지에 액세스 권한을 공유하면서도 자체 데이터 상태를 보유한다.

  • 이 다이어그램은 여러 컨테이너에서 동일한 Ubuntu 15.04 이미지를 공유하는 것을 보여준다.
  • 각 레이어에는 이전의 레이어와는 다른 항목만 모여 있으므로 이미지 크기가 더 작아진다.
    • 예를 들어 기본 애플리케이션 이미지는 200MB이지만 다음 포인트 출시 버전과의 차이는 200KB에 불과할 수 있다.
    • 그러면 전체 이미지를 복사하는 대신 컨테이너를 빌드하는 경우 차이만 포함된 레이어를 생성한다.
    • 컨테이너를 실행하면 컨테이너 런타임에서 필요한 레이어를 가져온다. 업데이트할 때는 차이가 나는 항목만 복사하면 된다. 이렇게 하면 새 가상 머신을 실행하는 것보다 훨씬 빠르다!
  • 누구나 사용 가능한 오픈소스 컨테이너 이미지를 고유 이미지의 기반으로 사용하거나 그대로 사용하는 경우가 많다.
    • 예를 들어 앞서 사용해 본 Ubuntu 컨테이너 이미지도 컨테이너 내에서 Ubuntu Linux 환경을 제공한다.
    • Alpine은 자주 사용되는 컨테이너 내 Linux 환경으로 매우 작은 크기로 잘 알려져 있다.
    • 또 NginX 웹 서버는 컨테이너 패키징에 자주 사용된다.

 

Google은 Container Registry인 gcr.io를 유지 관리한다. 이 레지스트리에는 공개 오픈소스 이미지가 다수 포함되어 있으며 Google Cloud 고객도 이를 사용하여 비공개 이미지를 Cloud IAM과 잘 통합되는 방식으로 저장한다.

  • Google Container Registry는 Cloud IAM과 통합되므로 예를 들어 공개되지 않은 이미지를 저장하는 데 사용할 수 있다. 이러한 이미지는 프로젝트 전용 비공개 이미지가 된다.
  • 컨테이너 이미지는 다른 공개 저장소, 예를 들면 Docker Hub 레지스트리 및 GitLab 등에서도 찾을 수 있다.

 

오픈소스 Docker 명령어는 고유 컨테이너 이미지 빌드 시 자주 쓰는 방법으로 널리 알려져 있고 광범위하게 사용된다.

  • Docker 명령어로 컨테이너를 빌드할 때 한 가지 단점은 반드시 신뢰할 수 있는 컴퓨터에서 빌드해야 한다는 점이다.
  • Google에서 제공하는 관리형 서비스는 Cloud IAM과도 통합되는 컨테이너 빌드용이다. 이걸 Cloud Build라고 한다.

 

 Cloud Build 

Cloud Build는 빌드에 필요한 소스 코드를 다양한 스토리지 위치에서 검색할 수 있다.

  • Cloud Source Repositories Google Cloud의 객체 스토리지 서비스인 Cloud Storage 또는 GitHub, Bitbucket 같은 Git 호환 저장소가 있다.
  • Cloud Build로 빌드를 생성하려면 일련의 단계를 정의한다.
    • 예를 들어 빌드 단계를 구성하여 종속 항목 가져오기 소스 코드 컴파일, 통합 테스트 실행, Docker, Gradle, Maven 등의 도구 사용이 가능하다.
  • Cloud Build의 각 빌드 단계는 Docker 컨테이너에서 실행된다.
  • 그런 다음 Cloud Build에서 새로 빌드한 이미지를 다양한 실행 환경에 제공할 수 있다. GKE는 물론 App Engine, Cloud Functions도 가능하다.