Docker에서 호스트 디렉토리에 액세스 할 때 권한이 거부되었습니다.


283

한마디로 : Docker에서 호스트 디렉토리를 마운트하려고하지만 액세스 권한이 좋아 보이지만 컨테이너 내에서 호스트 디렉토리에 액세스 할 수 없습니다.

세부 사항 :

내가 뭐하는 거지

sudo docker run -i -v /data1/Downloads:/Downloads ubuntu bash

그리고

ls -al

그것은 나에게 준다 :

total 8892
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 .
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 ..
-rwxr-xr-x.   1 root root       0 Jun 18 14:34 .dockerenv
-rwx------.   1 root root 9014486 Jun 17 22:09 .dockerinit
drwxrwxr-x.  18 1000 1000   12288 Jun 16 11:40 Downloads
drwxr-xr-x.   2 root root    4096 Jan 29 18:10 bin
drwxr-xr-x.   2 root root    4096 Apr 19  2012 boot
drwxr-xr-x.   4 root root     340 Jun 18 14:34 dev
drwxr-xr-x.  56 root root    4096 Jun 18 14:34 etc
drwxr-xr-x.   2 root root    4096 Apr 19  2012 home

그리고 더 많은 줄이 있습니다 (이것이 관련 부분이라고 생각합니다).

만약 내가한다면

cd /Downloads
ls

결과는

ls: cannot open directory .: Permission denied

호스트는 Fedora 20이며 Docker 1.0.0 및 go1.2.2입니다.

무슨 일이야?

답변:


269

전체 내용 은 Volumes 및 SELinux대한이 Project Atomic 블로그 게시물을 참조하십시오 .

구체적으로 특별히:

Docker가 최종적으로 docker-1.7에 나타날 패치를 병합 한 이후 최근에 쉬워졌습니다 (RHEL, CentOS 및 Fedora의 docker-1.6에서 패치를 수행했습니다).

이 패치는 볼륨 마운트 (-v)의 옵션으로 "z"및 "Z"에 대한 지원을 추가합니다.

예를 들면 다음과 같습니다.

docker run -v /var/db:/var/db:z rhel7 /bin/sh

chcon -Rt svirt_sandbox_file_t /var/db 매뉴얼 페이지에 설명 된 내용을 자동으로 수행합니다 .

더 나은 방법으로 Z를 사용할 수 있습니다.

docker run -v /var/db:/var/db:Z rhel7 /bin/sh

컨테이너 내부의 내용에 컨테이너가 실행될 정확한 MCS 레이블이 붙습니다. 기본적으로 각 컨테이너마다 다른 chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/db위치에서 실행됩니다 s0:c1,c2.


18
이것은 매력처럼 작동합니다. 다른 솔루션은 대부분 해결 방법입니다.
tuxdna

4
cf. docker documentation 의 볼륨 레이블 섹션
maxschlepzig

오, 정말 작동합니다. 나는 마침내 이것을 발견했다. 많은 감사합니다! 이것에 대한 공식적인 문서가 있습니까?
Kirby

1
업스트림은이 섹션에서 마지막 단락으로 사용합니다. docs.docker.com/engine/reference/commandline/run/…
gregswift

1
쉼표로 구분 된 두 옵션을 동시에 사용하여 볼륨을 읽기 전용으로 마운트하는 동시에 SELinux에서 권한을 수정할 수 있습니다 -v $(pwd):/app:ro,Z. 정답으로 표시해야합니다.
danirod

264

그것은이다 SELinux를 문제.

일시적으로 발행 할 수 있습니다

su -c "setenforce 0"

호스트에서 다음을 실행하여 SELinux 규칙에 액세스하거나 추가하십시오.

chcon -Rt svirt_sandbox_file_t /path/to/volume

3
/ path / to / volume은 호스트의 경로입니까? 그렇다면이 솔루션이 데이터 컨테이너에서 작동하지 않는 것 같습니까?
Roy Truelove

6
su -c "setenforce 1"을 잊지 마십시오. 그렇지 않으면 SELinux가 여전히 비활성화되어 있기 때문에 작동합니다
vcarel

