Odmowa dostępu do dostępu do katalogu hosta w Docker


283

Krótko mówiąc: próbuję zamontować katalog hosta w Dockerze, ale nie mogę uzyskać do niego dostępu z poziomu kontenera, nawet jeśli uprawnienia dostępu wyglądają dobrze.

Szczegóły:

robię

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

i wtedy

ls -al

To daje mi:

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

i wiele innych takich linii (myślę, że to odpowiednia część).

Jeśli zrobię

cd /Downloads
ls

wynik to

ls: cannot open directory .: Permission denied

Hostem jest Fedora 20, z Docker 1.0.0 i go1.2.2.

Co idzie nie tak?

Odpowiedzi:


269

Zobacz ten post na blogu projektu Atomic o Volumes i SELinux, aby uzyskać pełną historię.

Konkretnie:

Ostatnio stało się to łatwiejsze, odkąd Docker w końcu połączył łatkę, która pojawi się w docker-1.7 (Nosiliśmy łatkę w docker-1.6 na RHEL, CentOS i Fedorze).

Ta poprawka dodaje obsługę „z” i „Z” jako opcji montowania woluminów (-v).

Na przykład:

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

Automatycznie wykona czynności chcon -Rt svirt_sandbox_file_t /var/db opisane na stronie man.

Co więcej, możesz użyć Z.

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

Spowoduje to oznaczenie zawartości wewnątrz kontenera dokładną etykietą MCS, z którą kontener będzie działał, w zasadzie działa chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/dbtam, gdzie s0:c1,c2różni się dla każdego kontenera.


18
To działa jak urok. Inne rozwiązania to głównie obejścia.
— tuxdna

4
por. sekcja etykiety woluminów w dokumentacji
— dokera

Och, stary, to naprawdę działa. W końcu to znalazłem. Wielkie dzięki! Czy jest na to oficjalna dokumentacja?
— Kirby

1
Upstream ma go jako ostatni akapit w tej sekcji docs.docker.com/engine/reference/commandline/run/…
— gregswift,

1
Jest możliwe, aby naprawić uprawnienia pod SELinux podczas montażu głośności jako tylko do odczytu w tym samym czasie przy użyciu obu opcji jednocześnie oddzielone przecinkiem: -v $(pwd):/app:ro,Z. To powinno być oznaczone jako poprawna odpowiedź.
— danirod

263

Jest to problem z SELinux .

Możesz tymczasowo wydać

su -c "setenforce 0"

na hoście, aby uzyskać dostęp lub dodać regułę SELinux, uruchamiając

chcon -Rt svirt_sandbox_file_t /path/to/volume

3
jest / path / to / volume ścieżką hosta? Jeśli tak, to nie wydaje się, aby to rozwiązanie działało z kontenerami danych?
— Roy Truelove,

6
nie zapomnij zrobić su -c "setenforce 1" ... inaczej to zadziała tylko dlatego, że SELinux jest nadal dezaktywowany
— vcarel

to rozwiązało mój problem. dziękuję, mam nadzieję, że uda się to naprawić.
— Hokutosei

19
Dodanie reguły selinux jest najlepszym sposobem, ponieważ w większości przypadków uruchamianie kontenerów w trybie uprzywilejowanym nie jest dobrym pomysłem.
— Zoro_77

7
Jak powiedział Zoro_77, dodaj regułę i przestań wyłączaćselinux.com ;)
— GabLeRoux

71

OSTRZEŻENIE: To rozwiązanie wiąże się z zagrożeniami bezpieczeństwa.

Spróbuj uruchomić kontener jako uprzywilejowany:

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

Inną opcją (której nie próbowałem) byłoby utworzenie uprzywilejowanego kontenera, a następnie utworzenie w nim kontenerów nieuprzywilejowanych.


1
@JBernardo Która z dwóch opcji rozwiązała problem?
— user100464

@ user100464--privileged=true
— JBernardo

