mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-05-17 06:16:37 +00:00
435 lines
9.3 KiB
Markdown
435 lines
9.3 KiB
Markdown
# Advanced Dockerfiles
|
|
|
|

|
|
|
|
---
|
|
|
|
## Objectives
|
|
|
|
We have seen simple Dockerfiles to illustrate how Docker build
|
|
container images.
|
|
|
|
In this section, we will see more Dockerfile commands.
|
|
|
|
---
|
|
|
|
## `Dockerfile` usage summary
|
|
|
|
* `Dockerfile` instructions are executed in order.
|
|
|
|
* Each instruction creates a new layer in the image.
|
|
|
|
* Docker maintains a cache with the layers of previous builds.
|
|
|
|
* When there are no changes in the instructions and files making a layer,
|
|
the builder re-uses the cached layer, without executing the instruction for that layer.
|
|
|
|
* The `FROM` instruction MUST be the first non-comment instruction.
|
|
|
|
* Lines starting with `#` are treated as comments.
|
|
|
|
* Some instructions (like `CMD` or `ENTRYPOINT`) update a piece of metadata.
|
|
|
|
(As a result, each call to these instructions makes the previous one useless.)
|
|
|
|
---
|
|
|
|
## The `MAINTAINER` instruction
|
|
|
|
The `MAINTAINER` instruction tells you who wrote the `Dockerfile`.
|
|
|
|
```dockerfile
|
|
MAINTAINER Docker Education Team <education@docker.com>
|
|
```
|
|
|
|
It's optional but recommended.
|
|
|
|
---
|
|
|
|
## The `RUN` instruction
|
|
|
|
The `RUN` instruction can be specified in two ways.
|
|
|
|
With shell wrapping, which runs the specified command inside a shell,
|
|
with `/bin/sh -c`:
|
|
|
|
```dockerfile
|
|
RUN apt-get update
|
|
```
|
|
|
|
Or using the `exec` method, which avoids shell string expansion, and
|
|
allows execution in images that don't have `/bin/sh`:
|
|
|
|
```dockerfile
|
|
RUN [ "apt-get", "update" ]
|
|
```
|
|
|
|
---
|
|
|
|
## More about the `RUN` instruction
|
|
|
|
`RUN` will do the following:
|
|
|
|
* Execute a command.
|
|
* Record changes made to the filesystem.
|
|
* Work great to install libraries, packages, and various files.
|
|
|
|
`RUN` will NOT do the following:
|
|
|
|
* Record state of *processes*.
|
|
* Automatically start daemons.
|
|
|
|
If you want to start something automatically when the container runs,
|
|
you should use `CMD` and/or `ENTRYPOINT`.
|
|
|
|
---
|
|
|
|
## Collapsing layers
|
|
|
|
It is possible to execute multiple commands in a single step:
|
|
|
|
```dockerfile
|
|
RUN apt-get update && apt-get install -y wget && apt-get clean
|
|
```
|
|
|
|
It is also possible to break a command onto multiple lines:
|
|
|
|
It is possible to execute multiple commands in a single step:
|
|
|
|
```dockerfile
|
|
RUN apt-get update \
|
|
&& apt-get install -y wget \
|
|
&& apt-get clean
|
|
```
|
|
|
|
---
|
|
|
|
## The `EXPOSE` instruction
|
|
|
|
The `EXPOSE` instruction tells Docker what ports are to be published
|
|
in this image.
|
|
|
|
```dockerfile
|
|
EXPOSE 8080
|
|
EXPOSE 80 443
|
|
EXPOSE 53/tcp 53/udp
|
|
```
|
|
|
|
* All ports are private by default.
|
|
|
|
* Declaring a port with `EXPOSE` is not enough to make it public.
|
|
|
|
* The `Dockerfile` doesn't control on which port a service gets exposed.
|
|
|
|
---
|
|
|
|
## Exposing ports
|
|
|
|
* When you `docker run -p <port> ...`, that port becomes public.
|
|
|
|
(Even if it was not declared with `EXPOSE`.)
|
|
|
|
* When you `docker run -P ...` (without port number), all ports
|
|
declared with `EXPOSE` become public.
|
|
|
|
A *public port* is reachable from other containers and from outside the host.
|
|
|
|
A *private port* is not reachable from outside.
|
|
|
|
---
|
|
|
|
## The `COPY` instruction
|
|
|
|
The `COPY` instruction adds files and content from your host into the
|
|
image.
|
|
|
|
```dockerfile
|
|
COPY . /src
|
|
```
|
|
|
|
This will add the contents of the *build context* (the directory
|
|
passed as an argument to `docker build`) to the directory `/src`
|
|
in the container.
|
|
|
|
---
|
|
|
|
## Build context isolation
|
|
|
|
Note: you can only reference files and directories *inside* the
|
|
build context. Absolute paths are taken as being anchored to
|
|
the build context, so the two following lines are equivalent:
|
|
|
|
```dockerfile
|
|
COPY . /src
|
|
COPY / /src
|
|
```
|
|
|
|
Attempts to use `..` to get out of the build context will be
|
|
detected and blocked with Docker, and the build will fail.
|
|
|
|
Otherwise, a `Dockerfile` could succeed on host A, but fail on host B.
|
|
|
|
---
|
|
|
|
## `ADD`
|
|
|
|
`ADD` works almost like `COPY`, but has a few extra features.
|
|
|
|
`ADD` can get remote files:
|
|
|
|
```dockerfile
|
|
ADD http://www.example.com/webapp.jar /opt/
|
|
```
|
|
|
|
This would download the `webapp.jar` file and place it in the `/opt`
|
|
directory.
|
|
|
|
`ADD` will automatically unpack zip files and tar archives:
|
|
|
|
```dockerfile
|
|
ADD ./assets.zip /var/www/htdocs/assets/
|
|
```
|
|
|
|
This would unpack `assets.zip` into `/var/www/htdocs/assets`.
|
|
|
|
*However,* `ADD` will not automatically unpack remote archives.
|
|
|
|
---
|
|
|
|
## `ADD`, `COPY`, and the build cache
|
|
|
|
* Before creating a new layer, Docker checks its build cache.
|
|
|
|
* For most Dockerfile instructions, Docker only looks at the
|
|
`Dockerfile` content to do the cache lookup.
|
|
|
|
* For `ADD` and `COPY` instructions, Docker also checks if the files
|
|
to be added to the container have been changed.
|
|
|
|
* `ADD` always needs to download the remote file before
|
|
it can check if it has been changed.
|
|
|
|
(It cannot use,
|
|
e.g., ETags or If-Modified-Since headers.)
|
|
|
|
---
|
|
|
|
## `VOLUME`
|
|
|
|
The `VOLUME` instruction tells Docker that a specific directory
|
|
should be a *volume*.
|
|
|
|
```dockerfile
|
|
VOLUME /var/lib/mysql
|
|
```
|
|
|
|
Filesystem access in volumes bypasses the copy-on-write layer,
|
|
offering native performance to I/O done in those directories.
|
|
|
|
Volumes can be attached to multiple containers, allowing to
|
|
"port" data over from a container to another, e.g. to
|
|
upgrade a database to a newer version.
|
|
|
|
It is possible to start a container in "read-only" mode.
|
|
The container filesystem will be made read-only, but volumes
|
|
can still have read/write access if necessary.
|
|
|
|
---
|
|
|
|
## The `WORKDIR` instruction
|
|
|
|
The `WORKDIR` instruction sets the working directory for subsequent
|
|
instructions.
|
|
|
|
It also affects `CMD` and `ENTRYPOINT`, since it sets the working
|
|
directory used when starting the container.
|
|
|
|
```dockerfile
|
|
WORKDIR /src
|
|
```
|
|
|
|
You can specify `WORKDIR` again to change the working directory for
|
|
further operations.
|
|
|
|
---
|
|
|
|
## The `ENV` instruction
|
|
|
|
The `ENV` instruction specifies environment variables that should be
|
|
set in any container launched from the image.
|
|
|
|
```dockerfile
|
|
ENV WEBAPP_PORT 8080
|
|
```
|
|
|
|
This will result in an environment variable being created in any
|
|
containers created from this image of
|
|
|
|
```bash
|
|
WEBAPP_PORT=8080
|
|
```
|
|
|
|
You can also specify environment variables when you use `docker run`.
|
|
|
|
```bash
|
|
$ docker run -e WEBAPP_PORT=8000 -e WEBAPP_HOST=www.example.com ...
|
|
```
|
|
|
|
---
|
|
|
|
## The `USER` instruction
|
|
|
|
The `USER` instruction sets the user name or UID to use when running
|
|
the image.
|
|
|
|
It can be used multiple times to change back to root or to another user.
|
|
|
|
---
|
|
|
|
## The `CMD` instruction
|
|
|
|
The `CMD` instruction is a default command run when a container is
|
|
launched from the image.
|
|
|
|
```dockerfile
|
|
CMD [ "nginx", "-g", "daemon off;" ]
|
|
```
|
|
|
|
Means we don't need to specify `nginx -g "daemon off;"` when running the
|
|
container.
|
|
|
|
Instead of:
|
|
|
|
```bash
|
|
$ docker run <dockerhubUsername>/web_image nginx -g "daemon off;"
|
|
```
|
|
|
|
We can just do:
|
|
|
|
```bash
|
|
$ docker run <dockerhubUsername>/web_image
|
|
```
|
|
|
|
---
|
|
|
|
## More about the `CMD` instruction
|
|
|
|
Just like `RUN`, the `CMD` instruction comes in two forms.
|
|
The first executes in a shell:
|
|
|
|
```dockerfile
|
|
CMD nginx -g "daemon off;"
|
|
```
|
|
|
|
The second executes directly, without shell processing:
|
|
|
|
```dockerfile
|
|
CMD [ "nginx", "-g", "daemon off;" ]
|
|
```
|
|
|
|
---
|
|
|
|
class: extra-details
|
|
|
|
## Overriding the `CMD` instruction
|
|
|
|
The `CMD` can be overridden when you run a container.
|
|
|
|
```bash
|
|
$ docker run -it <dockerhubUsername>/web_image bash
|
|
```
|
|
|
|
Will run `bash` instead of `nginx -g "daemon off;"`.
|
|
|
|
---
|
|
|
|
## The `ENTRYPOINT` instruction
|
|
|
|
The `ENTRYPOINT` instruction is like the `CMD` instruction,
|
|
but arguments given on the command line are *appended* to the
|
|
entry point.
|
|
|
|
Note: you have to use the "exec" syntax (`[ "..." ]`).
|
|
|
|
```dockerfile
|
|
ENTRYPOINT [ "/bin/ls" ]
|
|
```
|
|
|
|
If we were to run:
|
|
|
|
```bash
|
|
$ docker run training/ls -l
|
|
```
|
|
|
|
Instead of trying to run `-l`, the container will run `/bin/ls -l`.
|
|
|
|
---
|
|
|
|
class: extra-details
|
|
|
|
## Overriding the `ENTRYPOINT` instruction
|
|
|
|
The entry point can be overriden as well.
|
|
|
|
```bash
|
|
$ docker run -it training/ls
|
|
bin dev home lib64 mnt proc run srv tmp var
|
|
boot etc lib media opt root sbin sys usr
|
|
$ docker run -it --entrypoint bash training/ls
|
|
root@d902fb7b1fc7:/#
|
|
```
|
|
|
|
---
|
|
|
|
## How `CMD` and `ENTRYPOINT` interact
|
|
|
|
The `CMD` and `ENTRYPOINT` instructions work best when used
|
|
together.
|
|
|
|
```dockerfile
|
|
ENTRYPOINT [ "nginx" ]
|
|
CMD [ "-g", "daemon off;" ]
|
|
```
|
|
|
|
The `ENTRYPOINT` specifies the command to be run and the `CMD`
|
|
specifies its options. On the command line we can then potentially
|
|
override the options when needed.
|
|
|
|
```bash
|
|
$ docker run -d <dockerhubUsername>/web_image -t
|
|
```
|
|
|
|
This will override the options `CMD` provided with new flags.
|
|
|
|
---
|
|
|
|
## Advanced Dockerfile instructions
|
|
|
|
* `ONBUILD` lets you stash instructions that will be executed
|
|
when this image is used as a base for another one.
|
|
* `LABEL` adds arbitrary metadata to the image.
|
|
* `ARG` defines build-time variables (optional or mandatory).
|
|
* `STOPSIGNAL` sets the signal for `docker stop` (`TERM` by default).
|
|
* `HEALTHCHECK` defines a command assessing the status of the container.
|
|
* `SHELL` sets the default program to use for string-syntax RUN, CMD, etc.
|
|
|
|
---
|
|
|
|
class: extra-details
|
|
|
|
## The `ONBUILD` instruction
|
|
|
|
The `ONBUILD` instruction is a trigger. It sets instructions that will
|
|
be executed when another image is built from the image being build.
|
|
|
|
This is useful for building images which will be used as a base
|
|
to build other images.
|
|
|
|
```dockerfile
|
|
ONBUILD COPY . /src
|
|
```
|
|
|
|
* You can't chain `ONBUILD` instructions with `ONBUILD`.
|
|
* `ONBUILD` can't be used to trigger `FROM` and `MAINTAINER`
|
|
instructions.
|