이전 편에서 Rootless Docker 설치를 완료했습니다. 이번 편에서는 실무 운용에 필요한 세부 설정을 다룹니다. systemd user 서비스 관리, Rootless 전용 daemon.json 설정, 스토리지 드라이버 선택, 그리고 cgroup v2 기반 리소스 제한까지 체계적으로 정리합니다.


1. Rootless 모드의 파일 시스템 구조 이해

1.1 Root 모드 vs Rootless 모드 파일 경로 비교

Rootless 모드는 Root 모드와 모든 주요 파일 경로가 다릅니다. 운용 중 혼동을 방지하기 위해 먼저 전체 경로 차이를 파악하세요.

항목 Root 모드 Rootless 모드
Docker 소켓 /var/run/docker.sock /run/user/UID/docker.sock
daemon.json /etc/docker/daemon.json ~/.config/docker/daemon.json
데이터 루트 /var/lib/docker ~/.local/share/docker
systemd 서비스 /etc/systemd/system/docker.service ~/.config/systemd/user/docker.service
실행 바이너리 /usr/bin/dockerd /usr/bin/dockerd-rootless.sh
containerd 소켓 /run/containerd/containerd.sock /run/user/UID/docker/containerd/containerd.sock
로그 경로 journalctl -u docker journalctl --user -u docker
# 실제 경로 확인 (UID 예시: 1000)
echo "소켓: /run/user/$(id -u)/docker.sock"
echo "데이터: $HOME/.local/share/docker"
echo "설정: $HOME/.config/docker/daemon.json"
echo "systemd: $HOME/.config/systemd/user/docker.service"

1.2 XDG_RUNTIME_DIR 환경 변수의 역할

Rootless Docker 소켓 경로는 XDG_RUNTIME_DIR 환경 변수를 기반으로 합니다. 이 변수는 systemd가 사용자 세션 시작 시 자동으로 /run/user/UID로 설정합니다.

# XDG_RUNTIME_DIR 확인
echo $XDG_RUNTIME_DIR
# /run/user/1000

# 만약 미설정 상태라면 (SSH 접속 시 일부 환경)
export XDG_RUNTIME_DIR=/run/user/$(id -u)
export DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/docker.sock

Pro-tip: SSH로 원격 접속 시 XDG_RUNTIME_DIR가 자동 설정되지 않는 경우가 있습니다. 이럴 때는 .bashrc에 명시적으로 설정하거나, systemctl --user 명령이 실패할 경우 export XDG_RUNTIME_DIR=/run/user/$(id -u)를 먼저 실행하세요.


2. systemd User 서비스 관리

2.1 systemctl –user 명령어 완전 정리

Rootless Docker는 시스템 서비스(systemctl)가 아닌 사용자 서비스(systemctl --user)로 관리됩니다.

# 서비스 상태 확인
systemctl --user status docker

# 서비스 시작 / 중지 / 재시작
systemctl --user start docker
systemctl --user stop docker
systemctl --user restart docker

# 부팅 시 자동 시작 활성화 / 비활성화
systemctl --user enable docker
systemctl --user disable docker

# 서비스 파일 내용 확인
systemctl --user cat docker

# 데몬 설정 재로드 (daemon.json 변경 후)
systemctl --user daemon-reload
systemctl --user restart docker

2.2 시스템 부팅 시 자동 시작 — loginctl enable-linger

기본적으로 사용자 서비스는 해당 사용자가 로그인한 동안에만 실행됩니다. 서버 재부팅 후 로그인 없이도 Docker 데몬이 자동 시작되려면 linger를 활성화해야 합니다.

# linger 활성화
loginctl enable-linger $USER

# 활성화 상태 확인
loginctl show-user $USER | grep Linger
# Linger=yes

# 비활성화 (필요 시)
loginctl disable-linger $USER

# linger 파일 직접 확인 (활성화 시 파일이 존재)
ls /var/lib/systemd/linger/
# huni

linger 동작 원리:

loginctl enable-linger를 활성화하면 systemd가 사용자 로그인/로그아웃과 무관하게 해당 사용자의 systemd 인스턴스를 유지합니다. 이를 통해 부팅 후 로그인 없이도 Docker 데몬이 자동으로 시작됩니다.

2.3 서비스 로그 확인

# 실시간 로그 스트리밍
journalctl --user -u docker -f

# 최근 50줄
journalctl --user -u docker -n 50

# 특정 시간 이후 로그
journalctl --user -u docker --since "1 hour ago"
journalctl --user -u docker --since "2026-04-11 09:00:00"

# 오류 로그만 필터링
journalctl --user -u docker -p err

# 부팅 이후 로그
journalctl --user -u docker -b

3. daemon.json 설정 (Rootless 전용)

3.1 설정 파일 위치

Rootless 모드의 daemon.json 위치는 Root 모드와 완전히 다릅니다. Root 모드의 /etc/docker/daemon.json을 수정해도 Rootless 데몬에는 영향이 없습니다.

# Rootless daemon.json 디렉토리 생성
mkdir -p ~/.config/docker

