Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

(시리즈 글이 2개 있습니다.)
Linux: 127. "USER ..." 설정이 된 Docker 컨테이너의 호스트 측 볼륨 권한
; https://www.sysnet.pe.kr/2/0/14030

Linux: 128. "USER ..." 설정이 된 Docker 컨테이너의 호스트 측 볼륨 권한 (2)
; https://www.sysnet.pe.kr/2/0/14031




"USER ..." 설정이 된 Docker 컨테이너의 호스트 측 볼륨 권한

테스트를 위해 다음과 같은 Dockerfile을 작성 후,

$ echo ${USER}
testusr

$ echo "FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base" > Dockerfile

컨테이너를 빌드한 다음, volume을 매핑해 실행해 봅니다.

$ docker build -t dotnet_test .

$ docker run --rm -it -v dotnet_test_dir:/app --name dotnet_test_inst dotnet_test /bin/bash

컨테이너 내부에서 sleep 명령어를 실행한 후,

// dotnet_test_inst 컨테이너 내부에서 실행

root@fecc129e121d:/# echo "TEST" > /app/test.txt

root@fecc129e121d:/# sleep 200

호스팅하는 리눅스 서버에서 해당 프로세스를 확인해 보면 root 권한으로 실행 중임을 알 수 있습니다.

// docker 호스팅 서버에서 실행

$ ps aux | grep " sleep 200"
root     2950631  0.0  0.0   2492  1304 pts/0    S+   13:15   0:00 sleep 200

그렇다면 당연히 매핑된 volume도 root 소유권이 됩니다.

// docker 호스팅 서버에서 실행

$ docker volume inspect dotnet_test_dir
[
    {
        "CreatedAt": "2025-10-11T04:15:18Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/mnt/docker-data/docker/volumes/dotnet_test_dir/_data",
        "Name": "dotnet_test_dir",
        "Options": null,
        "Scope": "local"
    }
]

$ ls -la /mnt/docker-data/docker/volumes/dotnet_test_dir/_data      
total 4
drwxr-xr-x 2 root root 30 Oct 11 13:43 .
drwx-----x 3 root root 27 Oct 11 13:15 ..
-rw-r--r-- 1 root root  5 Oct 11 13:43 test.txt

$ cat /mnt/docker-data/docker/volumes/dotnet_test_dir/_data/test.txt
TEST

$ sudo ls -la /mnt/docker-data/docker/volumes/ | grep dotnet_test_dir
drwx-----x   3 root     root     27 Oct 11 13:15 dotnet_test_dir

$ sudo ls -la /mnt/docker-data/docker/volumes/dotnet_test_dir
total 24
drwx-----x   3 root root     27 Oct 11 13:15 .
drwxrwxr-x 238 root test  20480 Oct 11 13:15 ..
drwxr-xr-x   2 root root      6 Oct 11 13:15 _data

그리고 root 이외의 사용자/그룹에 대해서는 'w' 쓰기 권한이 없습니다.




저렇게 생성한 volume을 그대로 두고, Dockerfile을 "User app"으로 시작하도록 수정해 보겠습니다.

// runtime:8.0 이미지에는 "app"이라는 비루트 사용자가 미리 정의돼 있음

$ echo -e "FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base\nUSER app" > app.Dockerfile

$ docker build -f app.Dockerfile -t dotnet_test_non_root .

우선 볼륨 매핑 없이 컨테이너를 실행해 볼까요?

$ docker run -it --name dotnet_test_non_root_inst dotnet_test_non_root /bin/bash

app@4638f8e580ed:/$ whoami
app

app@4638f8e580ed:/$ id -u
1654

app@4638f8e580ed:/$ echo $UID
1654

app@4638f8e580ed:/$ id
uid=1654(app) gid=1654(app) groups=1654(app)

app@4638f8e580ed:/$ sleep 200

그럼 저 프로세스(sleep 200)의 소유권을 docker 호스팅 서버에서 확인해 보면,

$ ps aux | grep " sleep 200"
1654     2954740  0.0  0.0   2492  1316 pts/0    S+   13:25   0:00 sleep 200

이전에 "root"로 나왔던 사용자 칼럼의 값이 저렇게 번호(위의 경우 1654)로 나옵니다. 그러니까, 컨테이너를 위해 격리된 user namespace 내에서만 존재하는 사용자이기 때문에 호스팅 서버에서는 저렇게 UID(사용자 ID)로만 표시되는 것입니다.

그렇다면 이제 이전에 매핑했던 볼륨을 "USER ..."로 실행한 컨테이너 내에서 접근하면 어떻게 될까요?

$ docker run --rm -it -v dotnet_test_dir:/app --name dotnet_test_non_root_inst dotnet_test_non_root /bin/bash

