본문 바로가기
쿠버네티스,도커

컨테이너 기술, 쿠버네티스, 도커

by 흰색남자 2022. 11. 21.

최근 on-premis 환경보다 클라우드 서비스가 보편화되면서 도커, 쿠버네티스 등 컨테이너 시스템을 사용하는 아키텍처가 각광받고 있다.

그래서 컨테이너 기술, 쿠버네티스, 도커를 정리해보자. 

컨테이너는 가상화 ( 하이퍼바이저 ) 기술을 사용하여 애플리케이션에 필요한 모든 구성요소 ( 네트워크, memory, cpu, 파일) 을 하나의 런타임 환경으로 묶는데 사용한다.

cgroupfs 를 사용하여 리눅스 os에서 자원을 할당받고, 네임스페이스를 활용하여 할당받은 자원을 다른 네임스페이스와 격리시킨다. 마지막으로 chroot 기술을 사용하여 다른 컨테이너와 루트 디렉터리를 격리시킨다.

 

그래서 컨테이너는 ‘애플리케이션’과 ‘애플리케이션을 구동하는 환경’을, ‘Host OS’ 로부터 격리한 공간을 의미한다.

 

 

컨테이너 기술을 사용하는 이유는 기존에 사용하는 

1. 모든 자원이 이미 컨테이너 안에 들어있으므로, 플랫폼에 종속되지 않고 운영/배포가 가능하다.

2. 컨테이너 별 자원을 다르게 할당하여 자원 관리에서 효율적으로 할 수 있다.

3. 개발 측면에서도 개발자는 디버킹, 환경에서 미치는 요인을 신경쓰지 않고 애플리케이션 개발에만 집중이 가능하다.

 

그럼 기존의 하이퍼바이저보다 컨테이너 기술이 뛰어난 이유는 무엇일까

1. vm은 일단 type2 가상화 기술을 사용한다. 그러므로 하드웨어 / os / 하이퍼바이저 / os ~ os 이런 구조로 존재한다.

그래서 하나의 vm을 구성하려면 os이미지, 환경 구성에 필요한 라이브러리, 애플리케이션에 필요한 파일 및 라이브러리가 묶여있다.

하지만, 컨테이너 기술을 사용하면 최소한의 애플리케이션에 필요한 파일 및 라이브러리만 필요로한다.

왜냐하면 호스트 시스템의 os 커널을 공유하여 사용하기 때문이다. 또한 부팅할 os도 없기 때문에 시작시간도 빠르다.

하이퍼 바이저 기술은 하드웨어를 사용하려고 하면  type1 기준

다음과 같은 여러 단계를 거쳐야하기 때문에 느리다. 물론 반가상화 환경에서는 2단계로 줄어든다.

그래도 여전히 호스트 os의 커널을 공유하지 못하여 vm마다 겹치는 환경이 존재한다.

 

이러이러한 이유때문에 컨테이너 기술이 중요하다.

 

그렇다면 컨테이너 기술을 사용하기 위한 기술에는 무엇이 있을까?

1. 일단 이미지를 빌드해야한다.

# 도커란? 프로세스 격리 기술( containerd, chroot, namespace, cgroupfs 등 )을 활용하여 컨테이너로 실행하고 관리하는 오픈소스 프로젝트. 하나의 컴퓨터에서 여러개의 시스템, 환경이 충돌하지 않고 동시에 사용할 수 있도록 격시키려 실행하는 프로그램.

 

도커 이미지 빌드 과정을 설명하면,

다음과 같은 순서로 실행한다.

 

도커 이미지는 다음과 같이 구성되어 있다.

흡사 zip파일과 비슷하다는 것을 볼 수 있다.

특이한 점이라면 레이어를 공유한다는 것인데, 처음 이미지를 빌드할 경우에는 구축된 레이어가 하나도 없어 느리지만,

2번째 빌드하는 이미지 부터는 처음 이미지의 일정 부분을 공유하기 때문에 빌드 속도가 빠르다.

공유되는 이미지 레이어가 있으므로 파일 시스템에서 차지하는 전체 용량도 감소한다는 장점이 있다.

 

