도커 공유 볼륨에 대한 권한을 관리하는 가장 좋은 방법은 무엇입니까?
저는 한동안 도커를 가지고 놀다가 지속적인 데이터를 처리할 때 계속 같은 문제를 발견합니다.
나는 내 것을 만듭니다.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
데이터 컨테이너로서.그래서 항만이나 그런 것들을 무시하고,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
도커 파일도 동일한 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
slimage
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/graphite
uid/트에된게가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
입니다.현재 디렉터리(/데이터) 소유권 변경 및 다음에서 아래로 이동root
redis
redis-server
를 직접 (실행된 명령어가 redis-server가 아닌 경우 명령어를 직접 실행합니다.)
이는 다음과 같은 효과가 있습니다.
는 /data 가 는 에서 에 합니다 를 을 하기 를 합니다 을 redis
사용자.
이렇게 하면 볼륨 구성에서 컨테이너를 실행할 수 있는 제로 설정이 가능하다는 점에서 안심할 수 있습니다.
물론 서로 다른 이미지 간에 볼륨을 공유해야 하는 경우에는 동일한 userid/groupid를 사용하는지 확인해야 합니다. 그렇지 않으면 최신 컨테이너가 이전 컨테이너에서 사용 권한을 가로채게 됩니다.
이것은 거의 틀림없이 대부분의 상황에서 최선의 방법은 아니지만, 아직 언급되지 않았기 때문에 아마도 누군가에게 도움이 될 것입니다.
호스트 볼륨 바인딩 마운트
Host folder FOOBAR is mounted in container /volume/FOOBAR
컨테이너의 시작 스크립트를 수정하여 원하는 볼륨의 GID를 찾습니다.
$ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)
사용자가 이 GID를 가진 그룹에 속해 있는지 확인합니다(새 그룹을 만들어야 할 수도 있음).이는가이는럼다과다eysr는는d이sl이가i'ee과sy
nobody
안에 때, 는 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 플래그는 현재 작업 디렉토리를 컨테이너에 마운트합니다.바인딩 마운트 볼륨의 호스트 디렉토리가 존재하지 않으면 도커가 자동으로 호스트에 이 디렉토리를 생성합니다.
그러나 여기에는 두 가지 문제가 있습니다.
- 공유 파일은 호스트의 다른 사용자가 소유하므로 루트 사용자가 아닌 경우 마운트된 볼륨에 쓸 수 없습니다.
- 컨테이너 내부의 프로세스를 루트로 실행해서는 안 되지만 하드 코딩된 사용자로 실행해도 노트북/Jenkins의 사용자와 일치하지 않습니다.
해결책:
Container: 'testuser'라고 말하는 사용자를 생성합니다. 기본적으로 사용자 ID는 1000부터 시작합니다.
호스트: 그룹 ID 1000으로 'testgroup'이라고 하는 그룹을 만들고 디렉토리를 새 그룹(testgroup)으로 전환합니다.
만약 당신이 개발을 위해 이것을 한다면 좋은 해결책은 사용하는 것입니다.bindfs
:
- 컨테이너 사용자가 소유한 소스 코드를 유지합니다. (가능한 경우 컨테이너가 소스 코드를 복제하도록 합니다.)
- 사용하다
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
'it-source' 카테고리의 다른 글
리소스 폴더에서 파일 목록 가져오기 - iOS (0) | 2023.09.18 |
---|---|
행에 발생하지 않는 값 목록을 반환하는 SELECT (0) | 2023.09.18 |
CV_RETR_LIST,CV_RETR_TREE,CV_RETR_EXTER 간의 차이? (0) | 2023.09.18 |
열 1에서 같은 값으로 색 그룹에 행 형식을 지정하는 방법 (0) | 2023.09.18 |
argv[0]는 언제 null을 가질 수 있습니까? (0) | 2023.09.18 |