app@66d0fca6897b:/app$ ls -la /app
total 4
drwxr-xr-x 2 root root 30 Oct 11 04:43 .
drwxr-xr-x 1 root root 25 Oct 11 04:46 ..
-rw-r--r-- 1 root root  5 Oct 11 04:43 test.txt

app@66d0fca6897b:/app$ cat /app/test.txt
TEST

app@66d0fca6897b:/app$ echo "TEST2" > test2.txt"
bash: test2.txt: Permission denied

app@66d0fca6897b:/app$ mkdir test
mkdir: cannot create directory 'test': Permission denied

보는 바와 같이, "USER ..." 설정의 추가로 인해 기존에 생성해 두었던 볼륨을 읽기 전용으로만 접근할 수 있게 되었습니다. 따라서, 새롭게 변경한 환경에서 기존 볼륨을 사용하고 싶다면 호스팅 서버에서 해당 볼륨의 소유권을 적절하게 변경해 주어야 합니다.




그렇다면 궁금해지는군요. 처음부터 "USER ..." 설정을 사용한 docker 컨테이너에 볼륨이 매핑되었다면 해당 볼륨의 소유권은 어떻게 될까요?

$ docker run --rm -it -v dotnet_test_dir2:/app --name dotnet_test_non_root_inst2 dotnet_test_non_root /bin/bash

// docker 호스팅 서버에서 실행

$ docker volume inspect dotnet_test_dir2
...[생략]...

$ ls -la /mnt/docker-data/docker/volumes/dotnet_test_dir2/_data
total 0
drwxr-xr-x 2 root root 10 Oct 11 13:54 .
drwx-----x 3 root root 27 Oct 11 13:54 ..

오호~~~, root로 나옵니다. 그렇다면 저렇게 "USER ..." 설정이 된 컨테이너에서는 해당 볼륨에 대해 쓰기 권한이 없다는 건데요, 실제로 컨테이너 내부에서 시도해 보면,

$ docker run --rm -it -v dotnet_test_dir2:/app --name dotnet_test_non_root_inst2 dotnet_test_non_root /bin/bash

app@813e761de7e4:/$ id
uid=1654(app) gid=1654(app) groups=1654(app)

app@813e761de7e4:/$ cd /app

app@813e761de7e4:/app$ echo "TEST" > test.txt
bash: test.txt: Permission denied

app@813e761de7e4:/app$ mkdir test
mkdir: cannot create directory 'test': Permission denied

쓰기가 안 됩니다. 이에 대해 검색해 보면,

How to give non-root user in Docker container access to a volume mounted on the host
; https://stackoverflow.com/questions/39397548/how-to-give-non-root-user-in-docker-container-access-to-a-volume-mounted-on-the

대략 해법으로 제공되는 것이 3가지 정도인데요, 첫 번째는 "USER ..." 설정을 하지 말고 컨테이너를 기존처럼 실행한 다음 내부에서 "exec runuser -u ..." 명령어로 프로그램을 (제한된 권한으로) 실행하도록 바꾸는 것입니다. 해당 답변은 +67의 투표를 얻었는데... 여러분은 어떤가요? ^^ 방법이 마음에 드시나요?

두 번째는, 호스트 측에서 컨테이너의 uid/gid에 해당하는 값으로 볼륨 디렉터리의 소유권을 변경하는 것입니다. 예를 들어, 위와 같은 환경에서는 컨테이너의 uid/gid가 모두 1654이므로, 호스트 측에서 다음과 같이 볼륨 권한을 바꿔야 합니다.

// docker 호스팅 서버에서 실행

$ sudo chown -R 1654:1654 /mnt/docker-data/docker/volumes/dotnet_test_dir2

$ sudo ls -la /mnt/docker-data/docker/volumes/dotnet_test_dir2
total 24
drwx-----x   3 1654 1654    27 Oct 11 13:54 .
drwxrwxr-x 239 root rnd  20480 Oct 11 13:54 ..
drwxr-xr-x   2 1654 1654    30 Oct 11 14:13 _data

그럼 저렇게 1654:1654로 소유권이 변경되었으므로 컨테이너 내부에서 쓰기가 가능해집니다.

마지막 세 번째 방법은, 그냥 아예 "chmod 777 ..."로 볼륨 디렉터리의 권한을 바꾸자는 건데요, 이건 -3개의 투표를 얻어맞았습니다. ^^




참고로, 컨테이너 내에서 설정한 "USER ..."의 사용자 명은 해당 컨테이너 이미지에 미리 정의된 값입니다. 예를 들어, 위에서 사용한 "mcr.microsoft.com/dotnet/runtime:8.0" 이미지의 경우 "app" 사용자는 다음과 같이 정의돼 있어,

app@119fdfa35e6d:/$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
...[생략]...
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
app:x:1654:1654::/home/app:/bin/sh

