Docker dan --userns-remap, bagaimana cara mengelola izin volume untuk berbagi data antara host dan container?

96

Di buruh pelabuhan, file yang dibuat di dalam container cenderung memiliki kepemilikan yang tidak dapat diprediksi saat memeriksanya dari host. Pemilik file pada volume adalah root (uid 0) secara default, tetapi segera setelah akun pengguna non-root terlibat dalam penampung dan menulis ke sistem file, pemilik menjadi kurang lebih acak dari perspektif host.

Ini adalah masalah ketika Anda perlu mengakses data volume dari host menggunakan akun pengguna yang sama yang memanggil perintah buruh pelabuhan.

Solusi umumnya adalah

  • memaksa uID pengguna pada waktu pembuatan di Dockerfiles (non portabel)
  • meneruskan UID pengguna host ke docker runperintah sebagai variabel lingkungan dan kemudian menjalankan beberapa chownperintah pada volume dalam skrip entrypoint.

Kedua solusi ini dapat memberikan kontrol atas izin aktual di luar penampung.

Saya berharap ruang nama pengguna menjadi solusi terakhir untuk masalah ini. Saya telah menjalankan beberapa pengujian dengan versi 1.10 yang baru dirilis dan --userns-remap disetel ke akun desktop saya. Namun, saya tidak yakin itu dapat membuat kepemilikan file pada volume yang terpasang lebih mudah ditangani, saya khawatir itu sebenarnya bisa sebaliknya.

Misalkan saya memulai wadah dasar ini

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

Dan kemudian periksa konten dari host:

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

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

Nomor '100000' ini adalah sub-UID pengguna host saya, tetapi karena tidak sesuai dengan UID pengguna saya, saya masih tidak dapat mengedit test.txt tanpa hak istimewa. Sub-pengguna ini tampaknya tidak memiliki ketertarikan dengan pengguna biasa saya yang sebenarnya di luar buruh pelabuhan. Ini tidak dipetakan kembali.

Solusi yang disebutkan sebelumnya dalam posting ini yang terdiri dari menyelaraskan UID antara host dan penampung tidak berfungsi lagi karena UID->sub-UIDpemetaan yang terjadi di namespace.

Lalu, apakah ada cara untuk menjalankan buruh pelabuhan dengan namespace pengguna diaktifkan (untuk keamanan yang lebih baik), sementara masih memungkinkan bagi pengguna host yang menjalankan buruh pelabuhan untuk memiliki file yang dihasilkan pada volume?

Stéphane C.
sumber
Saya pikir jika Anda akan berbagi volume antara host dan wadah, ruang nama pengguna tidak akan menjadi bagian dari solusi. Pilihan kedua Anda ("meneruskan UID pengguna host ke perintah jalankan buruh pelabuhan sebagai variabel lingkungan dan kemudian menjalankan beberapa perintah chown pada volume dalam skrip titik masuk") mungkin merupakan solusi terbaik.
Larsks
4
Docker sendiri tampaknya tidak mendorong penggunaan volume yang dapat ditulis yang dipasang di host. Karena saya tidak menjalankan layanan cloud dan hanya menggunakan gambar tepercaya saya sendiri, sekarang saya bertanya-tanya apakah manfaat keamanan pengguna NS layak untuk mengorbankan begitu banyak kenyamanan.
Stéphane C.
@ Stéane. apakah Anda sudah menemukan pendekatan yang lebih baik?
EightyEight
4
Sayangnya tidak, tidak menggunakan ruang nama pengguna dan meneruskan UID dari host masih menjadi pilihan saya. Saya berharap akan ada cara yang tepat untuk memetakan pengguna di masa mendatang. Aku meragukannya tapi tetap saja, aku tetap membuka mata.
Stéphane C.

Jawaban:

46

Jika Anda dapat mengatur sebelumnya pengguna dan grup, maka dimungkinkan untuk menetapkan UID dan GID dengan cara yang spesifik sehingga pengguna host sesuai dengan pengguna dengan namespace di dalam container.

Berikut contohnya (Ubuntu 14.04, Docker 1.10):

  1. Buat beberapa pengguna dengan ID numerik tetap:

    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. Edit secara manual rentang ID bawahan yang dibuat secara otomatis dalam /etc/subuiddan /etc/subgidfile:

    ns1:500000:65536
    

    (perhatikan tidak ada catatan untuk ns1-rootdan ns1-user1karena MAX_UIDdan MAX_GIDbatas dalam /etc/login.defs)

  3. Aktifkan ruang nama pengguna di /etc/default/docker:

    DOCKER_OPTS="--userns-remap=ns1"
    

    Mulai ulang daemon service docker restart, pastikan /var/lib/docker/500000.500000direktori dibuat.

    Sekarang, di dalam container Anda memiliki rootdan user1, dan pada host - ns1-rootdan ns1-user1, dengan ID yang cocok

    UPDATE: untuk menjamin bahwa pengguna non-root memiliki ID tetap dalam penampung (misalnya, pengguna1 1000: 1000), buatlah secara eksplisit selama pembuatan gambar.

