|
@@ -2,7 +2,7 @@ page_title: Best Practices for Writing Dockerfiles
|
|
page_description: Hints, tips and guidelines for writing clean, reliable Dockerfiles
|
|
page_description: Hints, tips and guidelines for writing clean, reliable Dockerfiles
|
|
page_keywords: Examples, Usage, base image, docker, documentation, dockerfile, best practices, hub, official repo
|
|
page_keywords: Examples, Usage, base image, docker, documentation, dockerfile, best practices, hub, official repo
|
|
|
|
|
|
-# Best Practices for Writing `Dockerfile`s
|
|
|
|
|
|
+# Best Practices for Writing Dockerfiles
|
|
|
|
|
|
## Overview
|
|
## Overview
|
|
|
|
|
|
@@ -14,7 +14,7 @@ specific set of instructions. You can learn the basics on the
|
|
you’re new to writing `Dockerfile`s, you should start there.
|
|
you’re new to writing `Dockerfile`s, you should start there.
|
|
|
|
|
|
This document covers the best practices and methods recommended by Docker,
|
|
This document covers the best practices and methods recommended by Docker,
|
|
-Inc. and the Docker Community for creating easy-to-use, effective
|
|
|
|
|
|
+Inc. and the Docker community for creating easy-to-use, effective
|
|
`Dockerfile`s. We strongly suggest you follow these recommendations (in fact,
|
|
`Dockerfile`s. We strongly suggest you follow these recommendations (in fact,
|
|
if you’re creating an Official Image, you *must* adhere to these practices).
|
|
if you’re creating an Official Image, you *must* adhere to these practices).
|
|
|
|
|
|
@@ -28,21 +28,21 @@ You can see many of these practices and recommendations in action in the [buildp
|
|
### Containers should be ephemeral
|
|
### Containers should be ephemeral
|
|
|
|
|
|
The container produced by the image your `Dockerfile` defines should be as
|
|
The container produced by the image your `Dockerfile` defines should be as
|
|
-ephemeral as possible. “Ephemeral” here means that it can be stopped and
|
|
|
|
|
|
+ephemeral as possible. By “ephemeral,” we mean that it can be stopped and
|
|
destroyed and a new one built and put in place with an absolute minimum of
|
|
destroyed and a new one built and put in place with an absolute minimum of
|
|
set-up and configuration.
|
|
set-up and configuration.
|
|
|
|
|
|
-### Use a [`.dockerignore` file](https://docs.docker.com/reference/builder/#the-dockerignore-file)
|
|
|
|
|
|
+### Use [a .dockerignore file](https://docs.docker.com/reference/builder/#the-dockerignore-file)
|
|
|
|
|
|
-For faster uploading and efficiency during `docker build`, you should make use
|
|
|
|
-of a `.dockerignore` file to exclude files or directories from the build
|
|
|
|
|
|
+For faster uploading and efficiency during `docker build`, you should use
|
|
|
|
+a `.dockerignore` file to exclude files or directories from the build
|
|
context and final image. For example, unless`.git` is needed by your build
|
|
context and final image. For example, unless`.git` is needed by your build
|
|
process or scripts, you should add it to `.dockerignore`, which can save many
|
|
process or scripts, you should add it to `.dockerignore`, which can save many
|
|
megabytes worth of upload time.
|
|
megabytes worth of upload time.
|
|
|
|
|
|
### Avoid installing unnecessary packages
|
|
### Avoid installing unnecessary packages
|
|
|
|
|
|
-You should avoid installing extra or unnecessary packages just because they
|
|
|
|
|
|
+In order to reduce complexity, dependencies, file sizes and build times, you should avoid installing extra or unnecessary packages just because they
|
|
might be “nice to have.” For example, you don’t need to include a text editor
|
|
might be “nice to have.” For example, you don’t need to include a text editor
|
|
in a database image.
|
|
in a database image.
|
|
|
|
|
|
@@ -112,33 +112,40 @@ the command string itself will be used to find a match.
|
|
Once the cache is invalidated, all subsequent `Dockerfile` commands will
|
|
Once the cache is invalidated, all subsequent `Dockerfile` commands will
|
|
generate new images and the cache will not be used.
|
|
generate new images and the cache will not be used.
|
|
|
|
|
|
|
|
+ bzr \
|
|
|
|
+ cvs \
|
|
|
|
+ git \
|
|
|
|
+ mercurial \
|
|
|
|
+ subversion
|
|
|
|
+
|
|
## The `Dockerfile` instructions
|
|
## The `Dockerfile` instructions
|
|
|
|
|
|
-This section contains specific recommendations for the correct usage of the
|
|
|
|
-various instructions contained in a `Dockerfile`.
|
|
|
|
|
|
+Below you'll find recommendations for the best way to write the
|
|
|
|
+various instructions available for use in a `Dockerfile`.
|
|
|
|
|
|
### [`FROM`](https://docs.docker.com/reference/builder/#from)
|
|
### [`FROM`](https://docs.docker.com/reference/builder/#from)
|
|
|
|
|
|
-Whenever possible, use Official Repositories as the basis for your image. We
|
|
|
|
-recommend the [Debian image](https://registry.hub.docker.com/_/debian/) since
|
|
|
|
-it’s very tightly controlled and kept extremely minimal (currently under 100
|
|
|
|
-mb), while still being a full distribution.
|
|
|
|
|
|
+Whenever possible, use current Official Repositories as the basis for your
|
|
|
|
+image. We recommend the [Debian image](https://registry.hub.docker.com/_/debian/)
|
|
|
|
+since it’s very tightly controlled and kept extremely minimal (currently under
|
|
|
|
+100 mb), while still being a full distribution.
|
|
|
|
|
|
### [`RUN`](https://docs.docker.com/reference/builder/#run)
|
|
### [`RUN`](https://docs.docker.com/reference/builder/#run)
|
|
|
|
|
|
As always, to make your `Dockerfile` more readable, understandable, and
|
|
As always, to make your `Dockerfile` more readable, understandable, and
|
|
-maintainable, put long or complex `RUN` statements on multiple lines separated with
|
|
|
|
-backslashes.
|
|
|
|
|
|
+maintainable, put long or complex `RUN` statements on multiple lines separate
|
|
|
|
+with backslashes.
|
|
|
|
|
|
-Probably the most common use-case for `RUN` is an application of `apt-get`.
|
|
|
|
|
|
+Probably the most common use-case for `RUN` is an application of `apt-get`
|
|
When using `apt-get`, here a few things to keep in mind:
|
|
When using `apt-get`, here a few things to keep in mind:
|
|
|
|
|
|
* Don’t do `RUN apt-get update` on a single line. This will cause
|
|
* Don’t do `RUN apt-get update` on a single line. This will cause
|
|
caching issues if the referenced archive gets updated, which will make your
|
|
caching issues if the referenced archive gets updated, which will make your
|
|
subsequent `apt-get install` fail without comment.
|
|
subsequent `apt-get install` fail without comment.
|
|
|
|
|
|
-* For the most part, to keep your code more readable and maintainable, avoid
|
|
|
|
-`RUN apt-get install -y package-foo && apt-get install -y package-bar`.
|
|
|
|
|
|
+* For the most part, to keep your code more readable and maintainable, avoid instructions like:
|
|
|
|
+
|
|
|
|
+ RUN apt-get install -y package-foo && apt-get install -y package-bar
|
|
|
|
|
|
* Avoid `RUN apt-get upgrade` or `dist-upgrade`, since many of the “essential”
|
|
* Avoid `RUN apt-get upgrade` or `dist-upgrade`, since many of the “essential”
|
|
packages from the base images will fail to upgrade inside an unprivileged
|
|
packages from the base images will fail to upgrade inside an unprivileged
|
|
@@ -146,8 +153,11 @@ container. If a base package is out of date, you should contact its
|
|
maintainers. If you know there’s a particular package, `foo`, that needs to be
|
|
maintainers. If you know there’s a particular package, `foo`, that needs to be
|
|
updated, use `apt-get install -y foo` and it will update automatically.
|
|
updated, use `apt-get install -y foo` and it will update automatically.
|
|
|
|
|
|
-* Do use `RUN apt-get update && apt-get install -y package-bar package-foo
|
|
|
|
-package-baz`. Writing the instruction this way not only makes it easier to read
|
|
|
|
|
|
+* Do write something like:
|
|
|
|
+
|
|
|
|
+ `RUN apt-get update && apt-get install -y package-bar package-foo package-baz`.
|
|
|
|
+
|
|
|
|
+Writing the instruction this way not only makes it easier to read
|
|
and maintain, but also, by including `apt-get update`, ensures that the cache
|
|
and maintain, but also, by including `apt-get update`, ensures that the cache
|
|
will naturally be busted and the latest versions will be installed with no
|
|
will naturally be busted and the latest versions will be installed with no
|
|
further coding or manual intervention required.
|
|
further coding or manual intervention required.
|
|
@@ -273,9 +283,14 @@ auto-extraction capability, you should always use `COPY`.
|
|
|
|
|
|
The best use for `ENTRYPOINT` is as a helper script. Using `ENTRYPOINT` for
|
|
The best use for `ENTRYPOINT` is as a helper script. Using `ENTRYPOINT` for
|
|
other tasks can make your code harder to understand. For example,
|
|
other tasks can make your code harder to understand. For example,
|
|
-`docker run -it official-image bash` is much easier to understand than
|
|
|
|
-`docker run -it --entrypoint bash official-image -i`, especially for Docker
|
|
|
|
-beginners.
|
|
|
|
|
|
+
|
|
|
|
+....docker run -it official-image bash
|
|
|
|
+
|
|
|
|
+is much easier to understand than
|
|
|
|
+
|
|
|
|
+....docker run -it --entrypoint bash official-image -i
|
|
|
|
+
|
|
|
|
+especially for Docker beginners.
|
|
|
|
|
|
In order to avoid a situation where commands are run without clear visibility
|
|
In order to avoid a situation where commands are run without clear visibility
|
|
to the user, make sure your script ends with something like `exec "$@"`. After
|
|
to the user, make sure your script ends with something like `exec "$@"`. After
|
|
@@ -305,8 +320,8 @@ fi
|
|
exec "$@"
|
|
exec "$@"
|
|
```
|
|
```
|
|
|
|
|
|
-That script then gets copied into the container and the run via `ENTRYPOINT` on
|
|
|
|
-container startup:
|
|
|
|
|
|
+That script then gets copied into the container and run via `ENTRYPOINT` on
|
|
|
|
+container startup:
|
|
|
|
|
|
COPY ./docker-entrypoint.sh /
|
|
COPY ./docker-entrypoint.sh /
|
|
ENTRYPOINT ["/docker-entrypoint.sh"]
|
|
ENTRYPOINT ["/docker-entrypoint.sh"]
|
|
@@ -324,7 +339,7 @@ If a service can run without privileges, use `USER` to change to a non-root
|
|
user. Start by creating the user and group in the `Dockerfile` with something
|
|
user. Start by creating the user and group in the `Dockerfile` with something
|
|
like `RUN groupadd -r postgres && useradd -r -g postgres postgres`.
|
|
like `RUN groupadd -r postgres && useradd -r -g postgres postgres`.
|
|
|
|
|
|
->**Note** that users/groups in an image get assigned a non-deterministic
|
|
|
|
|
|
+>**Note** Users and groups in an image get a non-deterministic
|
|
>UID/GID in that the “next” UID/GID gets assigned regardless of image
|
|
>UID/GID in that the “next” UID/GID gets assigned regardless of image
|
|
>rebuilds. So, if it’s critical, you should assign an explicit UID/GID.
|
|
>rebuilds. So, if it’s critical, you should assign an explicit UID/GID.
|
|
|
|
|
|
@@ -334,7 +349,7 @@ you absolutely need functionality similar to `sudo` (e.g., initializing the
|
|
daemon as root but running it as non-root), you may be able to use
|
|
daemon as root but running it as non-root), you may be able to use
|
|
[“gosu”](https://github.com/tianon/gosu).
|
|
[“gosu”](https://github.com/tianon/gosu).
|
|
|
|
|
|
-Lastly, to reduce layers and complexity, try to minimize switching `USER` back
|
|
|
|
|
|
+Lastly, to reduce layers and complexity, avoid switching `USER` back
|
|
and forth frequently.
|
|
and forth frequently.
|
|
|
|
|
|
### [`WORKDIR`](https://docs.docker.com/reference/builder/#workdir)
|
|
### [`WORKDIR`](https://docs.docker.com/reference/builder/#workdir)
|