본문 바로가기

OS,가상화

Docker inside Docker(DinD)와 Docker Out of Docker (DooD)

문제 상황

젠킨스를 기존 EC2 기반 서버 슬레이브를 운영하다가, cloud-native 방식으로 운영하고자, 필요에 따라 pod를 띄워 사용하고자 했다. 그런데 한번 시도해보았다면 알겠지만, 컨테이너 내부에서는 도커를 설치해도 사용할 수가 없다. CI 작업용으로 활용할 것이기 때문에, 컨테이너 내부에서 docker build가 가능한가가 주요 문제가 되었다. 불가능하다면 CI 작업용으로는 활용이 불가능하기 때문이다.

때문에 관련 내용을 조사해 문서로 정리한다.

결론적으로 도커 내부에서 도커를 사용할 수 있는 방법은 없다.

주요원인

1. 파일시스템을 중첩할 수 없기 때문이다.

도커는 이미지 빌드시 빌드속도 개선&이미지 용량 절감목적으로 레이어 구조를 사용한다. 이를 위해 CoW(Copy on Write)을 지원하는 파일 시스템을 사용하며, 일반적으로는 unionFS의 일종인 OverlayFS를 사용한다. UnionFS는 저장된 파일에 변경사항이 생겼을 때 파일을 직접 수정하는 것이 아니라 변경사항만을 순차적으로 기록해 레이어를 형성하고 이를 마운트하는 식으로 변경사항을 반영한다.

문제는 DinD를 사용할 때 두 파일시스템 간 중첩이 어렵다는 것이다. 파일시스템에 따라 완전히 마운트가 불가능한 경우도 있고, 마운트는 가능하되 일괄삭제가 불가능해 운용에 복잡성을 더할 수도 있다.

이 때문에 정 DinD를 사용하고 싶다면 UnionFS가 아닌 범용파일 시스템(EFS4 등)을 사용해야 하는데, 이렇게 할 경우 컨테이너의 장점이 크게 퇴색된다. 이미지 간 캐싱이 불가능해져 빌드속도 개선/이미지 용량 절감 등이 불가능해지기 때문이다.

2. Linux 보안 모듈 충돌 문제

리눅스는 보호/보안을 목적으로한 보안 모듈(LSM)이 존재하는데, 대표적으로 AppArmorSELinux등이 있다. 이 둘은 권한제어를 하는 모듈인데, 컨테이너 간 보안 모듈이 충돌할 수 있다.

부차적 문제

1. 성능 문제

DinD를 사용할 경우 도커 이미지 저장소를 공유하지 않으므로 필요한 이미지를 매번 pull/build해야 한다.

2. 보안 문제

docker를 사용하기 위해서는 privileged mode를 설정해야 하는데, 권한을 폭넓게 부여하는 것은 언제나 보안 위험의 요소가 된다.

해결 방법

도커의 동작 방식을 살펴보면, 호스트에서 CLI로 명령을 내리면 docker daemon으로 요청을 보내고, 실제 작업은 docker daemon이 처리하는 구조다. 그리고 컨테이너 안에서 도커를 설치할 경우, 명령을 내릴 수 있는 docker-cli까지는 이상없이 설치되는 것을 확인할 수 있다. docker daemon과 통신하지 못해 동작되지 못하는 것이다. 이 때문에 docker-cli는 컨테이너 내부에 설치하되, docker daemon은 컨테이너를 띄운 호스트의 것을 사용하도록 하면 된다. 이 방식을 Docker Out of Docker (DooD) 라고 부른다.

docker run -v /var/run/docker.sock:/var/run/docker.sock ....

단, 컨테이너 내에서 도커를 사용할 수는 있지만, 자식 도커를 사용하고 있는 것은 아님을 유념해야 한다. 어디까지나 호스트의 도커 데몬을 사용하고 있기 때문에, 엄밀히 말하면 형제 컨테이너를 띄우고 있는 것이다.

참고문서 : Using Docker-in-Docker for your CI or testing environment? Think twice.