이것은 내 문제를 해결했다. 고마워, 나는 그들이 이것에 대한 수정이 있기를 바랍니다.
Hokutosei

19
대부분의 경우 권한 모드로 컨테이너를 실행하는 것은 좋지 않으므로 selinux 규칙을 추가하는 것이 가장 좋습니다.
Zoro_77

7
Zoro_77이 말했듯이 규칙을 추가하고 stopdisablingselinux.com ;)
GabLeRoux

71

경고 :이 솔루션에는 보안 위험이 있습니다.

특권으로 컨테이너를 실행하십시오.

sudo docker run --privileged=true -i -v /data1/Downloads:/Downloads ubuntu bash

시도하지 않은 다른 옵션은 권한있는 컨테이너를 만든 다음 권한이없는 컨테이너를 만드는 것입니다.


1
@JBernardo 두 옵션 중 어느 것이 문제를 해결 했습니까?
user100464

@ user100464--privileged=true
JBernardo

1
내 경우에는 도움이되지 마십시오. 백 포트 커널 3.16을 사용하지만 SELinux 구성을 활성화하지 않은 데비안 Whezzy. :(
aholbreich

docker-composer를 사용하여 'privileged : true'를 추가하는 경우
Lionel Morrison

35
이러지 마십시오. --privileged보안 위험입니다
Navin

38

일반적으로 호스트 볼륨 마운트와 관련된 권한 문제는 컨테이너 내의 uid / gid가 호스트에있는 파일의 uid / gid 권한에 따라 파일에 액세스 할 수 없기 때문입니다. 그러나이 특정 사례는 다릅니다.

권한 문자열의 끝에있는 점 drwxr-xr-x.은 SELinux가 구성되었음을 나타냅니다. SELinux와 함께 호스트 마운트를 사용하는 경우 볼륨 정의 끝에 추가 옵션을 전달해야합니다.

  • 그만큼 z 옵션은 바인드 마운트 컨텐츠가 여러 컨테이너간에 공유됨을 나타냅니다.
  • Z옵션은 바인드 마운트 컨텐츠가 개인용이며 공유되지 않음을 나타냅니다.

그러면 볼륨 마운트 명령은 다음과 같습니다.

sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash

SELinux를 사용한 호스트 마운트에 대한 자세한 내용은 https://docs.docker.com/storage/#configure-the-selinux-label을 참조하십시오.


다른 사용자로 실행중인 컨테이너에서이 문제가 발생하는 다른 사용자의 경우 컨테이너 내부 사용자의 uid / gid에 호스트의 파일에 대한 권한이 있는지 확인해야합니다. 프로덕션 서버에서는 이미지 빌드 프로세스에서 uid / gid를 제어하여 파일에 액세스 할 수있는 호스트의 uid / gid와 일치 시키거나 프로덕션 환경에서 호스트 마운트를 사용하지 않는 경우가 종종 있습니다.

명명 된 볼륨은 파일 소유권 및 권한을 포함하여 이미지 디렉토리에서 볼륨 디렉토리를 초기화하므로 마운트를 호스트하는 것이 선호됩니다. 이것은 볼륨이 비어 있고 명명 된 볼륨으로 컨테이너가 생성 될 때 발생합니다.

MacOS 사용자는 이제 OSXFS를 습니다 Mac 호스트와 컨테이너 사이에서 자동으로 uid / gid를 처리하는 를 . 도움이되지 않는 곳은 /var/lib/docker.sock과 같이 컨테이너에 마운트 된 내장 VM 내부의 파일입니다.

호스트 uid / gid가 개발자마다 변경 될 수있는 개발 환경의 경우 선호되는 솔루션은 루트로 실행되는 진입 점으로 컨테이너를 시작하고 컨테이너 내 사용자의 uid / gid를 호스트 볼륨 uid / gid와 일치하도록 수정하는 것입니다. 그런 다음 gosu루트에서 컨테이너 사용자에게 드롭하여 컨테이너 내부에서 애플리케이션을 실행하십시오. 이것에 대한 중요한 스크립트는 fix-perms내 기본 이미지 스크립트에 있으며 https://github.com/sudo-bmitch/docker-base에 있습니다.

fix-perms스크립트 에서 중요한 부분 은 다음과 같습니다.

# update the uid
if [ -n "$opt_u" ]; then
  OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:)
  NEW_UID=$(stat -c "%u" "$1")
  if [ "$OLD_UID" != "$NEW_UID" ]; then
    echo "Changing UID of $opt_u from $OLD_UID to $NEW_UID"
    usermod -u "$NEW_UID" -o "$opt_u"
    if [ -n "$opt_r" ]; then
      find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \;
    fi
  fi