그래서 "1654"라는 uid/gid가 할당된 것입니다. 또는, "USER ..." 설정이 없는 Dockerfile 설정이라면 docker run 시에 --user 옵션을 사용해 USER 명령어를 흉내 낼 수 있습니다.

// USER 설정이 없다면 root 권한으로 실행됨

$ docker run --rm -it --name dotnet_test_inst dotnet_test /bin/bash
root@6c18a4075d7a:/# id
uid=0(root) gid=0(root) groups=0(root)

// --user 옵션으로 USER 설정을 대신

$ docker run --rm -it --user 1654:1654 --name dotnet_test_inst dotnet_test /bin/bash
app@4c2548122e80:/$ id
uid=1654(app) gid=1654(app) groups=1654(app)

그렇다면 이미 USER 설정이 있는 경우 --user 옵션을 주면 어떻게 될까요?

$ docker run --rm -it --user 0:0 --name dotnet_test_non_root_inst2 dotnet_test_non_root /bin/bash
root@339c5441731b:/# id
uid=0(root) gid=0(root) groups=0(root)

보는 바와 같이 USER 설정을 무시하고 --user 옵션이 우선 적용됩니다. 그리고 --user, -u 옵션은 docker exec 명령어에서도 그대로 적용할 수 있습니다.




마지막으로 위의 글을 실습했다면! ^^

docker rmi dotnet_test
docker rmi dotnet_test_non_root

docker volume rm dotnet_test_dir
docker volume rm dotnet_test_dir2




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 10/20/2025]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 181  [182]  183  184  185  186  187  188  189  190  191  192  193  194  195  ...
NoWriterDateCnt.TitleFile(s)
547정성태12/4/200734039.NET Framework: 98. .NET 비동기 Socket과 스레드
546정성태12/4/200724756Team Foundation Server: 21. Microsoft Office가 참조된 경우의 빌드 환경 구성
545정성태12/4/200732004Windows: 27. 눈으로 확인해 보는 ASLR 기능 [1]
544정성태11/25/200727333오류 유형: 48. VS.NET 2008 설치 오류 - Error code 1602 [5]
543정성태11/25/200730556개발 환경 구성: 31. ROBOCOPY XP026 버전 [1]
542정성태11/3/200745567VS.NET IDE: 55. XML/XSLT로 구현하는 매크로 확장 [5]파일 다운로드2
538정성태10/11/200732156스크립트: 10. VBScript - "Sub를 호출할 때는 괄호를 사용할 수 없습니다." [2]
537정성태9/28/200741224개발 환경 구성: 30. 64비트 OS에서의 ChartFX 라이선스 문제
536정성태9/12/200738208.NET Framework: 97. WCF : netTcpBinding에서의 각종 Timeout 값 설명 [11]
535정성태9/11/200735496.NET Framework: 96. WCF - PerSession에서의 클라이언트 연결 관리 [5]
534정성태9/3/200731051개발 환경 구성: 29. VHD 파일 크기 줄이기
533정성태9/2/200733966개발 환경 구성: 28. CA 서비스 - 사용자 정의 템플릿 유형 추가
532정성태9/2/200735716개발 환경 구성: 27. AD CA에서 Code Signing 인증서 유형 추가 방법
531정성태9/2/200731593.NET Framework: 95. WCF에서의 DataTable 사용
530정성태9/1/200728535.NET Framework: 94. WCF 예외에 대한 시행착오
529정성태8/31/200731443.NET Framework: 93. WCF - DataContract와 KnownType 특성 [1]
528정성태8/30/200725885오류 유형: 47. VPC - 네트워크 어댑터 MAC 주소 중복 오류
527정성태8/30/200736374Team Foundation Server: 20. 잠긴 파일을 강제로 해제 [2]
526정성태8/29/200725864오류 유형: 46. VS.NET 2008 - ASP.NET 디버깅 : Strong name validation failed.
525정성태8/27/200728152VS.NET IDE: 54. VS.NET 2008 - 새롭게 도입되는 XSD Schema Designer
524정성태8/23/200745763오류 유형: 45. 요청한 작업은, 사용자가 매핑한 구역이 열려 있는...
523정성태8/16/200728642VS.NET IDE: 53. VS.NET 2008 - 서비스 참조 시 기존 데이터 컨테이너 DLL 사용
522정성태8/13/200731953VS.NET IDE: 52. VS.NET 2008 - WCF를 위한 디버깅 환경 개선
521정성태8/8/200731555.NET Framework: 92. XmlSerializer 생성자의 실행 속도를 올리는 방법 - 두 번째 이야기 [3]
520정성태8/7/200727063VS.NET IDE: 51. Visual Studio 2008 베타 2 설치
519정성태7/27/200733543오류 유형: 44. System.BadImageFormatException [2]
... 181  [182]  183  184  185  186  187  188  189  190  191  192  193  194  195  ...