it-source

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

criticalcode 2023. 9. 18. 21:31
반응형

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

저는 한동안 도커를 가지고 놀다가 지속적인 데이터를 처리할 때 계속 같은 문제를 발견합니다.

나는 내 것을 만듭니다.Dockerfile볼륨 또는 용도를 노출합니다.--volumes-from컨테이너 안에 호스트 폴더를 탑재할 수 있습니다.

호스트의 공유 볼륨에 적용할 권한은 무엇입니까?

다음 두 가지 옵션을 생각할 수 있습니다.

  • 지금까지는 도커 컨테이너에서 폴더에 쓸 수 있도록 모든 사용자에게 읽기/쓰기 권한을 부여했습니다.

  • 호스트의 사용자를 컨테이너에 매핑하여 보다 세분화된 권한을 할당할 수 있습니다.하지만 이것이 가능한지 확실하지 않고 그것에 대해 많이 찾지 못했습니다.지금까지 제가 할 수 있는 일은 컨테이너를 일부 사용자로 실행하는 것입니다.docker run -i -t -user="myuser" postgres, 하지만 이 사용자는 내 호스트와는 다른 UID를 가지고 있습니다.myuser이 작동하지 , 이 하지 하지 이 .또한 사용자를 매핑하는 것이 보안 위험을 초래할지 확신할 수 없습니다.

다른 대안이 있습니까?

이 문제에 대해 어떻게 대처하고 있습니까?

업데이트 2016-03-02: 도커 1.9.0 현재 도커는 데이터 전용 컨테이너를 대체하는 볼륨 이름을 지정했습니다.아래의 답변과 저의 링크된 블로그 게시물은 도커 내부의 데이터에 대해 어떻게 생각할 것인가라는 의미에서 여전히 가치가 있지만, 데이터 컨테이너보다는 아래에 설명된 패턴을 구현하기 위해 명명된 볼륨을 사용하는 것을 고려합니다.


이를 해결하기 위한 표준적인 방법은 데이터 전용 컨테이너를 사용하는 것이라고 생각합니다.이 방법을 사용하면 볼륨 데이터에 대한 모든 액세스가 다음을 사용하는 컨테이너를 통해 이루어집니다.-volumes-from호스트 id/hostuid가 중요하지 않도록 데이터 컨테이너.

예를 들어, 설명서에 나와 있는 사용 사례 중 하나는 데이터 볼륨 백업입니다.이 작업을 수행하려면 다른 컨테이너를 사용하여 다음을 통해 백업을 수행합니다.tar, 그리고 그것도 사용합니다.-volumes-from ∙ ∙ 은: 가지고 하는 것보다 를 통해 하는 입니다.그래서 제가 생각하기에 중요한 점은 적절한 권한을 가지고 호스트의 데이터에 액세스하는 방법을 생각하는 것보다 다른 컨테이너를 통해 백업, 브라우징 등 필요한 모든 작업을 수행하는 방법을 생각하는 것입니다.컨테이너 자체는 일관된 uid/gid를 사용해야 하지만 호스트의 어떤 것에도 매핑할 필요가 없으므로 휴대용으로 유지됩니다.

이것은 저에게도 비교적 새로운 일이지만, 특별한 사용 사례가 있으시면 자유롭게 의견을 주시면 답변을 확대해 보겠습니다.

업데이트: 댓글에 주어진 사용 사례에 대해 이미지가 있을 수 있습니다.some/graphite를다와다e를no와n,desome/graphitedata데이터 컨테이너로서.그래서 항만이나 그런 것들을 무시하고,Dockerfilesome/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도커 파일도 동일한 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/graphiteslimage

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"]

을 은 을 로 some/graphite아니면some/graphitedata도커 파일에서 또는 새 이미지를 생성하는 대신 기존 이미지 중 하나를 다시 사용합니다(필요에 따라 엔트리 포인트/cmd 무시).

이제, 당신은 그냥 다음을 실행합니다.

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

