# Dockerfile

A declarative setup file with steps of instructions for the Image.

{% hint style="info" %}
*By default an Image starts from a blank image, but most of the time you will start from another base image.*
{% endhint %}

## Syntax Example

{% code title="Dockerfile" %}

```docker
FROM image:lastest
RUN command
EXPOSE 8000
```

{% endcode %}

### Working with multiple Dockerfiles

If necessary when creating multiple containers, you can create multiple Dockerfiles in the same folder like.

```
/dockerfiles
├── php.dockerfile
├── nginx.dockerfile
├── mysql.dockerfile
└── ...
```

Or one folder per Dockerfile.

```
/php
└── Dockerfile
/nginx
└── Dockerfile
/mysql
└── Dockerfile
```

## [Building the Image](https://docs.docker.com/reference/cli/docker/buildx/build/)

`docker build [OPTIONS] (Path | Url | -)`

{% code title="Ex.:" %}

```bash
docker build -t "your-image-name" .
```

{% endcode %}

<table><thead><tr><th width="189">Flag</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://docs.docker.com/reference/cli/docker/buildx/build/#annotation"><code>--annotation</code></a></td><td>Add annotation to the image.</td></tr><tr><td><code>--build-arg</code></td><td>Overwrite or set <code>ARG</code> values.</td></tr><tr><td><a href="https://docs.docker.com/reference/cli/docker/buildx/build/#file"><code>-f</code></a> or <a href="https://docs.docker.com/reference/cli/docker/buildx/build/#file"><code>--file</code></a></td><td>The name of the Dockerfile. (default: <code>PATH/Dockerfile</code>)</td></tr><tr><td><code>--no-cache</code></td><td>Don't use cache when building the Image.</td></tr><tr><td><code>-o</code> or <code>--output</code></td><td>Output destination. (format: <code>type=local,dest=path</code>)</td></tr><tr><td><code>-t</code> or <code>--tag</code></td><td>Name and optionally a tag (format: <code>name:tag</code>)</td></tr></tbody></table>

## Dockerfile Commands

{% embed url="<https://docs.docker.com/reference/dockerfile/>" %}
CLI commands
{% endembed %}

### [`ARG`](https://docs.docker.com/reference/dockerfile/#arg)

Set `<varname>=<value>` pairs that will be available:

* During ONLY at **build stages**.
* In Dockerfile as soon as you define them through `ARG` instructions.

Defines variables to be used ONLY at build-time. So they are accessable to the Dockerfile and `docker build`.

{% hint style="info" %}
`ARG`s are useful for variables that should be used or changed at build-time, and that should not be persisted after the image was build.
{% endhint %}

{% hint style="danger" %}
`ARG` values can be inspected with `docker history` on an Image.

**For this reason it is not recommended to use them for credentials, secrets or sensitive data, if untrusted users have access to the Image.**
{% endhint %}

| Forms                   |
| ----------------------- |
| `ARG <varname>=<value>` |

#### Not accessible at run-time, what it means in practice

This means that these variables are not accessible inside running containers.

But it also means that `CMD` and `ENTRYPOINT` instructions won't see these values by default.

#### Default \<value>

You can define these variables without value, and expect the value inline at `docker build`. If not provided Docker will generate an error.

```docker
ARG USERNAME
```

You may also specify default values for these variables.

```docker
ARG USERNAME="user"
```

#### Access the `ARG` values within the Dockerfile

Access with `$` or `${}`.

```docker
ARG USERNAME="user"
USER $USERNAME
# OR
ARG VALUE="development"
RUN echo "The value is $VALUE"

# Using ARG to supply build only data for ENV
ARG NODE_ENV_VALUE="development"
ENV NODE_ENV=$NODE_ENV_VALUE
```

#### Overwriting \<value>

You can overwrite values from an inline `docker build --build-arg <varname>=<value>`.

### [`ADD`](https://docs.docker.com/reference/dockerfile/#add)

Copies new files or folders from the `SOURCE` and adds them to the filesystem of the image at `DEST`.

{% hint style="info" %}
Allows you to copy files from remote URL, or GIT repositories. `ADD` **is ideal for remote file copy**.

