浏览代码

Merge pull request #8197 from fredlf/adding_official-repo-guidelines

Docs for Official Repo release
Fred Lifton 10 年之前
父节点
当前提交
8dd11c7175

+ 6 - 4
docs/mkdocs.yml

@@ -65,6 +65,7 @@ pages:
 - ['docker-hub/accounts.md', 'Docker Hub', 'Accounts']
 - ['docker-hub/repos.md', 'Docker Hub', 'Repositories']
 - ['docker-hub/builds.md', 'Docker Hub', 'Automated Builds']
+- ['docker-hub/official_repos.md', 'Docker Hub', 'Official Repo Guidelines']
 
 # Examples:
 - ['examples/index.md', '**HIDDEN**']
@@ -83,17 +84,18 @@ pages:
 - ['articles/networking.md', 'Articles', 'Advanced networking']
 - ['articles/security.md', 'Articles', 'Security']
 - ['articles/https.md', 'Articles', 'Running Docker with HTTPS']
-- ['articles/host_integration.md', 'Articles', 'Automatically starting Containers']
+- ['articles/host_integration.md', 'Articles', 'Automatically starting containers']
+- ['articles/baseimages.md', 'Articles', 'Creating a base image']
+- ['articles/dockerfile_best-practices.md', 'Articles', 'Best practices for writing Dockerfiles']
 - ['articles/certificates.md', 'Articles', 'Using certificates for repository client verification']
 - ['articles/using_supervisord.md', 'Articles', 'Using Supervisor']
 - ['articles/cfengine_process_management.md', 'Articles', 'Process management with CFEngine']
 - ['articles/puppet.md', 'Articles', 'Using Puppet']
 - ['articles/chef.md', 'Articles', 'Using Chef']
 - ['articles/dsc.md', 'Articles', 'Using PowerShell DSC']
-- ['articles/ambassador_pattern_linking.md', 'Articles', 'Cross-Host linking using Ambassador Containers']
+- ['articles/ambassador_pattern_linking.md', 'Articles', 'Cross-Host linking using ambassador containers']
 - ['articles/runmetrics.md', 'Articles', 'Runtime metrics']
-- ['articles/baseimages.md', 'Articles', 'Creating a Base Image']
-- ['articles/b2d_volume_resize.md', 'Articles', 'Increasing a Boot2Docker Volume']
+- ['articles/b2d_volume_resize.md', 'Articles', 'Increasing a Boot2Docker volume']
 
 # Reference
 - ['reference/index.md', '**HIDDEN**']

+ 10 - 1
docs/sources/articles/baseimages.md

@@ -55,5 +55,14 @@ image to base your new minimal containers `FROM`:
     COPY true-asm /true
     CMD ["/true"]
 