fi

컨테이너 내 사용자의 uid와 파일의 uid를 가져오고 일치하지 않으면 usermoduid를 조정하기 위해 호출 합니다. 마지막으로 uid를 변경하지 않은 파일을 수정하기 위해 재귀 찾기를 수행합니다. -u $(id -u):$(id -g)위의 엔트리 포인트 코드는 각 개발자가 컨테이너를 시작하기 위해 스크립트를 실행할 필요가 없으며 사용자가 소유 한 볼륨 외부의 파일은 권한이 수정되므로 플래그 로 컨테이너를 실행하는 것보다 낫습니다 .


바인드 마운트를 수행하는 명명 된 볼륨을 사용하여 이미지에서 docker가 호스트 디렉토리를 초기화하도록 할 수도 있습니다. 이 디렉토리는 미리 존재해야하며 상대 경로 일 수있는 작성 파일의 호스트 볼륨과 달리 호스트 디렉토리의 절대 경로를 제공해야합니다. 도 커가 디렉토리를 초기화하려면 디렉토리도 비어 있어야합니다. 바인드 마운트에 이름 지정된 볼륨을 정의하는 세 가지 옵션은 다음과 같습니다.

  # create the volume in advance
  $ docker volume create --driver local \
      --opt type=none \
      --opt device=/home/user/test \
      --opt o=bind \
      test_vol

  # create on the fly with --mount
  $ docker run -it --rm \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=none,volume-opt=o=bind,volume-opt=device=/home/user/test \
    foo

  # inside a docker-compose file
  ...
  volumes:
    bind-test:
      driver: local
      driver_opts:
        type: none
        o: bind
        device: /home/user/test
  ...

마지막으로, 사용자 네임 스페이스를 사용하려고하면 컨테이너의 uid / gid가 이동되므로 호스트 볼륨에 권한 문제가있는 것을 알 수 있습니다. 이 시나리오에서는 호스트 볼륨을 피하고 명명 된 볼륨 만 사용하는 것이 가장 쉬운 방법입니다.


32

에서 access.redhat.com:Sharing_Data_Across_Containers :

호스트 볼륨 설정은 호스트에 따라 다르며 다른 시스템에서는 작동하지 않을 수 있으므로 이식성이 없습니다. 이러한 이유로 호스트 디렉토리를 컨테이너에 마운트하는 데 해당하는 Dockerfile이 없습니다. 또한 호스트 시스템에는 컨테이너 SELinux 정책에 대한 지식이 없습니다. 따라서 SELinux 정책이 적용되면 마운트 된 호스트 디렉토리는 rw 설정에 관계없이 컨테이너에 쓸 수 없습니다. 현재 적절한 SELinux 정책 유형을 호스트 디렉토리에 지정하여이 문제를 해결할 수 있습니다. "

chcon -Rt svirt_sandbox_file_t host_dir

여기서 host_dir은 컨테이너에 마운트 된 호스트 시스템의 디렉토리 경로입니다.

해결 방법 일 뿐이지 만 시도했지만 작동합니다.


14

나는 그것을 확인 chcon -Rt svirt_sandbox_file_t /path/to/volume 작동하고 당신은 특권 컨테이너로 실행할 필요가 없음을 .

