[docker] Docker 공유 볼륨에 대한 권한을 관리하는 가장 좋은 방법은 무엇입니까?

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/graphiteDockerfile도 같은 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/graphitedataDockerfile에, 또는 대신에 새로운 이미지를 만들어 단지 기존의 하나를 사용 재 (엔트리 포인트 / cmd를 필요에 따라 무시).

이제 다음을 실행하면됩니다.

docker run -ti --rm --volumes-from=graphitedata some/graphitetools

다음 vi /data/graphite/whatever.txt. 이는 모든 컨테이너에 uid / gid가 일치하는 동일한 흑연 사용자가 있으므로 완벽하게 작동합니다.

/data/graphite호스트에서 마운트 하지 않으므로 호스트 uid / gid가 graphiteand 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)의 소유권을 변경하고 스텝 다운 rootredis사용자에서 실행으로 변경합니다 redis-server. (실행 된 명령이 redis-server가 아닌 경우 명령을 직접 실행합니다.)

이것은 다음과 같은 효과가 있습니다

/ data 디렉토리가 호스트에 바인드 마운트 된 경우, docker-entrypoint는 사용자에서 redis-server를 실행하기 전에 사용자 권한을 준비합니다 redis.

이렇게하면 모든 볼륨 구성에서 컨테이너를 실행하기 위해 설정이 0임을 쉽게 알 수 있습니다.

물론 다른 이미지간에 볼륨을 공유 해야하는 경우 동일한 사용자 ID / 그룹 ID를 사용해야합니다. 그렇지 않으면 최신 컨테이너가 이전 이미지의 사용자 권한을 빼앗습니다.


답변

이것은 대부분의 상황에서 가장 좋은 방법은 아니지만 아직 언급되지 않았으므로 아마도 누군가를 도울 것입니다.

  1. 마운트 호스트 볼륨 바인드

    Host folder FOOBAR is mounted in container /volume/FOOBAR

  2. 컨테이너의 시작 스크립트를 수정하여 원하는 볼륨의 GID를 찾으십시오.

    $ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)

  3. 사용자가이 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를 사용하는 컨테이너 내부의 임의의 그룹에 자신을 추가 할 위험이 없다고 가정하기 때문에 이것을 좋아하지 않습니다. USERDockerfile 의 절 과 함께 사용할 수 없습니다 (사용자가 루트 권한을 가지고 있지 않는 한). 또한, 그것은 해킹 작업을 비명;;)

하드 코어가 되려면 여러 방법으로이를 확장 할 수 있습니다. 예를 들어 서브 파일, 여러 볼륨에서 모든 그룹 검색 등


답변

좋아, 이것은 현재 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

업데이트 저는 현재 Hamy 답변에 더 기울입니다.


답변

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; $@"