-The Dockerfile above is from extremely minimal image - [tianon/true](
+The `Dockerfile` above is from an extremely minimal image - [tianon/true](
 https://github.com/tianon/dockerfiles/tree/master/true).
+
+## More resources
+
+There are lots more resources available to help you write your 'Dockerfile`.
+
+* There's a [complete guide to all the instructions](/reference/builder/) available for use in a `Dockerfile` in the reference section.
+* To help you write a clear, readable, maintainable `Dockerfile`, we've also
+written a [`Dockerfile` Best Practices guide](/articles/dockerfile_best-practices).
+* If you're working on an Official Repo, be sure to check out the [Official Repo Guidelines](/docker-hub/official_repos/).

+ 339 - 0
docs/sources/articles/dockerfile_best-practices.md

@@ -0,0 +1,339 @@
+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 `Dockerfile`s
+
+## Overview
+
+Docker can build images automatically by reading the instructions from a
+`Dockerfile`, a text file that contains all the commands, in order, needed to
+build a given image. `Dockerfile`s adhere to a specific format and use a
+specific set of instructions. You can learn the basics on the 
+[Dockerfile Reference](https://docs.docker.com/reference/builder/) page. If
+you’re new to writing `Dockerfile`s, you should start there.
+
+This document covers the best practices and methods recommended by Docker,
+Inc. and the Docker Community for creating easy-to-use, effective
+`Dockerfile`s. We strongly suggest you follow these recommendations (in fact,
+if you’re creating an Official Image, you *must* adhere to these practices).
+
+You can see many of these practices and recommendations in action in the [buildpack-deps `Dockerfile`](https://github.com/docker-library/buildpack-deps/blob/master/jessie/Dockerfile).
+
+> 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
+
+### Containers should be ephemeral
+
+The container produced by the image your `Dockerfile` defines should be as
+ephemeral as possible. “Ephemeral” here means that it can be stopped and
+destroyed and a new one built and put in place with an absolute minimum of
+set-up and configuration.
+
+### 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
+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
+megabytes worth of upload time.
+
+### Avoid installing unnecessary packages
+
+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.
+
+### Run only one process per container
+
+In almost all cases, you should only run a single process in a single
+container. Decoupling applications into multiple containers makes it much
+easier to scale horizontally and reuse containers. If that service depends on
+another service, make use of [container linking](https://docs.docker.com/userguide/dockerlinks/).
+
+### Minimize the number of layers
+
+You need to find the balance between readability (and thus long-term
+maintainability) of the `Dockerfile` and minimizing the number of layers it
+uses. Be strategic and cautious about the number of layers you use.
+
+### Sort multi-line arguments
+
+Whenever possible, ease later changes by sorting multi-line arguments
+alphanumerically. This will help you avoid duplication of packages and make the
+list much easier to update. This also makes PRs a lot easier to read and
+review. Adding a space before a backslash (`\`) helps as well. 
+
+Here’s an example from the [`buildpack-deps` image](https://github.com/docker-library/buildpack-deps):
+
+ RUN apt-get update && apt-get install -y \
+    bzr \
+    cvs \
+    git \
+    mercurial \
+    subversion
+
+## The `Dockerfile` instructions
+
+This section contains specific recommendations for the correct usage of the
+various instructions contained in a `Dockerfile`.
+
+### [`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.
+
+### [`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 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:
+
+* 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
+`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 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
+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
+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
+failures due to unanticipated changes in required packages.
+
+#### Example
+
+Below is a well-formed `RUN` instruction that demonstrates the above
+recommendations. Note that the last package, `s3cmd`, specifies a version
+`1.1.0*`. If the image previously used an older version, specifying the new one
+will cause a cache bust of `apt-get update` and ensure the installation of
+the new version (which in this case had a new, required feature).
+
+    RUN apt-get update && apt-get install -y \
+        aufs-tools \
+        automake \
+        btrfs-tools \
+        build-essential \
+        curl \
+        dpkg-sig \
+        git \
+        iptables \
+        libapparmor-dev \
+        libcap-dev \
+        libsqlite3-dev \
+        lxc=1.0* \
+        mercurial \
+        parallel \
+        reprepro \
+        ruby1.9.1 \
+        ruby1.9.1-dev \
+        s3cmd=1.1.0*
+
+### [`CMD`](https://docs.docker.com/reference/builder/#cmd)
+
+The `CMD` instruction should be used to run the software contained by your
+image, along with any arguments. `CMD` should almost always be used in the
+form of `CMD [“executable”, “param1”, “param2”…]`. Thus, if the image is for a
+service (Apache, Rails, etc.), you would run something like
+`CMD ["apache2","-DFOREGROUND"]`. Indeed, this form of the instruction is
+recommended for any service-based image.
+
+In most other cases, `CMD` should be given an interactive shell (bash, python,
+perl, etc), for example, `CMD ["perl", "-de0"]`, `CMD ["python"]`, or
+`CMD [“php”, “-a”]`. Using this form means that when you execute something like
+`docker run -it python`, you’ll get dropped into a usable shell, ready to go.
+`CMD` should rarely be used in the manner of `CMD [“param”, “param”]` in
+conjunction with [`ENTRYPOINT`](https://docs.docker.com/reference/builder/#entrypoint), unless
+you and your expected users are already quite familiar with how `ENTRYPOINT`
+works. 
+
+### [`EXPOSE`](https://docs.docker.com/reference/builder/#expose)
+
+The `EXPOSE` instruction indicates the ports on which a container will listen
+for connections. Consequently, you should use the common, traditional port for
+your application. For example, an image containing the Apache web server would
+use `EXPOSE 80`, while an image containing MongoDB would use `EXPOSE 27017` and
+so on.
+
+For external access, your users can execute `docker run` with a flag indicating
+how to map the specified port to the port of their choice.
+For container linking, Docker provides environment variables for the path from
+the recipient container back to the source (ie, `MYSQL_PORT_3306_TCP`).
+
+### [`ENV`](https://docs.docker.com/reference/builder/#env)
+
+In order to make new software easier to run, you can use `ENV` to update the
+`PATH` environment variable for the software your container installs. For
+example, `ENV PATH /usr/local/nginx/bin:$PATH` will ensure that `CMD [“nginx”]`
+just works.
+
+The `ENV` instruction is also useful for providing required environment
+variables specific to services you wish to containerize, such as Postgres’s
+`PGDATA`.
+
+Lastly, `ENV` can also be used to set commonly used version numbers so that
+version bumps are easier to maintain, as seen in the following example:
+
+    ENV PG_MAJOR 9.3
+    ENV PG_VERSION 9.3.4
+    RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
+    ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
+
+Similar to having constant variables in a program (as opposed to hard-coding
+values), this approach lets you change a single `ENV` instruction to
+auto-magically bump the version of the software in your container.
+
+### [`ADD`](https://docs.docker.com/reference/builder/#add) or [`COPY`](https://docs.docker.com/reference/builder/#copy)
+
+Although `ADD` and `COPY` are functionally similar, generally speaking, `COPY`
+is preferred. That’s because it’s more transparent than `ADD`. `COPY` only
+supports the basic copying of local files into the container, while `ADD` has
+some features (like local-only tar extraction and remote URL support) that are
+not immediately obvious. Consequently, the best use for `ADD` is local tar file
+auto-extraction into the image, as in `ADD rootfs.tar.xz /`.
+
+Because image size matters, using `ADD` to fetch packages from remote URLs is
+strongly discouraged; you should use `curl` or `wget` instead. That way you can
+delete the files you no longer need after they’ve been extracted and you won't
+have to add another layer in your image. For example, you should avoid doing
+things like:
+
+    ADD http://example.com/big.tar.xz /usr/src/things/
+    RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
+    RUN make -C /usr/src/things all
+
+And instead, do something like:
+
+    RUN mdkir -p /usr/src/things \
+        && curl -SL http://example.com/big.tar.gz \
+        | tar -xJC /usr/src/things \
+        && make -C /usr/src/things all
+
+For other items (files, directories) that do not require `ADD`’s tar
+auto-extraction capability, you should always use `COPY`.
+
+### [`ENTRYPOINT`](https://docs.docker.com/reference/builder/#entrypoint)
+
+The best use for `ENTRYPOINT` is as a helper script. Using `ENTRYPOINT` for
+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.
+
+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
+the entrypoint completes, the script will transparently bootstrap the command
+invoked by the user, making what has been run clear to the user (for example,
+`docker run -it mysql mysqld --some --flags` will transparently run
+`mysqld --some --flags` after `ENTRYPOINT` runs `initdb`).
+
+For example, let’s look at the `Dockerfile` for the
+[Postgres Official Image](https://github.com/docker-library/postgres).
+It refers to the following script: 
+
+```bash
+#!/bin/bash
+set -e
+
+if [ "$1" = 'postgres' ]; then
+    chown -R postgres "$PGDATA"
+
+    if [ -z "$(ls -A "$PGDATA")" ]; then
+        gosu postgres initdb
+    fi
+
+    exec gosu postgres "$@"
+fi
+
+exec "$@"
+```
+
+That script then gets copied into the container and the run via `ENTRYPOINT` on
+container startup: 
+
+    COPY ./docker-entrypoint.sh /
+    ENTRYPOINT ["/docker-entrypoint.sh"]
+
+### [`VOLUME`](https://docs.docker.com/reference/builder/#volume)
+
+The `VOLUME` instruction should be used to expose any database storage area,
+configuration storage, or files/folders created by your docker container. You
+are strongly encouraged to use `VOLUME` for any mutable and/or user-serviceable
+parts of your image.
+
+### [`USER`](https://docs.docker.com/reference/builder/#user)
+
+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** that users/groups in an image get assigned 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
+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
+[“gosu”](https://github.com/tianon/gosu). 
+
+Lastly, to reduce layers and complexity, try to minimize switching `USER` back
+and forth frequently.
+
+### [`WORKDIR`](https://docs.docker.com/reference/builder/#workdir)
+
+For clarity and reliability, you should always use absolute paths for your
+`WORKDIR`. Also, you should use `WORKDIR` instead of  proliferating
+instructions like `RUN cd … && do-something`, which are hard to read,
+troubleshoot, and maintain.
+
+### [`ONBUILD`](https://docs.docker.com/reference/builder/#onbuild)
+
+`ONBUILD` is only useful for images that are going to be built `FROM` a given
+image. For example, you would use `ONBUILD` for a language stack image that
+builds arbitrary user software written in that language within the
+`Dockerfile`, as you can see in [Ruby’s `ONBUILD` variants](https://github.com/docker-library/ruby/blob/master/2.1/onbuild/Dockerfile). 
+
+Images built from `ONBUILD` should get a separate tag, for example:
+`ruby:1.9-onbuild` or `ruby:2.0-onbuild`.
+
+Be careful when putting `ADD` or `COPY` in `ONBUILD`. The “onbuild” image will
+fail catastrophically if the new build's context is missing the resource being
+added. Adding a separate tag, as recommended above, will help mitigate this by
+allowing the `Dockerfile` author to make a choice.
+
+## Examples For Official Repositories
+
+These Official Repos have exemplary `Dockerfile`s:
+
+* [Go](https://registry.hub.docker.com/_/golang/)
+* [Perl](https://registry.hub.docker.com/_/perl/)
+* [Hy](https://registry.hub.docker.com/_/hylang/)
+* [Rails](https://registry.hub.docker.com/_/rails)
+
+## Additional Resources:
+
+* [Dockerfile Reference](https://docs.docker.com/reference/builder/#onbuild)
+* [More about Base Images](https://docs.docker.com/articles/baseimages/)
+* [More about Automated Builds](https://docs.docker.com/docker-hub/builds/)
+* [Guidelines for Creating Official Repositories](https://docs.docker.com/docker-hub/official_repos/)

+ 178 - 0
docs/sources/docker-hub/official_repos.md

@@ -0,0 +1,178 @@
+page_title: Guidelines for Official Repositories on Docker Hub
+page_description: Guidelines for Official Repositories on Docker Hub
+page_keywords: Docker, docker, registry, accounts, plans, Dockerfile, Docker Hub, docs, official, image, documentation
+
+# Guidelines for Creating and Documenting Official Repositories
+
+## Introduction
+
+You’ve been given the job of creating an image for an Official Repository
+hosted on [Docker Hub Registry](https://registry.hub.docker.com/). These are
+our guidelines for getting that task done. Even if you’re not
+planning to create an Official Repo, you can think of these guidelines as best
+practices for image creation generally.
+
+This document consists of two major sections:
+
+* A list of expected files, resources and supporting items for your image
+* Examples embodying those practices
+
+## Expected Files & Resources
+
+### A Git repository
+
+Your image needs to live in a Git repository, preferably on GitHub. (If you’d
+like to use a different provider, please [contact us](mailto:feedback@docker.com)
+directly.) Docker **strongly** recommends that this repo be publicly
+accessible.
+
+If the repo is private or has otherwise limited access, you must provide a
+means of at least “read-only” access for both general users and for the
+docker-library maintainers, who need access for review and building purposes.
+
+### A `Dockerfile`
+
+Complete information on `Dockerfile`s can be found in the [Reference section](https://docs.docker.com/reference/builder/).
+We also have a page discussing [best practices for writing `Dockerfile`s](/articles/dockerfile_best-practices).
+Your `Dockerfile` should adhere to the following:
+
+* It must be written either by using `FROM scratch` or be based on another,
+established Official Image.
+* It must follow `Dockerfile` best practices. These are discussed in the
+[Best Practices document](/articles/dockerfile_best-practices). In addition,
+Docker engineer Michael Crosby has a good discussion of Dockerfiles in
+this [blog post](http://crosbymichael.com/dockerfile-best-practices-take-2.html).
+
+While [`ONBUILD` triggers](https://docs.docker.com/reference/builder/#onbuild)
+are not required, if you choose to use them you should:
+
+* Build both `ONBUILD` and non-`ONBUILD` images, with the `ONBUILD` image
+built `FROM` the non-`ONBUILD` image.
+* The `ONBUILD` image should be specifically tagged, for example, `ruby:
+latest`and `ruby:onbuild`, or `ruby:2` and  `ruby:2-onbuild`.
+
+### A short description
+
+Include a brief description of your image (in plaintext). Only one description
+is required; you don’t need additional descriptions for each tag. The file
+should also: 
+
+* Be named `README-short.txt`
+* Reside in the repo for the “latest” tag
+* Not exceed 200 characters.
+
+### A logo
+
+Include a logo of your company or the product (png format preferred). Only one
+logo is required; you don’t need additional logo files for each tag. The logo
+file should have the following characteristics: 
+
+* Be named `logo.png`
+* Should reside in the repo for the “latest” tag
+* Should be 200px min. in one dimension, 200px max. in the other.
+* Square or wide (landscape) is preferred over tall (portrait), but exceptions
+can be made based on the logo needed.
+
+### A long description
+
+Include a comprehensive description of your image (in markdown format). Only
+one description is required; you don’t need additional descriptions for each
+tag. The file should also: 
+
+* Be named `README.md`
+* Reside in the repo for the “latest” tag
+* Be no longer than absolutely necessary, while still addressing all the
+content requirements.
+
+In terms of content, the long description must include the following sections:
+
+* Overview & Links
+* How-to/Usage
+* Issues & Contribution Info
+
+#### Overview & links
+
+This section should provide:
+
+* an overview of the software contained in the image, similar to the
+introduction in a Wikipedia entry,
+
+* a selection of links to outside resources that help to describe the software,
+
+* a *mandatory* link to the `Dockerfile`.
+
+#### How-to/usage
+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
+In this part, 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
+they can file issues with the repo. Point them to any specific IRC channels,
+issue trackers, contacts, additional “how-to” information or other resources.
+
+### License
+
+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).
+
+## Examples
+
+Below are sample short and long description files for an imaginary image
+containing Ruby on Rails.
+
+### Short description
+
+`README-short.txt`
+
+`Ruby on Rails is an open-source application framework written in Ruby. It emphasizes best practices such as convention over configuration, active record pattern, and the model-view-controller pattern.`
+
+### Long description
+
+`README.md`
+
+```markdown
+# What is Ruby on Rails
+
+Ruby on Rails, often simply referred to as Rails, is an open source web application framework which runs via the Ruby programming language. It is a full-stack framework: it allows creating pages and applications that gather information from the web server, talk to or query the database, and render templates out of the box. As a result, Rails features a routing system that is independent of the web server.
+
+> [wikipedia.org/wiki/Ruby_on_Rails](https://en.wikipedia.org/wiki/Ruby_on_Rails)
+
+# How to use this image
+
+## Create a `Dockerfile` in your rails app project
+
+    FROM rails:onbuild
+
+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.
+
+    docker build -t my-rails-app .
+    docker run --name some-rails-app -d my-rails-app
+
+Test it by visiting `http://container-ip:3000` in a browser. On the other hand, if you need access outside the host on port 8080:
+
+    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.
+```
+
+For more examples, take a look at these repos: 
+
+* [Go](https://github.com/docker-library/golang)
+* [PostgreSQL](https://github.com/docker-library/postgres)
+* [Buildpack-deps](https://github.com/docker-library/buildpack-deps)
+* ["Hello World" minimal container](https://github.com/docker-library/hello-world)
+* [Node](https://github.com/docker-library/node)

+ 5 - 0
docs/sources/reference/builder.md

@@ -11,6 +11,11 @@ Docker image. By calling `docker build` from your terminal, you can have
 Docker build your image step by step, executing the instructions
 successively.
 
+This page discusses the specifics of all the instructions you can use in your
+`Dockerfile`. To further help you write a clear, readable, maintainable
+`Dockerfile`, we've also written a [`Dockerfile` Best Practices guide](/articles/dockerfile_best-practices).
+
+
 ## Usage
 
 To [*build*](../commandline/cli/#cli-build) an image from a source repository,

+ 3 - 1
docs/sources/userguide/dockerimages.md

@@ -468,11 +468,13 @@ We can then create a container from our new image.
     root@8196968dac35:/#
 
 > **Note:** 
-> This is just the briefest introduction to creating images. We've
+> This is just a brief introduction to creating images. We've
 > skipped a whole bunch of other instructions that you can use. We'll see more of
 > those instructions in later sections of the Guide or you can refer to the
 > [`Dockerfile`](/reference/builder/) reference for a
 > detailed description and examples of every instruction.
+> To help you write a clear, readable, maintainable `Dockerfile`, we've also
+> written a [`Dockerfile` Best Practices guide](/articles/dockerfile_best-practices).
 
 ## Setting tags on an image