# 파일 경로
# ~/.config/docker/daemon.json

3.2 권장 daemon.json 설정

{
  "storage-driver": "overlay2",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3",
    "compress": "true"
  },
  "data-root": "/home/huni/.local/share/docker",
  "live-restore": true,
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 65536,
      "Soft": 65536
    }
  },
  "features": {
    "buildkit": true
  }
}

각 설정 항목 설명:

설정 설명
storage-driver 컨테이너 레이어 저장 방식. Ubuntu 22.04+는 overlay2 권장
log-driver 컨테이너 로그 드라이버. json-file이 기본값
log-opts.max-size 로그 파일 최대 크기 (무제한 증가 방지)
log-opts.max-file 최대 로테이션 파일 수
data-root 이미지/컨테이너/볼륨 저장 경로
live-restore 데몬 재시작 시 실행 중인 컨테이너 유지
default-ulimits 컨테이너 기본 ulimit 설정
# 설정 적용 (데몬 재시작)
systemctl --user restart docker

# 설정 적용 확인
docker info | grep -E "Storage Driver|Logging Driver|Docker Root Dir|Live Restore"
# Storage Driver: overlay2
# Logging Driver: json-file
# Docker Root Dir: /home/huni/.local/share/docker
# Live Restore Enabled: true

3.3 데이터 저장 경로 변경

홈 디렉토리의 용량이 부족한 경우, 더 큰 디스크 파티션으로 데이터 경로를 변경할 수 있습니다.

# 1. 기존 데몬 중지
systemctl --user stop docker

# 2. 기존 데이터 이동 (필요 시)
mkdir -p /data/docker-rootless
rsync -aP ~/.local/share/docker/ /data/docker-rootless/

# 3. daemon.json 수정
cat > ~/.config/docker/daemon.json << 'EOF'
{
  "data-root": "/data/docker-rootless",
  "storage-driver": "overlay2"
}
EOF

# 4. 데몬 재시작 및 확인
systemctl --user start docker
docker info | grep "Docker Root Dir"
# Docker Root Dir: /data/docker-rootless

4. 스토리지 드라이버 상세 설정

4.1 Ubuntu 버전별 권장 드라이버

Ubuntu 버전 커널 권장 드라이버
20.04 LTS 5.4 fuse-overlayfs
22.04 LTS 5.15 overlay2 (네이티브 지원)
24.04 LTS 6.8 overlay2 (네이티브 지원)

Ubuntu 22.04부터는 커널이 User Namespace에서 네이티브 overlay 파일시스템을 지원합니다. 별도의 fuse-overlayfs 없이도 overlay2를 바로 사용할 수 있습니다.

4.2 Ubuntu 22.04+에서 네이티브 overlay2 확인

# 커널의 overlay 지원 확인
cat /proc/filesystems | grep overlay
# nodev   overlay  ← 이 라인이 있어야 함

# 현재 스토리지 드라이버 확인
docker info | grep "Storage Driver"
# Storage Driver: overlay2

# overlay2가 올바르게 사용 중인지 검증
docker system df
docker info | grep -A5 "Storage Driver"
# Storage Driver: overlay2
#  Backing Filesystem: extfs
#  Supports d_type: true
#  Using metacopy: false
#  Native Overlay Diff: true  ← 네이티브 overlay 사용 확인

4.3 Ubuntu 20.04에서 fuse-overlayfs 설정

# fuse-overlayfs 설치
sudo apt-get install -y fuse-overlayfs

# 모듈 로드 확인
lsmod | grep fuse
# fuse  ...

# daemon.json에서 명시적 지정
cat > ~/.config/docker/daemon.json << 'EOF'
{
  "storage-driver": "fuse-overlayfs"
}
EOF

systemctl --user restart docker
docker info | grep "Storage Driver"
# Storage Driver: fuse-overlayfs

4.4 vfs 드라이버 (최후 수단)

overlay 계열 드라이버를 사용할 수 없는 매우 제한된 환경(일부 NFS, 구형 커널 등)에서는 vfs 드라이버를 사용할 수 있습니다. 단, 성능이 매우 낮고 디스크 사용량이 폭발적으로 증가하므로 최후의 수단으로만 사용하세요.

# vfs는 권장하지 않음 — 성능 및 디스크 효율 매우 낮음
# {
#   "storage-driver": "vfs"
# }

5. 환경 변수 설정 완벽 정리

5.1 ~/.bashrc 완전 설정 예시

# ~/.bashrc 하단에 추가
# ======= Docker Rootless 환경 설정 =======
export XDG_RUNTIME_DIR=/run/user/$(id -u)
export DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/docker.sock
export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
# ==========================================
# 적용 및 확인
source ~/.bashrc
docker info | grep -E "Server Version|rootless"

5.2 다중 사용자 환경에서의 격리 확인

Rootless 모드의 큰 장점 중 하나는 사용자별 완전한 격리입니다. 사용자 A의 컨테이너가 사용자 B에게는 보이지 않습니다.

# huni 사용자로 확인
docker ps
# CONTAINER ID  IMAGE  ...  NAMES
# abc123        nginx  ...  my-nginx