그리고 나서.vi /data/graphite/whatever.txt은 모든 하는 uid한 흑연 합니다. 이것은 모든 용기에 일치하는 uid/gid를 가진 동일한 흑연 사용자가 있기 때문에 완벽하게 작동합니다.

네가 절대로 말을 타지 않으니깐/data/graphiteuid/트에된게가d에지지dd/t된ue에meoeewte다uun,etds서utu게트graphite그리고.graphitetools 이러한 를 모든할 수 , 하게 작동할입니다.이제 이러한 컨테이너를 모든 호스트에 배포할 수 있으며 계속해서 완벽하게 작동할 것입니다.

이것의 멋진 점은graphitetools모든 종류의 유용한 유틸리티와 스크립트를 가질 수 있으며, 이제는 휴대용으로 배포할 수도 있습니다.

업데이트 2: 이 답변을 작성한 후, 저는 이 접근 방식에 대해 좀 더 완벽한 블로그 게시물을 작성하기로 결정했습니다.도움이 되었으면 좋겠습니다.

업데이트 3: 이 답변을 수정하고 자세한 내용을 추가했습니다.이전에는 소유권과 퍼머스에 대한 몇 가지 잘못된 가정이 포함되어 있었습니다. 일반적으로 데이터 컨테이너에서 볼륨을 생성할 때 소유권이 할당되기 때문입니다. 블로그를 봅니다.데이터 컨테이너를 "참조/핸들"로 사용하고 엔트리 포인트에서 chown을 통해 다른 컨테이너의 소유권/펌을 설정할 수 있습니다. 그러면 명령을 올바른 사용자로 실행하기 위해 gosu로 끝납니다.이 접근법에 관심 있는 사람이 있다면 의견을 주시면 이 접근법을 사용하여 샘플에 대한 링크를 제공해 드리겠습니다.

매우 우아한 솔루션은 공식 레디스 이미지와 일반적으로 모든 공식 이미지에서 볼 수 있습니다.

단계별 프로세스로 설명:

  • 무엇보다도 redis 사용자/그룹을 만듭니다.

도커 파일 주석에서 볼 수 있듯이:

사용자와 그룹을 먼저 추가하여 종속성에 관계없이 ID가 일관되게 할당되도록 합니다.

  • 도커 파일로 고수 설치

는 입니다의 입니다.su/sudo사용자로부터 할 수 있도록 (트터날수록다다께과상게는다(d께hr과상srn )로 실행됩니다.redis사용자)

  • 하다 구성/data을 합니다.

을 /data 을 로 하여 하여 로 VOLUME /data명령어는 이제 도커 볼륨을 갖거나 호스트 디어에 바인딩 마운트할 수 있는 별도의 볼륨을 갖게 되었습니다.

하기 (workdir()WORKDIR /data)에서에서 명령이 실행되는 기본 디렉토리가 됩니다.

  • 도커-엔트리포인트 파일을 추가하고 기본 CMD redis-server로 ENTERYPOINT로 설정

즉, 모든 컨테이너 실행은 도커-엔트리포인트 스크립트를 통해 실행되며, 기본적으로 실행될 명령은 redis-server입니다.

docker-entrypoint입니다.현재 디렉터리(/데이터) 소유권 변경 및 다음에서 아래로 이동rootredisredis-server를 직접 (실행된 명령어가 redis-server가 아닌 경우 명령어를 직접 실행합니다.)

이는 다음과 같은 효과가 있습니다.

는 /data 가 는 에서 에 합니다 를 을 하기 를 합니다 을 redis사용자.

이렇게 하면 볼륨 구성에서 컨테이너를 실행할 수 있는 제로 설정이 가능하다는 점에서 안심할 수 있습니다.

물론 서로 다른 이미지 간에 볼륨을 공유해야 하는 경우에는 동일한 userid/groupid를 사용하는지 확인해야 합니다. 그렇지 않으면 최신 컨테이너가 이전 컨테이너에서 사용 권한을 가로채게 됩니다.