1
Nie pomagaj w moim przypadku. Debian Whezzy z jądrem w wersji 3.16, ale nie aktywowanej konfiguracji SELinux. :(
— aholbreich,

jeśli używasz Dockera-kompozytora, dodaj „uprzywilejowany: prawda”
— Lionel Morrison

35
Nie rób tego. --privilegedstanowi zagrożenie bezpieczeństwa
— Navin

38

Zazwyczaj problemy z uprawnieniami do montowania woluminu hosta są spowodowane tym, że identyfikator UID / GID w kontenerze nie ma dostępu do pliku zgodnie z uprawnieniami UID / GID pliku na hoście. Jednak ten konkretny przypadek jest inny.

Kropka na końcu ciągu uprawnień drwxr-xr-x.wskazuje, że SELinux jest skonfigurowany. Gdy używasz montowania hosta w SELinux, musisz przekazać dodatkową opcję na końcu definicji woluminu:

  • Ta zopcja wskazuje, że zawartość podłączenia wiązania jest współużytkowana przez wiele kontenerów.
  • Ta Zopcja wskazuje, że treść podłączenia powiązania jest prywatna i nieudostępniona.

Polecenie podłączenia woluminu wyglądałoby wtedy następująco:

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

Więcej informacji o podłączeniach hosta za pomocą SELinuksa można znaleźć na stronie : https://docs.docker.com/storage/#configure-the-selinux-label


W przypadku innych, którzy widzą ten problem z kontenerami działającymi jako inny użytkownik, musisz upewnić się, że identyfikator użytkownika / identyfikator użytkownika w kontenerze ma uprawnienia do pliku na hoście. Na serwerach produkcyjnych jest to często wykonywane przez kontrolowanie identyfikatora UID / GID w procesie kompilacji obrazu, aby dopasować identyfikator UID / GID na hoście, który ma dostęp do plików (lub jeszcze lepiej, nie używaj montowań hosta w produkcji).

Nazwany wolumin jest często preferowany zamiast montowania hosta, ponieważ zainicjuje on katalog woluminów z katalogu obrazów, w tym wszelkie prawa własności i uprawnienia do plików. Dzieje się tak, gdy wolumin jest pusty i kontener jest tworzony z nazwanym woluminem.

Użytkownicy systemu MacOS mają teraz system OSXFS, który automatycznie obsługuje identyfikatory uid / gid między hostem Mac a kontenerami. Jednym z miejsc, w którym nie pomaga, są pliki z wbudowanej maszyny wirtualnej, które są montowane w kontenerze, takie jak /var/lib/docker.sock.

W środowiskach programistycznych, w których identyfikator uid / gid hosta może się zmieniać w zależności od programisty, moim preferowanym rozwiązaniem jest uruchomienie kontenera z punktem wejścia działającym jako root, poprawienie identyfikatora uid / gid użytkownika w kontenerze, aby pasowało do identyfikatora uid / gid woluminu hosta, i następnie użyj, gosuaby upuścić z katalogu głównego do użytkownika kontenera, aby uruchomić aplikację w kontenerze. Ważny skrypt do tego znajduje się fix-permsw moich podstawowych skryptach graficznych, które można znaleźć na stronie : https://github.com/sudo-bmitch/docker-base

Ważnym fragmentem fix-permsskryptu jest:

# 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

To dostaje identyfikator użytkownika w kontenerze i identyfikator pliku, a jeśli się nie zgadzają, wzywa usermoddo dostosowania identyfikatora użytkownika. Na koniec wyszukuje rekursywnie, aby naprawić pliki, które nie zmieniły identyfikatora użytkownika. Podoba mi się to bardziej niż uruchamianie kontenera z -u $(id -u):$(id -g)flagą, ponieważ powyższy kod punktu wejścia nie wymaga od każdego programisty uruchomienia skryptu w celu uruchomienia kontenera, a wszelkie pliki poza woluminem, które są własnością użytkownika, zostaną poprawione.


Można również zlecić dokerowi zainicjowanie katalogu hosta z obrazu przy użyciu nazwanego woluminu, który wykonuje podłączenie wiązania. Ten katalog musi istnieć wcześniej i należy podać bezwzględną ścieżkę do katalogu hosta, w przeciwieństwie do woluminów hosta w pliku tworzenia, które mogą być ścieżkami względnymi. Katalog musi być również pusty, aby doker mógł go zainicjować. Wyglądają trzy różne opcje definiowania nazwanego woluminu dla montowania wiązania:

  # 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
  ...

Na koniec, jeśli spróbujesz użyć przestrzeni nazw użytkownika, okaże się, że woluminy hosta mają problemy z uprawnieniami, ponieważ uid / gid kontenerów są przesunięte. W tym scenariuszu prawdopodobnie najłatwiej jest uniknąć woluminów hosta i używać tylko woluminów nazwanych.


32

Od access.redhat.com:Sharing_Data_Across_Containers :

Ustawienia głośności hosta nie są przenośne, ponieważ są zależne od hosta i mogą nie działać na żadnym innym komputerze. Z tego powodu nie ma odpowiednika Dockerfile do montowania katalogów hosta w kontenerze. Należy również pamiętać, że system hosta nie ma wiedzy o zasadach kontenera SELinux. Dlatego jeśli wymuszone są zasady SELinux, podłączonego katalogu hosta nie można zapisać w kontenerze, niezależnie od ustawienia rw. Obecnie można obejść ten problem, przypisując odpowiedni typ zasad SELinux do katalogu hosta „:

chcon -Rt svirt_sandbox_file_t host_dir

Gdzie katalog_hosta jest ścieżką do katalogu w systemie hosta, który jest podłączony do kontenera.

Wydaje się, że to tylko obejście, ale próbowałem i działa.


14

Sprawdziłem, że chcon -Rt svirt_sandbox_file_t /path/to/volumeto działa i nie musisz działać jako uprzywilejowany kontener.

To jest na:

  • Wersja Docker 0.11.1-dev, kompilacja 02d20af / 0.11.1
  • CentOS 7 jako host i kontener z włączonym SELinux.

2
Zobacz github.com/docker/docker/pull/5910, aby uzyskać oficjalne wsparcie dla ponownego etykietowania w Docker.
— cpuguy83,

13

Spróbować 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

Spójrz na dokument https://docs.docker.com/engine/reference/commandline/volume_create/


3
Próbowałem wiele odpowiedzi na ten temat na SO, ale w rzeczywistości ta pomogła. Dzięki!
— Paul

Rozwiązał błąd uprawnień. Ale teraz, gdy próbuję zamontować fizyczną lokalizację, montuje voulme ???? @ cupen
— kunal verma

1
@kunalverma Tak. Jeśli ci się nie podoba, oto łatwiejsza odpowiedź. stackoverflow.com/a/31334443/4909388
— cupen

4

Miałem podobny problem, mój był spowodowany niedopasowaniem między UID hosta a UID użytkownika kontenera. Rozwiązaniem było przekazanie UID użytkownika jako argumentu do kompilacji dokera i utworzenie użytkownika kontenera z tym samym UID.

W DockerFile:

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

W kroku kompilacji:

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

Następnie uruchomienie kontenera i poleceń zgodnie z OP dało mi oczekiwany wynik.


1
Co zrobić, jeśli nie znasz identyfikatora UID do czasu wykonania? (Buduję obraz dla kolegów, aby spakować niektóre narzędzia, które zapisują z powrotem do swojego systemu plików, ale mają różne UID). Wydaje mi się, że mógłbym utrzymać rootowanie i tylko adduser w biegu?
— inger

Niestety nie mam na to dobrej odpowiedzi. Jeśli ktoś ma jakieś rozwiązanie, zainteresowałbym się nim również. Podejrzewam, że funkcjonalność punktu wejścia Dockera może zapewnić rozwiązanie.
— RoboCop87

0

Rozwiązałem ten problem, używając kontenera danych, ma to również tę zaletę, że izoluję dane od warstwy aplikacji. Możesz uruchomić go w następujący sposób:

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

To samouczek zawiera dobre objaśnienie korzystania z kontenerów danych.


-1

W mojej sytuacji problem był inny. Nie wiem dlaczego, ale nawet jeśli katalog na hoście chmod 777działał na nim, wewnątrz dokera było to widoczne jako755 .

sudo chmod 777 my_volume_dirNaprawiono je w kontenerze .


5
chmod 777prawie nigdy niczego nie naprawia.
— Erki Aring,

Przepraszam, ale nie rozumiesz sedna sprawy. Chodzi o to, że uprawnienia wewnątrz kontenera zostały obniżone i nie można go naprawić z zewnątrz.
— CodeSandwich,

-2

sudo -s zrobił mi lewę na MAC


1
Jeśli przegłosujesz, zostaw komentarz i wyjaśnij dlaczego. Napotkałem dokładnie ten sam problem i udało mi się go rozwiązać przez sudo -s.
— Nachiket Joshi,

Nie każdy obraz dokera ma sudo i nie jest to możliwe w każdym scenariuszu.
— SOFe

2
Nie instaluj sudo na kontenerach. Atakujący może użyć sudo w pojemniku.
— Arnold Balliu
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.