Also if files are TAR files, they are automatically decompressed.
{% endhint %}

<table><thead><tr><th width="405">Forms</th><th>Description</th></tr></thead><tbody><tr><td><code>ADD [OPTIONS] ...SOURCE DEST</code></td><td></td></tr><tr><td><code>ADD [OPTIONS] [...SOURCE, DEST]</code></td><td>Required for paths with whitespace.</td></tr></tbody></table>

If multiple source files are specified, the last argument must be a `DEST`, with a trailing `/`.

#### Trailing `/` at `DEST`

If the destination has a trailing `/`, the file or folder is copied **inside** this path.

If the destination doesn't have, the file or folder is copied **beside** the path.

#### `DEST` path

Destinations that begin with `/`, are considered absolute paths.

Destinations without `/` at the start, are considered relative to the working directory.

### [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd)

Run variable commands when running a container from an image.

* It doesn't run on build time, only specify intended commands for the image.

{% hint style="info" %}
If more than one CMD is specified, **ONLY** the **LAST** one takes effect.
{% endhint %}

{% hint style="info" %}
`CMD` can specify only params *(The 2° form)*, if there is an `ENTRYPOINT` command specified before. Both `CMD` and `ENTRYPOINT` **must be** in *Exec form*.
{% endhint %}

{% hint style="danger" %}
Inline specified `COMMAND` on a `docker run` **WILL** overwrite the `CMD` of the Dockerfile.
{% endhint %}

<table><thead><tr><th width="405">Forms</th><th>Description</th></tr></thead><tbody><tr><td><code>CMD ["executable","param1","param2"]</code></td><td>Exec form as Array.</td></tr><tr><td><code>CMD ["param1","param2"]</code></td><td>As default params for a previous <code>ENTRYPOINT</code>.</td></tr><tr><td><code>CMD command param1 param2</code></td><td>Shell form as string.</td></tr></tbody></table>

### [`COPY`](https://docs.docker.com/reference/dockerfile/#copy)

Copies new files or folders from the `SOURCE` and adds them to the filesystem of the image at `DEST`.

<table><thead><tr><th width="405">Forms</th><th>Description</th></tr></thead><tbody><tr><td><code>COPY [OPTIONS] ...SOURCE DEST</code></td><td></td></tr><tr><td><code>COPY [OPTIONS] [...SOURCE, DEST]</code></td><td>Required for paths with whitespace.</td></tr></tbody></table>

If multiple source files are specified, the last argument must be a `DEST`, with a trailing `/`.

#### Trailing `/` at `DEST`

If the destination has a trailing `/`, the file or folder is copied **inside** this path.

If the destination doesn't have, the file or folder is copied **beside** the path.

#### `DEST` path

Destinations that begin with `/`, are considered absolute paths.

Destinations without `/` at the start, are considered relative to the working directory.

### [`ENTRYPOINT`](https://docs.docker.com/reference/dockerfile/#entrypoint)

Run fixed commands when running a container from an image.

{% hint style="info" %}
If more than one `ENTRYPOINT` is specified, **ONLY** the **LAST** one takes effect.
{% endhint %}

{% hint style="info" %}
You may pass inline arguments to `docker run "image-name" -d`, that will be appended to the `ENTRYPOINT` arguments.
{% endhint %}

{% hint style="info" %}
You can overwrite entirely an `ENTRYPOINT` with the `--entrypoint` flag `docker run "image-name" --entrypoint`.
{% endhint %}

<table><thead><tr><th width="484">Forms</th><th>Description</th></tr></thead><tbody><tr><td><code>ENTRYPOINT ["executable","param1","param2"]</code></td><td>Exec form as Array.</td></tr><tr><td><code>ENTRYPOINT command param1 param2</code></td><td>Shell form as string.</td></tr></tbody></table>

### [`EXPOSE`](https://docs.docker.com/reference/dockerfile/#expose)

Informs Docker that the container listens on the specified network ports at runtime.

You may specify if the port is `UDP` or `TCP`(Default).

{% hint style="info" %}
The `EXPOSE` instruction doesn't actually publish the port.

