호스트 디렉터리를 -v로 마운트했는데 컨테이너 안에서 Permission denied가 뜨거나, 반대로 컨테이너가 만든 파일이 호스트에서 root 소유라 지울 수 없다 — 바인드마운트의 가장 흔한 함정입니다. 원인은 거의 항상 호스트와 컨테이너의 UID/GID가 다르기 때문입니다.
왜 권한이 어긋나는가
리눅스 파일 권한은 이름이 아니라 숫자 UID/GID로 저장됩니다. 바인드마운트는 호스트 디렉터리를 그대로 컨테이너에 노출할 뿐, 소유권을 변환하지 않습니다. 호스트의 내 계정이 1000인데 컨테이너 프로세스가 root(0)나 다른 UID로 돈다면, 같은 파일을 서로 "남의 것"으로 봅니다.
# 호스트에서 내 UID 확인
id -u # 예: 1000
# 컨테이너 프로세스가 어떤 UID로 도는지
docker exec <container> id
uid=0(root) gid=0(root) groups=0(root)
컨테이너가 root로 돌면 그 컨테이너가 마운트 경로에 만든 파일은 호스트에서 root 소유가 됩니다. 반대로 컨테이너 프로세스가 1001인데 마운트한 폴더가 호스트에서 1000 소유에 750 권한이면, 컨테이너는 읽지도 못합니다.
해결 — 상황별 정렬 방법
| 상황 | 방법 |
|---|---|
| 컨테이너 UID를 호스트에 맞추고 싶다 | docker run --user $(id -u):$(id -g) |
| 이미지가 특정 UID를 요구한다 | 호스트 폴더를 그 UID로 chown |
| 여러 사람이 같은 마운트를 쓴다 | 공용 GID 그룹을 만들고 chmod g+rwx |
| 소유권 자체를 격리하고 싶다 | rootless Docker / userns-remap |
1) 컨테이너를 내 UID로 실행
가장 직관적인 방법입니다. 컨테이너 프로세스가 호스트의 나와 같은 UID로 돌면 새로 만든 파일도 내 소유가 됩니다.
docker run --rm \
-u "$(id -u):$(id -g)" \
-v "$PWD/data:/data" \
alpine sh -c 'touch /data/test.txt && ls -l /data'
주의: --user로 지정한 UID가 이미지의 /etc/passwd에 없어도 실행은 되지만, $HOME이 없어 일부 앱이 깨질 수 있습니다.
2) 호스트 폴더 소유권 맞추기
이미지가 node(보통 UID 1000)처럼 비루트 사용자로 고정돼 있다면, 호스트 폴더를 그 UID로 맞춥니다.
sudo chown -R 1000:1000 ./data
체크리스트
id -u; id -g # 호스트 내 UID/GID
docker exec <container> id # 컨테이너 프로세스 UID/GID
ls -ln ./data # 마운트 폴더의 숫자 소유권
docker run -u "$(id -u):$(id -g)" ... # 정렬해서 재실행
ls -ln으로 이름이 아닌 숫자 소유권을 보는 것이 핵심입니다 — 호스트와 컨테이너가 같은 숫자를 보고 있는지가 전부입니다.
바인드마운트와 볼륨의 차이, 권한이 어긋날 때 컨테이너 안팎에서 어떻게 보이는지 직접 마운트해 보며 익히는 실습은 도커 트랙에서 무료로 할 수 있습니다.