WORKDIR บน Dockerfile คืออะไร?


115

ฉันกำลังเรียนรู้ Docker หลายครั้งที่ฉันเห็นว่าDockerfileมีWORKDIRคำสั่ง:

FROM node:latest
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/
RUN npm install
COPY . /usr/src/app
EXPOSE 3000
CMD [ “npm”, “start” ] 

ฉันไม่สามารถละเว้นWORKDIRและCopyมีเพียงแค่Dockerfileรากของโครงการของฉันได้หรือไม่? อะไรคือข้อเสียของการใช้แนวทางนี้?


ในเวลาสร้างคุณจะเปลี่ยนไดเรกทอรีโดยWORKDIR
Ultraviolet

1
@Ultraviolet คุณช่วยอธิบายเรื่องนี้ได้ไหม ฉันไม่ค่อยเข้าใจ
Le garcon

คำตอบ:


125

ตามเอกสาร :

คำสั่ง WORKDIR ตั้งค่าไดเร็กทอรีการทำงานสำหรับคำสั่ง RUN, CMD, ENTRYPOINT, COPY และ ADD ใด ๆ ที่ตามมาใน Dockerfile หากไม่มี WORKDIR จะสร้างขึ้นแม้ว่าจะไม่ได้ใช้ในคำสั่ง Dockerfile ที่ตามมาก็ตาม

นอกจากนี้ในแนวทางปฏิบัติที่ดีที่สุดของ Dockerแนะนำให้คุณใช้:

... คุณควรใช้ WORKDIR แทนคำแนะนำที่แพร่หลายเช่น RUN cd … && do-something ซึ่งยากต่อการอ่านแก้ไขปัญหาและดูแลรักษา

ผมขอแนะนำให้เก็บไว้

ฉันคิดว่าคุณสามารถ refactor Dockerfile ของคุณเป็น:

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 

2
@MarioGil โปรดดูเอกสาร COPY
juanlumn

1
เมื่อฉันใช้FROM ubuntu as builderแล้วใช้รูปภาพต่อเนื่องCOPY"รู้" หรือไม่ว่าฉันใช้ WORKDIR ในอิมเมจ "ตัวสร้าง" หรือฉันต้องถือว่าไม่ (และใช้เส้นทางสัมบูรณ์)
Alex 75

อ้างอิงถึงเอกสารนักเทียบท่าที่ผมจะบอกว่ามันช่วยให้WORKDIRคุ้มค่าเพราะเป็นคำสั่งที่วิ่งใน Dockerfile ก่อนที่คุณจะเรียกใช้COPYอย่างใดอย่างหนึ่ง
juanlumn

RUN mkdirคำสั่งของคุณไม่จำเป็น กล่าวคือสามารถลบบรรทัดนั้นได้ ตามเอกสารประกอบ "หากไม่มี WORKDIR จะถูกสร้างขึ้นแม้ว่าจะไม่ได้ใช้ในคำสั่ง Dockerfile ที่ตามมาก็ตาม" - docs.docker.com/engine/reference/builder/#workdir
Purplejacket

@Purplejacket ถูกต้องฉันจะอัปเดตคำตอบ
juanlumn

61

คุณไม่จำเป็นต้องทำ

RUN mkdir -p /usr/src/app

สิ่งนี้จะถูกสร้างขึ้นโดยอัตโนมัติเมื่อคุณระบุไฟล์ WORKDIR

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 

4
อย่างไรก็ตามบางครั้งต้องใช้ RUN mkdir เนื่องจาก WORKDIR ไม่เคารพ USER เมื่อสร้างไดเรกทอรี - github.com/moby/moby/issues/20295
Joe Bowbeer

24
ฉันชอบที่คุณระบุว่า WORKDIR จะสร้างโฟลเดอร์โดยอัตโนมัติ
GingerBeer

33

คุณสามารถคิดว่าWORKDIRเป็นcdภายในคอนเทนเนอร์ (มีผลต่อคำสั่งที่มาในภายหลังใน Dockerfile เช่นRUNคำสั่ง) หากคุณลบออกWORKDIRในตัวอย่างข้างต้นRUN npm installจะใช้ไม่ได้เพราะคุณจะไม่อยู่ใน/usr/src/appไดเร็กทอรีภายในคอนเทนเนอร์ของคุณ