이것은 거의 틀림없이 대부분의 상황에서 최선의 방법은 아니지만, 아직 언급되지 않았기 때문에 아마도 누군가에게 도움이 될 것입니다.

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

    Host folder FOOBAR is mounted in container /volume/FOOBAR

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

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

  3. 사용자가 이 GID를 가진 그룹에 속해 있는지 확인합니다(새 그룹을 만들어야 할 수도 있음).이는가이는럼다과다eysr는는d이sl이가i'ee과synobody안에 때, 는 user를 확인하고 싶습니다.nobody룹 ID과은에다가o 같은 그룹에 .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를 사용하고 있는 컨테이너 안의 임의의 그룹에 당신 자신을 추가하는 위험이 없다고 가정하기 때문에 이것을 좋아하지 않습니다.께할수다와a에는 할 수 .USER도커 파일의 절(해당 사용자가 루트 권한을 가지고 있지 않은 경우). job 고는 hack job ;-)

하드코어가 되고 싶다면 서브파일, 여러 볼륨 등에서 모든 그룹을 검색하는 등 다양한 방법으로 확장할 수 있습니다.

저도 당신과 마찬가지로 호스트에서 도커 컨테이너로 사용자/그룹을 매핑하는 방법을 찾고 있었습니다. 지금까지 찾은 방법 중 가장 짧은 방법입니다.

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

이것은 내 도커 컴포지트의 추출물입니다.

이 아이디어는 (읽기 전용 모드에서) 사용자/그룹 목록을 호스트에서 컨테이너로 마운트하는 것입니다. 따라서 컨테이너가 시작된 후에는 호스트와 동일한 uid->사용자 이름(및 그룹의 경우)이 일치하게 됩니다.이제 서비스가 호스트 시스템에서 작동하는 것처럼 컨테이너 내부에서 서비스에 대한 사용자/그룹 설정을 구성할 수 있습니다.

컨테이너를 다른 호스트로 이동하기로 결정한 경우 서비스 구성 파일의 사용자 이름을 해당 호스트에 있는 사용자 이름으로 변경하기만 하면 됩니다.

도커 파일에 명령을 추가합니다.

RUN usermod -u 1000 www-data

크레딧은 https://github.com/denderello/symfony-docker-example/issues/2#issuecomment-94387272 로 전송됩니다.

지금 도커호 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의 답변에 더 치우쳐 있습니다.

제 접근 방식은 현재 UID/GID를 탐지한 다음 컨테이너 내부에 이러한 사용자/그룹을 만들고 그 아래에서 스크립트를 실행하는 것입니다.결과적으로 호스트에서 사용자와 일치하는 파일을 모두 생성합니다.

# get the location of this script no matter what your current folder is, this might break between shells so make sure you run bash
LOCAL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# get current IDs
USER_ID=$(id -u)
GROUP_ID=$(id -g)

echo "Mount $LOCAL_DIR into docker, and match the host IDs ($USER_ID:$GROUP_ID) inside the container."

docker run -v $LOCAL_DIR:/host_mount -i debian:9.4-slim bash -c "set -euo pipefail && groupadd -r -g $GROUP_ID lowprivgroup && useradd -u $USER_ID lowprivuser -g $GROUP_ID && cd /host_mount && su -c ./runMyScriptAsRegularUser.sh lowprivuser"

여기에는 데이터 전용 컨테이너를 사용하지만 애플리케이션 컨테이너와 동기화할 필요가 없는 접근 방식이 있습니다(동일한 uid/gid를 사용한다는 측면에서).

컨테이너의 일부 앱을 로그인 셸이 없는 비루트 $USER로 실행하려고 할 수 있습니다.

도커 파일에서:

RUN useradd -s /bin/false myuser

# Set environment variables
ENV VOLUME_ROOT /data
ENV USER myuser

...

ENTRYPOINT ["./entrypoint.sh"]

그러면 진입점에서.sh:

chown -R $USER:$USER $VOLUME_ROOT
su -s /bin/bash - $USER -c "cd $repo/build; $@"

는 에 을 는 해 을 해 을 는 --uidmap그리고.--private-uids:

https://github.com/docker/docker/pull/4572#issuecomment-38400893

여러( 할 을 ).--cap-drop) 을 에 에 을

http://opensource.com/business/14/9/security-for-docker

UPDATE 지원이 들어와야 합니다.docker > 1.7.0

UPDATE 버전1.10.0 (2016-02-04) ①--userns-remap플래그 https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2

기본 이미지

이미지 사용: https://hub.docker.com/r/reduardo7/docker-host-user

아니면

중요: 호스트컨테이너 이동성이 파괴됩니다.

1)init.sh

#!/bin/bash

if ! getent passwd $DOCKDEV_USER_NAME > /dev/null
  then
    echo "Creating user $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME"
    groupadd --gid $DOCKDEV_GROUP_ID -r $DOCKDEV_GROUP_NAME
    useradd --system --uid=$DOCKDEV_USER_ID --gid=$DOCKDEV_GROUP_ID \
        --home-dir /home --password $DOCKDEV_USER_NAME $DOCKDEV_USER_NAME
    usermod -a -G sudo $DOCKDEV_USER_NAME
    chown -R $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME /home
  fi

sudo -u $DOCKDEV_USER_NAME bash

2)Dockerfile

FROM ubuntu:latest
# Volumes
    VOLUME ["/home/data"]
# Copy Files
    COPY /home/data/init.sh /home
# Init
    RUN chmod a+x /home/init.sh

3) run.sh

#!/bin/bash

DOCKDEV_VARIABLES=(\
  DOCKDEV_USER_NAME=$USERNAME\
  DOCKDEV_USER_ID=$UID\
  DOCKDEV_GROUP_NAME=$(id -g -n $USERNAME)\
  DOCKDEV_GROUP_ID=$(id -g $USERNAME)\
)

cmd="docker run"

if [ ! -z "${DOCKDEV_VARIABLES}" ]; then
  for v in ${DOCKDEV_VARIABLES[@]}; do
    cmd="${cmd} -e ${v}"
  done
fi

# /home/usr/data contains init.sh
$cmd -v /home/usr/data:/home/data -i -t my-image /home/init.sh

)로 docker

4) 뛰어요!

sh run.sh

저의 구체적인 경우는 배포 서버에 npm을 설치할 필요가 없도록 노드 도커 이미지로 노드 패키지를 구축하려고 했습니다.컨테이너 외부와 호스트 시스템에서 노드 도커 이미지가 생성한 node_modules 디렉토리로 파일을 이동하려고 했지만, 이 디렉토리는 루트가 소유하고 있기 때문에 사용 권한이 거부되었습니다.컨테이너의 디렉토리를 호스트 머신에 복사하면 이 문제를 해결할 수 있다는 것을 깨달았습니다.도커 문서를 통해...

로컬 시스템에 복사된 파일은 UID로 생성됩니다.docker cp 명령을 호출한 사용자의 GID.

이것은 내가 도커 컨테이너 내에서 작성한 디렉토리의 소유권을 변경하기 위해 사용한 bash 코드입니다.

NODE_IMAGE=node_builder
docker run -v $(pwd)/build:/build -w="/build" --name $NODE_IMAGE node:6-slim npm i --production
# node_modules is owned by root, so we need to copy it out 
docker cp $NODE_IMAGE:/build/node_modules build/lambda 
# you might have issues trying to remove the directory "node_modules" within the shared volume "build", because it is owned by root, so remove the image and its volumes
docker rm -vf $NODE_IMAGE || true

필요한 경우 두 번째 도커 컨테이너로 디렉토리를 제거할 수 있습니다.

docker run -v $(pwd)/build:/build -w="/build" --name $RMR_IMAGE node:6-slim rm -r node_modules

도커 호스트와 도커 컨테이너 간에 폴더를 공유하려면 아래 명령을 시도하십시오.

$ docker run -v "$(pwd):$(pwd)" -i -t ubuntu

-v 플래그는 현재 작업 디렉토리를 컨테이너에 마운트합니다.바인딩 마운트 볼륨의 호스트 디렉토리가 존재하지 않으면 도커가 자동으로 호스트에 이 디렉토리를 생성합니다.

