Docker 및 --userns-remap, 호스트와 컨테이너간에 데이터를 공유하기 위해 볼륨 권한을 관리하는 방법은 무엇입니까?


96

Docker에서 컨테이너 내부에 생성 된 파일은 호스트에서 검사하는 동안 예측할 수없는 소유권을 갖는 경향이 있습니다. 볼륨에있는 파일의 소유자는 기본적으로 루트 (uid 0)이지만 루트가 아닌 사용자 계정이 컨테이너에 포함되어 파일 시스템에 쓰는 즉시 소유자는 호스트 관점에서 다소 무작위가됩니다.

docker 명령을 호출하는 동일한 사용자 계정을 사용하여 호스트에서 볼륨 데이터에 액세스해야하는 경우 문제가됩니다.

일반적인 해결 방법은 다음과 같습니다.

  • Dockerfiles (이식 불가능)에서 생성시 사용자 uID 강제
  • 호스트 사용자의 UID를 docker run환경 변수로 명령에 전달한 다음 chown진입 점 스크립트의 볼륨에서 일부 명령 을 실행 합니다.

두 솔루션 모두 컨테이너 외부의 실제 권한을 제어 할 수 있습니다.

사용자 네임 스페이스가이 문제에 대한 최종 해결책이 될 것으로 예상했습니다. 최근에 출시 된 버전 1.10 및 --userns-remap을 내 데스크톱 계정으로 설정하여 몇 가지 테스트를 실행했습니다. 그러나 마운트 된 볼륨에 대한 파일 소유권을 더 쉽게 처리 할 수 ​​있는지 확신 할 수 없으며 실제로 그 반대 일 수 있습니다.

이 기본 컨테이너를 시작한다고 가정합니다.

docker run -ti -v /data debian:jessie /bin/bash
echo 'hello' > /data/test.txt
exit

그런 다음 호스트의 콘텐츠를 검사합니다.

ls -lh /var/lib/docker/100000.100000/volumes/<some-id>/_data/

-rw-r--r-- 1 100000 100000 6 Feb  8 19:43 test.txt

이 숫자 '100000'은 내 호스트 사용자의 하위 UID이지만 내 사용자의 UID와 일치하지 않기 때문에 권한없이 test.txt를 편집 할 수 없습니다. 이 하위 사용자는 docker 외부의 실제 일반 사용자와 친화력이없는 것 같습니다. 다시 매핑되지 않았습니다.

호스트와 컨테이너 간의 UID 정렬로 구성된이 게시물의 앞부분에서 언급 한 해결 방법 UID->sub-UID은 네임 스페이스에서 발생 하는 매핑 으로 인해 더 이상 작동하지 않습니다 .

그렇다면 사용자 네임 스페이스가 활성화 된 상태에서 (보안 향상을 위해) docker를 실행하는 방법이있는 반면, docker를 실행하는 호스트 사용자가 볼륨에서 생성 된 파일을 소유 할 수 있도록하는 방법이 있습니까?


호스트와 컨테이너간에 볼륨을 공유하려는 경우 사용자 네임 스페이스가 솔루션의 일부 가 되지 않을 것이라고 생각합니다. 두 번째 옵션 ( "호스트 사용자의 UID를 환경 변수로 docker run 명령에 전달한 다음 진입 점 스크립트의 볼륨에서 일부 chown 명령 실행")이 최상의 솔루션 일 것입니다.
larsks

4
Docker 자체는 호스트 마운트 쓰기 가능 볼륨 사용을 권장하지 않는 것 같습니다. 클라우드 서비스를 실행하지 않고 자신의 신뢰할 수있는 이미지 만 사용하기 때문에 이제 사용자 NS의 보안 이점이 그토록 많은 편의를 희생 할 가치가 있는지 궁금합니다.
Stéphane C.

@ StéphaneC. 아마도 더 나은 접근 방식을 찾았습니까?
EightyEight

4
안타깝게도 사용자 네임 스페이스를 사용하지 않고 호스트에서 UID를 전달하는 것은 여전히 ​​제가 선택할 수있는 옵션입니다. 앞으로 사용자를 매핑 할 수있는 적절한 방법이 있기를 바랍니다. 의심 스럽지만 여전히 눈을 뜨고 있습니다.
Stéphane C.

답변:


46

