วิธีที่ดีที่สุดในการจัดการการอนุญาตสำหรับโวลุ่มที่แชร์ของ Docker คืออะไร


345

ฉันเล่นกับ Docker มาพักหนึ่งแล้วก็หาปัญหาเดิมต่อไปเมื่อจัดการกับข้อมูลถาวร

ฉันจะสร้างของฉันDockerfileและเปิดเผยปริมาณหรือใช้--volumes-fromในการติดตั้งโฟลเดอร์โฮสต์ในภาชนะของฉัน

ฉันควรใช้สิทธิ์ใดกับปริมาณที่แชร์บนโฮสต์

ฉันนึกถึงตัวเลือกสองทาง:

  • จนถึงตอนนี้ฉันได้อนุญาตให้ทุกคนเข้าถึงการอ่าน / เขียนดังนั้นฉันจึงสามารถเขียนไปยังโฟลเดอร์ได้จากคอนเทนเนอร์ Docker

  • แม็พผู้ใช้จากโฮสต์ในคอนเทนเนอร์ดังนั้นฉันสามารถกำหนดสิทธิ์แบบละเอียดมากขึ้น ไม่แน่ใจว่าเป็นไปได้และไม่พบมากเกี่ยวกับเรื่องนี้ จนถึงตอนนี้สิ่งที่ฉันทำได้คือเรียกใช้คอนเทนเนอร์ในฐานะผู้ใช้บางคน: docker run -i -t -user="myuser" postgresแต่ผู้ใช้นี้มี UID ที่แตกต่างจากโฮสต์ของฉันmyuserดังนั้นการอนุญาตไม่ทำงาน นอกจากนี้ฉันไม่แน่ใจว่าการแมปผู้ใช้จะมีความเสี่ยงด้านความปลอดภัยหรือไม่

มีทางเลือกอื่นหรือไม่?

พวกคุณเป็นยังไงกับปัญหานี้?


ชำระเงินนี้คำตอบจากคำถามที่คล้ายกัน
Batandwa

1
คุณอาจสนใจในหัวข้อนี้ซึ่งกล่าวถึงหัวข้อนี้ในรายละเอียดบางอย่าง: groups.google.com/forum/#!msg/docker-user/cVov44ZFg_c/…
btiernay

1
คุณเห็นcontainer42.com/2014/11/18/data-only-container-madnessหรือไม่?
ฟิลิปป์

ในขณะนี้ทีมนักเทียบท่าไม่ได้วางแผนที่จะใช้โซลูชันเนทีฟเพื่อติดตั้งโฮสต์ไดเรกทอรีเป็นปริมาณที่มี uid / gid ที่ระบุ ดูความคิดเห็นและคำตอบของฉันเกี่ยวกับปัญหานี้: github.com/docker/docker/issues/7198#issuecomment-230636074
Quinn Comendant

คำตอบ:


168

UPDATE 2016/03/02 : ณ หาง 1.9.0, หางได้ชื่อไดรฟ์ซึ่งแทนที่ข้อมูลเท่านั้นภาชนะบรรจุ คำตอบด้านล่างรวมถึงโพสต์บล็อกที่เชื่อมโยงของฉันยังคงมีคุณค่าในแง่ของวิธีคิดเกี่ยวกับข้อมูลภายในตัวเชื่อมต่อแต่พิจารณาใช้โวลุ่มที่มีชื่อเพื่อใช้รูปแบบที่อธิบายด้านล่างมากกว่าที่เก็บข้อมูล


ผมเชื่อว่าวิธีที่เป็นที่ยอมรับในการแก้ปัญหานี้โดยใช้ข้อมูลเพียงภาชนะบรรจุ ด้วยวิธีนี้การเข้าถึงข้อมูลปริมาณทั้งหมดผ่านคอนเทนเนอร์ที่ใช้-volumes-fromdata container ดังนั้นโฮสต์ uid / gid จึงไม่สำคัญ

