Docker Rootless mode 설정, 포트·볼륨·자원 제한이 실제로 적용되는지 확인하는 법

일반 사용자 권한의 컨테이너 실행을 상징하는 서버 케이스와 네트워크 케이블, 잠금 장치가 놓인 현실적인 작업대

AI를 활용하여 생성한 이미지입니다.

Docker를 일반 사용자 권한으로 실행하는 Rootless mode는 컨테이너만 격리하는 방식과 출발점이 달라요. Docker 데몬과 컨테이너를 모두 사용자 네임스페이스 안에서 실행해 데몬 자체가 root 권한을 갖지 않도록 구성합니다.[1] 개발용 서버나 개인 작업 PC에서 Docker 소켓과 컨테이너가 사고의 출발점이 되는 범위를 줄이고 싶을 때 검토할 만하지만, rootless라고 해서 컨테이너 내부 애플리케이션이 자동으로 안전해지는 것은 아니에요.

중요한 건 설치 명령 하나보다 설치 전제, 포트와 볼륨의 권한, cgroup 기반 자원 제한이 실제로 적용됐는지 확인하는 일입니다. 아래 순서는 처음부터 rootful Docker 설정을 지우지 않고 별도 rootless 컨텍스트를 만들어 확인하는 흐름을 기준으로 해요.

Rootless가 바꾸는 권한 경계

일반 Docker에서는 데몬이 높은 권한으로 실행되기 때문에, 데몬 소켓에 접근할 수 있는 사용자가 컨테이너 생성과 호스트 자원 접근에 큰 영향력을 가질 수 있어요. Rootless mode는 데몬과 컨테이너를 모두 비root 사용자로 실행하고, 사용자 네임스페이스에서 컨테이너 UID·GID를 호스트의 subordinate UID·GID 범위에 매핑합니다.[1]

이 방식은 권한 상승 위험을 줄이는 데 도움이 되지만 네트워크, 파일 시스템, 장치 접근에 제한이 생길 수 있어요. 특히 1024 미만의 privileged port, 호스트 장치, 특정 파일 시스템 기능을 써야 하는 서비스라면 설치 전에 요구 사항을 적어 두는 게 좋습니다.

확인 영역 Rootless에서 달라지는 점 미리 판단할 것
데몬 사용자 세션과 사용자 소켓으로 실행 서버 재부팅 뒤 자동 시작이 필요한가
파일 컨테이너 UID가 호스트 파일 권한에 영향을 줌 bind mount 경로의 소유자와 쓰기 범위
포트 1024 미만 포트와 네트워크 드라이버에 제약 외부 공개 포트가 꼭 필요한가
자원 cgroup v2·systemd 조건이 맞아야 일부 제한 적용 docker info의 Cgroup Driver와 컨트롤러

설치 전에 확인할 호스트 조건

Docker 공식 문서가 요구하는 기본 조건은 newuidmap과 newgidmap이며, 일반적으로 uidmap 패키지에서 제공합니다. 또 /etc/subuid와 /etc/subgid에 해당 사용자에게 최소 65,536개의 subordinate UID·GID가 배정돼 있어야 해요.[1] 이 항목이 없으면 설치 스크립트가 끝까지 진행돼도 사용자 네임스페이스가 기대한 방식으로 동작하지 않을 수 있습니다.

command -v newuidmap
command -v newgidmap
grep "^$USER:" /etc/subuid
grep "^$USER:" /etc/subgid

배포판마다 계정 이름과 파일 형식은 다를 수 있으므로 위 결과를 그대로 복사해 수정하지 말고 현재 사용자에게 범위가 할당됐는지 먼저 읽어 보세요. 운영 서버에서 패키지를 추가할 권한이 없다면 관리자에게 rootless 전제 조건을 요청해야 합니다.

기존 Docker를 건드리지 않고 컨텍스트를 확인해요

Docker 공식 설치 도구는 사용자 systemd 서비스와 rootless CLI 컨텍스트를 만들고, 필요하면 DOCKER_HOST를 사용자 소켓으로 가리키도록 안내합니다.[1] 기존 rootful 데몬을 바로 중지하거나 Docker 데이터를 지우지 말고, 설치 후 현재 클라이언트가 어느 데몬을 보고 있는지부터 확인하세요.

dockerd-rootless-setuptool.sh install
docker context ls
docker context show
docker info

docker info의 Server 영역에 Rootless와 관련된 보안 옵션이 나타나는지 확인하고, 예상과 달리 rootful 데몬이 계속 선택돼 있다면 docker context use rootless 또는 사용자 소켓 환경 변수를 점검합니다. 같은 명령을 root 권한으로 다시 실행하면 다른 사용자의 데몬을 확인하게 될 수 있으니, 테스트할 때는 실제 컨테이너를 실행할 사용자 세션을 유지하세요.

포트 공개는 1024번부터 생각해요