Uji jalan:

  1. Siapkan direktori volume

    mkdir /vol1
    chown ns1-root:ns1-root /vol1
    
  2. Cobalah dari wadah

    docker run --rm -ti -v /vol1:/vol1 busybox sh
    echo "Hello from container" > /vol1/file
    exit
    
  3. Coba dari tuan rumah

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

Tidak portabel dan terlihat seperti retasan, tetapi berfungsi.

amartynov.dll
sumber
3
Sangat menarik dan layak mendapat +1. Tetapi Anda masih perlu memastikan bahwa pengguna1 dalam gambar Anda menggunakan UID 1000. Jika tidak, Anda tidak dapat memastikan bahwa ia akan menerima UID 501000 pada host. Btw apakah kita benar-benar yakin bahwa rumusnya selalu subUID lower bound + UID in imagejika kita menjalankan banyak gambar berbeda dengan pengguna yang memiliki ID disetel ke 1000?
Stéphane C.
@ Stéane. Poin bagus! Menambahkan catatan tentang memperbaiki ID di dalam gambar. Adapun rumusnya, saya akan bereksperimen lebih lanjut dengan gambar saya sendiri dan akan memperbarui jawabannya jika menemukan sesuatu
amartynov
1
Jika Anda mengatur pengguna dan grup secara manual di host dan di container, apakah Anda benar-benar memerlukan fitur "ruang nama pengguna"?
Tristan
1
Namespace yang Anda buat memisahkan pengguna host dari pengguna container, tetapi Anda mungkin memerlukan beberapa namespace untuk container, terutama saat gambar resmi (seperti mysql) membuat pengguna tanpa uid eksplisit. Bagaimana Anda menangani beberapa namespace ketika opsi --userns-remap hanya mengharapkan satu?
Tristan
2
@ amartynov Bolehkah saya bertanya mengapa Anda bersusah payah menentukan UID (5000) untuk pengguna "ns1" Anda? Karena ini adalah nama (bukan UID) yang Anda rujuk dalam file subuid dan subgid, sepertinya tidak masalah UID apa yang didapat pengguna ini. Apakah saya kehilangan beberapa hubungan, seperti yang mungkin disarankan oleh kesamaan antara 5000 dan 500000?
Jollymorphic
2

Salah satu solusinya adalah dengan menetapkan uid pengguna secara dinamis pada waktu pembuatan agar cocok dengan host.

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

Kemudian buat sebagai:

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

dan dijalankan sebagai:

docker run mycontainer

Jika Anda sudah memiliki penampung, buat penampung pembungkus dengan yang berikut ini Dockerfile:

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

Ini bisa dibungkus docker-compose.ymlseperti:

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

Kemudian buat dan jalankan sebagai:

docker-compose build --build-arg UID=$UID myservice; docker-compose run myservice
kenorb
sumber
1
Saya tidak ingin terlihat tidak ramah tetapi ini sebenarnya adalah salah satu solusi yang tercantum dalam pertanyaan asli, tetapi bukan solusi dan tidak terkait dengan ruang nama pengguna.
Stéphane C.
@ Stéane. Bisakah Anda mengomentari pertanyaan terkait ini? stackoverflow.com/questions/60274418/…
overexchange
-1

Anda dapat menghindari masalah izin dengan menggunakan docker cpperintah .

Kepemilikan ditetapkan untuk pengguna dan grup utama di tujuan. Misalnya, file yang disalin ke penampung dibuat dengan UID:GIDpengguna root. File yang disalin ke mesin lokal dibuat dengan UID:GIDpengguna yang memanggil docker cpperintah.

Berikut adalah contoh Anda yang beralih untuk digunakan 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
$ 

Namun, jika Anda hanya ingin membaca file dari sebuah wadah, Anda tidak memerlukan nama volume. Contoh ini menggunakan wadah bernama, bukan volume bernama:

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

Saya menemukan volume bernama berguna ketika saya ingin menyalin file ke dalam wadah, seperti yang dijelaskan dalam pertanyaan ini .

Don Kirkby
sumber
Tetapi docker cpmelibatkan duplikasi data. Selain itu, menurut dokumen tersebut, saat menyalin data ke penampung, ia menetapkan ID kepemilikan sesuai dengan pengguna root, yang seringkali bukan akun yang menjalankan aplikasi dalam container. Saya gagal untuk melihat bagaimana itu memecahkan masalah kita.
Stéphane C.
Anda benar, @ Stéphane, ini melibatkan penggandaan data. Namun, membuat salinan file memungkinkan Anda menetapkan kepemilikan dan izin yang berbeda pada host dan di penampung. docker cpmemberi Anda kendali penuh atas kepemilikan file ketika Anda mengalirkan arsip tar ke dalam atau keluar dari sebuah wadah. Anda dapat menyesuaikan kepemilikan dan izin setiap entri di file tar saat Anda streaming, jadi Anda tidak terbatas pada pengguna root.
Don Kirkby