ตัวอย่างเช่นกรณีการใช้งานหนึ่งกรณีที่ให้ไว้ในเอกสารกำลังสำรองปริมาณข้อมูล เมื่อต้องการทำเช่นนี้คอนเทนเนอร์อื่นถูกใช้เพื่อทำการสำรองข้อมูลผ่านtarและมันก็ใช้-volumes-fromในการเมานต์โวลุ่ม ดังนั้นฉันคิดว่าจุดสำคัญในการ grok คือ: แทนที่จะคิดเกี่ยวกับวิธีการเข้าถึงข้อมูลในโฮสต์ที่มีสิทธิ์ที่เหมาะสมคิดเกี่ยวกับวิธีการทำสิ่งที่คุณต้องการ - สำรองข้อมูลการเรียกดูและอื่น ๆ - ผ่านภาชนะอื่น . คอนเทนเนอร์เองจำเป็นต้องใช้ uid / gids ที่สอดคล้องกัน แต่ไม่จำเป็นต้องแมปกับสิ่งใดบนโฮสต์จึงยังคงพกพาได้

นี่เป็นสิ่งที่ค่อนข้างใหม่สำหรับฉันเช่นกัน แต่หากคุณมีกรณีการใช้งานเฉพาะโปรดแสดงความคิดเห็นและฉันจะพยายามขยายคำตอบ

ปรับปรุง : สำหรับกรณีการใช้งานที่กำหนดในความคิดเห็นที่คุณอาจมีภาพที่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 gids / จึงอาจมีลักษณะบางอย่างเช่นนี้

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/graphitedataใน Dockerfile หรือแทนที่จะสร้างภาพใหม่เพียงแค่ใช้หนึ่งในสิ่งที่มีอยู่เดิม (แทนที่จุดเข้า / cmd ตามความจำเป็น)

ตอนนี้คุณเพียงแค่เรียกใช้:

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

vi /data/graphite/whatever.txtแล้วก็ มันทำงานได้อย่างสมบูรณ์เพราะภาชนะทั้งหมดมีผู้ใช้กราไฟท์เดียวกันกับ uid / gid ที่ตรงกัน

เนื่องจากคุณไม่เคยเมานต์/data/graphiteจากโฮสต์คุณไม่สนใจวิธีที่โฮสต์ uid / gid แม็พกับ uid / gid ที่กำหนดภายในgraphiteและgraphitetoolsคอนเทนเนอร์ ขณะนี้คอนเทนเนอร์เหล่านั้นสามารถปรับใช้กับโฮสต์ใดก็ได้และจะยังคงทำงานได้อย่างสมบูรณ์

สิ่งที่เป็นระเบียบเกี่ยวกับเรื่องนี้คือgraphitetoolsอาจมียูทิลิตี้และสคริปต์ที่มีประโยชน์ทุกประเภทซึ่งตอนนี้คุณสามารถปรับใช้แบบพกพาได้

ปรับปรุง 2 : หลังจากเขียนคำตอบนี้ฉันตัดสินใจที่จะเขียนโพสต์บล็อกที่สมบูรณ์มากขึ้นเกี่ยวกับวิธีการนี้ ฉันหวังว่ามันจะช่วย

อัปเดต 3 : ฉันแก้ไขคำตอบนี้และเพิ่มรายละเอียดเฉพาะเพิ่มเติม ก่อนหน้านี้มีข้อสันนิษฐานที่ไม่ถูกต้องบางประการเกี่ยวกับความเป็นเจ้าของและ perms - โดยทั่วไปความเป็นเจ้าของจะถูกกำหนดในเวลาที่สร้างโวลุ่มเช่นในที่เก็บข้อมูลเพราะนั่นคือเมื่อสร้างโวลุ่ม ดูบล็อกนี้ นี่ไม่ใช่ข้อกำหนด - คุณสามารถใช้ data container เป็น "reference / handle" และตั้งค่าความเป็นเจ้าของ / perms ใน container อื่นผ่าน chownes ใน entrypoint ซึ่งลงท้ายด้วย gosu เพื่อรันคำสั่งเป็นผู้ใช้ที่ถูกต้อง หากใครสนใจวิธีนี้โปรดแสดงความคิดเห็นและฉันสามารถให้ลิงก์ไปยังตัวอย่างโดยใช้วิธีนี้


35
ฉันเกรงว่านี่ไม่ใช่วิธีการแก้ปัญหาเนื่องจากคุณจะมีปัญหาเดียวกันกับคอนเทนเนอร์ข้อมูลเท่านั้น ในตอนท้ายของวันคอนเทนเนอร์นี้จะใช้ปริมาณที่แชร์จากโฮสต์ดังนั้นคุณจะต้องจัดการสิทธิ์ในโฟลเดอร์ที่ใช้ร่วมกันเหล่านั้น
Xabs