Rootless Docker에서도 일반적인 비특권 포트 매핑은 사용할 수 있지만, 1024 미만의 privileged port는 별도 조건이 필요해요. Docker 문서는 rootlesskit에 CAP_NET_BIND_SERVICE를 설정하고 데몬을 재시작하는 방법을 설명하지만, 이 작업은 호스트의 권한 경계를 다시 넓힐 수 있으므로 먼저 외부 프록시나 상위 로드밸런서에서 80·443을 받고 내부 서비스는 8080·8443 같은 비특권 포트로 연결할 수 있는지 검토하는 편이 낫습니다.[2]

docker run --rm -p 8080:80 nginx
curl http://127.0.0.1:8080

이 테스트가 성공해도 외부에서 접근된다는 뜻은 아니에요. 방화벽, 공유기 포트 전달, 클라우드 보안 그룹을 따로 확인해야 합니다. Docker API 소켓을 TCP로 공개하는 방식은 더 신중해야 해요. 공식 문서도 TCP 노출에는 TLS 검증을 함께 구성하도록 예시를 제시하고 있으므로, 인증 없는 0.0.0.0:2375 같은 구성을 시험용이라도 피하세요.[2]

볼륨은 컨테이너 안의 숫자를 믿지 않아요

Rootless 컨테이너에서 bind mount를 쓸 때는 컨테이너 내부에서 보이는 UID와 호스트의 실제 소유자가 일치하지 않을 수 있어요. 먼저 읽기 전용으로 연결해 경로가 맞는지 확인하고, 쓰기가 필요한 디렉터리만 별도로 만들어 권한을 조정하는 게 안전합니다.

mkdir -p "$HOME/rootless-test-data"
printf 'host\n' > "$HOME/rootless-test-data/check.txt"
docker run --rm -v "$HOME/rootless-test-data:/data:ro" alpine cat /data/check.txt

애플리케이션이 파일을 만들지 못하면 컨테이너에 무조건 --privileged를 붙이지 마세요. 이미지가 어떤 UID로 실행되는지, 호스트 디렉터리의 소유자와 모드가 맞는지, named volume으로 바꾸는 편이 나은지 순서대로 확인해야 해요. rootless는 호스트 파일 권한을 무시하는 우회 장치가 아니기 때문에, 권한 오류를 정확히 드러내는 쪽이 오히려 운영에 도움이 됩니다.

메모리와 CPU 제한이 실제로 적용되는지 확인해요

Docker는 기본적으로 컨테이너에 자원 제한을 자동으로 걸지 않아요. --memory, --cpus 같은 실행 옵션으로 제한을 명시할 수 있지만, Rootless mode에서 cgroup 관련 제한을 쓰려면 cgroup v2와 systemd 조건이 맞아야 합니다. Docker 문서는 조건이 충족되지 않으면 cgroup 기반 플래그가 무시될 수 있다고 설명해요.[2][3] Docker Desktop에서 WSL2 환경의 메모리·swap·가상 디스크를 조정하는 경우는 별도 설정 흐름이므로 Docker Desktop WSL2 자원 제한 가이드에서 나눠 확인하세요.

docker info --format '{{.CgroupDriver}}'
docker run --rm --memory=512m --cpus=1.0 alpine sh -c 'cat /sys/fs/cgroup/memory.max; sleep 2'

출력값만으로 모든 배포판의 제한 적용을 단정하지 말고, 실제 부하 테스트에서 호스트와 컨테이너의 관찰값을 비교하세요. 메모리 제한에 도달하면 컨테이너 프로세스가 종료될 수 있고, Docker는 컨테이너보다 데몬이나 호스트 프로세스가 살아남도록 OOM 우선순위를 조정합니다.[3] --oom-kill-disable을 메모리 제한 없이 쓰면 호스트 전체가 위험해질 수 있으니 공식 경고처럼 두 옵션을 함께 고려해야 해요.[3]

실패 원인을 좁히는 순서

  1. docker context show와 docker info로 rootless 데몬을 보고 있는지 확인해요.
  2. 컨테이너가 시작되지 않으면 systemctl --user status docker와 사용자 소켓 경로를 읽어요.
  3. 포트 오류라면 1024 이상 포트로 바꿔 네트워크 문제와 privileged port 문제를 분리해요.
  4. 파일 권한 오류라면 bind mount를 읽기 전용으로 재현하고, 컨테이너 UID와 호스트 소유자를 비교해요.
  5. 자원 제한이 무시되면 cgroup v2, systemd, 컨트롤러 위임 상태를 확인해요.
  6. 한 번에 여러 설정을 바꾸지 말고 마지막으로 정상 동작한 컨텍스트와 환경 변수를 기록해요.

rootless는 운영 목적에 따라 좋은 기본값이 될 수 있지만, 호스트 장치·낮은 포트·특수 네트워크 드라이버가 핵심인 서비스에는 별도 설계가 필요해요. 권한을 줄였다는 문구보다 실제 데몬 사용자, 소켓 경로, 볼륨 소유자, 자원 제한이 기대대로 동작하는지를 확인해야 합니다.

Sources

  1. [1] Docker Docs, Rootless mode
  2. [2] Docker Docs, Rootless mode tips
  3. [3] Docker Docs, Resource constraints

함께 읽을 글