본문 바로가기
  • 오늘처럼
소프트웨어 아키텍처/Containerd

Container Runtime Migration : Docker -> Containerd

by bluefriday 2021. 9. 13.
반응형

Kubernetes v1.21 버전 이후로 Docker 가 deprecated 됨에 따라 Kubernetes 의 컨테이너 런타임으로 Docker 이외의 런타임을 사용하는 경우가 늘어나고 있다. 이와 더불어 기존 Kubernetes Cluster 에서 Docker를 런타임으로 사용하고 있는 경우에도 Containerd 로 런타임을 변경해야 하는 케이스도 발생한다.

이번에는 Container Runtime 으로 도커를 사용하고 있는 기존 클러스터에서 런타임을 Docker로 변경하는 과정에 대해 알아본다. 기본적으로 Kubernetes 클러스터가 필요하며 docker가 설치되어 있는 경우 containerd 가 이미 설치되어 있으므로 추가로 필요한 요소는 없다. 다만 도커를 containerd 로 변경하는 과정에서 기존 containerd 나 runc의 버전을 변경하려하는 경우 필요한 containerd, runc 패키지를 준비하도록 하자.

마이그레이션은 1)기본적으로 한 번에 한 개의 노드에 대해서 작업을 수행하며, 2)워커 노드의 마이그레이션을 먼저 수행한 후에 마스터노드(controlplane node)의 마이그레이션을 수행한다. 기본 과정은 다음과 같다.

  1. 노드를 잠시 클러스터에서 제외시켜 모든 파드를 다른 노드로 이동
  2. 해당 노드의 kubelet, docker, containerd 프로세스를 구동중지
  3. docker 패키지 삭제 후 containerd 패키지 설정
  4. conatained, kubelet 프로세스 구동
  5. 노드를 다시 클러스터에 합류(join) 시켜 파드가 구동 가능하게 허용

컨테이너 런타임 자체가 변경되면서 노드의 파드가 최소 1번 이상 다른 파드로 이동하게 되는데, 이 과정에서 순간적인 down-time 이 존재하게 된다. 운영중인 어플리케이션의 경우 down-time 에 대비하여 진행하도록 하자.

 

1. 노드를 클러스터에서 제외