그럼 이제 도커를 구성하는 환경에 대해서 설명해보자.

도커를 설치하면 docker, docker-init, docker-proxy, dockerd, containerd, containerd-shim 등 주요 파일이 생긴다.

이걸 이제 정리해보자.

1. docker

도커 클라이언트 ( CLI ) 를 수행하기 위한 바이너리 파일.

사용자가 도커 엔진으로부터 다양한 명령을 요청할 때 사용함.

도커 클라이언트와 서버 간 통신 방식으로는 Unix Domain Socker( IPC )를 사용함.

 

2. docker-init

docker run 실행 시 --init 옵션을 주면 실행됨. docker run 수행 시 넘겨준 command가 1번 프로세스가 됨.

 

container 내에서 init process 를 1 번으로 구동한다는 것은 중요한 의미가 있다.
이는 child process 를 받아주어 resource 의 누수나 zombie process 의 생성 등을 방지하는 init system 의 역할을 container 내에서 수행한다는 뜻이기 때문

 

3. docker-proxy

컨테이너가 기동될 경우 -p ${in port}:${container port} 옵션을 줄 경우. 도커 프록시에 의해 호스트로 들어온 요청을 컨테이너 포트로 넘겨주는 역할을 수행한다.

 

4. dockerd, containerd

이 둘을 합쳐서 docker engine라고 부른다.

  • dockerd ( docker daemon ) : volume, image, networking 관리 뿐 아니라 orchestration 까지 관장하여 처리한다. client 로부터 REST API 형식의 요청을 수신하여 처리한다.
  • containerd : 이미지를 push 하고 pull 하고, 스토리지를 관리하고, 네트워크 기능을 정의할 수 있는 독립 실행형 고수준(high-level) 컨테이너 런타임. runc 같은 저수준(low-level)의 컨테이너 런타임에 해당 명령을 전달하여 container 의 lifecycle 을 관리한다. client 로부터의 container 관리 관련 요청은 dockerd 를 거쳐 gRPC 통신을 통해 containerd 로 전달된다.

# GRPC : 프로그램간 통신 기법. Remote Produce Call

 

 

5. containerd-shim, runc

containerd-shim : containerd-shim runc를 실행하고, 컨테이너 프로세스를 제어하는 경량 데몬입니다. 컨테이너와 containerd 의 모든 통신은 containerd-shim 을 통해서 이루어짐

  • 컨테이너의 stdout 및 stderr의 스트림을 제공해 주고 있습니다. 그래서 containerd 가 재시작 중에도 문제가 발생하지 않습니다. containerd 는 stdout 및 stderr의 스트림을 받아서 로그 파일로 저장을 할 수 있습니다.
  • runc 는 컨테이너 프로세스를 실행(fork)한 다음, 포그라운드 프로세스를 종료하여, 컨테이너 프로세스를 의도적으로 데몬화 합니다. 이렇게 되면, 컨테이너 프로세스는 호스트의 init 프로세스가 담당하게 되어서, 컨테이너의 관리가 어려워집니다. 이 문제를 해결하기 위해 shim 프로세스를 subreaper로 만들어서, 컨테이너 프로세스를 shim 프로세스가 관리하도록 합니다.

runc : OCI 런타임 스펙을 구현하고 있는 저수준 컨테이너 런타임입니다. 저수준 컨테이너 런타임이라고 부르는 이유는, 오직 실행 중인 컨테이너 관리에만 그 범위를 집중시키고 있기 때문입니다. 리눅스 커널의 네임스페이스와 cgroups 을 사용하여 격리시키는 기능을 제공합니다. 컨테이너를 생성(spawning)과 실행(running) 할 수있는 CLI로 구현되어 있습니다.

 

 

쿠버네티스는?

도커가 이미지를 빌드시키고 하나의 컨테이너를 관리하기 위한 도구라면, 쿠버네티스는 도커를  관리하기 위한 도구라고 볼 수 있다.

쿠버네티스는 여러개의 컨테이너를 서비스 단위로 관리하기 위해 사용된다.

그러므로 쿠버네티스가 나온 배경에도 운영의 효율성 측면이 있다.

자세한건 다른곳에 써놨으니 그거보자