Docker와 잠시 동안 놀고 있었고 지속적인 데이터를 다룰 때 동일한 문제를 계속 발견했습니다.
내를 생성 Dockerfile
하고 볼륨을 노출 하거나 사용 --volumes-from
하는 내 컨테이너 내부에 호스트 폴더를 마운트 .
호스트의 공유 볼륨에 어떤 권한을 적용해야합니까?
두 가지 옵션을 생각할 수 있습니다.
-
지금까지 모든 사람에게 읽기 / 쓰기 액세스 권한을 부여 했으므로 Docker 컨테이너에서 폴더에 쓸 수 있습니다.
-
호스트의 사용자를 컨테이너에 매핑하여 더 세부적인 권한을 할당 할 수 있습니다. 이것이 가능하지는 않지만 확실하지 않습니다. 지금까지 내가 할 수있는 일은 컨테이너를 일부 사용자로 실행하는 것입니다.
docker run -i -t -user="myuser" postgres
,하지만이 사용자는 내 호스트myuser
와 다른 UID를 가지고 있으므로 권한이 작동하지 않습니다. 또한 사용자 매핑에 보안 위험이 있는지 확실하지 않습니다.
다른 대안이 있습니까?
이 문제를 어떻게 다루고 있습니까?
답변
업데이트 2016-03-02 : Docker 1.9.0부터 Docker는 데이터 전용 컨테이너 를 대체하는 볼륨의 이름을 지정했습니다 . 아래의 답변과 링크 된 블로그 게시물은 여전히 docker 내부의 데이터에 대해 생각하는 방법 에서 가치가 있지만 명명 된 볼륨을 사용하여 데이터 컨테이너가 아닌 아래에 설명 된 패턴을 구현하는 것을 고려하십시오.
이 문제를 해결하는 정식 방법은 데이터 전용 컨테이너를 사용하는 것 입니다. 이 방법을 사용하면 볼륨 데이터에 대한 모든 액세스는 데이터 컨테이너를 사용 -volumes-from
하는 컨테이너를 통해 이루어 지므로 호스트 uid / gid는 중요하지 않습니다.
예를 들어, 설명서에 제공된 사용 사례 중 하나는 데이터 볼륨을 백업하는 것입니다. 이를 위해 다른 컨테이너가를 통해 백업을 수행하는 데 사용되고 볼륨을 마운트하기 위해 tar
사용 -volumes-from
됩니다. 따라서 grok의 핵심 포인트는 적절한 권한으로 호스트의 데이터에 액세스하는 방법을 생각하는 대신 다른 컨테이너를 통해 필요한 모든 것을 수행하는 방법 (백업, 탐색 등)에 대해 생각하는 것입니다. . 컨테이너 자체는 일관된 uid / gid를 사용해야하지만 호스트의 어떤 것에도 매핑 할 필요가 없으므로 이식성이 유지됩니다.
이것은 나에게도 비교적 새로운 것이지만 특정 유스 케이스가 있으면 자유롭게 의견을 말하고 답변을 확장하려고 노력할 것입니다.
업데이트 : 주석에서 주어진 유스 케이스에 대해 some/graphite
흑연을 실행하기위한 이미지 some/graphitedata
와 데이터 컨테이너로 이미지 가있을 수 있습니다. 따라서 포트 등을 무시하면 Dockerfile
이미지 some/graphitedata
는 다음과 같습니다.
FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
&& useradd -r -g graphite graphite
RUN mkdir -p /data/graphite \
&& chown -R graphite:graphite /data/graphite
VOLUME /data/graphite
USER graphite
CMD ["echo", "Data container for graphite"]
데이터 컨테이너를 빌드하고 작성하십시오.
docker build -t some/graphitedata Dockerfile
docker run --name graphitedata some/graphitedata
some/graphite
Dockerfile도 같은 UID / GID를 얻을한다, 따라서는 다음과 같이 보일 수 있습니다 :
FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
&& useradd -r -g graphite graphite
# ... graphite installation ...
VOLUME /data/graphite
USER graphite
CMD ["/bin/graphite"]
그리고 그것은 다음과 같이 실행될 것입니다 :
docker run --volumes-from=graphitedata some/graphite
이제 흑연 컨테이너 및 관련 데이터 전용 컨테이너에 올바른 사용자 / 그룹이 제공됩니다 ( some/graphite
데이터 컨테이너 의 컨테이너를 재사용 하여 엔트리 포지션 / cmd를 실행할 때 재정의하지만 별도의 이미지 IMO가 더 선명합니다).
이제 데이터 폴더에서 무언가를 편집하고 싶다고합시다. 따라서 볼륨을 호스트에 마운트하여 호스트에서 편집하는 대신 해당 작업을 수행 할 새 컨테이너를 만듭니다. 그것을 호출 할 수 some/graphitetools
있습니다. some/graphite
이미지 와 같이 적절한 사용자 / 그룹을 만들 수도 있습니다 .
FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
&& useradd -r -g graphite graphite
VOLUME /data/graphite
USER graphite
CMD ["/bin/bash"]
당신은 상속하여 DRY를 만들 수 some/graphite
또는 some/graphitedata
Dockerfile에, 또는 대신에 새로운 이미지를 만들어 단지 기존의 하나를 사용 재 (엔트리 포인트 / cmd를 필요에 따라 무시).
이제 다음을 실행하면됩니다.
docker run -ti --rm --volumes-from=graphitedata some/graphitetools
다음 vi /data/graphite/whatever.txt
. 이는 모든 컨테이너에 uid / gid가 일치하는 동일한 흑연 사용자가 있으므로 완벽하게 작동합니다.
/data/graphite
호스트에서 마운트 하지 않으므로 호스트 uid / gid가 graphite
and graphitetools
컨테이너 내부에 정의 된 uid / gid에 어떻게 매핑되는지는 신경 쓰지 않습니다 . 이러한 컨테이너는 이제 모든 호스트에 배포 할 수 있으며 계속 완벽하게 작동합니다.
이것에 대한 좋은 점 graphitetools
은 모든 종류의 유용한 유틸리티와 스크립트를 가질 수 있다는 것입니다. 이제 이식 가능한 방식으로 배포 할 수 있습니다.
업데이트 2 :이 답변을 작성한 후이 접근법에 대한 보다 완벽한 블로그 게시물 을 작성하기로 결정했습니다 . 도움이 되길 바랍니다.
업데이트 3 :이 답변을 수정하고 더 구체적인 내용을 추가했습니다. 이전에는 소유권과 파마에 대한 잘못된 가정이 일부있었습니다. 소유권은 일반적으로 볼륨이 생성 될 때이므로 볼륨이 생성 될 때 즉 데이터 컨테이너에 할당됩니다. 이 블로그를 참조하십시오 . 이것은 필수 사항은 아닙니다. 데이터 컨테이너를 “참조 / 핸들”로 사용하고 진입 점에서 chown을 통해 다른 컨테이너의 소유권 / 펌을 설정하면 gosu로 끝나고 올바른 사용자로 명령을 실행할 수 있습니다. 이 방법에 관심이있는 사람은 의견을 말하고이 방법을 사용하여 샘플에 대한 링크를 제공 할 수 있습니다.
답변
매우 우아한 솔루션은 공식 redis 이미지 와 일반적으로 모든 공식 이미지에서 볼 수 있습니다 .
단계별 프로세스에 설명되어 있습니다.
- 다른 것보다 먼저 redis 사용자 / 그룹 만들기
Dockerfile 주석에서 볼 수 있듯이
사용자 및 그룹을 먼저 추가하여 추가 된 종속성에 관계없이 ID가 일관되게 할당되도록합니다.
- 설치를 고수 Dockerfile로
gosu는 루트 사용자로부터 쉽게 스텝 다운하기위한 su
/ 의 대안입니다 sudo
. (Redis는 항상 redis
사용자 와 함께 실행됩니다 )
/data
볼륨을 구성 하고 workdir로 설정
VOLUME /data
명령 을 사용하여 / data 볼륨을 구성하면 이제 도커 볼륨이거나 호스트 디렉토리에 바인드 마운트 될 수있는 별도의 볼륨이 있습니다.
workdir ( WORKDIR /data
) 로 구성하면 명령이 실행되는 기본 디렉토리가됩니다.
- docker-entrypoint 파일을 추가하고 기본 CMD redis-server를 사용하여 ENTRYPOINT로 설정하십시오.
이는 모든 컨테이너 실행이 docker-entrypoint 스크립트를 통해 실행되며 기본적으로 실행될 명령은 redis-server입니다.
docker-entrypoint
간단한 기능을 수행하는 스크립트입니다. 현재 디렉토리 (/ data)의 소유권을 변경하고 스텝 다운 root
을 redis
사용자에서 실행으로 변경합니다 redis-server
. (실행 된 명령이 redis-server가 아닌 경우 명령을 직접 실행합니다.)
이것은 다음과 같은 효과가 있습니다
/ data 디렉토리가 호스트에 바인드 마운트 된 경우, docker-entrypoint는 사용자에서 redis-server를 실행하기 전에 사용자 권한을 준비합니다 redis
.
이렇게하면 모든 볼륨 구성에서 컨테이너를 실행하기 위해 설정이 0임을 쉽게 알 수 있습니다.
물론 다른 이미지간에 볼륨을 공유 해야하는 경우 동일한 사용자 ID / 그룹 ID를 사용해야합니다. 그렇지 않으면 최신 컨테이너가 이전 이미지의 사용자 권한을 빼앗습니다.
답변
이것은 대부분의 상황에서 가장 좋은 방법은 아니지만 아직 언급되지 않았으므로 아마도 누군가를 도울 것입니다.
-
마운트 호스트 볼륨 바인드
Host folder FOOBAR is mounted in container /volume/FOOBAR
-
컨테이너의 시작 스크립트를 수정하여 원하는 볼륨의 GID를 찾으십시오.
$ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)
-
사용자가이 GID를 가진 그룹에 속해 있는지 확인하십시오 (새 그룹을 만들어야 할 수도 있습니다). 이 예제
nobody
에서는 컨테이너 내부에서 소프트웨어가 사용자 로 실행되는 것처럼 가장nobody
하여 그룹 ID가 같은 그룹에 속 하는지 확인하고 싶습니다.TARGET_GID
EXISTS=$(cat /etc/group | grep $TARGET_GID | wc -l)
# Create new group using target GID and add nobody user
if [ $EXISTS == "0" ]; then
groupadd -g $TARGET_GID tempgroup
usermod -a -G tempgroup nobody
else
# GID exists, find group name and add
GROUP=$(getent group $TARGET_GID | cut -d: -f1)
usermod -a -G $GROUP nobody
fi
호스트 볼륨에 대한 그룹 권한을 쉽게 수정할 수 있고 업데이트 된 권한이 도커 컨테이너 내부에 적용된다는 것을 알고 있기 때문에 이것을 좋아합니다. 이것은 호스트 폴더 / 파일에 대한 권한이나 소유권 수정없이 발생하므로 행복합니다.
원하는 GID를 사용하는 컨테이너 내부의 임의의 그룹에 자신을 추가 할 위험이 없다고 가정하기 때문에 이것을 좋아하지 않습니다. USER
Dockerfile 의 절 과 함께 사용할 수 없습니다 (사용자가 루트 권한을 가지고 있지 않는 한). 또한, 그것은 해킹 작업을 비명;;)
하드 코어가 되려면 여러 방법으로이를 확장 할 수 있습니다. 예를 들어 서브 파일, 여러 볼륨에서 모든 그룹 검색 등
답변
좋아, 이것은 현재 docker issue # 7198에서 추적되고있다.
지금은 두 번째 옵션을 사용 하여이 문제를 처리하고 있습니다.
호스트에서 컨테이너로 사용자를 맵핑하십시오.
도커 파일
#=======
# Users
#=======
# TODO: Idk how to fix hardcoding uid & gid, specifics to docker host machine
RUN (adduser --system --uid=1000 --gid=1000 \
--home /home/myguestuser --shell /bin/bash myguestuser)
CLI
# DIR_HOST and DIR_GUEST belongs to uid:gid 1000:1000
docker run -d -v ${DIR_HOST}:${DIR_GUEST} elgalu/myservice:latest
답변
Dockerfile에 명령을 추가하십시오
RUN usermod -u 1000 www-data
크레딧은 https://github.com/denderello/symfony-docker-example/issues/2#issuecomment-94387272 로 이동합니다
답변
당신과 마찬가지로, 나는 사용자 / 그룹을 호스트에서 도커 컨테이너로 매핑하는 방법을 찾고 있었고 이것이 지금까지 찾은 가장 짧은 방법입니다.
version: "3"
services:
my-service:
.....
volumes:
# take uid/gid lists from host
- /etc/passwd:/etc/passwd:ro
- /etc/group:/etc/group:ro
# mount config folder
- path-to-my-configs/my-service:/etc/my-service:ro
.....
이것은 내 docker-compose.yml에서 추출한 것입니다.
아이디어는 (읽기 전용 모드에서) 사용자 / 그룹 목록을 호스트에서 컨테이너로 마운트하는 것이므로 컨테이너가 시작된 후 호스트와 동일한 uid-> 사용자 이름 (및 그룹의 경우)과 일치합니다. 이제 컨테이너 내부에서 서비스가 호스트 시스템에서 작동하는 것처럼 서비스의 사용자 / 그룹 설정을 구성 할 수 있습니다.
컨테이너를 다른 호스트로 옮길 때는 서비스 구성 파일의 사용자 이름을 해당 호스트에있는 이름으로 변경하면됩니다.
답변
다음은 여전히 데이터 전용 컨테이너를 사용하지만 응용 프로그램 컨테이너와 동기화 할 필요가없는 접근법입니다 (같은 uid / gid를 갖는 관점에서).
아마도 로그인 쉘없이 루트가 아닌 $ USER로 컨테이너의 일부 앱을 실행하려고 할 것입니다.
Dockerfile에서 :
RUN useradd -s /bin/false myuser
# Set environment variables
ENV VOLUME_ROOT /data
ENV USER myuser
...
ENTRYPOINT ["./entrypoint.sh"]
그런 다음 entrypoint.sh에서
chown -R $USER:$USER $VOLUME_ROOT
su -s /bin/bash - $USER -c "cd $repo/build; $@"