Docker-DCO-1.1-Signed-off-by: Fred Lifton <fred.lifton@docker.com> (github: fredlf)
| ... | ... |
@@ -2,7 +2,7 @@ page_title: Best Practices for Writing Dockerfiles |
| 2 | 2 |
page_description: Hints, tips and guidelines for writing clean, reliable Dockerfiles |
| 3 | 3 |
page_keywords: Examples, Usage, base image, docker, documentation, dockerfile, best practices, hub, official repo |
| 4 | 4 |
|
| 5 |
-# Best Practices for Writing Dockerfiles |
|
| 5 |
+# Best practices for writing Dockerfiles |
|
| 6 | 6 |
|
| 7 | 7 |
## Overview |
| 8 | 8 |
|
| ... | ... |
@@ -23,7 +23,7 @@ You can see many of these practices and recommendations in action in the [buildp |
| 23 | 23 |
> Note: for more detailed explanations of any of the Dockerfile commands |
| 24 | 24 |
>mentioned here, visit the [Dockerfile Reference](https://docs.docker.com/reference/builder/) page. |
| 25 | 25 |
|
| 26 |
-## General Guidelines and Recommendations |
|
| 26 |
+## General guidelines and recommendations |
|
| 27 | 27 |
|
| 28 | 28 |
### Containers should be ephemeral |
| 29 | 29 |
|
| ... | ... |
@@ -42,7 +42,8 @@ megabytes worth of upload time. |
| 42 | 42 |
|
| 43 | 43 |
### Avoid installing unnecessary packages |
| 44 | 44 |
|
| 45 |
-In order to reduce complexity, dependencies, file sizes and build times, you should avoid installing extra or unnecessary packages just because they |
|
| 45 |
+In order to reduce complexity, dependencies, file sizes, and build times, you |
|
| 46 |
+should avoid installing extra or unnecessary packages just because they |
|
| 46 | 47 |
might be “nice to have.” For example, you don’t need to include a text editor |
| 47 | 48 |
in a database image. |
| 48 | 49 |
|
| ... | ... |
@@ -75,7 +76,7 @@ Here’s an example from the [`buildpack-deps` image](https://github.com/docker- |
| 75 | 75 |
mercurial \ |
| 76 | 76 |
subversion |
| 77 | 77 |
|
| 78 |
-### Build Cache |
|
| 78 |
+### Build cache |
|
| 79 | 79 |
|
| 80 | 80 |
During the process of building an image Docker will step through the |
| 81 | 81 |
instructions in your `Dockerfile` executing each in the order specified. |
| ... | ... |
@@ -118,7 +119,7 @@ generate new images and the cache will not be used. |
| 118 | 118 |
mercurial \ |
| 119 | 119 |
subversion |
| 120 | 120 |
|
| 121 |
-## The `Dockerfile` instructions |
|
| 121 |
+## The Dockerfile instructions |
|
| 122 | 122 |
|
| 123 | 123 |
Below you'll find recommendations for the best way to write the |
| 124 | 124 |
various instructions available for use in a `Dockerfile`. |
| ... | ... |
@@ -133,29 +134,25 @@ since it’s very tightly controlled and kept extremely minimal (currently under |
| 133 | 133 |
### [`RUN`](https://docs.docker.com/reference/builder/#run) |
| 134 | 134 |
|
| 135 | 135 |
As always, to make your `Dockerfile` more readable, understandable, and |
| 136 |
-maintainable, put long or complex `RUN` statements on multiple lines separate |
|
| 136 |
+maintainable, put long or complex `RUN` statements on multiple lines separated |
|
| 137 | 137 |
with backslashes. |
| 138 | 138 |
|
| 139 |
-Probably the most common use-case for `RUN` is an application of `apt-get` |
|
| 140 |
-When using `apt-get`, here a few things to keep in mind: |
|
| 139 |
+Probably the most common use-case for `RUN` is an application of `apt-get`. |
|
| 140 |
+When using `apt-get`, here are a few things to keep in mind: |
|
| 141 | 141 |
|
| 142 | 142 |
* Don’t do `RUN apt-get update` on a single line. This will cause |
| 143 | 143 |
caching issues if the referenced archive gets updated, which will make your |
| 144 | 144 |
subsequent `apt-get install` fail without comment. |
| 145 | 145 |
|
| 146 |
-* For the most part, to keep your code more readable and maintainable, avoid instructions like: |
|
| 147 |
- |
|
| 148 |
- RUN apt-get install -y package-foo && apt-get install -y package-bar |
|
| 149 |
- |
|
| 150 | 146 |
* Avoid `RUN apt-get upgrade` or `dist-upgrade`, since many of the “essential” |
| 151 | 147 |
packages from the base images will fail to upgrade inside an unprivileged |
| 152 | 148 |
container. If a base package is out of date, you should contact its |
| 153 | 149 |
maintainers. If you know there’s a particular package, `foo`, that needs to be |
| 154 | 150 |
updated, use `apt-get install -y foo` and it will update automatically. |
| 155 | 151 |
|
| 156 |
-* Do write something like: |
|
| 152 |
+* Do write instructions like: |
|
| 157 | 153 |
|
| 158 |
- `RUN apt-get update && apt-get install -y package-bar package-foo package-baz`. |
|
| 154 |
+ RUN apt-get update && apt-get install -y package-bar package-foo package-baz |
|
| 159 | 155 |
|
| 160 | 156 |
Writing the instruction this way not only makes it easier to read |
| 161 | 157 |
and maintain, but also, by including `apt-get update`, ensures that the cache |
| ... | ... |
@@ -165,7 +162,7 @@ further coding or manual intervention required. |
| 165 | 165 |
* Further natural cache-busting can be realized by version-pinning packages |
| 166 | 166 |
(e.g., `package-foo=1.3.*`). This will force retrieval of that version |
| 167 | 167 |
regardless of what’s in the cache. |
| 168 |
-Forming your `apt-get` code this way will greatly ease maintenance and reduce |
|
| 168 |
+Writing your `apt-get` code this way will greatly ease maintenance and reduce |
|
| 169 | 169 |
failures due to unanticipated changes in required packages. |
| 170 | 170 |
|
| 171 | 171 |
#### Example |
| ... | ... |
@@ -196,6 +193,11 @@ the new version (which in this case had a new, required feature). |
| 196 | 196 |
ruby1.9.1-dev \ |
| 197 | 197 |
s3cmd=1.1.0* |
| 198 | 198 |
|
| 199 |
+Writing the instruction this way also helps you avoid potential duplication of |
|
| 200 |
+a given package because it is much easier to read than an instruction like: |
|
| 201 |
+ |
|
| 202 |
+ RUN apt-get install -y package-foo && apt-get install -y package-bar |
|
| 203 |
+ |
|
| 199 | 204 |
### [`CMD`](https://docs.docker.com/reference/builder/#cmd) |
| 200 | 205 |
|
| 201 | 206 |
The `CMD` instruction should be used to run the software contained by your |
| ... | ... |
@@ -290,7 +292,11 @@ is much easier to understand than |
| 290 | 290 |
|
| 291 | 291 |
....docker run -it --entrypoint bash official-image -i |
| 292 | 292 |
|
| 293 |
-especially for Docker beginners. |
|
| 293 |
+This is especially true for new Docker users, who might naturally assume the |
|
| 294 |
+above command will work fine. In cases where an image uses `ENTRYPOINT` for |
|
| 295 |
+anything other than just a wrapper script, the command will fail and the |
|
| 296 |
+beginning user will then be forced to learn about `ENTRYPOINT` and |
|
| 297 |
+`--entrypoint`. |
|
| 294 | 298 |
|
| 295 | 299 |
In order to avoid a situation where commands are run without clear visibility |
| 296 | 300 |
to the user, make sure your script ends with something like `exec "$@"`. After |
| ... | ... |
@@ -339,9 +345,9 @@ If a service can run without privileges, use `USER` to change to a non-root |
| 339 | 339 |
user. Start by creating the user and group in the `Dockerfile` with something |
| 340 | 340 |
like `RUN groupadd -r postgres && useradd -r -g postgres postgres`. |
| 341 | 341 |
|
| 342 |
->**Note** Users and groups in an image get a non-deterministic |
|
| 343 |
->UID/GID in that the “next” UID/GID gets assigned regardless of image |
|
| 344 |
->rebuilds. So, if it’s critical, you should assign an explicit UID/GID. |
|
| 342 |
+> **Note:** Users and groups in an image get a non-deterministic |
|
| 343 |
+> UID/GID in that the “next” UID/GID gets assigned regardless of image |
|
| 344 |
+> rebuilds. So, if it’s critical, you should assign an explicit UID/GID. |
|
| 345 | 345 |
|
| 346 | 346 |
You should avoid installing or using `sudo` since it has unpredictable TTY and |
| 347 | 347 |
signal-forwarding behavior that can cause more more problems than it solves. If |
| ... | ... |
@@ -41,7 +41,7 @@ Your `Dockerfile` should adhere to the following: |
| 41 | 41 |
established Official Image. |
| 42 | 42 |
* It must follow `Dockerfile` best practices. These are discussed on the |
| 43 | 43 |
[best practices page](/articles/dockerfile_best-practices). In addition, |
| 44 |
-Docker engineer Michael Crosby has some good tips for Dockerfiles in |
|
| 44 |
+Docker engineer Michael Crosby has some good tips for `Dockerfiles` in |
|
| 45 | 45 |
this [blog post](http://crosbymichael.com/dockerfile-best-practices-take-2.html). |
| 46 | 46 |
|
| 47 | 47 |
While [`ONBUILD` triggers](https://docs.docker.com/reference/builder/#onbuild) |
| ... | ... |
@@ -77,7 +77,7 @@ can be made based on the logo needed |
| 77 | 77 |
|
| 78 | 78 |
### A long description |
| 79 | 79 |
|
| 80 |
-Include a comprehensive description of your image (in markdown format, GitHub |
|
| 80 |
+Include a comprehensive description of your image (in Markdown format, GitHub |
|
| 81 | 81 |
flavor preferred). Only one description is required; you don’t need additional |
| 82 | 82 |
descriptions for each tag. The file should also: |
| 83 | 83 |
|
| ... | ... |
@@ -88,9 +88,9 @@ content requirements |
| 88 | 88 |
|
| 89 | 89 |
In terms of content, the long description must include the following sections: |
| 90 | 90 |
|
| 91 |
-* Overview & Links |
|
| 92 |
-* How-to/Usage |
|
| 93 |
-* Issues & Contribution Info |
|
| 91 |
+* Overview & links |
|
| 92 |
+* How-to/usage |
|
| 93 |
+* Issues & contributions |
|
| 94 | 94 |
|
| 95 | 95 |
#### Overview & links |
| 96 | 96 |
|
| ... | ... |
@@ -109,15 +109,15 @@ A section that describes how to run and use the image, including common use |
| 109 | 109 |
cases and example `Dockerfile`s (if applicable). Try to provide clear, step-by- |
| 110 | 110 |
step instructions wherever possible. |
| 111 | 111 |
|
| 112 |
-##### Issues & contribution info |
|
| 112 |
+##### Issues & contributions |
|
| 113 |
+ |
|
| 113 | 114 |
In this section, point users to any resources that can help them contribute to |
| 114 | 115 |
the project. Include contribution guidelines and any specific instructions |
| 115 | 116 |
related to your development practices. Include a link to |
| 116 | 117 |
[Docker’s resources for contributors](https://docs.docker.com/contributing/contributing/). |
| 117 | 118 |
Be sure to include contact info, handles, etc. for official maintainers. |
| 118 | 119 |
|
| 119 |
-##### Issues |
|
| 120 |
-Include a brief section letting users know where they can go for help and how |
|
| 120 |
+Also include information letting users know where they can go for help and how |
|
| 121 | 121 |
they can file issues with the repo. Point them to any specific IRC channels, |
| 122 | 122 |
issue trackers, contacts, additional “how-to” information or other resources. |
| 123 | 123 |
|
| ... | ... |
@@ -125,8 +125,9 @@ issue trackers, contacts, additional “how-to” information or other resources |
| 125 | 125 |
|
| 126 | 126 |
Include a file, `LICENSE`, of any applicable license. Docker recommends using |
| 127 | 127 |
the license of the software contained in the image, provided it allows Docker, |
| 128 |
-Inc. to legally build and distribute the image. Otherwise, Docker recommends |
|
| 129 |
-adopting the [Expat license](http://directory.fsf.org/wiki/License:Expat). |
|
| 128 |
+Inc. to legally build and distribute the image. Otherwise, Docker recommends |
|
| 129 |
+adopting the [Expat license](http://directory.fsf.org/wiki/License:Expat) |
|
| 130 |
+(a.k.a., the MIT or X11 license). |
|
| 130 | 131 |
|
| 131 | 132 |
## Examples |
| 132 | 133 |
|
| ... | ... |
@@ -160,7 +161,7 @@ Put this file in the root of your app, next to the `Gemfile`. |
| 160 | 160 |
|
| 161 | 161 |
This image includes multiple `ONBUILD` triggers so that should be all that you need for most applications. The build will `ADD . /usr/src/app`, `RUN bundle install`, `EXPOSE 3000`, and set the default command to `rails server`. |
| 162 | 162 |
|
| 163 |
-Then build and run the docker image. |
|
| 163 |
+Then build and run the Docker image. |
|
| 164 | 164 |
|
| 165 | 165 |
docker build -t my-rails-app . |
| 166 | 166 |
docker run --name some-rails-app -d my-rails-app |
| ... | ... |
@@ -169,7 +170,7 @@ Test it by visiting `http://container-ip:3000` in a browser. On the other hand, |
| 169 | 169 |
|
| 170 | 170 |
docker run --name some-rails-app -p 8080:3000 -d my-rails-app |
| 171 | 171 |
|
| 172 |
-Then hit `http://localhost:8080` or `http://host-ip:8080` in a browser. |
|
| 172 |
+Then go to `http://localhost:8080` or `http://host-ip:8080` in a browser. |
|
| 173 | 173 |
``` |
| 174 | 174 |
|
| 175 | 175 |
For more examples, take a look at these repos: |
| ... | ... |
@@ -182,4 +183,7 @@ For more examples, take a look at these repos: |
| 182 | 182 |
|
| 183 | 183 |
## Submit your repo |
| 184 | 184 |
|
| 185 |
-Once you've checked off everything in these guidelines, and are confident your image is ready for primetime, please contact us at [partners@docker.com](mailto:partners@docker.com) to have your project considered for the Official Repos program. |
|
| 185 |
+Once you've checked off everything in these guidelines, and are confident your |
|
| 186 |
+image is ready for primetime, please contact us at |
|
| 187 |
+[partners@docker.com](mailto:partners@docker.com) to have your project |
|
| 188 |
+considered for the Official Repos program. |