From 36db0a30fa471aa96cf5acd8139b554db78cec22 Mon Sep 17 00:00:00 2001 From: Fred Lifton Date: Wed, 24 Sep 2014 16:05:35 -0700 Subject: [PATCH] Edits and fixes to Dockerfile Best Practices based on review feedback. Docker-DCO-1.1-Signed-off-by: Fred Lifton (github: fredlf) --- .../articles/dockerfile_best-practices.md | 44 +++++++++++-------- docs/sources/docker-hub/official_repos.md | 30 +++++++------ 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/docs/sources/articles/dockerfile_best-practices.md b/docs/sources/articles/dockerfile_best-practices.md index 113e256a2b..910912bbb5 100644 --- a/docs/sources/articles/dockerfile_best-practices.md +++ b/docs/sources/articles/dockerfile_best-practices.md @@ -2,7 +2,7 @@ page_title: Best Practices for Writing 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 -# Best Practices for Writing Dockerfiles +# Best practices for writing Dockerfiles ## Overview @@ -23,7 +23,7 @@ You can see many of these practices and recommendations in action in the [buildp > Note: for more detailed explanations of any of the Dockerfile commands >mentioned here, visit the [Dockerfile Reference](https://docs.docker.com/reference/builder/) page. -## General Guidelines and Recommendations +## General guidelines and recommendations ### Containers should be ephemeral @@ -42,7 +42,8 @@ megabytes worth of upload time. ### Avoid installing unnecessary packages -In order to reduce complexity, dependencies, file sizes and build times, 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 in a database image. @@ -75,7 +76,7 @@ Here’s an example from the [`buildpack-deps` image](https://github.com/docker- mercurial \ subversion -### Build Cache +### Build cache During the process of building an image Docker will step through the instructions in your `Dockerfile` executing each in the order specified. @@ -118,7 +119,7 @@ generate new images and the cache will not be used. mercurial \ subversion -## The `Dockerfile` instructions +## The Dockerfile instructions Below you'll find recommendations for the best way to write the various instructions available for use in a `Dockerfile`. @@ -133,29 +134,25 @@ since it’s very tightly controlled and kept extremely minimal (currently under ### [`RUN`](https://docs.docker.com/reference/builder/#run) As always, to make your `Dockerfile` more readable, understandable, and -maintainable, put long or complex `RUN` statements on multiple lines separate +maintainable, put long or complex `RUN` statements on multiple lines separated with backslashes. -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: +Probably the most common use-case for `RUN` is an application of `apt-get`. +When using `apt-get`, here are a few things to keep in mind: * 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 subsequent `apt-get install` fail without comment. -* 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” packages from the base images will fail to upgrade inside an unprivileged 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 updated, use `apt-get install -y foo` and it will update automatically. -* Do write something like: +* Do write instructions like: - `RUN apt-get update && apt-get install -y package-bar package-foo package-baz`. + 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 @@ -165,7 +162,7 @@ further coding or manual intervention required. * Further natural cache-busting can be realized by version-pinning packages (e.g., `package-foo=1.3.*`). This will force retrieval of that version regardless of what’s in the cache. -Forming your `apt-get` code this way will greatly ease maintenance and reduce +Writing your `apt-get` code this way will greatly ease maintenance and reduce failures due to unanticipated changes in required packages. #### Example @@ -196,6 +193,11 @@ the new version (which in this case had a new, required feature). ruby1.9.1-dev \ s3cmd=1.1.0* +Writing the instruction this way also helps you avoid potential duplication of +a given package because it is much easier to read than an instruction like: + + RUN apt-get install -y package-foo && apt-get install -y package-bar + ### [`CMD`](https://docs.docker.com/reference/builder/#cmd) The `CMD` instruction should be used to run the software contained by your @@ -290,7 +292,11 @@ is much easier to understand than ....docker run -it --entrypoint bash official-image -i -especially for Docker beginners. +This is especially true for new Docker users, who might naturally assume the +above command will work fine. In cases where an image uses `ENTRYPOINT` for +anything other than just a wrapper script, the command will fail and the +beginning user will then be forced to learn about `ENTRYPOINT` and +`--entrypoint`. 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 @@ -339,9 +345,9 @@ 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 like `RUN groupadd -r postgres && useradd -r -g postgres postgres`. ->**Note** Users and groups in an image get a non-deterministic ->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. +> **Note:** Users and groups in an image get a non-deterministic +> 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. You should avoid installing or using `sudo` since it has unpredictable TTY and signal-forwarding behavior that can cause more more problems than it solves. If diff --git a/docs/sources/docker-hub/official_repos.md b/docs/sources/docker-hub/official_repos.md index 92ce0dddfb..5a948c6263 100644 --- a/docs/sources/docker-hub/official_repos.md +++ b/docs/sources/docker-hub/official_repos.md @@ -41,7 +41,7 @@ Your `Dockerfile` should adhere to the following: established Official Image. * It must follow `Dockerfile` best practices. These are discussed on the [best practices page](/articles/dockerfile_best-practices). In addition, -Docker engineer Michael Crosby has some good tips for Dockerfiles in +Docker engineer Michael Crosby has some good tips for `Dockerfiles` in this [blog post](http://crosbymichael.com/dockerfile-best-practices-take-2.html). While [`ONBUILD` triggers](https://docs.docker.com/reference/builder/#onbuild) @@ -77,7 +77,7 @@ can be made based on the logo needed ### A long description -Include a comprehensive description of your image (in markdown format, GitHub +Include a comprehensive description of your image (in Markdown format, GitHub flavor preferred). Only one description is required; you don’t need additional descriptions for each tag. The file should also: @@ -88,9 +88,9 @@ content requirements In terms of content, the long description must include the following sections: -* Overview & Links -* How-to/Usage -* Issues & Contribution Info +* Overview & links +* How-to/usage +* Issues & contributions #### Overview & links @@ -109,15 +109,15 @@ A section that describes how to run and use the image, including common use cases and example `Dockerfile`s (if applicable). Try to provide clear, step-by- step instructions wherever possible. -##### Issues & contribution info +##### Issues & contributions + In this section, point users to any resources that can help them contribute to the project. Include contribution guidelines and any specific instructions related to your development practices. Include a link to [Docker’s resources for contributors](https://docs.docker.com/contributing/contributing/). Be sure to include contact info, handles, etc. for official maintainers. -##### Issues -Include a brief section letting users know where they can go for help and how +Also include information letting users know where they can go for help and how they can file issues with the repo. Point them to any specific IRC channels, issue trackers, contacts, additional “how-to” information or other resources. @@ -125,8 +125,9 @@ issue trackers, contacts, additional “how-to” information or other resources Include a file, `LICENSE`, of any applicable license. Docker recommends using the license of the software contained in the image, provided it allows Docker, -Inc. to legally build and distribute the image. Otherwise, Docker recommends -adopting the [Expat license](http://directory.fsf.org/wiki/License:Expat). +Inc. to legally build and distribute the image. Otherwise, Docker recommends +adopting the [Expat license](http://directory.fsf.org/wiki/License:Expat) +(a.k.a., the MIT or X11 license). ## Examples @@ -160,7 +161,7 @@ Put this file in the root of your app, next to the `Gemfile`. 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`. -Then build and run the docker image. +Then build and run the Docker image. docker build -t my-rails-app . 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, docker run --name some-rails-app -p 8080:3000 -d my-rails-app -Then hit `http://localhost:8080` or `http://host-ip:8080` in a browser. +Then go to `http://localhost:8080` or `http://host-ip:8080` in a browser. ``` For more examples, take a look at these repos: @@ -182,4 +183,7 @@ For more examples, take a look at these repos: ## Submit your repo -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. +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.