Od jakiegoś czasu bawię się Dockerem i ciągle znajduję ten sam problem, gdy mam do czynienia z trwałymi danymi.
Tworzę mój Dockerfile
i udostępniam wolumin lub używam --volumes-from
do zamontowania folderu hosta w moim kontenerze .
Jakie uprawnienia powinienem zastosować do udostępnionego woluminu na hoście?
Mogę wymyślić dwie opcje:
Do tej pory dałem wszystkim dostęp do odczytu / zapisu, dzięki czemu mogę pisać do folderu z kontenera Docker.
Mapuj użytkowników z hosta do kontenera, aby móc przypisać bardziej szczegółowe uprawnienia. Nie jestem pewien, czy jest to możliwe i nie znalazłem wiele na ten temat. Do tej pory wszystko, co mogę zrobić, to uruchomić kontener jako użytkownik:
docker run -i -t -user="myuser" postgres
ale ten użytkownik ma inny identyfikator UID niż mój hostmyuser
, więc uprawnienia nie działają. Nie jestem również pewien, czy mapowanie użytkowników będzie stanowić pewne zagrożenie bezpieczeństwa.
Czy są inne alternatywy?
Jak radzicie sobie z tym problemem?
Odpowiedzi:
AKTUALIZACJA 2016-03-02 : Od Docker 1.9.0 Docker nazwał woluminy, które zastępują kontenery tylko do danych . Poniższa odpowiedź, podobnie jak mój link do posta na blogu, wciąż ma wartość w sensie myślenia o danych w oknie dokowanym, ale rozważ użycie nazwanych woluminów w celu zaimplementowania wzoru opisanego poniżej zamiast kontenerów danych.
Uważam, że kanonicznym sposobem rozwiązania tego jest użycie kontenerów zawierających tylko dane . Przy takim podejściu cały dostęp do danych woluminu odbywa się za pośrednictwem kontenerów korzystających
-volumes-from
z kontenera danych, więc identyfikator użytkownika / identyfikator hosta nie ma znaczenia.Na przykład jednym z przypadków użycia podanych w dokumentacji jest utworzenie kopii zapasowej woluminu danych. Aby to zrobić, inny kontener służy do tworzenia kopii zapasowej za pośrednictwem
tar
, a także używa go-volumes-from
do zamontowania woluminu. Myślę więc, że kluczową kwestią dla grok jest: zamiast myśleć o tym, jak uzyskać dostęp do danych na hoście z odpowiednimi uprawnieniami, pomyśl o tym, jak zrobić to, czego potrzebujesz - kopie zapasowe, przeglądanie itp. - za pośrednictwem innego kontenera . Same kontenery muszą używać spójnego identyfikatora UID / GID, ale nie muszą mapować niczego na hoście, dzięki czemu pozostają przenośne.Jest to również stosunkowo nowe dla mnie, ale jeśli masz konkretny przypadek użycia, możesz skomentować, a ja postaram się rozwinąć odpowiedź.
AKTUALIZACJA : Dla danego przypadku użycia w komentarzach możesz mieć obraz
some/graphite
do uruchomienia grafitu i obrazsome/graphitedata
jako kontener danych. Ignorując porty i tym podobne,Dockerfile
obrazsome/graphitedata
wygląda tak:Zbuduj i utwórz kontener danych:
Plik
some/graphite
Docker powinien mieć również ten sam identyfikator UID / GID, dlatego może wyglądać mniej więcej tak:I byłby uruchamiany w następujący sposób:
Ok, teraz daje nam to nasz kontener grafitowy i powiązany pojemnik tylko z danymi z odpowiednim użytkownikiem / grupą (pamiętaj, że możesz również użyć
some/graphite
kontenera dla kontenera danych, zastępując entrypoing / cmd podczas jego uruchamiania, ale mając je jako oddzielne obrazy IMO jest wyraźniejsze).Powiedzmy, że chcesz edytować coś w folderze danych. Zamiast montować wolumin na hoście i edytować go tam, utwórz nowy kontener, aby wykonać to zadanie. Nazwijmy to
some/graphitetools
. Utwórzmy także odpowiedniego użytkownika / grupę, podobnie jaksome/graphite
obraz.Możesz zrobić ten OSUSZANIE, dziedzicząc z
some/graphite
lubsome/graphitedata
w Dockerfile, lub zamiast tworzyć nowy obraz, po prostu ponownie użyj jednego z istniejących (w razie potrzeby zastępując punkt wejścia / cmd).Teraz wystarczy uruchomić:
i potem
vi /data/graphite/whatever.txt
. Działa to doskonale, ponieważ wszystkie pojemniki mają tego samego użytkownika grafitowego z pasującym identyfikatorem uid / gid.Ponieważ nigdy nie montujesz
/data/graphite
z hosta, nie obchodzi cię, w jaki sposób identyfikator uid / gid hosta mapuje się na identyfikator uid / gid zdefiniowany w kontenerachgraphite
igraphitetools
. Kontenery te można teraz wdrożyć na dowolnym hoście i nadal będą działać idealnie.Ciekawą rzeczą jest to, że
graphitetools
może mieć wiele przydatnych narzędzi i skryptów, które można teraz wdrażać w przenośny sposób.AKTUALIZACJA 2 : Po napisaniu tej odpowiedzi postanowiłem napisać pełniejszy post na blogu o tym podejściu. Mam nadzieję, że to pomoże.
AKTUALIZACJA 3 : Poprawiłem tę odpowiedź i dodałem więcej szczegółów. Poprzednio zawierał on niepoprawne założenia dotyczące własności i perms - własność jest zwykle przypisywana w czasie tworzenia woluminu, tj. W kontenerze danych, ponieważ wtedy powstaje wolumin. Zobacz tego bloga . Nie jest to jednak wymagane - możesz po prostu użyć kontenera danych jako „referencji / uchwytu” i ustawić własność / perms w innym kontenerze poprzez chown w punkcie wejścia, który kończy się na gosu, aby uruchomić polecenie jako poprawny użytkownik. Jeśli ktoś jest zainteresowany tym podejściem, proszę o komentarz, a ja mogę podać linki do próbki przy użyciu tego podejścia.
źródło
/data/newcontainer
? Zakładam, że działaszdocker
jako root (czy to możliwe, aby tego nie robić?) Czy istnieje jakakolwiek różnica w tych uprawnieniach, jeśli dane są montowane bezpośrednio w głównym kontenerze lub za pośrednictwem kontenera zawierającego tylko dane ?/var/lib/docker
gdzieś będą, ale wciąż ogromny bólBardzo eleganckie rozwiązanie można zobaczyć na oficjalnym obrazie redis i ogólnie na wszystkich oficjalnych obrazach.
Opisane w procesie krok po kroku:
Jak widać na komentarzach Dockerfile:
gosu jest alternatywą
su
/sudo
dla łatwego opuszczania konta przez użytkownika root. (Redis jest zawsze uruchamiany zredis
użytkownikiem)/data
wolumin i ustaw go jako katalog roboczyPo skonfigurowaniu woluminu / data za pomocą
VOLUME /data
polecenia mamy teraz osobny wolumin, który może być woluminem dokującym lub montowanym na powiązaniu z katalogiem hosta.Skonfigurowanie go jako workdir (
WORKDIR /data
) powoduje, że jest to domyślny katalog, z którego wykonywane są polecenia.Oznacza to, że wszystkie wykonania kontenera będą uruchamiane przez skrypt dokera-punktu wejścia, a domyślnie polecenie do uruchomienia to serwer redis.
docker-entrypoint
Jest to skrypt, który ma prostą funkcję: Zmiana własności bieżącego katalogu (/ data) i step-down zroot
abyredis
użytkownik mógł uruchomićredis-server
. (Jeśli wykonane polecenie nie jest serwerem redis, uruchomi je bezpośrednio.)Ma to następujący efekt
Jeśli katalog / data zostanie podłączony do hosta, punkt wejścia dokera przygotuje uprawnienia użytkownika przed uruchomieniem serwera redis w ramach
redis
użytkownika.Zapewnia to spokój ducha, że konfiguracja zerowa umożliwia uruchomienie kontenera w dowolnej konfiguracji woluminu.
Oczywiście, jeśli chcesz udostępnić głośność między różnymi obrazami, musisz upewnić się, że używają tego samego identyfikatora użytkownika / groupid, w przeciwnym razie najnowszy kontener przejmie uprawnienia użytkownika z poprzedniego.
źródło
chown
to wENTRYPOINT
skrypcie?Prawdopodobnie nie jest to najlepszy sposób w większości przypadków, ale nie został jeszcze wspomniany, więc być może pomoże komuś.
Bindowanie woluminu hosta
Host folder FOOBAR is mounted in container /volume/FOOBAR
Zmodyfikuj skrypt startowy kontenera, aby znaleźć GID woluminu, który Cię interesuje
$ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)
Upewnij się, że użytkownik należy do grupy o tym identyfikatorze GID (może być konieczne utworzenie nowej grupy). W tym przykładzie będę udawać, że moje oprogramowanie działa jako
nobody
użytkownik w kontenerze, więc chcę się upewnić, żenobody
należy do grupy o identyfikatorze grupy równymTARGET_GID
Podoba mi się to, ponieważ mogę łatwo modyfikować uprawnienia grupowe na woluminach hosta i wiem, że te zaktualizowane uprawnienia obowiązują w kontenerze dokera. Dzieje się tak bez żadnych pozwoleń lub modyfikacji własności moich folderów / plików hosta, co mnie cieszy.
Nie podoba mi się to, ponieważ zakłada, że nie ma niebezpieczeństwa w dodawaniu się do dowolnych grup w kontenerze, które akurat używają żądanego GID. Nie można go używać z
USER
klauzulą w pliku Docker (chyba że ten użytkownik ma uprawnienia roota, jak sądzę). Poza tym krzyczy hackowanie ;-)Jeśli chcesz być hardkorowy, możesz oczywiście rozszerzyć to na wiele sposobów - np. Wyszukaj wszystkie grupy w dowolnych podplikach, wielu woluminach itp.
źródło
$TARGET_GID
byłoby użyciegrep ':$TARGET_GID:'
, w przeciwnym razie, jeśli kontener ma np. Gid 10001, a twój host ma 1000, to sprawdzenie przejdzie, ale nie powinno.Ok, teraz jest to śledzone w numerze dokera 7198
Na razie mam do czynienia z tą drugą opcją:
Plik Docker
CLI
AKTUALIZACJA Obecnie jestem bardziej skłonny do odpowiedzi Hamy'ego
źródło
id -u <username>
,id -g <username>
,id -G <username>
aby uzyskać identyfikator użytkownika i identyfikator grupy użytkownika określonego zamiastSpróbuj dodać polecenie do Dockerfile
kredyty trafiają na https://github.com/denderello/symfony-docker-example/issues/2#issuecomment-94387272
źródło
Tak samo jak Ty, szukałem sposobu mapowania użytkowników / grup z hosta na kontenery dokujące i jest to najkrótszy sposób, jaki do tej pory znalazłem:
To jest wyciąg z mojego docker-compose.yml.
Chodzi o to, aby montować (w trybie tylko do odczytu) listy użytkowników / grup z hosta do kontenera, więc po uruchomieniu kontenera będzie on miał takie same parametry uid-> nazwa użytkownika (jak również dla grup) z hostem. Teraz możesz skonfigurować ustawienia użytkownika / grupy dla usługi w kontenerze, tak jakby działała w systemie hosta.
Gdy zdecydujesz się przenieść kontener na inny host, wystarczy zmienić nazwę użytkownika w pliku konfiguracyjnym usługi na to, co masz na tym hoście.
źródło
-u $( id -u $USER ):$( id -g $USER )
i nie musisz się już martwić o nazwę użytkownika. Działa to dobrze w lokalnych środowiskach programistycznych, w których chcesz generować pliki (na przykład pliki binarne), do których domyślnie masz dostęp do odczytu / zapisu.Oto podejście, które nadal korzysta z kontenera tylko danych, ale nie wymaga jego synchronizacji z kontenerem aplikacji (pod względem posiadania tego samego identyfikatora UID / GID).
Przypuszczalnie chcesz uruchomić jakąś aplikację w kontenerze jako użytkownik inny niż root $ USER bez powłoki logowania.
W Dockerfile:
Następnie w entrypoint.sh:
źródło
Aby zabezpieczyć i zmienić root dla kontenera dokowanego, host dokera spróbuj użyć
--uidmap
i--private-uids
opcjihttps://github.com/docker/docker/pull/4572#issuecomment-38400893
Możesz również usunąć kilka możliwości (
--cap-drop
) w kontenerze dokera dla bezpieczeństwahttp://opensource.com/business/14/9/security-for-docker
Wsparcie UPDATE powinno wejść
docker > 1.7.0
AKTUALIZACJA Wersja
1.10.0
(2016-02-04) dodaj--userns-remap
flagę https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2źródło
--uidmap
ani--private-uids
opcji. Wygląda na to, że PR nie udało się i nie został scalony."We apparently do have so some of conflicting designs between libnetwork and user namespaces ... and something we'd like to get in for 1.8.0. So don't think we're dropping this, we're definitely going to take a break after all these, and see how we need to reconsider the current design and integration of libnetwork to make this possible. Thanks!"
github.com/docker/docker/pull/12648 Więc myślę, że powinniśmy poczekać na następną stabilną wersję.Moje podejście polega na wykryciu bieżącego identyfikatora UID / GID, a następnie utworzenie takiego użytkownika / grupy w kontenerze i wykonanie skryptu pod nim. W rezultacie wszystkie pliki, które utworzy, będą pasować do użytkownika na hoście (którym jest skrypt):
źródło
Obraz podstawowy
Użyj tego obrazu: https://hub.docker.com/r/reduardo7/docker-host-user
lub
Ważne: niszczy to przenośność kontenerów między hostami .
1)
init.sh
2)
Dockerfile
3) run.sh
4) Buduj z
docker
4) Uruchom!
źródło
W moim konkretnym przypadku próbowałem zbudować pakiet węzła z obrazem dokera węzła, aby nie musiałem instalować npm na serwerze wdrażania. Działało dobrze, dopóki poza kontenerem i na maszynie hosta nie próbowałem przenieść pliku do katalogu node_modules, który utworzył obraz dokera węzła, do którego odmówiono mi uprawnień, ponieważ był własnością root. Zdałem sobie sprawę, że mogę to obejść, kopiując katalog z kontenera na maszynę hosta. Za pomocą dokerów ...
To jest kod bashowy, którego użyłem do zmiany własności katalogu utworzonego przez i wewnątrz kontenera dokowanego.
W razie potrzeby możesz usunąć katalog za pomocą drugiego kontenera dokera.
źródło
Aby udostępnić folder między hostem dokera a kontenerem dokowania, spróbuj wykonać poniższe polecenie
Flaga -v montuje bieżący katalog roboczy w kontenerze. Gdy katalog hosta woluminu podłączonego nie istnieje, Docker automatycznie utworzy ten katalog na hoście,
Mamy jednak 2 problemy:
Rozwiązanie:
Kontener: utwórz użytkownika o nazwie „testser”, domyślnie identyfikator użytkownika zaczyna się od 1000,
Host: utwórz grupę, powiedz „grupa testowa” o identyfikatorze grupy 1000, i prześlij katalog do nowej grupy (grupa testowa
źródło
Jeśli używasz Docker Compose, uruchom kontener w trybie uprzywilejowanym:
źródło