2
จำไว้ว่าฉันอาจต้องแก้ไขโฟลเดอร์ข้อมูลจากโฮสต์ของฉัน (เช่น: ลบคีย์ทดสอบกราไฟท์ลบโฟลเดอร์ทดสอบ JIRA ของฉันหรืออัปเดตด้วยข้อมูลสำรองการผลิตล่าสุด ... ) เท่าที่ฉันเข้าใจจากความคิดเห็นของคุณฉันควรทำสิ่งต่าง ๆ เช่นอัปเดตข้อมูล JIRA ผ่านคอนเทนเนอร์ที่ 3 ในกรณีใด ๆ สิ่งสิทธิ์ที่คุณจะนำไปใช้กับโฟลเดอร์ข้อมูลใหม่/data/newcontainer? ฉันคิดว่าคุณทำงานdockerเป็น root (เป็นไปได้หรือไม่ที่จะไม่ทำเช่นนั้น) นอกจากนี้ยังมีความแตกต่างในการอนุญาตเหล่านั้นหรือไม่หากข้อมูลถูกเมาท์โดยตรงในคอนเทนเนอร์หลักหรือผ่านคอนเทนเนอร์ข้อมูลเท่านั้น ?
Xabs

2
ขอขอบคุณสำหรับการตอบกลับอย่างละเอียด จะทดสอบสิ่งนี้ทันทีที่ฉันมีโอกาส นอกจากนี้ยังมีการอ้างอิงที่ดีทั้งบล็อกของคุณโพสต์และหนึ่งเกี่ยวกับการใช้ภาพน้อยที่สุดสำหรับบรรจุข้อมูล
Xabs

3
ปัญหาเดียวของวิธีนี้คือมันง่ายมากที่จะลบคอนเทนเนอร์โดยไม่ได้ตั้งใจ ลองนึกภาพถ้ามันเป็นที่เก็บข้อมูลของคุณ ฉันคิดว่า (CMIIW) ข้อมูลจะยังคงอยู่ในที่/var/lib/dockerใดที่หนึ่ง แต่ก็ยังมีอาการปวดมาก
lolski

3
"คุณสามารถใช้ data container เป็น" reference / handle "และตั้งค่าความเป็นเจ้าของ / perms ใน container อื่นผ่าน chown ใน entrypoint" ... @Raman: นี่เป็นส่วนที่ช่วยฉันในที่สุดหลังจากมีปัญหาการอนุญาตจำนวนมาก นึกออก, คิดออก, หาคำตอบได้. การใช้สคริปต์จุดเข้าใช้งานและการตั้งค่าการอนุญาตในสิ่งนี้ใช้ได้กับฉัน ขอบคุณสำหรับคำอธิบายที่ละเอียด มันเป็นสิ่งที่ดีที่สุดที่ฉันพบบนเว็บจนถึงตอนนี้
Vanderstaaij

59

วิธีการแก้ปัญหาที่สง่างามมากสามารถมองเห็นได้บนภาพสีแดงอย่างเป็นทางการและโดยทั่วไปในภาพที่เป็นทางการทั้งหมด

อธิบายไว้ในกระบวนการทีละขั้นตอน:

  • สร้างผู้ใช้ใหม่ / กลุ่มก่อนสิ่งอื่นใด

เท่าที่เห็นในความคิดเห็น Dockerfile:

เพิ่มผู้ใช้และกลุ่มของเราก่อนเพื่อให้แน่ใจว่า ID ของพวกเขาได้รับมอบหมายอย่างสม่ำเสมอโดยไม่คำนึงถึงการเพิ่มสิ่งที่ต้องพึ่งพาใด ๆ

  • ติดตั้งgosuด้วย Dockerfile

gosu เป็นทางเลือกของsu/ sudoเพื่อให้ง่ายต่อการก้าวลงจากผู้ใช้รูท (Redis จะทำงานกับredisผู้ใช้เสมอ)

  • กำหนดค่า/dataระดับเสียงและตั้งเป็น workdir

โดยการกำหนดค่า / data data ด้วยVOLUME /dataคำสั่งตอนนี้เรามีไดรฟ์ข้อมูลแยกต่างหากที่สามารถเป็นไดรฟ์ข้อมูลระดับเสียงนักเทียบท่าหรือผูกติดกับโฮสต์ dir

