[k8s] 쿠버네티스와 컨테이너 한방 정리
Linux의 흐름
- 최초의 OS는 Unix
- 그 이후 오랜 시간이 흘러 Linux 운영체제 개발
- Linux는 두개의 버전으로 나뉘어짐
- 무료 버전인 `debian` Linux
- 유료 버전인 `RedHat` Linux
- debian Linux는 커뮤니티 버전으로 무료. 이 OS를 기반으로 전세계에서 가장 많이 사용하는 ubuntu가 탄생
- RedHat Linux는 RedHat 기업에서 개발한 유료 OS이다. 보통 유지보수를 위해 기업에서 주로 사용
- 여기서 RedHat Linux는 새로운 버전이 배포되는 순서가 있음
- Fedora Linux: 개발 버전, 새로운 기능들을 먼저 선보임 (Dev)
- RHEL(RedHat Enterprise Linux): 개발 버전이 안정화 된 버전. 유료
- CentOS: RHEL을 복제해서 만든 무료 버전
- CentOS는 무료이기 때문에 개발 환경에서는 CentOS를 사용하고 운영 환경을 RHEL을 쓰기도 한다고 함
- 하지만 CentOS는 곧 서비스가 종료 될 예정
- 여기서 RedHat Linux는 새로운 버전이 배포되는 순서가 있음
- 이후에 IBM이 RedHat을 인수하고 배포되는 순서가 바뀜
- Fedota Linux: 개발 버전(같음)
- CentOS Stream: 이 부분에서 테스트를 진행
- RHEL: CentOS Stream에서 안정화가 된 버전을 RHEL로 배포
- 여기서 REHL을 복제한 Rocky Linux와 Alma Linux가 있음
- 이럴떄는 Goole trend와 Repo의 github Star를 확인하여 선택
Container의 흐름
- 컨테이너의 격리 기술은 1979년부터 발전해왔음
- chroot: 사용자를 격리, 파일 및 네트워크 격리
- cgroup: 자원 격리(cpu, memory) 즉, 각 App 마다 Cpu 및 Memory를 할당할 수 있게 함
- namespace: App 하나가 하나의 프로세스를 차지하게 되는데, 프로세스 격리 기술이 만들어지게 되면서 각 App을 독립적인 환경에서 실행할 수 있게 됨
- 2008년에 chroot, cgroup, namespace 기능들이 집약된 LXC가 릴리즈 됨(Linux Container)
- Docker는 이 LXC를 기반으로 만들어짐
- Docker는 root 권한으로 설치하고 실행해야 하는 보안 이슈가 있음. 이 보안 이슈를 보완하여 개발된게 rkt
- 현재는 Docker에도 rootless 기능이 생겨서 보안이 강화됨
Container Orchestration이란?
- Container Orchestration은 운영자가 새로운 버전의 앱을 배포한다는 것을 가정할때 대부분의 과정을 자동화 함
- 아래는 기존에 구동되고 있던 App V1을 V2로 업그레이드 하는 플로우
기존 컨테이너 배포 플로우
- V1 컨테이너는 정상 기동 중
- 버전 업을 위해 V2 컨테이너를 생성하고 실행함
- V2 컨테이너가 잘 작동하는지 기동 확인을 함
- V1으로 흘러들어가던 트래픽을 V2로 변경함
- V1 컨테이너를 삭제함
- 끝
컨테이너 오케스트레이션 배포 플로우
- V1 컨테이너는 정상 기동 중
- 쿠버네티스에 V2 업그레이드를 명령하고 화장실을 갔다옴
- 끝 (?)
Container와 Container Orchestration의 관계
- 쿠버네티스 초기에는 Docker를 주 타켓으로 잡고 개발
- 하지만 쿠버네티스 인터페이스와 Docker의 호환성 문제로 Docker의 입지 감소
- 쿠버네티스의 점유율이 올라가고 표준화가 될 수록 쿠버네티스 인터페이스의 호환성이 중요한 요소
- 그 이후에 개발 된 컨테이너 서비스인 Containerd와 cri-o는 CNCF(Cloud Native Computing Foundation)에 기부
- Containerd는 Docker엔진에서 컨테이너 '생성' 기능이 분리된 프로젝트
- cri-o는 Redhat에서개발 됨
- 컨테이너 런타임에도 High Level, Low Level이 있음
- LXC는 커널 레벨의 기술로 개발 된 Low Level 컨테이너 런타임
- LXC를 기반으로 libcontainer라는 컨테이너 런타임을 만들고 이를 기반으로 사용자 친화적인 High Level 컨테이너 런타임 Docker가 개발 됨
Docker는 컨테이너를 생성하는 containerd 외에도 dockerd라는 부가 기능들을 많이 제공한다.
위 그림에 나와있는 것 처럼 컨테이너 생성 자체는 containerd가 libcontainer를 호출하는 방식으로 동작한다.
또한, LXC와 Docker는 사용 목적도 다르다. LXC는 기존에 있던 VM기술이 컨테이너로 동작하는 것이 목표인 프로젝트이고 Docker는 App을 컨테이너를 이용하여 독립적으로 실행시키는것이 목적이다.
쿠버네티스는 컨테이너 생성이 아닌 Pod생성 명령어가 존재한다.
이 Pod에서 컨테이너를 몇개 생성할 것인지 명시해야 한다.
쿠버네티스 초기버전(1.0)에는 kubelet이 컨테이너 런타임의 API를 호출했다.
Pod 생성 API를 kube-apisever에 요청하고 컨테이너 런타임에 요청하기 위해 kubelet으로 해당 요청을 전달한다.
요청을 받은 컨테이너 런타임은 컨테이너를 생성하는 흐름이다.
이는 컨테이너 런타임마다 분기를 해줘야하는 번거로움이 있다. Docker와 rkt도 실제로 분기가 되어있다.
하지만 이 방식은 컨테이너 런타임이 늘어가면서 1.5버전을 거듭하며 인터페이스를 추가하게 된다.
kubelet에 인터페이스 규격을 정하고 CRI(Container Runtime Interface) 규격에 대한 구현부에서 각각의 컨테이너 런타임을 호출한다.
이 과정에서 dockershim이 문제가 생겼고 결국 1.24버전부터 지원이 종료된다.
이후 Mirantis라는 기업이 Docker를 인수하고 cri-dockerd를 만들어서 다시 쿠버네티스에서 도커를 지원하게 만들었다.
kubelet과 CRI간 통신은 grpc로 통신한다. 하지만 기존 CRI가 컨테이너 런타임을 호출하는 것은 비효율적이다.
왜냐하면 컨테이너 런타임과 쿠버네티스는 엄연히 개발을 따로 하기 때문이다. 그래서 구조상 컨테이너 런타임의 변경에 대해 CRI 구현체도 수정을 해야하는 상황이다.
이러한 문제를 kubelet에서 컨테이너 런타임으로 바로 통신할 수 있게 구조가 변경되었다.
이 포스트는 쿠버네티스 어나더 클래스 (지상편) - Sprint 1, 2를 기반으로 작성되었습니다.