cordon 명령을 사용하여 노드에 더 이상 파드가 스케쥴링 되지 않도록 한다. 그 후에 drain 명령을 사용하여 해당 노드에 올라와 있는 파드를 다른 노드로 이동시킨다. (emptyDir 을 쓰는 노드나 daemonset 의 경우 예외사항을 두기 위하여 각각의 플래그('--ignore-daemonsets', '--delete-emptydir-data') 를 함께 사용한다.

### kubectl 명령을 수행할 수 있는 GW 등의 노드에서 수행
kubectl cordon 노드명
kubectl drain 노드명 --ignore-daemonsets --delete-emptydir-data

위 명령을 수행하게 되면 해당 노드의 상태가 "status : Ready,SchedulingDisabled" 변경되며 해당 노드의 모든 파드(daemonset 제외)가 다른 노드로 리스케쥴링 된 것을 확인할 수 있다.

 

2. 노드의 프로세스 구동 중지

해당 노드에 ssh 명령 등을 통하여 접속한 후에 kubelet, docker, containerd 의 프로세스를 중지한다. containerd 의 프로세스는 중지하지 않아도 무관하나 위에서 언급한것처럼 containerd 의 버전을 올리려는 경우 해당 바이너리 파일(/usr/bin/containerd)을 덮어쓰거나 교체해야 하는데 이 때 이 파일이 busy상태가 되지 않도록 하기 위하여 중지가 필요하다.

### 해당 노드로 이동
ssh 노드이름

### 해당 노드에서 명령어 실행
systemctl stop kubelet
systemctl stop docker
systemctl disable docker
systemctl stop containerd

 

3. docker 패키지 삭제

도커 관련 패키지를 삭제한다. 삭제하지 않고 내려두기만 해도 무방하나 노드가 재시작 되는 경우에 docker 프로세스가 자동으로 재시작 되는 경우를 방지하기 위하여 disable 처리가 필요하다. (삭제 권장)

### 해당 노드에서 수행
### ubuntu 계열의 경우
apt purge docker-ce* docker-ce-cli* 

### centos, rhel 의 경우
OR yum remove -y docker-ce* docker-ce-cli*

추가로 도커가 기존에 사용하던 데이터 디렉토리에 대한 정리도 필요하다. 기본적으로 docker가 구동되면서 containerd에 대한 데이터 디렉토리도 사용하기 때문에 이 과정에서 docker, containerd 와 관련된 데이터 디렉토리의 내용을 모두 삭제해주자. 만약 docker 디렉토리의 용량을 고려하여 블록스토리지 등을 사용한 경우 해당 디렉토리를 마운트하여 containerd 의 데이터 디렉토리로 변경해주도록 한다. 여기서는 /var/lib/docker 디렉토리가 블록스토리지로 /dev/sdb 영역을 사용한다고 가정하였다. 마운트 내용을 수정한 경우에는 하단과 같이 반드시 /etc/fstab 파일의 내용도 동일하게 수정해주도록 한다.

### docker, containerd data 디렉토리 삭제
[root@localhost ~]# rm -rf /var/lib/docker/* /var/lib/containerd
[root@localhost ~]#

### docker 의 블록스토리지 확인
[root@localhost ~]# df -Th | grep "/var/lib/docker"
/dev/sdb                xfs       100G   36M  100G   1% /var/lib/docker
[root@localhost ~]#

### docker 블록스토리지 언마운트
[root@localhost ~]# umount /var/lib/docker
[root@localhost ~]#

### containerd 데이터 디렉토리의 이름으로 재마운트
[root@localhost ~]# mv /var/lib/docker /var/lib/containerd
[root@localhost ~]#
[root@localhost ~]# mount /dev/sdb /var/lib/containerd
[root@localhost ~]#

### 마운트 결과 확인
[root@localhost ~]# df -Th | grep "/var/lib/containerd"
/dev/sdb                xfs       100G   36M  100G   1% /var/lib/containerd
[root@localhost ~]#

### fstab 파일 수정
[root@localhost ~]# vi /etc/fstab
[root@localhost ~]#
[root@localhost ~]# cat /etc/fstab | grep "/var/lib/containerd"
/dev/sdb /var/lib/containerd xfs defaults,pquota 0 0
[root@localhost ~]#

 

4. containerd, kubelet 설정 및 구동

기존에 Containerd + Docker 를 사용하고 있을 경우 containerd의 설정파일(/etc/containerd/config.toml)이 존재하지 않거나 존재하더라도 설정이 적용되지 않도록 내부에 『disabled_plugins = ["cri"]』 과 같은 구문이 지정되어 있을 수 있다.

기존 설정파일을 지운 후에 하단과 같이 새로 containerd 의 설정 파일을 생성한다. (설정에 관한 부분은 해당 포스트를 참조하자.) 설정 파일을 새로 생성하였으면 containerd 프로세스를 구동하자.

### containerd 설정파일 생성 및 수정
containerd config default > /etc/containerd/config.toml
vi /etc/containerd/config.toml

### containerd 프로세스 재시작
systemctl restart containerd

다음으로 kubelet 을 구동하기 전에, kubelet 의 container runtime 으로 containerd를 지정해줘야 한다. Docker가 삭제된 경우 kubelet이 containerd를 자동으로 볼 수도 있으나 명시해주는 것이 좋으며, docker를 삭제하지 않은 경우 kubernetes 버전에 따라 자동으로 docker를 컨테이너 런타임으로 우선적으로 보는 경우가 있으므로 kubelet 의 옵션을 다음같이 지정한 후에 kubelet 프로세스도 구동 해준다.

### kubelet 설정 추가(container runtime)
cat /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--container-runtime=remote --container-runtime-endpoint=/run/containerd/containerd.sock ..."

### kubelet 재시작
systemctl start kubelet

 

5. 노드를 클러스터에 재합류

4번 과정까지 정상적으로 동작하였을 경우 kubectl 명령어의 '-owide' 옵션으로 node를 조회해볼 때 node 의 컨테이너 런타임이 도커가 아닌 container로 변경되었음을 확인할 수 있다. 이제 uncordon 명령을 사용하여 다시 노드를 클러스터에 합류시키자.

### kubectl 명령을 수행할 수 있는 GW 등의 노드에서 수행
kubectl uncordon 노드명

노드의 상태가 "status : Ready,SchedulingDisabled" 에서 "status : Ready" 로 변경되며, 이와 같은 식으로 worker 노드부터 master 노드까지 모든 노드를 수동으로 마이그레이션하면 전체 과정이 종료된다.

 

댓글