การกำหนดค่าเป็น workdir ( WORKDIR /data) ทำให้เป็นไดเร็กทอรีเริ่มต้นซึ่งคำสั่งถูกเรียกใช้งาน

  • เพิ่มไฟล์ docker-entrypoint และตั้งเป็น ENTRYPOINT ด้วยค่าเริ่มต้น CMD redis-server

ซึ่งหมายความว่าการเรียกใช้คอนเทนเนอร์ทั้งหมดจะทำงานผ่านสคริปต์ docker-entrypoint และโดยค่าเริ่มต้นคำสั่งที่จะเรียกใช้คือ redis-server

docker-entrypointเป็นสคริปต์ที่ไม่ฟังก์ชั่นที่เรียบง่าย: การเปลี่ยนแปลงกรรมสิทธิ์ของไดเรกทอรีปัจจุบัน (ข้อมูล /) และขั้นตอนลงจากrootการใช้เพื่อการทำงานredis redis-server(หากคำสั่งที่ดำเนินการไม่ใช่เซิร์ฟเวอร์ redis คำสั่งนั้นจะเรียกใช้คำสั่งโดยตรง)

นี้มีผลต่อไปนี้

หากไดเร็กทอรี / data ถูกผูกเข้ากับโฮสต์จุดเชื่อมต่อจะเตรียมสิทธิ์ผู้ใช้ก่อนเรียกใช้ redis-server ภายใต้redisผู้ใช้

สิ่งนี้ช่วยให้คุณสบายใจว่าไม่มีการตั้งค่าเป็นศูนย์เพื่อเรียกใช้คอนเทนเนอร์ภายใต้การกำหนดค่าระดับเสียงใด ๆ

แน่นอนว่าถ้าคุณต้องการแบ่งระดับเสียงระหว่างรูปภาพต่าง ๆ คุณต้องแน่ใจว่าพวกเขาใช้หมายเลขผู้ใช้ / กลุ่มเดียวกันมิฉะนั้นคอนเทนเนอร์ล่าสุดจะขโมยสิทธิ์ผู้ใช้จากรูปภาพก่อนหน้า


11
คำตอบที่ได้รับการยอมรับนั้นเป็นข้อมูล แต่มันทำให้ฉันผิดหวังเมื่อสัปดาห์ที่ผ่านมาโดยมีสิทธิ์ในการค้นหาคำตอบนี้ซึ่งเป็นวิธีที่ได้รับการยอมรับในการแก้ปัญหา
m0meni

3
อธิบายได้ดีมากเช่นกันที่นี่: denibertovic.com/posts/handling-permissions-with-docker-volumes
kheraud

ดังนั้น? ฉันจะทำให้โวลุ่มที่เขียนได้จากอุปกรณ์เชื่อมต่อภายในได้อย่างไร chownมันอยู่ในENTRYPOINTสคริปต์?
Gherman

34

นี่ไม่ใช่วิธีที่ดีที่สุดสำหรับสถานการณ์ส่วนใหญ่ แต่ก็ยังไม่ได้รับการกล่าวถึงดังนั้นอาจช่วยคนได้

  1. ผูกปริมาณโฮสต์เมานต์

    Host folder FOOBAR is mounted in container /volume/FOOBAR

  2. แก้ไขสคริปต์เริ่มต้นของคอนเทนเนอร์ของคุณเพื่อค้นหา GID ของไดรฟ์ข้อมูลที่คุณสนใจ

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

  3. ตรวจสอบให้แน่ใจว่าผู้ใช้ของคุณอยู่ในกลุ่มที่มี GID นี้ (คุณอาจต้องสร้างกลุ่มใหม่) สำหรับตัวอย่างนี้ฉันจะแกล้งซอฟต์แวร์ของฉันทำงานเป็นnobodyผู้ใช้เมื่ออยู่ในคอนเทนเนอร์ดังนั้นฉันต้องการให้แน่ใจว่าnobodyเป็นของกลุ่มที่มีรหัสกลุ่มเท่ากับ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 ที่คุณต้องการ ไม่สามารถใช้ร่วมกับส่วนUSERคำสั่งใน Dockerfile (ยกเว้นว่าผู้ใช้นั้นมีสิทธิ์ใช้งานรูทที่ฉันคาดไว้) นอกจากนี้มันยังกรีดร้องการแฮ็คงาน ;-)