이것은 켜져 있습니다 :

  • Docker 버전 0.11.1-dev, 빌드 02d20af / 0.11.1
  • SELinux가 활성화 된 호스트 및 컨테이너 인 CentOS 7

2
Docker 내에서 레이블을 다시 지정하는 공식 지원에 대해서는 github.com/docker/docker/pull/5910 을 참조하십시오 .
cpuguy83

13

시도하십시오 docker volume create.

mkdir -p /data1/Downloads
docker volume create --driver local --name hello --opt type=none --opt device=/data1/Downloads --opt o=uid=root,gid=root --opt o=bind
docker run -i -v hello:/Downloads ubuntu bash

https://docs.docker.com/engine/reference/commandline/volume_create/ 문서를 살펴보십시오.


3
SO 에서이 문제에 대한 많은 답변을 시도했지만 실제로이 문제가 도움이되었습니다. 감사!
Paul

그것은 권한의 오류를 해결했습니다. 그러나 지금 내가 물리적 위치를 마운트하려고하면 그것은 voulme을 마운트 ???? @ cupen
kunal verma

1
@kunalverma 예. 마음에 들지 않으면 여기 더 쉬운 대답이 있습니다. stackoverflow.com/a/31334443/4909388
cupen

4

비슷한 문제가 있었는데, 호스트의 UID와 컨테이너 사용자의 UID가 일치하지 않아서 발생했습니다. 수정은 사용자의 UID를 docker 빌드에 대한 인수로 전달하고 동일한 UID로 컨테이너 사용자를 작성하는 것이 었습니다.

DockerFile에서 :

ARG UID=1000
ENV USER="ubuntu"
RUN useradd -u $UID -ms /bin/bash $USER

빌드 단계에서 :

docker build <path/to/Dockerfile> -t <tag/name> --build-arg UID=$UID

그 후 OP에 따라 컨테이너와 명령을 실행하면 예상 결과를 얻었습니다.


1
런타임까지 UID를 모른다면 어떻게해야합니까? (파일 시스템에 다시 쓰는 일부 도구를 패키지하기 위해 동료를위한 이미지를 작성하고 있지만 UID가 다릅니다). 루트로 유지하고 adduser 만 실행할 수 있다고 생각합니까?
inger

불행히도 그것에 대한 좋은 대답이 없습니다. 다른 사람이 해결책을 가지고 있다면 나는 그것에 관심이있을 것입니다. Docker 진입 점 기능이 솔루션을 제공 할 수 있다고 생각합니다.
RoboCop87

0

데이터 컨테이너를 사용하여이 문제를 해결했습니다. 또한 응용 프로그램 계층에서 데이터를 격리 할 수 ​​있다는 이점이 있습니다. 다음과 같이 실행할 수 있습니다.

docker run --volumes-from=<container-data-name> ubuntu

학습서 는 데이터 컨테이너 사용에 대한 좋은 설명을 제공합니다.


-1

제 상황에서는 문제가 달랐습니다. 왜 그런지 모르겠지만 호스트의 디렉토리가 디렉토리에서 chmod 777실행 된 경우에도 도커 내부에서는로 표시됩니다 755.

컨테이너 내부를 실행 sudo chmod 777 my_volume_dir하면 문제가 해결되었습니다.


5
chmod 777거의 아무것도 고치지 않습니다.
Erki Aring

미안하지만 요점을 놓쳤다. 요점은 내부 컨테이너 권한이 낮아져서 외부에서 수정할 수 없다는 것입니다.
CodeSandwich 12

-2

sudo -s MAC에서 나를 위해 트릭을 했어


1
당신이 downvoting하는 경우, 의견을 남기고 이유를 설명하십시오. 나는 똑같은 문제를 겪었고 sudo -s 로이 문제를 해결할 수있었습니다.
Nachiket Joshi

모든 도커 이미지에 sudo가있는 것은 아니며 모든 시나리오에서 가능하지는 않습니다.
SOFe

2
컨테이너에 sudo를 설치하지 마십시오. 공격자는 컨테이너 내부에서 sudo를 사용할 수 있습니다.
Arnold Balliu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.