301

I'm learning Docker. For many times I've seen that Dockerfile has WORKDIR command:

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

Can't I just omit WORKDIR and Copy and just have my Dockerfile at the root of my project? What are the downsides of using this approach?

ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
Le garcon
  • 7,197
  • 9
  • 31
  • 46

7 Answers7

299

According to the documentation:

The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile. If the WORKDIR doesn’t exist, it will be created even if it’s not used in any subsequent Dockerfile instruction.

Also, in the Docker best practices it recommends you to use it:

... you should use WORKDIR instead of proliferating instructions like RUN cd … && do-something, which are hard to read, troubleshoot, and maintain.

I would suggest to keep it.

I think you can refactor your Dockerfile to something like:

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ "npm", "start" ] 
Community
  • 1
  • 1
juanlumn
  • 6,155
  • 2
  • 30
  • 39
  • 4
    @MarioGil Please take a look into [the COPY documentation.](https://docs.docker.com/engine/reference/builder/#copy) – juanlumn May 16 '19 at 07:42
  • 2
    When I use ``FROM ubuntu as builder`` and then the successive image use ``COPY``, does it "know" I used WORKDIR in the "builder" image or I have to assume not (and use an absolute path) ? – Alex 75 Jan 01 '20 at 18:19
  • 1
    According to the [docker documentation](https://docs.docker.com/develop/develop-images/multistage-build/) I would say that it keeps the `WORKDIR` value because is an instruction ran in the Dockerfile before you run the `COPY` one – juanlumn Jan 02 '20 at 10:02
  • @Alex75 it does not. I have just tried it and it's not working. I'm still troubleshooting the issue. Also, the examples in the docs show code being copied from the root folder; I'll stick with absolute paths for now – José Henrique Feb 08 '22 at 14:23
  • would `RUN mkdir -p ~/new_folder` work? how do I use the working dir name to run docker commands in the docker file now? – Charlie Parker Jul 21 '22 at 18:41
  • @charlie-parker you should use just WORKDIR your_path, no RUN mkdir ... command – Leontsev Anton Mar 05 '23 at 16:06
117

You dont have to

RUN mkdir -p /usr/src/app

This will be created automatically when you specifiy your WORKDIR

FROM node:latest
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . ./
EXPOSE 3000
CMD [ “npm”, “start” ] 
0xsegfault
  • 2,899
  • 6
  • 28
  • 58
  • 8
    However, sometimes RUN mkdir is needed because WORKDIR doesn’t respect USER when creating directories - https://github.com/moby/moby/issues/20295 – Joe Bowbeer Nov 14 '18 at 08:19
  • 55
    I like the fact that you specified WORKDIR will create the folder automatically. – GingerBeer Dec 13 '18 at 10:16
80

You can think of WORKDIR like a cd inside the container (it affects commands that come later in the Dockerfile, like the RUN command). If you removed WORKDIR in your example above, RUN npm install wouldn't work because you would not be in the /usr/src/app directory inside your container.

I don't see how this would be related to where you put your Dockerfile (since your Dockerfile location on the host machine has nothing to do with the pwd inside the container). You can put the Dockerfile wherever you'd like in your project. However, the first argument to COPY is a relative path, so if you move your Dockerfile you may need to update those COPY commands.

mkasberg
  • 16,022
  • 3
  • 42
  • 46
  • 5
    If `WORKDIR` adds like `cd`, won't the two `COPY` in the original example have the same source and destination? – Jonas Rosenqvist Oct 24 '18 at 13:57
  • 25
    No. `WORKDIR` affects the working directory _inside the container_. In the original example, the first `COPY` copies from `package.json` _on the host_ (relative path to the Dockerfile) to `/usr/src/app/package.json` _in the container_. In fact, the `WORKDIR` has no impact on that particular command because the destination (inside the container) is not using a relative path (the path starts with `/`). – mkasberg Oct 25 '18 at 23:11
  • 5
    @mkasberg If `WORKDIR` acts like a `cd`. So does the 2 snippets below equivalent? `WORKDIR /usr/src/app` `COPY package.json /usr/src/app/` and `WORKDIR /usr/src/app` `COPY package.json .` Thanks – harry Nov 20 '18 at 15:12
  • 5
    Yes, those are equivalent. – mkasberg Nov 20 '18 at 15:32
  • 3
    I feel like Derek Zoolander saying, "*IN* the [Docker Container]!" O.o I get it now. Not relevant to the dev environment... only relevant to the runtime inside the Docker container. Got it. But... can it just be the root (i.e. "/")? – 4Z4T4R Feb 21 '21 at 02:04
  • 2
    Yes, you can do `WORKDIR /` and your workdir will be the root. However, it's very unusual to add non-standard folders in the root directory and it would also be a bit unusual to make that your workdir. So typically, you'd want to do use something like `/app`, `/root/app`, `/opt/app`, or `/usr/src/app` like the above example and copy your apps files to that location in the container and then build and run your app from there (in the container). So `WORKDIR /` is allowed but uncommon. – mkasberg Feb 21 '21 at 23:49
  • is the work directory present inside the container itself? or is it created on the OS? e.g if my docker file path is /path/to/dockerfile , will the work directory path be /path/to/dockerfile/usr/src/app ? or will it be simply /usr/src/app? – Altair21 Oct 10 '21 at 11:38
  • Simply `/usr/src/app`. It's a path inside the container. – mkasberg Oct 10 '21 at 14:01
  • To be clear, WORKDIR affects the working directory in the (current) build container, which is not necessarily the same as the (final) container built by the image created by the Dockerfile. – ryanwebjackson Jun 30 '22 at 15:40
  • what is the point of adding this extra dir? If it is only inside the container is it not just excess dirs? – Simon Chemnitz-Thomsen Aug 29 '22 at 09:59
10

Before applying WORKDIR. Here the WORKDIR is at the wrong place and is not used wisely.

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

We corrected the above code to put WORKDIR at the right location and optimised the following statements by removing /Publish

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

So it acts like a cd and sets the tone for the upcoming statements.

Blue Clouds
  • 7,295
  • 4
  • 71
  • 112
5

The answer by @juanlumn is great, but I wanted to add one more (important) thing.

In regular command line, if you cd somewhere, it stays there until you change it. However, in a Dockerfile, each RUN command starts back at the root directory! That's a gotcha for docker newbies, and something to be aware of.

So not only does WORKDIR make a more obvious visual cue to someone reading your code, but it also keeps the working directory for more than just the one RUN command.

stevec
  • 41,291
  • 27
  • 223
  • 311
1

Beware of using vars as the target directory name for WORKDIR - doing that appears to result in a "cannot normalize nothing" fatal error. IMO, it's also worth pointing out that WORKDIR behaves in the same way as mkdir -p <path> i.e. all elements of the path are created if they don't exist already.

UPDATE: I encountered the variable related problem (mentioned above) whilst running a multi-stage build - it now appears that using a variable is fine - if it (the variable) is "in scope" e.g. in the following, the 2nd WORKDIR reference fails ...

FROM <some image>
ENV varname varval
WORKDIR $varname

FROM <some other image>
WORKDIR $varname

whereas, it succeeds in this ...

FROM <some image>
ENV varname varval
WORKDIR $varname

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

.oO(Maybe it's in the docs & I've missed it)

  • 1
    If you put your `ENV` values before the first `FROM`, I believe they are in scope for all `FROM` sections. – ErikE Sep 11 '21 at 03:17
0

Be careful where you set WORKDIR because it can affect the continuous integration flow. For example, setting it to /home/circleci/project will cause error something like .ssh or whatever is the remote circleci is doing at setup time.

daparic
  • 3,794
  • 2
  • 36
  • 38