ถ้าคุณต้องการที่จะไม่ยอมใครง่ายๆคุณสามารถขยายได้อย่างชัดเจนในหลาย ๆ วิธีเช่นค้นหาทุกกลุ่มในไฟล์ย่อยใด ๆ หลายเล่ม ฯลฯ


4
นี่เป็นเป้าหมายของการอ่านไฟล์จากวอลลุ่มที่ติดตั้งหรือไม่? ฉันกำลังมองหาวิธีแก้ปัญหาสำหรับการเขียนไฟล์โดยที่พวกเขาไม่ได้เป็นเจ้าของโดยผู้ใช้รายอื่นมากกว่าผู้ที่สร้างคอนเทนเนอร์นักเทียบท่า
ThorSummoner

ฉันใช้วิธีนี้ตั้งแต่ 15 สิงหาคม ทุกอย่างโอเค เพียงสิทธิ์ของไฟล์ที่สร้างขึ้นภายในคอนเทนเนอร์นั้นแตกต่างกัน ทั้งผู้ใช้ (ภายในและภายนอกที่เก็บ) มีกรรมสิทธิ์ของไฟล์ แต่ทั้งคู่มีสิทธิ์เข้าถึงเพื่ออ่านเพราะพวกเขาอยู่ในกลุ่มเดียวกันที่สร้างขึ้นโดยโซลูชันนี้ ปัญหาเริ่มต้นขึ้นเมื่อกรณีการใช้งานได้กำหนดการเข้าถึงเพื่อเขียนไปยังไฟล์ทั่วไป ปัญหาที่ใหญ่กว่าคือปริมาณที่แชร์นั้นมีไฟล์ git (เป็นโวลุ่มเพื่อทดสอบไฟล์ต้นฉบับ dev ในบริบทการผลิตเดียวกัน) Git เริ่มเตือนเกี่ยวกับปัญหาการเข้าถึงรหัสที่ใช้ร่วมกัน
yucer

ฉันคิดว่าดีกว่าสำหรับ grep $TARGET_GIDจะใช้grep ':$TARGET_GID:'มิฉะนั้นถ้าภาชนะที่มีเช่น GID 10001 และโฮสต์ของคุณคือ 1000 ตรวจสอบนี้จะผ่าน แต่มันไม่ควร
robhudson

16

ตกลงตอนนี้มีการติดตามที่ปัญหานักเทียบท่า # 7198

สำหรับตอนนี้ฉันกำลังจัดการเรื่องนี้โดยใช้ตัวเลือกที่สองของคุณ:

แม็พผู้ใช้จากโฮสต์ลงในคอนเทนเนอร์

Dockerfile

#=======
# 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

UPDATEฉันมีแนวโน้มที่จะตอบHamy มากขึ้น


1
ใช้คำสั่งid -u <username>, id -g <username>, id -G <username>ที่จะได้รับรหัสผู้ใช้และรหัสกลุ่มผู้ใช้งานที่เฉพาะเจาะจงแทน
lolski


15
สิ่งนี้จะทำลายคอนเทนเนอร์พกพาข้ามโฮสต์
รามัน

2
ปัญหานักเทียบท่า # 7198 ได้มาถึงข้อสรุปว่าพวกเขาจะไม่ใช้วิธีแก้ปัญหาดั้งเดิมสำหรับเรื่องนี้ ดูความคิดเห็นการตอบกลับของฉันที่github.com/docker/docker/issues/7198#issuecomment-230636074
Quinn Comendant


12

เช่นเดียวกับคุณฉันกำลังมองหาวิธีแมปผู้ใช้ / กลุ่มจากโฮสต์ไปยังคอนเทนเนอร์นักเทียบท่าและนี่เป็นวิธีที่สั้นที่สุดที่ฉันพบ:

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

นี่เป็นสารสกัดจากนักเทียบท่าของฉัน-compose.yml