It functions as a type of documentation between the person who builds the image and the person who runs the container.
{% endhint %}

```docker
EXPOSE 80
```

### [`ENV`](https://docs.docker.com/reference/dockerfile/#env)

Set `<key>=<value>` pairs that will be available:

* During build stages AND **future running containers**.
* In Dockerfile as soon as you define them through `ENV` instructions.

{% hint style="danger" %}
You can inspect Image ENV values with `docker inspect "image-id"`.

**It is not recommended to use them for credentials, secrets or sensitive data, if untrusted users have access to the Image.**

*These variable leave traces in the Docker Image.*
{% endhint %}

{% hint style="danger" %}
Don't just place them at the top of the Dockerfile.

Their placement might impact the caching of layers when developing Images, if their values are constantly updated.
{% endhint %}

| Forms                   |
| ----------------------- |
| `ENV <key>=<value> ...` |

#### String \<value> can be in the form of

```docker
ENV MY_VAR="A string value"
# OR
ENV MY_VAR=A\ string \value
```

#### Access the `ENV` values within the Dockerfile

Access with `$` or `${}`.

```docker
ENV PORT=80
EXPOSE $PORT
```

#### Overwriting \<value>

To overwrite values at build-time, you must use `ARG` to set the default value for `ENV`.

```docker
ARG NODE_ENV
ENV NODE_ENV=$NODE_ENV
ENTRYPOINT ["node", "app.js", "NODE_ENV=$NODE_ENV"]
```

You can overwrite values at run-time `docker run "image-name" --env <key>=<value>`.

#### `.env` File

Read ENV variables from a file by specifiyng it when running the container.

```bash
docker run "image-name" --env-file ./.env
```

### [`RUN`](https://docs.docker.com/reference/dockerfile/#run)

Execute commands creating a new layer on top of the current image. (The added layer is used in the next step inside the Dockerfile)

<table><thead><tr><th width="484">Forms</th><th>Description</th></tr></thead><tbody><tr><td><code>RUN [OPTIONS] [...COMMAND]</code></td><td>Exec form as Array.</td></tr><tr><td><code>RUN [OPTIONS] ...COMMAND</code></td><td>Shell form as string.</td></tr></tbody></table>

The cache for RUN instructions can be forcely invalidated by using `--no-cache` flag.&#x20;

```bash
docker build --no-cache
```

### [USER](https://docs.docker.com/reference/dockerfile/#user)

The `USER` instruction sets the user name (or UID) and optionally the user group (or GID) to use as the default user and group for the remainder of the current stage.

{% hint style="danger" %}
When the user doesn't have a primary group, then it will use as part of the `root` group.
{% endhint %}

The specified user is used for `RUN` instructions and at runtime, runs the relevant `ENTRYPOINT` and `CMD` commands.

| Forms                   |
| ----------------------- |
| `USER <user>[:<group>]` |
| `USER <UID>[:GID]`      |

### [`WORKDIR`](https://docs.docker.com/reference/dockerfile/#workdir)

Sets the working directory for any `RUN`, `CMD`, `ENTRYPOINT`, `COPY` and `ADD` instructions that follow it in the Dockerfile.

{% hint style="info" %}
If the specified `WORKDIR` doesn't exist, it will be created.
{% endhint %}

{% hint style="info" %}
If multiple `WORKDIR` are defined, instructions will always use the last previous one for them.
{% endhint %}

{% hint style="danger" %}
Relative paths on multiple `WORKDIR` will add them up.
{% endhint %}

```docker
WORKDIR /path
```

### [`VOLUME`](https://docs.docker.com/reference/dockerfile/#volume)

Creates a mount point with the specified name and marks it as holding externally mounted volumes from native host or other containers.

<table><thead><tr><th width="381">Forms</th><th>Description</th></tr></thead><tbody><tr><td><code>VOLUME /var/log</code></td><td>As string with multiple arguments.</td></tr><tr><td><code>VOLUME ["/var/log"]</code></td><td>As JSON Array. <strong>(Preferred way)</strong></td></tr></tbody></table>
