Який сенс WORKDIR у Dockerfile?


106

Я вчу Докер. Я багато разів бачив, що 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

Відповіді:


118

Відповідно до документації :

Інструкція WORKDIR встановлює робочий каталог для будь-яких інструкцій RUN, CMD, ENTRYPOINT, COPY та ADD, які слідують за ним у Dockerfile. Якщо WORKDIR не існує, він буде створений, навіть якщо він не використовується в будь-якій наступній інструкції Dockerfile.

Крім того, в кращих практиках Docker рекомендується використовувати його:

... вам слід використовувати WORKDIR замість поширення таких інструкцій, як RUN CD ... && робити щось, що важко читати, вирішувати проблеми та підтримувати.

Я б запропонував зберегти його.

Я думаю, ви можете переробити свій 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 у зображенні "builder" чи я повинен вважати, що не (і використовую абсолютний шлях)?
Олексій 75

Згідно документації Docker я б сказав , що він зберігає WORKDIRзначення , тому що це RAN інструкції в Dockerfile , перш ніж запустити COPYодин
juanlumn

Ваша RUN mkdirкоманда не потрібна; тобто цей рядок можна видалити. Згідно з документацією "Якщо WORKDIR не існує, він буде створений, навіть якщо він не використовується в будь-якій наступній інструкції Dockerfile." - docs.docker.com/engine/reference/builder/#workdir
Purplejacket

@Purplejacket це правильно, я
оновлю

60

Ви не повинні

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/isissue/20295
Joe Bowbeer

24
Мені подобається те, що ви вказали, що WORKDIR створить папку автоматично.
GingerBeer

32

Ви можете думати WORKDIRяк про cdвнутрішній контейнер (це впливає на команди, які надходять пізніше в Dockerfile, як RUNкоманда). Якщо ви видалили WORKDIRу своєму прикладі вище, RUN npm installце не працюватиме, оскільки ви не знаходитесь в /usr/src/appкаталозі всередині контейнера.

Я не бачу, як це буде пов’язано з тим, куди ви поставите Dockerfile (оскільки ваше розташування Dockerfile на хост-машині не має нічого спільного з pwd всередині контейнера). Ви можете розмістити Dockerfile куди завгодно у своєму проекті. Однак перший аргумент до COPY- відносний шлях, тому, якщо ви перемістите Dockerfile, можливо, вам доведеться оновити ці COPYкоманди.


3
Якщо WORKDIRдодає подобається cd, чи не будуть двоє COPYв оригінальному прикладі однакового джерела та місця призначення?
Йонас Розенквіст

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, оскільки це призвело б до кореня контейнера
Тимофій c

1

Остерігайтеся використання vars як цільової назви каталогів для WORKDIRтого, що, як видається, призводить до фатальної помилки "нічого не може нормалізувати". IMO, також варто зазначити, що він WORKDIRведе себе так само, як mkdir -p <path>тобто всі елементи шляху створюються, якщо вони вже не існують.

ОНОВЛЕННЯ: Під час виконання багатоступеневої збірки я зіткнувся з проблемою, пов'язаною зі змінною - тепер, здається, нормально використовувати змінну - якщо вона (змінна) "в області", наприклад, у наступному, 2-е WORKDIRпосилання не вдається ...

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або будь-яку віддалену окружність, яку роблять під час налаштування.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.