แนวคิดคือการเมาท์ (ในโหมดอ่านอย่างเดียว) รายการผู้ใช้ / กลุ่มจากโฮสต์ไปยังคอนเทนเนอร์ดังนั้นหลังจากที่คอนเทนเนอร์เริ่มต้นขึ้นจะมีการจับคู่ uid-> ชื่อผู้ใช้ (รวมถึงกลุ่ม) เดียวกันกับโฮสต์ ตอนนี้คุณสามารถกำหนดการตั้งค่าผู้ใช้ / กลุ่มสำหรับบริการของคุณภายในคอนเทนเนอร์ราวกับว่ามันทำงานบนระบบโฮสต์ของคุณ

เมื่อคุณตัดสินใจย้ายคอนเทนเนอร์ไปยังโฮสต์อื่นคุณเพียงแค่เปลี่ยนชื่อผู้ใช้ในไฟล์ config บริการเป็นสิ่งที่คุณมีบนโฮสต์นั้น


นี่เป็นคำตอบที่ยอดเยี่ยมง่ายมากถ้าคุณต้องการเรียกใช้คอนเทนเนอร์ที่จัดการไฟล์บนระบบพื้นฐานโดยไม่ต้องเปิดเผยส่วนที่เหลือของระบบ
icarito

นี่คือคำตอบที่ฉันโปรดปราน นอกจากนี้ฉันเห็นคำแนะนำที่คล้ายกันที่อื่นด้วยคำสั่งเรียกใช้นักเทียบท่าที่คุณส่งผ่านชื่อผู้ใช้ / กลุ่มปัจจุบันของคุณผ่านทาง-u $( id -u $USER ):$( id -g $USER )และคุณไม่ต้องกังวลเกี่ยวกับชื่อผู้ใช้อีกต่อไป สิ่งนี้ทำงานได้ดีสำหรับสภาพแวดล้อม dev ท้องถิ่นที่คุณต้องการสร้างไฟล์ (เช่นไบนารี) ที่คุณมีการเข้าถึงแบบอ่าน / เขียนตามค่าเริ่มต้น
matthewcummings516

5

ต่อไปนี้เป็นวิธีการที่ยังคงใช้คอนเทนเนอร์ข้อมูลเท่านั้น แต่ไม่ต้องการให้ซิงค์กับแอปพลิเคชันคอนเทนเนอร์ (ในแง่ของการมี uid / gid เดียวกัน)

สมมุติว่าคุณต้องการเรียกใช้แอพบางตัวใน container เป็น US $ ที่ไม่ใช่รูทโดยไม่มีเชลล์ล็อกอิน

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

5

เพื่อความปลอดภัยและเปลี่ยนรูทสำหรับคอนเทนเนอร์นักเทียบท่าโฮสต์นักเทียบท่าลองใช้--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

เวอร์ชันอัปเดต1.10.0 (2016-02-04) เพิ่มการ--userns-remapตั้งค่าสถานะ https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2


ฉันใช้นักเทียบท่า 1.3.2 สร้าง 39fa2fa (ล่าสุด) และไม่เห็นร่องรอยของ--uidmapหรือ--private-uidsตัวเลือก ดูเหมือนว่า PR ไม่ได้ทำและไม่ถูกรวมเข้าด้วยกัน
Leo Gallucci

มันไม่ได้รวมอยู่ในคอร์หากคุณต้องการคุณสามารถใช้มันเป็นแพทช์ได้ ตอนนี้มีความเป็นไปได้ที่จะจำกัดความสามารถและเรียกใช้แอปพลิเคชั่นในคอนเทนเนอร์จากผู้ใช้ที่ไม่ใช่รูท
umount

มิถุนายน 2015 และฉันไม่เห็นสิ่งนี้ที่รวมอยู่ในนักเทียบท่า 1.6.2 คำตอบของคุณยังใช้ได้หรือไม่
Leo Gallucci

1
ปัญหายังคงเปิดอยู่ นักพัฒนาควรเพิ่มการสนับสนุนในรุ่น 1.7 (- ตัวเลือกราก) github.com/docker/docker/pull/12648
umount

2
ดูเหมือนว่านักพัฒนาจะย้ายการวางจำหน่ายอีกครั้งด้วยฟังก์ชันนี้ นักพัฒนา Docker "icecrime" พูด"We apparently do have so some of conflicting designs between libnetwork and user namespaces ... and something we'd like to get in for 1.8.0. So don't think we're dropping this, we're definitely going to take a break after all these, and see how we need to reconsider the current design and integration of libnetwork to make this possible. Thanks!" github.com/docker/docker/pull/12648 ดังนั้นฉันคิดว่าเราควรรอรุ่นเสถียรต่อไป
umount

