Điểm của WORKDIR trên Dockerfile là gì?


105

Tôi đang học Docker. Trong nhiều lần tôi đã thấy điều đóDockerfileWORKDIRlệnh:

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” ] 

Tôi không thể bỏ qua WORKDIRCopychỉ có Dockerfileở gốc của dự án của tôi? Nhược điểm của việc sử dụng phương pháp này là gì?


Tại build khi bạn thay đổi thư mục bằng cáchWORKDIR
cực tím

1
@Ultraviolet, bạn có thể vui lòng giải thích điều này. Tôi không hoàn toàn nhận được điểm
Lê Garcon

Câu trả lời:


118

Theo tài liệu :

Lệnh WORKDIR đặt thư mục làm việc cho bất kỳ lệnh RUN, CMD, ENTRYPOINT, COPY và ADD nào theo sau nó trong Dockerfile. Nếu WORKDIR không tồn tại, nó sẽ được tạo ngay cả khi nó không được sử dụng trong bất kỳ lệnh Dockerfile nào tiếp theo.

Ngoài ra, trong các phương pháp hay nhất của Docker, nó khuyên bạn nên sử dụng nó:

... bạn nên sử dụng WORKDIR thay vì các hướng dẫn phổ biến như RUN cd… && do-something khó đọc, khắc phục sự cố và duy trì.

Tôi sẽ đề nghị giữ nó.

Tôi nghĩ bạn có thể cấu trúc lại tệp Dockerfile của mình thành một cái gì đó như:

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

2
@MarioGil Vui lòng xem qua tài liệu COPY.
'19

1
Khi tôi sử dụng FROM ubuntu as buildervà sau đó sử dụng hình ảnh kế tiếp COPY, nó có "biết" tôi đã sử dụng WORKDIR trong hình ảnh "người xây dựng" hay tôi phải giả sử là không (và sử dụng đường dẫn tuyệt đối)?
Alex 75

Theo tài liệu Docker tôi sẽ nói rằng nó giữ các WORKDIRgiá trị vì là một ran hướng dẫn trong Dockerfile trước khi bạn chạy COPYmột
juanlumn

RUN mkdirLệnh của bạn là không cần thiết; tức là, dòng đó có thể bị xóa. Theo tài liệu "Nếu WORKDIR không tồn tại, nó sẽ được tạo ngay cả khi nó không được sử dụng trong bất kỳ hướng dẫn Dockerfile nào tiếp theo." - docs.docker.com/engine/reference/builder/#workdir
Purplejacket

@Purplejacket đó là chính xác, tôi sẽ cập nhật câu trả lời
juanlumn

59

Bạn không cần phải

RUN mkdir -p /usr/src/app

Điều này sẽ được tạo tự động khi bạn xác định WORKDIR

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

4
Tuy nhiên, đôi khi CHẠY mkdir là cần thiết vì workdir không tôn trọng USER khi tạo thư mục - github.com/moby/moby/issues/20295
Joe Bowbeer

22
Tôi thích thực tế là bạn đã chỉ định WORKDIR sẽ tự động tạo thư mục.
GingerBeer

32

Bạn có thể nghĩ WORKDIRgiống như một cdbên trong vùng chứa (nó ảnh hưởng đến các lệnh sau này trong Dockerfile, như RUNlệnh). Nếu bạn đã xóa WORKDIRtrong ví dụ trên, RUN npm installsẽ không hoạt động vì bạn sẽ không ở trong /usr/src/appthư mục bên trong vùng chứa của mình.

Tôi không hiểu điều này sẽ liên quan như thế nào đến nơi bạn đặt Dockerfile của mình (vì vị trí Dockerfile của bạn trên máy chủ không liên quan gì đến pwd bên trong vùng chứa). Bạn có thể đặt Dockerfile ở bất cứ đâu bạn muốn trong dự án của mình. Tuy nhiên, đối số đầu tiên COPYlà một đường dẫn tương đối, vì vậy nếu bạn di chuyển Dockerfile của mình, bạn có thể cần cập nhật các COPYlệnh đó.


3
Nếu WORKDIRthêm like cd, hai cái COPYtrong ví dụ ban đầu sẽ không có cùng nguồn và đích sao?
Jonas Rosenqvist

5
Không. Ảnh WORKDIRhưởng đến thư mục làm việc bên trong vùng chứa . Trong ví dụ ban đầu, các COPYbản sao đầu tiên từ package.json máy chủ lưu trữ (đường dẫn tương đối đến Dockerfile) đến /usr/src/app/package.json trong vùng chứa . Trên thực tế, lệnh WORKDIRkhông có tác động đến lệnh cụ thể đó vì đích (bên trong vùng chứa) không sử dụng một đường dẫn tương đối (đường dẫn bắt đầu bằng /).
mkasberg

@mkasberg Nếu WORKDIRhoạt động như a cd. Vậy 2 đoạn mã dưới đây có tương đương nhau không? WORKDIR /usr/src/app COPY package.json /usr/src/app/WORKDIR /usr/src/app COPY package.json . cám ơn
kcatstack

1
Vâng, đó là những thứ tương đương.
mkasberg

1

Trước khi áp dụng WORKDIR. Ở đây, WORKDIR không đúng chỗ và không được sử dụng một cách khôn ngoan.

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

Chúng tôi đã sửa mã ở trên để đặt WORKDIR vào đúng vị trí và tối ưu hóa các câu lệnh sau bằng cách xóa /Publish

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

1
Bạn không cần phải có trước mặt slash của api.dll như mà có con đường nó vào thư mục gốc của container
Timothy c

1

Hãy cẩn thận khi sử dụng vars làm tên thư mục đích WORKDIR- việc làm đó dường như dẫn đến lỗi nghiêm trọng "không thể chuẩn hóa không có gì". IMO, cũng cần chỉ ra rằng WORKDIRhoạt động theo cách giống như mkdir -p <path>tất cả các phần tử của đường dẫn được tạo nếu chúng chưa tồn tại.

CẬP NHẬT: Tôi đã gặp sự cố liên quan đến biến (đã đề cập ở trên) khi đang chạy một bản dựng nhiều giai đoạn - hiện tại có vẻ như việc sử dụng một biến là ổn - nếu nó (biến) ở "trong phạm vi", ví dụ như sau, WORKDIRtham chiếu thứ 2 không thành công ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

ngược lại, nó thành công trong việc này ...

FROM <some image>
ENV varname varval
WORKDIR $varname

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

.oO ( Có thể nó nằm trong tài liệu và tôi đã bỏ lỡ nó )


0

Hãy cẩn thận nơi bạn đặt WORKDIRvì nó có thể ảnh hưởng đến quy trình tích hợp liên tục. Ví dụ, đặt nó thành /home/circleci/projectsẽ gây ra lỗi gì đó giống như .sshhoặc bất cứ điều gì mà vòng tròn từ xa đang làm tại thời điểm thiết lập.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.