ฉันไม่เห็นว่าสิ่งนี้จะเกี่ยวข้องกับตำแหน่งที่คุณใส่ Dockerfile ของคุณอย่างไร (เนื่องจากตำแหน่ง Dockerfile ของคุณบนเครื่องโฮสต์ไม่มีส่วนเกี่ยวข้องกับ pwd ภายในคอนเทนเนอร์) คุณสามารถวาง Dockerfile ได้ทุกที่ที่คุณต้องการในโปรเจ็กต์ของคุณ อย่างไรก็ตามอาร์กิวเมนต์แรกCOPYเป็นพา ธ สัมพัทธ์ดังนั้นหากคุณย้าย Dockerfile คุณอาจต้องอัปเดตCOPYคำสั่งเหล่านั้น


3
ถ้าWORKDIRเพิ่มเช่นcdทั้งสองCOPYในตัวอย่างเดิมจะไม่มีต้นทางและปลายทางเดียวกันหรือไม่
Jonas Rosenqvist

5
ฉบับที่WORKDIRมีผลกระทบต่อไดเรกทอรีการทำงานภายในภาชนะ ในตัวอย่างเดิมเป็นครั้งแรกCOPYสำเนาจากpackage.json บนโฮสต์ (เส้นทางเทียบกับ Dockerfile) ไปในภาชนะที่/usr/src/app/package.json ในความเป็นจริงWORKDIRคำสั่งนั้นไม่มีผลกระทบใด ๆ เนื่องจากปลายทาง (ภายในคอนเทนเนอร์) ไม่ได้ใช้เส้นทางสัมพัทธ์ (เส้นทางเริ่มต้นด้วย/)
mkasberg

@mkasberg ถ้าWORKDIRทำหน้าที่เหมือนไฟล์cd. ตัวอย่างข้อมูล 2 รายการด้านล่างเท่ากันหรือไม่ WORKDIR /usr/src/app COPY package.json /usr/src/app/และ WORKDIR /usr/src/app COPY package.json . ขอบคุณ
kcatstack

1
ใช่สิ่งเหล่านี้เทียบเท่า
mkasberg

1

ก่อนสมัคร WORKDIR ที่นี่ WORKDIR อยู่ผิดที่และไม่ได้ใช้อย่างชาญฉลาด

FROM microsoft/aspnetcore:2
COPY --from=build-env /publish /publish
WORKDIR /publish
ENTRYPOINT ["dotnet", "/publish/api.dll"]

เราแก้ไขโค้ดด้านบนเพื่อวาง WORKDIR ในตำแหน่งที่ถูกต้องและเพิ่มประสิทธิภาพข้อความต่อไปนี้โดยการลบ /Publish

FROM microsoft/aspnetcore:2
WORKDIR /publish
COPY --from=build-env /publish .
ENTRYPOINT ["dotnet", "/api.dll"]

1
คุณไม่ควรมีเครื่องหมายทับของ api.dll เนื่องจากจะพามันไปยังรูทของคอนเทนเนอร์
ทิโมธีค

1

ระวังการใช้ vars เป็นชื่อไดเร็กทอรีเป้าหมายสำหรับWORKDIR- การทำเช่นนั้นจะส่งผลให้เกิดข้อผิดพลาดร้ายแรง "ไม่สามารถทำให้เป็นปกติได้" IMO นอกจากนี้ยังควรชี้ให้เห็นว่าWORKDIRทำงานในลักษณะเดียวกับmkdir -p <path>กล่าวคือองค์ประกอบทั้งหมดของเส้นทางจะถูกสร้างขึ้นหากไม่มีอยู่แล้ว

อัปเดต: ฉันพบปัญหาที่เกี่ยวข้องกับตัวแปร (ดังกล่าวข้างต้น) ในขณะที่เรียกใช้งานบิวด์หลายขั้นตอน - ตอนนี้ดูเหมือนว่าการใช้ตัวแปรนั้นใช้ได้ - ถ้า (ตัวแปร) เป็น "ในขอบเขต" เช่นในต่อไปนี้การWORKDIRอ้างอิงครั้งที่ 2 จะล้มเหลว ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

ในขณะที่มันประสบความสำเร็จในสิ่งนี้ ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
ENV varname varval
WORKDIR $varname

.oO ( อาจจะอยู่ในเอกสารและฉันพลาดไปแล้ว )


0

โปรดระวังตำแหน่งที่คุณตั้งไว้WORKDIRเนื่องจากอาจส่งผลต่อโฟลว์การรวมที่ต่อเนื่อง ตัวอย่างเช่นการตั้งค่าเป็น/home/circleci/projectจะทำให้เกิดข้อผิดพลาดบางอย่างเช่น.sshหรือสิ่งใดก็ตามที่ Circleci ระยะไกลกำลังทำในเวลาตั้งค่า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.