그러나 여기에는 두 가지 문제가 있습니다.

  1. 공유 파일은 호스트의 다른 사용자가 소유하므로 루트 사용자가 아닌 경우 마운트된 볼륨에 쓸 수 없습니다.
  2. 컨테이너 내부의 프로세스를 루트로 실행해서는 안 되지만 하드 코딩된 사용자로 실행해도 노트북/Jenkins의 사용자와 일치하지 않습니다.

해결책:

Container: 'testuser'라고 말하는 사용자를 생성합니다. 기본적으로 사용자 ID는 1000부터 시작합니다.

호스트: 그룹 ID 1000으로 'testgroup'이라고 하는 그룹을 만들고 디렉토리를 새 그룹(testgroup)으로 전환합니다.

만약 당신이 개발을 위해 이것을 한다면 좋은 해결책은 사용하는 것입니다.bindfs:

  1. 컨테이너 사용자가 소유한 소스 코드를 유지합니다. (가능한 경우 컨테이너가 소스 코드를 복제하도록 합니다.)
  2. 사용하다bindfs호스트 사용자의 폴더를 매핑합니다.

지금 내 도커 구성 설정은 어떻게 되어 있는지 다음과 같습니다.

project:
  web/src # Container clones it using init scripts.
  web/log
  __web__/src # Host user uses this. It's just bindfs mirror.
  __web__/log

는 이 1년 , ① ③ ④ ⑤ ⑥ ⑦ 에 는 ,bindfs내가 찾은 가장 쉬운 선택입니다.클로닝 외에 런타임 비용은 없습니다.

사용자 모드와 그룹 모드를 사용하여 선택한 사용자 ID와 그룹 ID를 호스트에서 컨테이너로 동기화하는 스크립트를 작성했습니다.

도커 구성:

volumes:
    - /etc/passwd:/etc/passwd.src:ro
    - /etc/group:/etc/group.src:ro
environment:
    - host_users=www-data,mysql
    - host_groups=www-data,mysql,staff

스크립트:

#!/bin/bash

for user in ${host_users//,/ }; do
    echo "syncing user $user" 
    uid=$(grep "^$user:" /etc/passwd.src | awk -F: '{print $3}')
    if [ ! -z "$uid" ]; then
        RET=1
        while [[ RET -ne 0 ]]; do
            usermod -u $uid $user
            RET=$?
            if [[ RET -eq 4 ]]; then
                existing_user=$(id $uid -u)
                existing_user_new_id=$(shuf -i 101-498 -n 1)
                usermod -u $existing_user_new_id $existing_user
                sleep 1
            elif [[ RET -ne 0 ]]; then
                sleep 5
            fi
        done
    else
        echo "syncing user $user, not found in host" 
    fi
done

for group in ${host_groups//,/ }; do
    echo "syncing group $group" 
    gid=$(grep "^$group:" /etc/group.src | awk -F: '{print $3}')
    if [ ! -z "$gid" ]; then
        RET=1
        while [[ RET -ne 0 ]]; do
            groupmod -g $gid $group
            RET=$?
            if [[ RET -eq 4 ]]; then
                existing_group=$(getent group $gid | awk -F: '{print $1}')
                existing_group_new_id=$(shuf -i 1-32766 -n 1)
                groupmod -g $existing_group_new_id $existing_group
                sleep 1
            elif [[ RET -ne 0 ]]; then
                sleep 5
            fi
        done
    else
        echo "syncing group $group, not found in host" 
    fi
done

여기서도 이용 가능: https://github.com/Varun-garg/docker-sync-ids

Docker Composition(도커 합성)을 사용하는 경우 컨테이너를 권한 모드로 시작합니다.

wordpress:
    image: wordpress:4.5.3
    restart: always
    ports:
      - 8084:80
    privileged: true

언급URL : https://stackoverflow.com/questions/23544282/what-is-the-best-way-to-manage-permissions-for-docker-shared-volumes

반응형