- 컨테이너를 다루다 보면 자주 듣는 용어로 컨테이너 런타임이 있다.
- runc, containerd, podman, cri-o 등 다양한 런타임이 있는데, 이 런타임들은 각각 다른 상황에 맞게 만들어졌으면 다른 기능을 구현하고 있다.
- containerd와 cri-o는 이미지 관리와 api를 구현하고 runc를 사용하여 컨테이너를 실행한다.
- 이미지 전송, 관리, 압축 & 해제 및 API를 포함하는 이러한 기능을 일반적으로 고수준의 컨테이너 런타임이라하며, runc와 같은 컨테이너를 실행 및 생성에만 초점을 맞춘 런타임을 일반적으로 저수준의 컨테이너 런타임이라한다.
- podman은 OCI 컨테이너 및 컨테이너 이미지를 사용하여 애플리케이션을 쉽게 찾고, 실행, 구축, 공유, 배포할 수 있도록 설계된 daemonless 형태인 open source이다.
- podman은 docker 컨테이너 엔진을 사용한 사람들에게 친숙한 CLI를 제공하며, docker를 podman으로 alias(별칭) 지정할 경우 동일한 방식으로 사용할 수 있다.
- 일반적으로 다른 컨테이너 엔진(docker, containerd, CRI-O)과 마찬가지로, podman은 운영체제와 인터페이스하고 실행중인 컨테이너를 만들기 위해 OCI 호환 컨테이너 런타임(runc)에 의존한다.
- 이를 통해 podman이 만든 실행 중인 컨테이너를 다른 일반적인 컨테이너 엔진(docker, containerd, CRI-O)에 의해 만들어진 것과 거의 구별할 수 없다.
- podman은 docker build를 대체한 buildah 유틸리티를 사용하여 컨테이너 이미지를 생성한다.
- 이미지 레지스트리와 컨테이너 엔진 사이에 이미지 전송을 위한 docker push는 skopeo가 대체한다.
Podman과 docker의 차이(daemonless)
docker 동작 방식
- docker와의 가장 큰 차이점은 podman은 데몬(daemon-less)이 필요 없다는 점이다.
- docker는 docker daemon을 구동하며 모든 작업이 이루어지며, 사용자는 docker client 명령어를 사용하여 도커 데몬을 제어하였다.
podman 동작 방식
- container daemon을 사용하는 docker와는 다르게 podman은 daemon 프로세스를 사용하지 않기 때문에, systemd에 서비스를 생성해서 관리하는 방법을 많이 사용한다.
- systemd를 위한 서비스를 생성하기 위해서는 설정들을 담고 잇는 서비스 파일을 만들어야 한다.
# 컨테이너 생성 $ podman run -it nginx # podman은 generate 명령을 이용하여 systemd 서비스 파일을 생성해 준다. # 컨테이너 이름 혹은 ID를 사용하여 systemd 장치 파일을 생성하고 이를 ~/.config/systemd/user/container-myubi.service 경로로 파일을 보낸다. $ podman generate systemd --name nginx > ~/.config/systemd/user/container-myubi.service # 확인 $ cat ~/.config/systemd/user/container-myubi.service # Restart=on-failure 행은 재시작 정책을 설정하고 서비스를 완전히 시작하거나 중지할 수 없거나 프로세스가 0이 아닌 경우 다시 시작하도록 systemd 에 지시 # ExecStart 행은 컨테이너를 시작하는 방법을 설명 # ExecStop 행은 컨테이너를 중지하고 제거하는 방법을 설명
- 출력되는 내용을 기반으로 추가적인 설정을 변경하여 systemctl을 이용하여 서비스를 시작할 수 있다.
- podman generate 명령을 이용하여 kubernetes yaml 파일 생성 가능하다.
root 권한 불필요(rootless)
- docker는 docker daemon에 모든 권한이 집중되다 보니 아무나 docker client로 docker daemon을 제어하지 못하도록 root 사용자만 docker client를 사용하도록 했다.
- 하지만 이 방식은 시스템 운영자가 컨테이너 운영자가 되어야 하므로 업무 분리가 제대로 안되며, 과도한 root 권한이 필요하여 보안에 취약하다.
- podman은 fork/exec으로 개별 컨테이너를 실행할 수 있으므로 1024 이하의 well know 포트를 사용하는 등의 root 권한으로 싱행해야 하는 작업이 아니라면 일반 사용자로 실행할 수 있으므로 담당자 병로 권한을 분리 할 수 있어 시스템 운영자와 서비스/컨테이너 운영자로 전문화할 수 있어 보안 측면에서 docker 보다 뛰어나다.
사용 방법
# podman은 docker와 명령어가 완전히 호환되므로 docker를 사용할 줄 안다면 별도로 podman 명령어를 배울 필요가 없다. # docker 를 podman 으로 대체하려면 다음과 같이 alias 만 하나 적어주면 된다. $ alias docker=podman # 만약 이미 docker 를 설치했고 docker daemon 도 구동되었다면 먼저 중지해야한다. 중지 하지 않으면 충돌 발생 $ sudo systemctl stop docker $ sudo systemctl disable docker # 컨테이너 생성 $ podman run -it nginx # 컨테이너 상태확인 $ podman ps -a # 컨테이너 실행 $ podman start [conatainer ID] # 컨테이너 중지 $ podman stop [container ID] # 컨테이너 삭제 $ podman rm [container ID] # 컨테이너 이미지 빌드 # 현재 작업 디렉토리에 dockerfile이 있다면 build 명령으로 컨테이너 이미지 빌드 가능 $ podman build -t dockerfile:1.0 . # 컨테이너 이미지 조회 $ podman images # 레지스트리에서 컨테이너 이미지 pull $ podman pull docker.io/library/yangseunghyun:latest # 컨테이너 이미지 삭제 $ podman rmi [image ID] # pod 생성 $ podman pod create --name yangseunghyun # pod 조회 $ podman pod ls $ podman ps -a --pod # pod에 컨테이너 추가 $ podman run -dt --pod [pod name] [container name] # pod 시작/중지/삭제 $ podman pod start [container ID] $ podman pod stop [container ID] $ podman pod rm [container ID]
- 컨테이너 실행에만 초점
runc(runc)
- runc는 OCI 런타임 표준을 준수하며, 리눅스 재단의 런타임 사양(runtime-spec)을 기반으로 컨테이너를 생성 및 실행하기 위한 컨테이너 런타임이다.
- Docker는 LXC등의 외부 드라이버에 의존하여 namespace 분리와 cgroups 관리 등의 시스템 제어를 하였으나, 이후 libcontainer라는 별도의 구현체를 개발하여 사용하였다.
- runc는 이러한 libcontainer의 client wrapper로 Go 언어로 개발되었으며, 현재 Docker에서 저수준 컨테이너 런타임으로 사용되고 있다
- runc는 docker, Podman 또는 CRI-O를 사용하든, runc를 사용할 가능성이 높다. 해당 패키지(docker, containerd, Podman, CRI-O)들에 runc가 포함되어 있으며, 패키지 설치시 runc가 함께 설치된다.
# runc만 설치하기 $ yum install runc -y
$ man runc
- 위 명령어를 사용하여 확인해보면, 왜 runc를 사용할 가능성이 높은지 알수있다.
- runc는 OCI(Open Container Initiative) 형식에 따라 패키지된 애플리케이션을 실행하기 위한 명령줄 클라이언트이며, Open Container Initiative 사양을 준수하는 구현한다고 설명하고 있다.
- 이 외 저수준 런타임 gVisor, Kata Containers 또는 Nabla Containers등이 있다.
- 이미지 관리 및 gRPC/Web API와 같은 더 높은 수준의 기능을 지원
- 높은 수준이라하면 컨테이너 이미지 전송 및 관리, 이미지 압축해제, 컨테이너를 실행하기 위해 낮은 수준의 런타임으로 전달하는 역할을 수행한다.
CRI-O(Open Container Initiative)(cri-o)
Docker VS Containerd VS CRI-O
- CRI-O는 OCI(Open Container Initiative) 호환 런타임을 사용할 수 있는 쿠버네티스 CRI(컨테이너 런타임 인터페이스)의 구현입니다.
- 쿠버네티스는 OCI 호환 런타임을 파드를 실행하기 위한 컨테이너 런타임으로 사용할 수 있게 해준다. 오늘날 그것은 runc와 Kata Containers를 컨테이너 런타임으로 지원하지만 OCI를 준수하는 모든 런타임은 원칙적으로 연결될 수 있다.
- CRI-O는 OCI 컨테이너 이미지를 지원하며 모든 컨테이너 레지스트리에서 가져올 수 있습니다. 도커, 모비 또는 rkt를 쿠버네티스의 런타임으로 사용하는 것에 대한 가벼운 대안이다.
- 로컬 쿠버네티스인 minikube에서 기본으로 사용한다.
containerd(containerd)
- containerd는 Docker에서 moby project 와 함께 발표하여 CNCF에 기증한 오픈소스이다.
- moby project는 Docker에서 2017 년에 발표 한 오픈소스 소프트웨어 프로젝트로서 Docker를 구성하는 기능들 중에 일부를 공개한 것이다.
- Containerd 는 Kubernetes 의 하이 레벨 런타임 표준인 CRI 런타임으로 현재는 CRI-O 와 함께 두 가지 구현체가 있다.
- docker build 커맨드로 생성된 이미지는 OCI image spec을 준수하기 때문에 kubernetes에서도 도커에서 생성한 이미지를 사용할 수 있다.
- Docker는 2016년 12월 컨테이너 런타임 부분을 독립적인 오픈 소스 프로젝트인 “containerd”로 분리하여 마이크로 소프트, Google, AWS, IBM 등과 공동으로 개발하며 관리된다.
2017년 12월 CNCF에서 v1.0에 도달한 containerd는 kubelet과 containerd사이에서 작동하려면 cri-containerd라는 데몬이 필요했다.
Cri-containerd는 Kubelet의 CRI (Container Runtime Interface) 서비스 요청을 처리하고 containerd를 사용하여 해당 컨테이너 및 컨테이너 이미지를 관리한다.
containerd v1.1에서는 cri-containerd 데몬이 이제 containerd CRI 플러그인으로 리팩터링된다.
CRI 플러그인은 containerd v1.1에 내장되어 있으며 기본적으로 활성화되어 있다.
cri-containerd와 달리 CRI 플러그인은 직접 함수 호출을 통해 containerd와 상호 작용한다.
사용자는 이제 containerd1.1과 함께 Kubernetes를 직접 사용할 수 있다.
cri-containerd 데몬은 더 이상 필요하지 않다.
containerd v1.1부터는 Docker 18.03 CE와 dockershim의 통합과 비교하여 containerd v1.1이 pod 시작 지연 시간이 더 낮으며 전체 CPU와 메모리를 덜 소모한다.
'sudo systemctl status containerd.service'를 통해 containerd 상태를 확인할 수 있다.
위 커맨드에서 알 수 있듯이 containerd는 systemd의 자식 프로세스이다.
containerd 설정파일
# default path /etc/containerd/config.toml
- 참고
(containerd)
ctr(containerd CLI tool -default)
- ctr tool은 containerd 데몬과 상호작용하여 호스트 노드의 컨테이너 관리를 지원해주는 containerd의 커맨드라인 클라이언트 툴이다.
- containerd 진영에서 개발 되어 동일 프로젝트 소스이나 Description을 보면 하위호환성이나 안정성을 보장하지 않는다.
- containerd 패키지 설치시 하위 패키지로 함께 설치된다.
사용 예시
# 버전 확인 $ ctr version # Ctr은 containerd에게 컨테이너 이미지를 pull하는데 사용할 수 있다. $ sudo ctr images pull docker.io/library/yangseunghyun:latest # 컨테이너 이미지 리스트 확인 $ sudo ctr images list # 이미지를 기반으로 컨테이너를 실행 $ sudo ctr container create docker.io/library/yangseunghyun:latest yang # namespace 확인 $ ctr ns list # 실행 중인 컨테이너 목록 확인 $ sudo ctr container list # 컨테이너 삭제 $ sudo ctr container delete yang
- 위 사용 예시처럼 도커와 상호 작용하는 방식과 유사하다.
- ctr 명령어는 containerd 프로세스와 상호작용하지만 containerd의 설정파일 자체는 ctr과 연관이 없다.
- ctr은 도커와 달리 별도로 로그인 명령을 지원하지 않음으로, 이미지를 pull & push 할 경우 ctr 명령어에 별도로 계정 정보와 registry주소를 입력해 주어야 한다.
# ctr image pull --user 유저명:비밀번호 registry주소/이미지명(전체경로) # $ ctr image pull --user yang:Password docker.io/nginx:latest # private registry를 사용하며, https를 지원하지 않을때는 --plain-http를 명시해주어야 한다. $ ctr image pull --plain-http --user yang:Password docker.io/nginx:latest
ctr containerd 연동하기
- containerd endpoint의 default 경로는 /var/run/containerd/containerd.sock 이며, 해당 경로에서 ctr을 구성할 수 있다.
# default path - /var/run/containerd/containerd.sock $ cat <<EOF | sudo tee /etc/ctr.yaml runtime-endpoint: unix:///var/run/containerd/containerd.sock image-endpoint: unix:///var/run/containerd/containerd.sock EOF
- 하지만 도커와는 대조적으로 컨테이너 실행에만 초점을 맞추고 있음으로 컨테이너를 구축하기 위한 메커니즘은 제공하지 않는다.
- 도커는 최종 사용자 및 개발자 사용에 초점을 맞추었으나, containerd는 서버에서 컨테이너 실행하는 것과 같은 운영 사용에 초점을 맞추고 있다.
- 컨테이너 이미지를 만드는 것(build)과 같은 작업은 다른 도구에 의해 실행된다.
참고 자료
https://cloudyuga.guru/hands_on_lab/containerdnerdctl(containerd 진영)
- ctr 명령어는 dockrt client 명령어를 대체하는 것처럼 보이나 완전히 호환되지 않는다.
- 컨테이너 이미지를 확인하거나 pull,push,create와 같은 것은 가능하다.
- containerd 진영에서는 ctr을 보완하는 방법으로, nerdctl tool을 개발하였다.
- nerdctl은 containerd의 알파벳 끝 4개를 따와서 명명하였으며, docker명령어와 거의 동일하게 사용 가능하다.
crictl(kubernetes-sigs 진영)
- ctr의 경우 containerd 전용 tool이지만 기능이 제한적이다.
- 그렇기 때문에, 더 많은 기능을 제공하고 containerd 이외의 다양한 container runtime tool을 지원하는 crictl이 있다.
- 쿠버네티스에서는 cri표준을 준수하는 컨테이너 런타임을 통합하여 관리하기 위해 crictl이란 명령어 툴을 제공한다.
- 일반적으로 kubeadm으로 쿠버네티스를 설치했다면 자동으로 설치된다.
사용 예시
# 레지스트리에서 이미지 가져오기 $ crictl pull docker.io/library/yangseunghyun:latest # 이미지 목록 $ crictl images # 이미지 삭제 $ crictl rmi <imgae-id>
crictl containerd와 연동하기
- containerd endpoint의 default 경로는 /var/run/containerd/containerd.sock 이며, 해당 경로에서 crictl을 구성할 수 있다.
# default path - /var/run/containerd/containerd.sock $ cat <<EOF | sudo tee /etc/crictl.yaml runtime-endpoint: unix:///var/run/containerd/containerd.sock image-endpoint: unix:///var/run/containerd/containerd.sock EOF
ctr과 crictl의 차이
- cri-o의 command line tool인 crictl은 ctr과 마찬가지로 호스트 컨테이너 런타임과 상호 작용하며 컨테이너의 정보를 조회하고 관리할 수 있는 툴이다.
- docker가 docker 서버와 통신을, ctr이 containerd와 통신을을 위한 반면 crictl은 특정적으로 containerd를 위한 툴은 아니며 ctr과 진영 또한 다르고 동일 프로젝트도 아니다.
- crictl 은 kuberneetes-sigs 진영에서 만들어진 container runtime 에 대한 툴로 docker와 달리 container 레벨을 넘어 k8s 오브젝트의 관점에서 파드(Pods)를 생성하거나 조회할 수도 있다. 컨테이너 이미지 조회, 컨테이너 조회 등 ctr 과 유사한 기능은 제공한다.