사용자와 그룹을 미리 정렬 할 수 있다면 호스트 사용자가 컨테이너 내부의 네임 스페이스 사용자에 해당하도록 특정 방식으로 UID 및 GID를 할당 할 수 있습니다.

다음은 그 예입니다 (Ubuntu 14.04, Docker 1.10).

  1. 고정 된 숫자 ID로 일부 사용자를 만듭니다.

    useradd -u 5000 ns1
    
    groupadd -g 500000 ns1-root
    groupadd -g 501000 ns1-user1
    
    useradd -u 500000 -g ns1-root ns1-root
    useradd -u 501000 -g ns1-user1 ns1-user1 -m
    
  2. /etc/subuid/etc/subgid파일 에서 자동 생성 된 하위 ID 범위를 수동으로 편집 합니다.

    ns1:500000:65536
    

    (주 더 레코드가없는 ns1-rootns1-user1인한 MAX_UIDMAX_GID한계에 /etc/login.defs)

  3. 에서 사용자 네임 스페이스 활성화 /etc/default/docker:

    DOCKER_OPTS="--userns-remap=ns1"
    

    데몬을 다시 시작 service docker restart하고 /var/lib/docker/500000.500000디렉토리가 생성 되었는지 확인 합니다.

    이제 컨테이너 내부에는 rootuser1, 호스트에 ns1-rootns1-user1, 일치하는 ID가 있습니다.

    업데이트 : 루트가 아닌 사용자가 컨테이너 (예 : user1 1000 : 1000)에 고정 ID를 갖도록하려면 이미지 빌드 중에 명시 적으로 생성하십시오.

테스트 드라이브:

  1. 볼륨 디렉터리 준비

    mkdir /vol1
    chown ns1-root:ns1-root /vol1
    
  2. 컨테이너에서 시도

    docker run --rm -ti -v /vol1:/vol1 busybox sh
    echo "Hello from container" > /vol1/file
    exit
    
  3. 호스트에서 시도

    passwd ns1-root
    login ns1-root
    cat /vol1/file
    echo "can write" >> /vol1/file
    

휴대용이 아니며 해킹처럼 보이지만 작동합니다.


3
매우 흥미롭고 +1을받을 만합니다. 그러나 이미지의 user1에 UID 1000이 할당되어 있는지 확인해야합니다. 그렇지 않으면 호스트에서 UID 501000을 수신할지 확신 할 수 없습니다. Btw subUID lower bound + UID in image우리는 ID가 1000으로 설정된 사용자로 많은 다른 이미지를 실행하는 경우 공식이 항상 확실 합니까?
Stéphane C.

@ StéphaneC. 좋은 지적! 이미지 내부의 ID 수정에 대한 메모를 추가했습니다. 공식에 관해서는, 나는 경우 찾기 아무것도 내 자신의 이미지와 더 실험을거야하고 대답을 업데이트합니다
amartynov

1
호스트와 컨테이너에서 사용자와 그룹을 직접 정렬하는 경우 "사용자 네임 스페이스"기능이 정말로 필요합니까?
Tristan

1
생성 한 네임 스페이스는 호스트 사용자와 컨테이너 사용자를 구분하지만, 특히 공식 이미지 (예 : mysql 이미지)가 명시 적 uid없이 사용자를 생성하는 경우 컨테이너에 여러 네임 스페이스가 필요할 수 있습니다. --userns-remap 옵션이 하나만 예상 할 때 여러 네임 스페이스를 어떻게 처리합니까?
Tristan

2
@amartynov "ns1"사용자에 대해 UID (5000)를 지정하는 데 어려움을 겪은 이유를 물어봐도 될까요? subuid 및 subgid 파일에서 참조하는 이름 (UID가 아님)이므로이 사용자가 가져 오는 UID는 중요하지 않은 것 같습니다. 5000과 500000 사이의 유사성이 제안 할 수 있듯이 일부 관계가 누락 되었습니까?
Jollymorphic

2

한 가지 해결 방법은 호스트와 일치하도록 빌드시 사용자의 uid를 동적으로 할당하는 것입니다.

Dockerfile:

FROM ubuntu
# Defines argument which can be passed during build time.
ARG UID=1000
# Create a user with given UID.
RUN useradd -d /home/ubuntu -ms /bin/bash -g root -G sudo -u $UID ubuntu
# Switch to ubuntu user by default.
USER ubuntu
# Check the current uid of the user.
RUN id
# ...