4

แนวทางของฉันคือการตรวจจับ UID / GID ปัจจุบันจากนั้นสร้างผู้ใช้ / กลุ่มดังกล่าวภายในคอนเทนเนอร์และรันสคริปต์ภายใต้เขา ดังนั้นไฟล์ทั้งหมดที่เขาจะสร้างจะตรงกับผู้ใช้บนโฮสต์ (ซึ่งเป็นสคริปต์):

# get 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"

3

ภาพฐาน

ใช้ภาพนี้: 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

4) สร้างด้วย docker

4) วิ่ง!

sh run.sh

0

ในกรณีเฉพาะของฉันฉันพยายามสร้างแพ็คเกจโหนดของฉันด้วยอิมเมจ node docker เพื่อที่ฉันจะได้ไม่ต้องติดตั้ง npm บนเซิร์ฟเวอร์การปรับใช้ มันทำงานได้ดีจนกระทั่งนอกคอนเทนเนอร์และบนเครื่องโฮสต์ฉันพยายามย้ายไฟล์ไปยังไดเร็กทอรี node_modules ที่อิมเมจโหนด docker สร้างขึ้นซึ่งฉันถูกปฏิเสธสิทธิ์เนื่องจากเป็นเจ้าของโดย root ฉันรู้ว่าฉันสามารถแก้ไขได้โดยการคัดลอกไดเรกทอรีออกจากภาชนะไปยังเครื่องโฮสต์ ผ่านเอกสารนักเทียบท่า ...

ไฟล์ที่คัดลอกไปยังเครื่องโลคัลถูกสร้างด้วย UID: GID ของผู้ใช้ซึ่งเรียกใช้คำสั่ง docker cp

นี่คือรหัสทุบตีที่ฉันใช้เพื่อเปลี่ยนความเป็นเจ้าของของไดเรกทอรีที่สร้างโดยและภายในคอนเทนเนอร์นักเทียบท่า

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

0

หากต้องการแชร์โฟลเดอร์ระหว่างโฮสต์นักเทียบท่าและคอนเทนเนอร์นักเทียบท่าลองด้านล่างคำสั่ง

$ นักเทียบท่าวิ่ง -v "$ (pwd): $ (pwd)" -i -t ubuntu

แฟล็ก -v เมาท์ไดเร็กทอรีการทำงานปัจจุบันลงในคอนเทนเนอร์ เมื่อไม่มีไดเรกทอรีโฮสต์ของไดรฟ์ข้อมูลที่ผูกติดนักเทียบท่าจะสร้างไดเรกทอรีนี้โดยอัตโนมัติบนโฮสต์สำหรับคุณ

อย่างไรก็ตามเรามี 2 ปัญหาที่นี่:

  1. คุณไม่สามารถเขียนไปยังไดรฟ์ข้อมูลที่เมาท์หากคุณไม่ใช่ผู้ใช้รูทเพราะไฟล์ที่แชร์จะเป็นของผู้ใช้อื่นในโฮสต์
  2. คุณไม่ควรเรียกใช้กระบวนการภายในคอนเทนเนอร์ของคุณในฐานะรูท แต่แม้ว่าคุณจะเรียกใช้ในฐานะผู้ใช้ที่ใช้รหัสแบบแข็ง แต่ก็ยังไม่ตรงกับผู้ใช้บนแล็ปท็อป / เจนกินส์ของคุณ

สารละลาย:

คอนเทนเนอร์: สร้างผู้ใช้ว่า 'testuser' โดยรหัสผู้ใช้เริ่มต้นจะเริ่มจาก 1,000

โฮสต์: สร้างกลุ่มว่า 'testgroup' ที่มีกลุ่ม id 1000 และ chown ไดเรกทอรีไปยังกลุ่มใหม่ (testgroup


-5

หากคุณใช้ Docker Compose ให้เริ่มต้นคอนเทนเนอร์ในโหมด previleged:

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

2
สิ่งนี้อาจทำให้ติดวอลลุ่มได้ง่ายขึ้น แต่ .. Wordpress เปิดตัวในโหมด Priviledge หรือไม่? นั่นเป็นความคิดที่น่ากลัว - นั่นคือการขอให้ถูกโจมตี wpvulndb.com/wordpresses/453
Colin Harrington
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.