Apa gunanya WORKDIR di Dockerfile?

108

Saya belajar Docker. Untuk banyak kali saya telah melihat yang Dockerfilememiliki WORKDIRperintah:

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

Tidak bisakah saya mengabaikan WORKDIRdan Copydan hanya memiliki Dockerfileakar proyek saya? Apa kerugian menggunakan pendekatan ini?

Le garcon
sumber
Pada waktu pembuatan Anda mengubah direktori denganWORKDIR
Ultraviolet
1
@Ultraviolet bisakah Anda menjelaskan ini. Saya tidak mengerti maksudnya
Le garcon

Jawaban:

119

Menurut dokumentasi :

Instruksi WORKDIR mengatur direktori kerja untuk instruksi RUN, CMD, ENTRYPOINT, COPY dan ADD yang mengikutinya di Dockerfile. Jika WORKDIR tidak ada, itu akan dibuat meskipun tidak digunakan dalam instruksi Dockerfile berikutnya.

Selain itu, dalam praktik terbaik Docker , Anda disarankan untuk menggunakannya:

... Anda harus menggunakan WORKDIR daripada menyebarkan instruksi seperti RUN cd… && do-something, yang sulit dibaca, dipecahkan, dan dipelihara.

Saya akan menyarankan untuk menyimpannya.

Saya pikir Anda dapat merefaktor Dockerfile Anda menjadi seperti:

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
juanlumn
sumber
2
@MarioGil Silakan lihat dokumentasi COPY.
juanlumn
1
Ketika saya menggunakan FROM ubuntu as builderdan kemudian menggunakan gambar yang berurutan COPY, apakah "tahu" saya menggunakan WORKDIR dalam gambar "pembuat" atau saya harus menganggap tidak (dan menggunakan jalur absolut)?
Alex 75
Menurut dokumentasi buruh pelabuhan saya akan mengatakan bahwa itu membuat WORKDIRnilai karena merupakan berlari instruksi dalam Dockerfile sebelum Anda menjalankan COPYsatu
juanlumn
RUN mkdirPerintah Anda tidak perlu; yaitu, baris itu bisa dihapus. Sesuai dokumentasi "Jika WORKDIR tidak ada, itu akan dibuat meskipun tidak digunakan dalam instruksi Dockerfile berikutnya." - docs.docker.com/engine/reference/builder/#workdir
Purplejacket
@Purplejacket itu benar, saya akan memperbarui jawabannya
juanlumn
60

Anda tidak perlu melakukannya

RUN mkdir -p /usr/src/app

Ini akan dibuat secara otomatis saat Anda menentukan WORKDIR

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
Samuel Dare
sumber
4
Namun, terkadang RUN mkdir diperlukan karena WORKDIR tidak menghormati PENGGUNA saat membuat direktori - github.com/moby/moby/issues/20295
Joe Bowbeer
24
Saya suka fakta bahwa WORKDIR yang Anda tentukan akan membuat folder secara otomatis.
GingerBeer
32

Anda dapat menganggapnya WORKDIRseperti cddi dalam container (ini memengaruhi perintah yang datang nanti di Dockerfile, seperti RUNperintah). Jika Anda menghapus WORKDIRdalam contoh Anda di atas, RUN npm installtidak akan berfungsi karena Anda tidak akan berada di /usr/src/appdirektori di dalam penampung Anda.

Saya tidak melihat bagaimana ini akan terkait dengan tempat Anda meletakkan Dockerfile Anda (karena lokasi Dockerfile Anda di mesin host tidak ada hubungannya dengan pwd di dalam wadah). Anda dapat meletakkan Dockerfile di mana pun Anda suka dalam proyek Anda. Namun, argumen pertama ke COPYadalah jalur relatif, jadi jika Anda memindahkan Dockerfile, Anda mungkin perlu memperbarui COPYperintah tersebut.

mkasberg.dll
sumber
3
Jika WORKDIRmenambahkan suka cd, bukankah keduanya COPYdalam contoh asli memiliki sumber dan tujuan yang sama?
Jonas Rosenqvist
5
Tidak. WORKDIRMemengaruhi direktori kerja di dalam penampung . Dalam contoh asli, COPYsalinan pertama dari package.json pada host (jalur relatif ke Dockerfile) ke /usr/src/app/package.json dalam penampung . Faktanya, WORKDIRtidak berdampak pada perintah tertentu itu karena tujuan (di dalam penampung) tidak menggunakan jalur relatif (jalur dimulai dengan /).
mkasberg
@mkasberg Jika WORKDIRbertindak seperti a cd. Jadi, apakah 2 cuplikan di bawah ini setara? WORKDIR /usr/src/app COPY package.json /usr/src/app/dan WORKDIR /usr/src/app COPY package.json . Terima kasih
kcatstack
1
Ya, itu setara.
mkasberg
1

Sebelum menerapkan WORKDIR. Di sini WORKDIR berada di tempat yang salah dan tidak digunakan dengan bijak.

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

Kami mengoreksi kode di atas untuk menempatkan WORKDIR di lokasi yang benar dan mengoptimalkan pernyataan berikut dengan menghapus /Publish

FROM microsoft/aspnetcore:2
WORKDIR /publish
COPY --from=build-env /publish .
ENTRYPOINT ["dotnet", "/api.dll"]
Awan Biru
sumber
1
Anda tidak boleh memiliki garis miring di depan api.dll karena itu akan mengarahkannya ke akar wadah
Timothy c
1

Berhati-hatilah menggunakan vars sebagai nama direktori target WORKDIR- melakukan hal itu tampaknya menghasilkan kesalahan fatal "tidak dapat menormalkan apa pun". IMO, juga perlu ditunjukkan bahwa WORKDIRberperilaku dengan cara yang sama seperti mkdir -p <path>yaitu semua elemen dari jalur dibuat jika belum ada.

PEMBARUAN: Saya mengalami masalah terkait variabel (disebutkan di atas) saat menjalankan build multi-tahap - sekarang tampaknya menggunakan variabel tidak masalah - jika (variabel) berada "dalam cakupan" misalnya berikut ini, WORKDIRreferensi ke-2 gagal ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

sedangkan, berhasil dalam ini ...

FROM <some image>
ENV varname varval
WORKDIR $varname

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

.oO ( Mungkin ada di dokumen & saya melewatkannya )

David Pointon
sumber
0

Berhati-hatilah saat Anda menyetelnya WORKDIRkarena dapat memengaruhi aliran integrasi berkelanjutan. Misalnya, mengaturnya ke /home/circleci/projectakan menyebabkan kesalahan seperti .sshatau apa pun yang dilakukan oleh remote pada saat pengaturan.

kebenaranadjustr
sumber