# alice 사용자로 전환 후 확인
su - alice
docker ps
# CONTAINER ID  IMAGE  COMMAND  CREATED  STATUS  PORTS  NAMES
# (비어 있음 — huni의 컨테이너가 보이지 않음)

6. 리소스 제한 설정 (cgroup v2)

6.1 cgroup v2에서 메모리/CPU 제한 검증

cgroup v2 환경에서는 Rootless 모드에서도 컨테이너 리소스 제한이 완전히 동작합니다.

# 메모리 제한 설정 및 검증
docker run --rm --memory=256m alpine sh -c "cat /sys/fs/cgroup/memory.max"
# 268435456  (256MB = 256 × 1024 × 1024 bytes)

# CPU 제한 설정 및 검증
docker run --rm --cpus=0.5 alpine sh -c "cat /sys/fs/cgroup/cpu.max"
# 50000 100000  (50ms per 100ms = 0.5 CPU)

# 실제 메모리 제한 동작 확인
docker run --rm --memory=64m alpine sh -c \
  "dd if=/dev/zero of=/tmp/test bs=1M count=100 2>&1 || echo 'OOM 발생'"
# Killed  또는  OOM 발생  ← 제한 정상 작동

6.2 cgroup 위임(delegation) 확인

cgroup v2에서 리소스 제한이 동작하지 않는다면, systemd의 cgroup 위임 설정을 확인하세요.

# cgroup 위임 상태 확인
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers
# cpuset cpu io memory pids  ← 이 항목들이 있어야 함

# 위임이 설정되지 않은 경우 (Ubuntu 20.04 등)
sudo mkdir -p /etc/systemd/system/user@.service.d/
sudo tee /etc/systemd/system/user@.service.d/delegate.conf << 'EOF'
[Service]
Delegate=cpu cpuset io memory pids
EOF

sudo systemctl daemon-reload
# 재부팅 또는 loginctl 재시작 필요

6.3 컨테이너별 리소스 제한 설정 예시

# 메모리 512MB, CPU 1코어, 스왑 없음으로 실행
docker run -d \
  --name web-app \
  --memory=512m \
  --memory-swap=512m \
  --cpus=1.0 \
  --memory-reservation=256m \
  nginx:alpine

# 실행 중인 컨테이너의 리소스 사용량 실시간 확인
docker stats web-app

# 컨테이너 리소스 제한 정보 확인
docker inspect web-app | grep -A5 '"Memory"'

7. systemd user 서비스 파일 커스터마이징

설치 과정에서 자동 생성된 서비스 파일을 직접 확인하고 필요 시 수정할 수 있습니다.

# 서비스 파일 위치 및 내용 확인
cat ~/.config/systemd/user/docker.service

기본 서비스 파일 내용:

[Unit]
Description=Docker Application Container Engine (Rootless)
Documentation=https://docs.docker.com/go/rootless/
BindsTo=docker.socket

[Service]
Environment=PATH=/usr/bin:/sbin:/usr/sbin:/bin
ExecStart=/usr/bin/dockerd-rootless.sh
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
Type=notify
NotifyAccess=all
KillMode=mixed

[Install]
WantedBy=default.target

커스터마이징 예시 — 환경 변수 추가:

# 서비스 파일 직접 수정 대신 drop-in 파일 사용 (권장)
mkdir -p ~/.config/systemd/user/docker.service.d/
cat > ~/.config/systemd/user/docker.service.d/override.conf << 'EOF'
[Service]
Environment=DOCKERD_ROOTLESS_ROOTLESSKIT_NET=pasta
Environment=DOCKERD_ROOTLESS_ROOTLESSKIT_MTU=65520
EOF

systemctl --user daemon-reload
systemctl --user restart docker

결론

Rootless Docker의 운용 설정은 Root 모드와 경로만 다를 뿐, 동일한 방식으로 관리합니다. 핵심 포인트를 정리하면 다음과 같습니다.

  • 파일 경로: 모든 설정/데이터가 ~/ 하위에 위치 (~/.config/docker/, ~/.local/share/docker/)
  • systemd: systemctl --user 명령 사용, loginctl enable-linger로 부팅 자동 시작
  • 스토리지: Ubuntu 22.04+ 환경에서는 네이티브 overlay2 그대로 사용
  • cgroup v2: 메모리/CPU 제한이 완전히 동작하며, 위임 설정이 핵심

다음 편에서는 Docker Compose 실전 운용, 포트 1024 미만 바인딩 우회 방법, 그리고 자주 발생하는 트러블슈팅을 다룹니다.

참고자료


Docker Rootless Mode 시리즈

  • [Part 1] Rootless 모드란? 보안 개념과 필요성
  • [Part 2] Ubuntu에서 Rootless Docker 설치하기
  • [Part 3] Rootless Docker 설정 및 운용 가이드 ← 현재 글
  • [Part 4] Rootless Docker 실전 활용 및 트러블슈팅](/container/docker-rootless-mode-practical-guide/)

댓글남기기