그런 다음 다음과 같이 빌드하십시오.

docker build --build-arg UID=$UID -t mycontainer .

다음으로 실행 :

docker run mycontainer

기존 컨테이너가있는 경우 다음을 사용하여 래퍼 컨테이너를 만듭니다 Dockerfile.

FROM someexistingcontainer
ARG UID=1000
USER root
# This assumes you've the existing user ubuntu.
RUN usermod -u $UID ubuntu
USER ubuntu

다음 docker-compose.yml과 같이 래핑 할 수 있습니다 .

version: '3.4'
services:
  myservice:
    command: id
    image: myservice
    build:
      context: .
    volumes:
    - /data:/data:rw

그런 다음 다음과 같이 빌드하고 실행하십시오.

docker-compose build --build-arg UID=$UID myservice; docker-compose run myservice

1
나는 비우호적으로 보이고 싶지 않지만 실제로 이것은 원래 질문에 나열된 해결 방법 중 하나이지만 솔루션이 아니며 사용자 네임 스페이스와 관련이 없습니다.
Stéphane C.

@ StéphaneC. 이 관련 질문에 대해 언급 할 수 있습니까? stackoverflow.com/questions/60274418/…
overexchange

-1

docker cp명령 을 사용하여 권한 문제를 방지 할 수 있습니다 .

소유권은 대상의 사용자 및 기본 그룹으로 설정됩니다. 예를 들어 컨테이너에 복사 된 파일 UID:GID은 루트 사용자 로 만들어집니다 . 로컬 시스템에 복사 된 파일 UID:GIDdocker cp명령 을 호출 한 사용자의로 생성됩니다 .

다음은 사용하도록 전환 한 예입니다 docker cp.

$ docker run -ti -v /data debian:jessie /bin/bash
root@e33bb735a70f:/# echo 'hello' > /data/test.txt
root@e33bb735a70f:/# exit
exit
$ docker volume ls
DRIVER              VOLUME NAME
local               f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93
$ sudo ls -l /var/lib/docker/100000.100000/volumes/f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93/_data
total 4
-rw-r--r-- 1 100000 100000 6 Oct  6 10:34 test.txt
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
e33bb735a70f        debian:jessie       "/bin/bash"         About a minute ago   Exited (0) About a minute ago                       determined_hypatia
$ docker cp determined_hypatia:/data/test.txt .
$ ls -l test.txt 
-rw-r--r-- 1 don don 6 Oct  6 10:34 test.txt
$ cat test.txt
hello
$ 

그러나 컨테이너에서 파일을 읽으려는 경우에는 명명 된 볼륨이 필요하지 않습니다. 이 예에서는 명명 된 볼륨 대신 명명 된 컨테이너를 사용합니다.

$ docker run -ti --name sandbox1 debian:jessie /bin/bash
root@93d098233cf3:/# echo 'howdy' > /tmp/test.txt
root@93d098233cf3:/# exit
exit
$ docker cp sandbox1:/tmp/test.txt .
$ ls -l test.txt
-rw-r--r-- 1 don don 6 Oct  6 10:52 test.txt
$ cat test.txt
howdy
$ 

이 질문에 설명 된대로 파일을 컨테이너에 복사 할 때 명명 된 볼륨이 유용하다는 것을 알았습니다 .


그러나 docker cp데이터 복제가 포함됩니다. 또한 문서에 따르면 컨테이너에 데이터를 복사 할 때 컨테이너화 된 앱을 실행하는 계정이 아닌 루트 사용자에 따라 소유권 ID를 설정합니다. 나는 그것이 우리의 문제를 어떻게 해결하는지 보지 못한다.
Stéphane C.

맞습니다, @ Stéphane, 데이터 복제가 포함됩니다. 그러나 파일 복사본을 만들면 호스트와 컨테이너에서 다른 소유권과 권한을 할당 할 수 있습니다. docker cptar 아카이브를 컨테이너 안팎으로 스트리밍 할 때 파일 소유권을 완전히 제어 할 수 있습니다. 스트리밍 할 때 tar 파일에있는 각 항목의 소유권과 권한을 조정할 수 있으므로 루트 사용자로 제한되지 않습니다.
Don Kirkby
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.