init submit all files
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
---
|
||||
description: How to create base images
|
||||
keywords: images, base image, examples
|
||||
redirect_from:
|
||||
- /engine/articles/baseimages/
|
||||
- /engine/userguide/eng-image/baseimages/
|
||||
title: Create a base image
|
||||
---
|
||||
|
||||
Most Dockerfiles start from a parent image. If you need to completely control
|
||||
the contents of your image, you might need to create a base image instead.
|
||||
Here's the difference:
|
||||
|
||||
- A [parent image](../../glossary.md#parent_image) is the image that your
|
||||
image is based on. It refers to the contents of the `FROM` directive in the
|
||||
Dockerfile. Each subsequent declaration in the Dockerfile modifies this parent
|
||||
image. Most Dockerfiles start from a parent image, rather than a base image.
|
||||
However, the terms are sometimes used interchangeably.
|
||||
|
||||
- A [base image](../../glossary.md#base_image) has `FROM scratch` in its Dockerfile.
|
||||
|
||||
This topic shows you several ways to create a base image. The specific process
|
||||
will depend heavily on the Linux distribution you want to package. We have some
|
||||
examples below, and you are encouraged to submit pull requests to contribute new
|
||||
ones.
|
||||
|
||||
## Create a full image using tar
|
||||
|
||||
In general, start with a working machine that is running
|
||||
the distribution you'd like to package as a parent image, though that is
|
||||
not required for some tools like Debian's
|
||||
[Debootstrap](https://wiki.debian.org/Debootstrap), which you can also
|
||||
use to build Ubuntu images.
|
||||
|
||||
It can be as simple as this to create an Ubuntu parent image:
|
||||
|
||||
$ sudo debootstrap xenial xenial > /dev/null
|
||||
$ sudo tar -C xenial -c . | docker import - xenial
|
||||
|
||||
a29c15f1bf7a
|
||||
|
||||
$ docker run xenial cat /etc/lsb-release
|
||||
|
||||
DISTRIB_ID=Ubuntu
|
||||
DISTRIB_RELEASE=16.04
|
||||
DISTRIB_CODENAME=xenial
|
||||
DISTRIB_DESCRIPTION="Ubuntu 16.04 LTS"
|
||||
|
||||
There are more example scripts for creating parent images in the Docker
|
||||
GitHub Repo:
|
||||
|
||||
- [BusyBox](https://github.com/moby/moby/blob/master/contrib/mkimage/busybox-static)
|
||||
- CentOS / Scientific Linux CERN (SLC) [on Debian/Ubuntu](
|
||||
https://github.com/moby/moby/blob/master/contrib/mkimage/rinse) or
|
||||
[on CentOS/RHEL/SLC/etc.](
|
||||
https://github.com/moby/moby/blob/master/contrib/mkimage-yum.sh)
|
||||
- [Debian / Ubuntu](
|
||||
https://github.com/moby/moby/blob/master/contrib/mkimage/debootstrap)
|
||||
|
||||
## Create a simple parent image using scratch
|
||||
|
||||
You can use Docker's reserved, minimal image, `scratch`, as a starting point for
|
||||
building containers. Using the `scratch` "image" signals to the build process
|
||||
that you want the next command in the `Dockerfile` to be the first filesystem
|
||||
layer in your image.
|
||||
|
||||
While `scratch` appears in Docker's repository on the hub, you can't pull it,
|
||||
run it, or tag any image with the name `scratch`. Instead, you can refer to it
|
||||
in your `Dockerfile`. For example, to create a minimal container using
|
||||
`scratch`:
|
||||
|
||||
```dockerfile
|
||||
FROM scratch
|
||||
ADD hello /
|
||||
CMD ["/hello"]
|
||||
```
|
||||
|
||||
Assuming you built the "hello" executable example by following the instructions
|
||||
at
|
||||
[https://github.com/docker-library/hello-world/](https://github.com/docker-library/hello-world/),
|
||||
and you compiled it with the `-static` flag, you can build this Docker
|
||||
image using this `docker build` command:
|
||||
|
||||
```bash
|
||||
docker build --tag hello .
|
||||
```
|
||||
|
||||
Don't forget the `.` character at the end, which sets the build context to the
|
||||
current directory.
|
||||
|
||||
> **Note**: Because Docker Desktop for Mac and Docker Desktop for Windows use a Linux VM,
|
||||
> you need a Linux binary, rather than a Mac or Windows binary.
|
||||
> You can use a Docker container to build it:
|
||||
>
|
||||
> ```bash
|
||||
> $ docker run --rm -it -v $PWD:/build ubuntu:16.04
|
||||
>
|
||||
> container# apt-get update && apt-get install build-essential
|
||||
> container# cd /build
|
||||
> container# gcc -o hello -static -nostartfiles hello.c
|
||||
> ```
|
||||
|
||||
To run your new image, use the `docker run` command:
|
||||
|
||||
```bash
|
||||
docker run --rm hello
|
||||
```
|
||||
|
||||
This example creates the hello-world image used in the tutorials.
|
||||
If you want to test it out, you can clone
|
||||
[the image repo](https://github.com/docker-library/hello-world).
|
||||
|
||||
|
||||
## More resources
|
||||
|
||||
There are lots of resources available to help you write your `Dockerfile`.
|
||||
|
||||
* There's a [complete guide to all the instructions](../../engine/reference/builder.md) 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](dockerfile_best-practices.md).
|
||||
* If your goal is to create a new Official Image, be sure to read up on Docker's [Official Images](../../docker-hub/official_images.md).
|
||||
@@ -0,0 +1,269 @@
|
||||
---
|
||||
title: Build images with BuildKit
|
||||
description: Learn the new features of Docker Build with BuildKit
|
||||
keywords: build, security, engine, secret, BuildKit
|
||||
---
|
||||
|
||||
Docker Build is one of the most used features of the Docker Engine - users
|
||||
ranging from developers, build teams, and release teams all use Docker Build.
|
||||
|
||||
Docker Build enhancements for 18.09 release introduces a much-needed overhaul of
|
||||
the build architecture. By integrating BuildKit, users should see an improvement
|
||||
on performance, storage management, feature functionality, and security.
|
||||
|
||||
* Docker images created with BuildKit can be pushed to Docker Hub just like
|
||||
Docker images created with legacy build
|
||||
* the Dockerfile format that works on legacy build will also work with BuildKit
|
||||
builds
|
||||
* The new `--secret` command line option allows the user to pass secret
|
||||
information for building new images with a specified Dockerfile
|
||||
|
||||
For more information on build options, see the reference guide on the
|
||||
[command line build options](/engine/reference/commandline/build/).
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
* A current version of Docker (18.09 or higher)
|
||||
* Network connection required for downloading images of custom frontends
|
||||
|
||||
## Limitations
|
||||
|
||||
* Only supported for building Linux containers
|
||||
|
||||
## To enable BuildKit builds
|
||||
|
||||
Easiest way from a fresh install of docker is to set the `DOCKER_BUILDKIT=1`
|
||||
environment variable when invoking the `docker build` command, such as:
|
||||
|
||||
```bash
|
||||
$ DOCKER_BUILDKIT=1 docker build .
|
||||
```
|
||||
|
||||
To enable docker BuildKit by default, set daemon configuration in
|
||||
`/etc/docker/daemon.json` feature to true and restart the daemon:
|
||||
|
||||
```json
|
||||
{ "features": { "buildkit": true } }
|
||||
```
|
||||
|
||||
## New Docker Build command line build output
|
||||
|
||||
New docker build BuildKit TTY output (default):
|
||||
|
||||
```console
|
||||
$ docker build .
|
||||
|
||||
[+] Building 70.9s (34/59)
|
||||
=> [runc 1/4] COPY hack/dockerfile/install/install.sh ./install.sh 14.0s
|
||||
=> [frozen-images 3/4] RUN /download-frozen-image-v2.sh /build buildpa 24.9s
|
||||
=> [containerd 4/5] RUN PREFIX=/build/ ./install.sh containerd 37.1s
|
||||
=> [tini 2/5] COPY hack/dockerfile/install/install.sh ./install.sh 4.9s
|
||||
=> [vndr 2/4] COPY hack/dockerfile/install/vndr.installer ./ 1.6s
|
||||
=> [dockercli 2/4] COPY hack/dockerfile/install/dockercli.installer ./ 5.9s
|
||||
=> [proxy 2/4] COPY hack/dockerfile/install/proxy.installer ./ 15.7s
|
||||
=> [tomlv 2/4] COPY hack/dockerfile/install/tomlv.installer ./ 12.4s
|
||||
=> [gometalinter 2/4] COPY hack/dockerfile/install/gometalinter.install 25.5s
|
||||
=> [vndr 3/4] RUN PREFIX=/build/ ./install.sh vndr 33.2s
|
||||
=> [tini 3/5] COPY hack/dockerfile/install/tini.installer ./ 6.1s
|
||||
=> [dockercli 3/4] RUN PREFIX=/build/ ./install.sh dockercli 18.0s
|
||||
=> [runc 2/4] COPY hack/dockerfile/install/runc.installer ./ 2.4s
|
||||
=> [tini 4/5] RUN PREFIX=/build/ ./install.sh tini 11.6s
|
||||
=> [runc 3/4] RUN PREFIX=/build/ ./install.sh runc 23.4s
|
||||
=> [tomlv 3/4] RUN PREFIX=/build/ ./install.sh tomlv 9.7s
|
||||
=> [proxy 3/4] RUN PREFIX=/build/ ./install.sh proxy 14.6s
|
||||
=> [dev 2/23] RUN useradd --create-home --gid docker unprivilegeduser 5.1s
|
||||
=> [gometalinter 3/4] RUN PREFIX=/build/ ./install.sh gometalinter 9.4s
|
||||
=> [dev 3/23] RUN ln -sfv /go/src/github.com/docker/docker/.bashrc ~/.ba 4.3s
|
||||
=> [dev 4/23] RUN echo source /usr/share/bash-completion/bash_completion 2.5s
|
||||
=> [dev 5/23] RUN ln -s /usr/local/completion/bash/docker /etc/bash_comp 2.1s
|
||||
```
|
||||
|
||||
New docker build BuildKit plain output:
|
||||
|
||||
```console
|
||||
$ docker build --progress=plain .
|
||||
|
||||
#1 [internal] load .dockerignore
|
||||
#1 digest: sha256:d0b5f1b2d994bfdacee98198b07119b61cf2442e548a41cf4cd6d0471a627414
|
||||
#1 name: "[internal] load .dockerignore"
|
||||
#1 started: 2018-08-31 19:07:09.246319297 +0000 UTC
|
||||
#1 completed: 2018-08-31 19:07:09.246386115 +0000 UTC
|
||||
#1 duration: 66.818µs
|
||||
#1 started: 2018-08-31 19:07:09.246547272 +0000 UTC
|
||||
#1 completed: 2018-08-31 19:07:09.260979324 +0000 UTC
|
||||
#1 duration: 14.432052ms
|
||||
#1 transferring context: 142B done
|
||||
|
||||
|
||||
#2 [internal] load Dockerfile
|
||||
#2 digest: sha256:2f10ef7338b6eebaf1b072752d0d936c3d38c4383476a3985824ff70398569fa
|
||||
#2 name: "[internal] load Dockerfile"
|
||||
#2 started: 2018-08-31 19:07:09.246331352 +0000 UTC
|
||||
#2 completed: 2018-08-31 19:07:09.246386021 +0000 UTC
|
||||
#2 duration: 54.669µs
|
||||
#2 started: 2018-08-31 19:07:09.246720773 +0000 UTC
|
||||
#2 completed: 2018-08-31 19:07:09.270231987 +0000 UTC
|
||||
#2 duration: 23.511214ms
|
||||
#2 transferring dockerfile: 9.26kB done
|
||||
```
|
||||
|
||||
## Overriding default frontends
|
||||
|
||||
The new syntax features in `Dockerfile` are available if you override the default
|
||||
frontend. To override the default frontend, set the first line of the
|
||||
`Dockerfile` as a comment with a specific frontend image:
|
||||
|
||||
```dockerfile
|
||||
# syntax = <frontend image>, e.g. # syntax = docker/dockerfile:1.0-experimental
|
||||
```
|
||||
|
||||
## New Docker Build secret information
|
||||
|
||||
The new `--secret` flag for docker build allows the user to pass secret
|
||||
information to be used in the Dockerfile for building docker images in a safe
|
||||
way that will not end up stored in the final image.
|
||||
|
||||
`id` is the identifier to pass into the `docker build --secret`. This identifier
|
||||
is associated with the `RUN --mount` identifier to use in the Dockerfile. Docker
|
||||
does not use the filename of where the secret is kept outside of the Dockerfile,
|
||||
since this may be sensitive information.
|
||||
|
||||
`dst` renames the secret file to a specific file in the Dockerfile `RUN` command
|
||||
to use.
|
||||
|
||||
For example, with a secret piece of information stored in a text file:
|
||||
|
||||
```console
|
||||
$ echo 'WARMACHINEROX' > mysecret.txt
|
||||
```
|
||||
|
||||
And with a Dockerfile that specifies use of a BuildKit frontend
|
||||
`docker/dockerfile:1.0-experimental`, the secret can be accessed.
|
||||
|
||||
For example:
|
||||
|
||||
```dockerfile
|
||||
# syntax = docker/dockerfile:1.0-experimental
|
||||
FROM alpine
|
||||
|
||||
# shows secret from default secret location:
|
||||
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
|
||||
|
||||
# shows secret from custom secret location:
|
||||
RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
|
||||
```
|
||||
|
||||
This Dockerfile is only to demonstrate that the secret can be accessed. As you
|
||||
can see the secret printed in the build output. The final image built will not
|
||||
have the secret file:
|
||||
|
||||
```console
|
||||
$ docker build --no-cache --progress=plain --secret id=mysecret,src=mysecret.txt .
|
||||
...
|
||||
#8 [2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
|
||||
#8 digest: sha256:5d8cbaeb66183993700828632bfbde246cae8feded11aad40e524f54ce7438d6
|
||||
#8 name: "[2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret"
|
||||
#8 started: 2018-08-31 21:03:30.703550864 +0000 UTC
|
||||
#8 1.081 WARMACHINEROX
|
||||
#8 completed: 2018-08-31 21:03:32.051053831 +0000 UTC
|
||||
#8 duration: 1.347502967s
|
||||
|
||||
|
||||
#9 [3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
|
||||
#9 digest: sha256:6c7ebda4599ec6acb40358017e51ccb4c5471dc434573b9b7188143757459efa
|
||||
#9 name: "[3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar"
|
||||
#9 started: 2018-08-31 21:03:32.052880985 +0000 UTC
|
||||
#9 1.216 WARMACHINEROX
|
||||
#9 completed: 2018-08-31 21:03:33.523282118 +0000 UTC
|
||||
#9 duration: 1.470401133s
|
||||
...
|
||||
```
|
||||
|
||||
## Using SSH to access private data in builds
|
||||
|
||||
> **Acknowledgment**
|
||||
>
|
||||
> Please see [Build secrets and SSH forwarding in Docker 18.09](https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066)
|
||||
> for more information and examples.
|
||||
|
||||
The `docker build` has a `--ssh` option to allow the Docker Engine to forward
|
||||
SSH agent connections. For more information on SSH agent, see the
|
||||
[OpenSSH man page](https://man.openbsd.org/ssh-agent).
|
||||
|
||||
Only the commands in the `Dockerfile` that have explicitly requested the SSH
|
||||
access by defining `type=ssh` mount have access to SSH agent connections. The
|
||||
other commands have no knowledge of any SSH agent being available.
|
||||
|
||||
To request SSH access for a `RUN` command in the `Dockerfile`, define a mount
|
||||
with type `ssh`. This will set up the `SSH_AUTH_SOCK` environment variable to
|
||||
make programs relying on SSH automatically use that socket.
|
||||
|
||||
Here is an example Dockerfile using SSH in the container:
|
||||
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:experimental
|
||||
FROM alpine
|
||||
|
||||
# Install ssh client and git
|
||||
RUN apk add --no-cache openssh-client git
|
||||
|
||||
# Download public key for github.com
|
||||
RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
|
||||
# Clone private repository
|
||||
RUN --mount=type=ssh git clone git@github.com:myorg/myproject.git myproject
|
||||
```
|
||||
|
||||
Once the `Dockerfile` is created, use the `--ssh` option for connectivity with
|
||||
the SSH agent.
|
||||
|
||||
```bash
|
||||
$ docker build --ssh default .
|
||||
```
|
||||
|
||||
You may need to run `ssh-add` to add private key identities to the authentication agent first for this to work.
|
||||
|
||||
## Troubleshooting : issues with private registries
|
||||
|
||||
#### x509: certificate signed by unknown authority
|
||||
|
||||
If you are fetching images from insecure registry (with self-signed certificates)
|
||||
and/or using such a registry as a mirror, you are facing a known issue in
|
||||
Docker 18.09 :
|
||||
|
||||
```console
|
||||
[+] Building 0.4s (3/3) FINISHED
|
||||
=> [internal] load build definition from Dockerfile
|
||||
=> => transferring dockerfile: 169B
|
||||
=> [internal] load .dockerignore
|
||||
=> => transferring context: 2B
|
||||
=> ERROR resolve image config for docker.io/docker/dockerfile:experimental
|
||||
------
|
||||
> resolve image config for docker.io/docker/dockerfile:experimental:
|
||||
------
|
||||
failed to do request: Head https://repo.mycompany.com/v2/docker/dockerfile/manifests/experimental: x509: certificate signed by unknown authority
|
||||
```
|
||||
|
||||
Solution : secure your registry properly. You can get SSL certificates from
|
||||
Let's Encrypt for free. See /registry/deploying/
|
||||
|
||||
|
||||
#### image not found when the private registry is running on Sonatype Nexus version < 3.15
|
||||
|
||||
If you are running a private registry using Sonatype Nexus version < 3.15, and
|
||||
receive an error similar to the following :
|
||||
|
||||
```console
|
||||
------
|
||||
> [internal] load metadata for docker.io/library/maven:3.5.3-alpine:
|
||||
------
|
||||
------
|
||||
> [1/4] FROM docker.io/library/maven:3.5.3-alpine:
|
||||
------
|
||||
rpc error: code = Unknown desc = docker.io/library/maven:3.5.3-alpine not found
|
||||
```
|
||||
|
||||
you may be facing the bug below : [NEXUS-12684](https://issues.sonatype.org/browse/NEXUS-12684)
|
||||
|
||||
Solution is to upgrade your Nexus to version 3.15 or above.
|
||||
@@ -0,0 +1,926 @@
|
||||
---
|
||||
description: Hints, tips and guidelines for writing clean, reliable Dockerfiles
|
||||
keywords: parent image, images, dockerfile, best practices, hub, official image
|
||||
redirect_from:
|
||||
- /articles/dockerfile_best-practices/
|
||||
- /engine/articles/dockerfile_best-practices/
|
||||
- /docker-cloud/getting-started/intermediate/optimize-dockerfiles/
|
||||
- /docker-cloud/tutorials/optimize-dockerfiles/
|
||||
- /engine/userguide/eng-image/dockerfile_best-practices/
|
||||
title: Best practices for writing Dockerfiles
|
||||
---
|
||||
|
||||
This document covers recommended best practices and methods for building
|
||||
efficient images.
|
||||
|
||||
Docker builds images automatically by reading the instructions from a
|
||||
`Dockerfile` -- a text file that contains all commands, in order, needed to
|
||||
build a given image. A `Dockerfile` adheres to a specific format and set of
|
||||
instructions which you can find at [Dockerfile reference](../../engine/reference/builder.md).
|
||||
|
||||
A Docker image consists of read-only layers each of which represents a
|
||||
Dockerfile instruction. The layers are stacked and each one is a delta of the
|
||||
changes from the previous layer. Consider this `Dockerfile`:
|
||||
|
||||
```dockerfile
|
||||
FROM ubuntu:18.04
|
||||
COPY . /app
|
||||
RUN make /app
|
||||
CMD python /app/app.py
|
||||
```
|
||||
|
||||
Each instruction creates one layer:
|
||||
|
||||
- `FROM` creates a layer from the `ubuntu:18.04` Docker image.
|
||||
- `COPY` adds files from your Docker client's current directory.
|
||||
- `RUN` builds your application with `make`.
|
||||
- `CMD` specifies what command to run within the container.
|
||||
|
||||
When you run an image and generate a container, you add a new _writable layer_
|
||||
(the "container layer") on top of the underlying layers. All changes made to
|
||||
the running container, such as writing new files, modifying existing files, and
|
||||
deleting files, are written to this thin writable container layer.
|
||||
|
||||
For more on image layers (and how Docker builds and stores images), see
|
||||
[About storage drivers](../../storage/storagedriver/index.md).
|
||||
|
||||
## General guidelines and recommendations
|
||||
|
||||
### Create ephemeral containers
|
||||
|
||||
The image defined by your `Dockerfile` should generate containers that are as
|
||||
ephemeral as possible. By "ephemeral", we mean that the container can be stopped
|
||||
and destroyed, then rebuilt and replaced with an absolute minimum set up and
|
||||
configuration.
|
||||
|
||||
Refer to [Processes](https://12factor.net/processes) under _The Twelve-factor App_
|
||||
methodology to get a feel for the motivations of running containers in such a
|
||||
stateless fashion.
|
||||
|
||||
### Understand build context
|
||||
|
||||
When you issue a `docker build` command, the current working directory is called
|
||||
the _build context_. By default, the Dockerfile is assumed to be located here,
|
||||
but you can specify a different location with the file flag (`-f`). Regardless
|
||||
of where the `Dockerfile` actually lives, all recursive contents of files and
|
||||
directories in the current directory are sent to the Docker daemon as the build
|
||||
context.
|
||||
|
||||
> Build context example
|
||||
>
|
||||
> Create a directory for the build context and `cd` into it. Write "hello" into
|
||||
> a text file named `hello` and create a Dockerfile that runs `cat` on it. Build
|
||||
> the image from within the build context (`.`):
|
||||
>
|
||||
> ```shell
|
||||
> mkdir myproject && cd myproject
|
||||
> echo "hello" > hello
|
||||
> echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > Dockerfile
|
||||
> docker build -t helloapp:v1 .
|
||||
> ```
|
||||
>
|
||||
> Move `Dockerfile` and `hello` into separate directories and build a second
|
||||
> version of the image (without relying on cache from the last build). Use `-f`
|
||||
> to point to the Dockerfile and specify the directory of the build context:
|
||||
>
|
||||
> ```shell
|
||||
> mkdir -p dockerfiles context
|
||||
> mv Dockerfile dockerfiles && mv hello context
|
||||
> docker build --no-cache -t helloapp:v2 -f dockerfiles/Dockerfile context
|
||||
> ```
|
||||
|
||||
Inadvertently including files that are not necessary for building an image
|
||||
results in a larger build context and larger image size. This can increase the
|
||||
time to build the image, time to pull and push it, and the container runtime
|
||||
size. To see how big your build context is, look for a message like this when
|
||||
building your `Dockerfile`:
|
||||
|
||||
```none
|
||||
Sending build context to Docker daemon 187.8MB
|
||||
```
|
||||
|
||||
### Pipe Dockerfile through `stdin`
|
||||
|
||||
Docker has the ability to build images by piping `Dockerfile` through `stdin`
|
||||
with a _local or remote build context_. Piping a `Dockerfile` through `stdin`
|
||||
can be useful to perform one-off builds without writing a Dockerfile to disk,
|
||||
or in situations where the `Dockerfile` is generated, and should not persist
|
||||
afterwards.
|
||||
|
||||
> The examples in this section use [here documents](https://tldp.org/LDP/abs/html/here-docs.html)
|
||||
> for convenience, but any method to provide the `Dockerfile` on `stdin` can be
|
||||
> used.
|
||||
>
|
||||
> For example, the following commands are equivalent:
|
||||
>
|
||||
> ```bash
|
||||
> echo -e 'FROM busybox\nRUN echo "hello world"' | docker build -
|
||||
> ```
|
||||
>
|
||||
> ```bash
|
||||
> docker build -<<EOF
|
||||
> FROM busybox
|
||||
> RUN echo "hello world"
|
||||
> EOF
|
||||
> ```
|
||||
>
|
||||
> You can substitute the examples with your preferred approach, or the approach
|
||||
> that best fits your use-case.
|
||||
|
||||
|
||||
#### Build an image using a Dockerfile from stdin, without sending build context
|
||||
|
||||
Use this syntax to build an image using a `Dockerfile` from `stdin`, without
|
||||
sending additional files as build context. The hyphen (`-`) takes the position
|
||||
of the `PATH`, and instructs Docker to read the build context (which only
|
||||
contains a `Dockerfile`) from `stdin` instead of a directory:
|
||||
|
||||
```bash
|
||||
docker build [OPTIONS] -
|
||||
```
|
||||
|
||||
The following example builds an image using a `Dockerfile` that is passed through
|
||||
`stdin`. No files are sent as build context to the daemon.
|
||||
|
||||
```bash
|
||||
docker build -t myimage:latest -<<EOF
|
||||
FROM busybox
|
||||
RUN echo "hello world"
|
||||
EOF
|
||||
```
|
||||
|
||||
Omitting the build context can be useful in situations where your `Dockerfile`
|
||||
does not require files to be copied into the image, and improves the build-speed,
|
||||
as no files are sent to the daemon.
|
||||
|
||||
If you want to improve the build-speed by excluding _some_ files from the build-
|
||||
context, refer to [exclude with .dockerignore](#exclude-with-dockerignore).
|
||||
|
||||
> **Note**: Attempting to build a Dockerfile that uses `COPY` or `ADD` will fail
|
||||
> if this syntax is used. The following example illustrates this:
|
||||
>
|
||||
> ```bash
|
||||
> # create a directory to work in
|
||||
> mkdir example
|
||||
> cd example
|
||||
>
|
||||
> # create an example file
|
||||
> touch somefile.txt
|
||||
>
|
||||
> docker build -t myimage:latest -<<EOF
|
||||
> FROM busybox
|
||||
> COPY somefile.txt .
|
||||
> RUN cat /somefile.txt
|
||||
> EOF
|
||||
>
|
||||
> # observe that the build fails
|
||||
> ...
|
||||
> Step 2/3 : COPY somefile.txt .
|
||||
> COPY failed: stat /var/lib/docker/tmp/docker-builder249218248/somefile.txt: no such file or directory
|
||||
> ```
|
||||
|
||||
#### Build from a local build context, using a Dockerfile from stdin
|
||||
|
||||
Use this syntax to build an image using files on your local filesystem, but using
|
||||
a `Dockerfile` from `stdin`. The syntax uses the `-f` (or `--file`) option to
|
||||
specify the `Dockerfile` to use, using a hyphen (`-`) as filename to instruct
|
||||
Docker to read the `Dockerfile` from `stdin`:
|
||||
|
||||
```bash
|
||||
docker build [OPTIONS] -f- PATH
|
||||
```
|
||||
|
||||
The example below uses the current directory (`.`) as the build context, and builds
|
||||
an image using a `Dockerfile` that is passed through `stdin` using a [here
|
||||
document](https://tldp.org/LDP/abs/html/here-docs.html).
|
||||
|
||||
```bash
|
||||
# create a directory to work in
|
||||
mkdir example
|
||||
cd example
|
||||
|
||||
# create an example file
|
||||
touch somefile.txt
|
||||
|
||||
# build an image using the current directory as context, and a Dockerfile passed through stdin
|
||||
docker build -t myimage:latest -f- . <<EOF
|
||||
FROM busybox
|
||||
COPY somefile.txt .
|
||||
RUN cat /somefile.txt
|
||||
EOF
|
||||
```
|
||||
|
||||
#### Build from a remote build context, using a Dockerfile from stdin
|
||||
|
||||
Use this syntax to build an image using files from a remote `git` repository,
|
||||
using a `Dockerfile` from `stdin`. The syntax uses the `-f` (or `--file`) option to
|
||||
specify the `Dockerfile` to use, using a hyphen (`-`) as filename to instruct
|
||||
Docker to read the `Dockerfile` from `stdin`:
|
||||
|
||||
```bash
|
||||
docker build [OPTIONS] -f- PATH
|
||||
```
|
||||
|
||||
This syntax can be useful in situations where you want to build an image from a
|
||||
repository that does not contain a `Dockerfile`, or if you want to build with a custom
|
||||
`Dockerfile`, without maintaining your own fork of the repository.
|
||||
|
||||
The example below builds an image using a `Dockerfile` from `stdin`, and adds
|
||||
the `hello.c` file from the ["hello-world" Git repository on GitHub](https://github.com/docker-library/hello-world).
|
||||
|
||||
```bash
|
||||
docker build -t myimage:latest -f- https://github.com/docker-library/hello-world.git <<EOF
|
||||
FROM busybox
|
||||
COPY hello.c .
|
||||
EOF
|
||||
```
|
||||
|
||||
> **Under the hood**
|
||||
>
|
||||
> When building an image using a remote Git repository as build context, Docker
|
||||
> performs a `git clone` of the repository on the local machine, and sends
|
||||
> those files as build context to the daemon. This feature requires `git` to be
|
||||
> installed on the host where you run the `docker build` command.
|
||||
|
||||
### Exclude with .dockerignore
|
||||
|
||||
To exclude files not relevant to the build (without restructuring your source
|
||||
repository) use a `.dockerignore` file. This file supports exclusion patterns
|
||||
similar to `.gitignore` files. For information on creating one, see the
|
||||
[.dockerignore file](../../engine/reference/builder.md#dockerignore-file).
|
||||
|
||||
### Use multi-stage builds
|
||||
|
||||
[Multi-stage builds](multistage-build.md) allow you to drastically reduce the
|
||||
size of your final image, without struggling to reduce the number of intermediate
|
||||
layers and files.
|
||||
|
||||
Because an image is built during the final stage of the build process, you can
|
||||
minimize image layers by [leveraging build cache](#leverage-build-cache).
|
||||
|
||||
For example, if your build contains several layers, you can order them from the
|
||||
less frequently changed (to ensure the build cache is reusable) to the more
|
||||
frequently changed:
|
||||
|
||||
* Install tools you need to build your application
|
||||
|
||||
* Install or update library dependencies
|
||||
|
||||
* Generate your application
|
||||
|
||||
A Dockerfile for a Go application could look like:
|
||||
|
||||
```dockerfile
|
||||
FROM golang:1.11-alpine AS build
|
||||
|
||||
# Install tools required for project
|
||||
# Run `docker build --no-cache .` to update dependencies
|
||||
RUN apk add --no-cache git
|
||||
RUN go get github.com/golang/dep/cmd/dep
|
||||
|
||||
# List project dependencies with Gopkg.toml and Gopkg.lock
|
||||
# These layers are only re-built when Gopkg files are updated
|
||||
COPY Gopkg.lock Gopkg.toml /go/src/project/
|
||||
WORKDIR /go/src/project/
|
||||
# Install library dependencies
|
||||
RUN dep ensure -vendor-only
|
||||
|
||||
# Copy the entire project and build it
|
||||
# This layer is rebuilt when a file changes in the project directory
|
||||
COPY . /go/src/project/
|
||||
RUN go build -o /bin/project
|
||||
|
||||
# This results in a single layer image
|
||||
FROM scratch
|
||||
COPY --from=build /bin/project /bin/project
|
||||
ENTRYPOINT ["/bin/project"]
|
||||
CMD ["--help"]
|
||||
```
|
||||
|
||||
### Don't install unnecessary packages
|
||||
|
||||
To reduce complexity, dependencies, file sizes, and build times, 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.
|
||||
|
||||
### Decouple applications
|
||||
|
||||
Each container should have only one concern. Decoupling applications into
|
||||
multiple containers makes it easier to scale horizontally and reuse containers.
|
||||
For instance, a web application stack might consist of three separate
|
||||
containers, each with its own unique image, to manage the web application,
|
||||
database, and an in-memory cache in a decoupled manner.
|
||||
|
||||
Limiting each container to one process is a good rule of thumb, but it is not a
|
||||
hard and fast rule. For example, not only can containers be
|
||||
[spawned with an init process](../../engine/reference/run.md#specify-an-init-process),
|
||||
some programs might spawn additional processes of their own accord. For
|
||||
instance, [Celery](https://docs.celeryproject.org/) can spawn multiple worker
|
||||
processes, and [Apache](https://httpd.apache.org/) can create one process per
|
||||
request.
|
||||
|
||||
Use your best judgment to keep containers as clean and modular as possible. If
|
||||
containers depend on each other, you can use [Docker container networks](../../network/index.md)
|
||||
to ensure that these containers can communicate.
|
||||
|
||||
### Minimize the number of layers
|
||||
|
||||
In older versions of Docker, it was important that you minimized the number of
|
||||
layers in your images to ensure they were performant. The following features
|
||||
were added to reduce this limitation:
|
||||
|
||||
- Only the instructions `RUN`, `COPY`, `ADD` create layers. Other instructions
|
||||
create temporary intermediate images, and do not increase the size of the build.
|
||||
|
||||
- Where possible, use [multi-stage builds](multistage-build.md), and only copy
|
||||
the artifacts you need into the final image. This allows you to include tools
|
||||
and debug information in your intermediate build stages without increasing the
|
||||
size of the final image.
|
||||
|
||||
### Sort multi-line arguments
|
||||
|
||||
Whenever possible, ease later changes by sorting multi-line arguments
|
||||
alphanumerically. This helps to 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):
|
||||
|
||||
```dockerfile
|
||||
RUN apt-get update && apt-get install -y \
|
||||
bzr \
|
||||
cvs \
|
||||
git \
|
||||
mercurial \
|
||||
subversion \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
### Leverage build cache
|
||||
|
||||
When building an image, Docker steps through the instructions in your
|
||||
`Dockerfile`, executing each in the order specified. As each instruction is
|
||||
examined, Docker looks for an existing image in its cache that it can reuse,
|
||||
rather than creating a new (duplicate) image.
|
||||
|
||||
If you do not want to use the cache at all, you can use the `--no-cache=true`
|
||||
option on the `docker build` command. However, if you do let Docker use its
|
||||
cache, it is important to understand when it can, and cannot, find a matching
|
||||
image. The basic rules that Docker follows are outlined below:
|
||||
|
||||
- Starting with a parent image that is already in the cache, the next
|
||||
instruction is compared against all child images derived from that base
|
||||
image to see if one of them was built using the exact same instruction. If
|
||||
not, the cache is invalidated.
|
||||
|
||||
- In most cases, simply comparing the instruction in the `Dockerfile` with one
|
||||
of the child images is sufficient. However, certain instructions require more
|
||||
examination and explanation.
|
||||
|
||||
- For the `ADD` and `COPY` instructions, the contents of the file(s)
|
||||
in the image are examined and a checksum is calculated for each file.
|
||||
The last-modified and last-accessed times of the file(s) are not considered in
|
||||
these checksums. During the cache lookup, the checksum is compared against the
|
||||
checksum in the existing images. If anything has changed in the file(s), such
|
||||
as the contents and metadata, then the cache is invalidated.
|
||||
|
||||
- Aside from the `ADD` and `COPY` commands, cache checking does not look at the
|
||||
files in the container to determine a cache match. For example, when processing
|
||||
a `RUN apt-get -y update` command the files updated in the container
|
||||
are not examined to determine if a cache hit exists. In that case just
|
||||
the command string itself is used to find a match.
|
||||
|
||||
Once the cache is invalidated, all subsequent `Dockerfile` commands generate new
|
||||
images and the cache is not used.
|
||||
|
||||
## Dockerfile instructions
|
||||
|
||||
These recommendations are designed to help you create an efficient and
|
||||
maintainable `Dockerfile`.
|
||||
|
||||
### FROM
|
||||
|
||||
[Dockerfile reference for the FROM instruction](../../engine/reference/builder.md#from)
|
||||
|
||||
Whenever possible, use current official images as the basis for your
|
||||
images. We recommend the [Alpine image](https://hub.docker.com/_/alpine/) as it
|
||||
is tightly controlled and small in size (currently under 5 MB), while still
|
||||
being a full Linux distribution.
|
||||
|
||||
### LABEL
|
||||
|
||||
[Understanding object labels](../../config/labels-custom-metadata.md)
|
||||
|
||||
You can add labels to your image to help organize images by project, record
|
||||
licensing information, to aid in automation, or for other reasons. For each
|
||||
label, add a line beginning with `LABEL` and with one or more key-value pairs.
|
||||
The following examples show the different acceptable formats. Explanatory comments are included inline.
|
||||
|
||||
> Strings with spaces must be quoted **or** the spaces must be escaped. Inner
|
||||
> quote characters (`"`), must also be escaped.
|
||||
|
||||
```dockerfile
|
||||
# Set one or more individual labels
|
||||
LABEL com.example.version="0.0.1-beta"
|
||||
LABEL vendor1="ACME Incorporated"
|
||||
LABEL vendor2=ZENITH\ Incorporated
|
||||
LABEL com.example.release-date="2015-02-12"
|
||||
LABEL com.example.version.is-production=""
|
||||
```
|
||||
|
||||
An image can have more than one label. Prior to Docker 1.10, it was recommended
|
||||
to combine all labels into a single `LABEL` instruction, to prevent extra layers
|
||||
from being created. This is no longer necessary, but combining labels is still
|
||||
supported.
|
||||
|
||||
```dockerfile
|
||||
# Set multiple labels on one line
|
||||
LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"
|
||||
```
|
||||
|
||||
The above can also be written as:
|
||||
|
||||
```dockerfile
|
||||
# Set multiple labels at once, using line-continuation characters to break long lines
|
||||
LABEL vendor=ACME\ Incorporated \
|
||||
com.example.is-beta= \
|
||||
com.example.is-production="" \
|
||||
com.example.version="0.0.1-beta" \
|
||||
com.example.release-date="2015-02-12"
|
||||
```
|
||||
|
||||
See [Understanding object labels](../../config/labels-custom-metadata.md)
|
||||
for guidelines about acceptable label keys and values. For information about
|
||||
querying labels, refer to the items related to filtering in
|
||||
[Managing labels on objects](../../config/labels-custom-metadata.md#manage-labels-on-objects).
|
||||
See also [LABEL](../../engine/reference/builder.md#label) in the Dockerfile reference.
|
||||
|
||||
### RUN
|
||||
|
||||
[Dockerfile reference for the RUN instruction](../../engine/reference/builder.md#run)
|
||||
|
||||
Split long or complex `RUN` statements on multiple lines separated with
|
||||
backslashes to make your `Dockerfile` more readable, understandable, and
|
||||
maintainable.
|
||||
|
||||
#### apt-get
|
||||
|
||||
Probably the most common use-case for `RUN` is an application of `apt-get`.
|
||||
Because it installs packages, the `RUN apt-get` command has several gotchas to
|
||||
look out for.
|
||||
|
||||
Avoid `RUN apt-get upgrade` and `dist-upgrade`, as many of the "essential"
|
||||
packages from the parent images cannot upgrade inside an
|
||||
[unprivileged container](../../engine/reference/run.md#security-configuration). If a package
|
||||
contained in the parent image is out-of-date, contact its maintainers. If you
|
||||
know there is a particular package, `foo`, that needs to be updated, use
|
||||
`apt-get install -y foo` to update automatically.
|
||||
|
||||
Always combine `RUN apt-get update` with `apt-get install` in the same `RUN`
|
||||
statement. For example:
|
||||
|
||||
```dockerfile
|
||||
RUN apt-get update && apt-get install -y \
|
||||
package-bar \
|
||||
package-baz \
|
||||
package-foo \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
Using `apt-get update` alone in a `RUN` statement causes caching issues and
|
||||
subsequent `apt-get install` instructions fail. For example, say you have a
|
||||
Dockerfile:
|
||||
|
||||
```dockerfile
|
||||
FROM ubuntu:18.04
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y curl
|
||||
```
|
||||
|
||||
After building the image, all layers are in the Docker cache. Suppose you later
|
||||
modify `apt-get install` by adding extra package:
|
||||
|
||||
```dockerfile
|
||||
FROM ubuntu:18.04
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y curl nginx
|
||||
```
|
||||
|
||||
Docker sees the initial and modified instructions as identical and reuses the
|
||||
cache from previous steps. As a result the `apt-get update` is _not_ executed
|
||||
because the build uses the cached version. Because the `apt-get update` is not
|
||||
run, your build can potentially get an outdated version of the `curl` and
|
||||
`nginx` packages.
|
||||
|
||||
Using `RUN apt-get update && apt-get install -y` ensures your Dockerfile
|
||||
installs the latest package versions with no further coding or manual
|
||||
intervention. This technique is known as "cache busting". You can also achieve
|
||||
cache-busting by specifying a package version. This is known as version pinning,
|
||||
for example:
|
||||
|
||||
```dockerfile
|
||||
RUN apt-get update && apt-get install -y \
|
||||
package-bar \
|
||||
package-baz \
|
||||
package-foo=1.3.*
|
||||
```
|
||||
|
||||
Version pinning forces the build to retrieve a particular version regardless of
|
||||
what’s in the cache. This technique can also reduce failures due to unanticipated changes
|
||||
in required packages.
|
||||
|
||||
Below is a well-formed `RUN` instruction that demonstrates all the `apt-get`
|
||||
recommendations.
|
||||
|
||||
```dockerfile
|
||||
RUN apt-get update && apt-get install -y \
|
||||
aufs-tools \
|
||||
automake \
|
||||
build-essential \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
libcap-dev \
|
||||
libsqlite3-dev \
|
||||
mercurial \
|
||||
reprepro \
|
||||
ruby1.9.1 \
|
||||
ruby1.9.1-dev \
|
||||
s3cmd=1.1.* \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
The `s3cmd` argument specifies a version `1.1.*`. If the image previously
|
||||
used an older version, specifying the new one causes a cache bust of `apt-get
|
||||
update` and ensures the installation of the new version. Listing packages on
|
||||
each line can also prevent mistakes in package duplication.
|
||||
|
||||
In addition, when you clean up the apt cache by removing `/var/lib/apt/lists` it
|
||||
reduces the image size, since the apt cache is not stored in a layer. Since the
|
||||
`RUN` statement starts with `apt-get update`, the package cache is always
|
||||
refreshed prior to `apt-get install`.
|
||||
|
||||
> Official Debian and Ubuntu images [automatically run `apt-get clean`](https://github.com/moby/moby/blob/03e2923e42446dbb830c654d0eec323a0b4ef02a/contrib/mkimage/debootstrap#L82-L105),
|
||||
> so explicit invocation is not required.
|
||||
|
||||
#### Using pipes
|
||||
|
||||
Some `RUN` commands depend on the ability to pipe the output of one command into another, using the pipe character (`|`), as in the following example:
|
||||
|
||||
```dockerfile
|
||||
RUN wget -O - https://some.site | wc -l > /number
|
||||
```
|
||||
|
||||
Docker executes these commands using the `/bin/sh -c` interpreter, which only
|
||||
evaluates the exit code of the last operation in the pipe to determine success.
|
||||
In the example above this build step succeeds and produces a new image so long
|
||||
as the `wc -l` command succeeds, even if the `wget` command fails.
|
||||
|
||||
If you want the command to fail due to an error at any stage in the pipe,
|
||||
prepend `set -o pipefail &&` to ensure that an unexpected error prevents the
|
||||
build from inadvertently succeeding. For example:
|
||||
|
||||
```dockerfile
|
||||
RUN set -o pipefail && wget -O - https://some.site | wc -l > /number
|
||||
```
|
||||
> Not all shells support the `-o pipefail` option.
|
||||
>
|
||||
> In cases such as the `dash` shell on
|
||||
> Debian-based images, consider using the _exec_ form of `RUN` to explicitly
|
||||
> choose a shell that does support the `pipefail` option. For example:
|
||||
>
|
||||
> ```dockerfile
|
||||
> RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://some.site | wc -l > /number"]
|
||||
> ```
|
||||
|
||||
### CMD
|
||||
|
||||
[Dockerfile reference for the CMD instruction](../../engine/reference/builder.md#cmd)
|
||||
|
||||
The `CMD` instruction should be used to run the software contained in 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, such as Apache and Rails, 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, such as bash,
|
||||
python and perl. 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`](../../engine/reference/builder.md#entrypoint), unless
|
||||
you and your expected users are already quite familiar with how `ENTRYPOINT`
|
||||
works.
|
||||
|
||||
### EXPOSE
|
||||
|
||||
[Dockerfile reference for the EXPOSE instruction](../../engine/reference/builder.md#expose)
|
||||
|
||||
The `EXPOSE` instruction indicates the ports on which a container listens
|
||||
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
|
||||
|
||||
[Dockerfile reference for the ENV instruction](../../engine/reference/builder.md#env)
|
||||
|
||||
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` ensures 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:
|
||||
|
||||
```dockerfile
|
||||
ENV PG_MAJOR=9.3
|
||||
ENV PG_VERSION=9.3.4
|
||||
RUN curl -SL https://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.
|
||||
|
||||
Each `ENV` line creates a new intermediate layer, just like `RUN` commands. This
|
||||
means that even if you unset the environment variable in a future layer, it
|
||||
still persists in this layer and its value can't be dumped. You can test this by
|
||||
creating a Dockerfile like the following, and then building it.
|
||||
|
||||
```dockerfile
|
||||
FROM alpine
|
||||
ENV ADMIN_USER="mark"
|
||||
RUN echo $ADMIN_USER > ./mark
|
||||
RUN unset ADMIN_USER
|
||||
```
|
||||
|
||||
```bash
|
||||
$ docker run --rm test sh -c 'echo $ADMIN_USER'
|
||||
|
||||
mark
|
||||
```
|
||||
|
||||
To prevent this, and really unset the environment variable, use a `RUN` command
|
||||
with shell commands, to set, use, and unset the variable all in a single layer.
|
||||
You can separate your commands with `;` or `&&`. If you use the second method,
|
||||
and one of the commands fails, the `docker build` also fails. This is usually a
|
||||
good idea. Using `\` as a line continuation character for Linux Dockerfiles
|
||||
improves readability. You could also put all of the commands into a shell script
|
||||
and have the `RUN` command just run that shell script.
|
||||
|
||||
```dockerfile
|
||||
FROM alpine
|
||||
RUN export ADMIN_USER="mark" \
|
||||
&& echo $ADMIN_USER > ./mark \
|
||||
&& unset ADMIN_USER
|
||||
CMD sh
|
||||
```
|
||||
|
||||
```bash
|
||||
$ docker run --rm test sh -c 'echo $ADMIN_USER'
|
||||
|
||||
```
|
||||
|
||||
|
||||
### ADD or COPY
|
||||
|
||||
- [Dockerfile reference for the ADD instruction](../../engine/reference/builder.md#add)
|
||||
- [Dockerfile reference for the COPY instruction](../../engine/reference/builder.md#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 /`.
|
||||
|
||||
If you have multiple `Dockerfile` steps that use different files from your
|
||||
context, `COPY` them individually, rather than all at once. This ensures that
|
||||
each step's build cache is only invalidated (forcing the step to be re-run) if
|
||||
the specifically required files change.
|
||||
|
||||
For example:
|
||||
|
||||
```dockerfile
|
||||
COPY requirements.txt /tmp/
|
||||
RUN pip install --requirement /tmp/requirements.txt
|
||||
COPY . /tmp/
|
||||
```
|
||||
|
||||
Results in fewer cache invalidations for the `RUN` step, than if you put the
|
||||
`COPY . /tmp/` before it.
|
||||
|
||||
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 don't
|
||||
have to add another layer in your image. For example, you should avoid doing
|
||||
things like:
|
||||
|
||||
```dockerfile
|
||||
ADD https://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:
|
||||
|
||||
```dockerfile
|
||||
RUN mkdir -p /usr/src/things \
|
||||
&& curl -SL https://example.com/big.tar.xz \
|
||||
| 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
|
||||
|
||||
[Dockerfile reference for the ENTRYPOINT instruction](../../engine/reference/builder.md#entrypoint)
|
||||
|
||||
The best use for `ENTRYPOINT` is to set the image's main command, allowing that
|
||||
image to be run as though it was that command (and then use `CMD` as the
|
||||
default flags).
|
||||
|
||||
Let's start with an example of an image for the command line tool `s3cmd`:
|
||||
|
||||
```dockerfile
|
||||
ENTRYPOINT ["s3cmd"]
|
||||
CMD ["--help"]
|
||||
```
|
||||
|
||||
Now the image can be run like this to show the command's help:
|
||||
|
||||
```bash
|
||||
$ docker run s3cmd
|
||||
```
|
||||
|
||||
Or using the right parameters to execute a command:
|
||||
|
||||
```bash
|
||||
$ docker run s3cmd ls s3://mybucket
|
||||
```
|
||||
|
||||
This is useful because the image name can double as a reference to the binary as
|
||||
shown in the command above.
|
||||
|
||||
The `ENTRYPOINT` instruction can also be used in combination with a helper
|
||||
script, allowing it to function in a similar way to the command above, even
|
||||
when starting the tool may require more than one step.
|
||||
|
||||
For example, the [Postgres Official Image](https://hub.docker.com/_/postgres/)
|
||||
uses the following script as its `ENTRYPOINT`:
|
||||
|
||||
```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 "$@"
|
||||
```
|
||||
|
||||
> Configure app as PID 1
|
||||
>
|
||||
> This script uses [the `exec` Bash command](https://wiki.bash-hackers.org/commands/builtin/exec)
|
||||
> so that the final running application becomes the container's PID 1. This
|
||||
> allows the application to receive any Unix signals sent to the container.
|
||||
> For more, see the [`ENTRYPOINT` reference](../../engine/reference/builder.md#entrypoint).
|
||||
|
||||
The helper script is copied into the container and run via `ENTRYPOINT` on
|
||||
container start:
|
||||
|
||||
```dockerfile
|
||||
COPY ./docker-entrypoint.sh /
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["postgres"]
|
||||
```
|
||||
|
||||
This script allows the user to interact with Postgres in several ways.
|
||||
|
||||
It can simply start Postgres:
|
||||
|
||||
```bash
|
||||
$ docker run postgres
|
||||
```
|
||||
|
||||
Or, it can be used to run Postgres and pass parameters to the server:
|
||||
|
||||
```bash
|
||||
$ docker run postgres postgres --help
|
||||
```
|
||||
|
||||
Lastly, it could also be used to start a totally different tool, such as Bash:
|
||||
|
||||
```bash
|
||||
$ docker run --rm -it postgres bash
|
||||
```
|
||||
|
||||
### VOLUME
|
||||
|
||||
[Dockerfile reference for the VOLUME instruction](../../engine/reference/builder.md#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
|
||||
|
||||
[Dockerfile reference for the USER instruction](../../engine/reference/builder.md#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 --no-log-init -r -g postgres postgres`.
|
||||
|
||||
> Consider an explicit UID/GID
|
||||
>
|
||||
> Users and groups in an image are assigned a non-deterministic UID/GID in that
|
||||
> the "next" UID/GID is assigned regardless of image rebuilds. So, if it’s
|
||||
> critical, you should assign an explicit UID/GID.
|
||||
|
||||
> Due to an [unresolved bug](https://github.com/golang/go/issues/13548) in the
|
||||
> Go archive/tar package's handling of sparse files, attempting to create a user
|
||||
> with a significantly large UID inside a Docker container can lead to disk
|
||||
> exhaustion because `/var/log/faillog` in the container layer is filled with
|
||||
> NULL (\0) characters. A workaround is to pass the `--no-log-init` flag to
|
||||
> useradd. The Debian/Ubuntu `adduser` wrapper does not support this flag.
|
||||
|
||||
Avoid installing or using `sudo` as it has unpredictable TTY and
|
||||
signal-forwarding behavior that can cause problems. If you absolutely need
|
||||
functionality similar to `sudo`, such as initializing the daemon as `root` but
|
||||
running it as non-`root`, consider using [“gosu”](https://github.com/tianon/gosu).
|
||||
|
||||
Lastly, to reduce layers and complexity, avoid switching `USER` back and forth
|
||||
frequently.
|
||||
|
||||
### WORKDIR
|
||||
|
||||
[Dockerfile reference for the WORKDIR instruction](../../engine/reference/builder.md#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
|
||||
|
||||
[Dockerfile reference for the ONBUILD instruction](../../engine/reference/builder.md#onbuild)
|
||||
|
||||
An `ONBUILD` command executes after the current `Dockerfile` build completes.
|
||||
`ONBUILD` executes in any child image derived `FROM` the current image. Think
|
||||
of the `ONBUILD` command as an instruction the parent `Dockerfile` gives
|
||||
to the child `Dockerfile`.
|
||||
|
||||
A Docker build executes `ONBUILD` commands before any command in a child
|
||||
`Dockerfile`.
|
||||
|
||||
`ONBUILD` is 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/c43fef8a60cea31eb9e7d960a076d633cb62ba8d/2.4/jessie/onbuild/Dockerfile).
|
||||
|
||||
Images built with `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
|
||||
fails catastrophically if the new build's context is missing the resource being
|
||||
added. Adding a separate tag, as recommended above, helps mitigate this by
|
||||
allowing the `Dockerfile` author to make a choice.
|
||||
|
||||
## Examples for Official Images
|
||||
|
||||
These Official Images have exemplary `Dockerfile`s:
|
||||
|
||||
* [Go](https://hub.docker.com/_/golang/)
|
||||
* [Perl](https://hub.docker.com/_/perl/)
|
||||
* [Hy](https://hub.docker.com/_/hylang/)
|
||||
* [Ruby](https://hub.docker.com/_/ruby/)
|
||||
|
||||
## Additional resources:
|
||||
|
||||
* [Dockerfile Reference](../../engine/reference/builder.md)
|
||||
* [More about Base Images](baseimages.md)
|
||||
* [More about Automated Builds](../../docker-hub/builds/index.md)
|
||||
* [Guidelines for Creating Official Images](../../docker-hub/official_images.md)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
redirect_from:
|
||||
- /reference/api/hub_registry_spec/
|
||||
- /userguide/image_management/
|
||||
- /engine/userguide/eng-image/image_management/
|
||||
description: Documentation for docker Registry and Registry API
|
||||
keywords: docker, registry, api, hub
|
||||
title: Manage images
|
||||
---
|
||||
|
||||
The easiest way to make your images available for use by others inside or
|
||||
outside your organization is to use a Docker registry, such as [Docker Hub](#docker-hub),
|
||||
or by running your own [private registry](#docker-registry).
|
||||
|
||||
|
||||
## Docker Hub
|
||||
|
||||
[Docker Hub](../../docker-hub/index.md) is a public registry managed by Docker,
|
||||
Inc. It centralizes information about organizations, user accounts, and images.
|
||||
It includes a web UI, authentication and authorization using organizations, CLI
|
||||
and API access using commands such as `docker login`, `docker pull`, and `docker
|
||||
push`, comments, stars, search, and more.
|
||||
|
||||
## Docker Registry
|
||||
|
||||
The Docker Registry is a component of Docker's ecosystem. A registry is a
|
||||
storage and content delivery system, holding named Docker images, available in
|
||||
different tagged versions. For example, the image `distribution/registry`, with
|
||||
tags `2.0` and `latest`. Users interact with a registry by using docker push and
|
||||
pull commands such as `docker pull myregistry.com/stevvooe/batman:voice`.
|
||||
|
||||
Docker Hub is an instance of a Docker Registry.
|
||||
|
||||
## Content Trust
|
||||
|
||||
When transferring data among networked systems, *trust* is a central concern. In
|
||||
particular, when communicating over an untrusted medium such as the internet, it
|
||||
is critical to ensure the integrity and publisher of all of the data a system
|
||||
operates on. You use Docker to push and pull images (data) to a registry.
|
||||
Content trust gives you the ability to both verify the integrity and the
|
||||
publisher of all the data received from a registry over any channel.
|
||||
|
||||
See [Content trust](../../engine/security/trust/index.md) for information about
|
||||
configuring and using this feature on Docker clients.
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
description: Keeping your images small with multi-stage images
|
||||
keywords: images, containers, best practices, multi-stage, multistage
|
||||
title: Use multi-stage builds
|
||||
redirect_from:
|
||||
- /engine/userguide/eng-image/multistage-build/
|
||||
---
|
||||
|
||||
Multistage builds are useful to anyone who has struggled to optimize Dockerfiles
|
||||
while keeping them easy to read and maintain.
|
||||
|
||||
> **Acknowledgment**:
|
||||
> Special thanks to [Alex Ellis](https://twitter.com/alexellisuk) for granting
|
||||
> permission to use his blog post
|
||||
> [Builder pattern vs. Multi-stage builds in Docker](https://blog.alexellis.io/mutli-stage-docker-builds/)
|
||||
> as the basis of the examples below.
|
||||
|
||||
## Before multi-stage builds
|
||||
|
||||
One of the most challenging things about building images is keeping the image
|
||||
size down. Each instruction in the Dockerfile adds a layer to the image, and you
|
||||
need to remember to clean up any artifacts you don't need before moving on to
|
||||
the next layer. To write a really efficient Dockerfile, you have traditionally
|
||||
needed to employ shell tricks and other logic to keep the layers as small as
|
||||
possible and to ensure that each layer has the artifacts it needs from the
|
||||
previous layer and nothing else.
|
||||
|
||||
It was actually very common to have one Dockerfile to use for development (which
|
||||
contained everything needed to build your application), and a slimmed-down one
|
||||
to use for production, which only contained your application and exactly what
|
||||
was needed to run it. This has been referred to as the "builder
|
||||
pattern". Maintaining two Dockerfiles is not ideal.
|
||||
|
||||
Here's an example of a `Dockerfile.build` and `Dockerfile` which adhere to the
|
||||
builder pattern above:
|
||||
|
||||
**`Dockerfile.build`**:
|
||||
|
||||
```dockerfile
|
||||
FROM golang:1.7.3
|
||||
WORKDIR /go/src/github.com/alexellis/href-counter/
|
||||
COPY app.go .
|
||||
RUN go get -d -v golang.org/x/net/html \
|
||||
&& CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
|
||||
```
|
||||
|
||||
Notice that this example also artificially compresses two `RUN` commands together
|
||||
using the Bash `&&` operator, to avoid creating an additional layer in the image.
|
||||
This is failure-prone and hard to maintain. It's easy to insert another command
|
||||
and forget to continue the line using the `\` character, for example.
|
||||
|
||||
**`Dockerfile`**:
|
||||
|
||||
```dockerfile
|
||||
FROM alpine:latest
|
||||
RUN apk --no-cache add ca-certificates
|
||||
WORKDIR /root/
|
||||
COPY app .
|
||||
CMD ["./app"]
|
||||
```
|
||||
|
||||
**`build.sh`**:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
echo Building alexellis2/href-counter:build
|
||||
|
||||
docker build --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy \
|
||||
-t alexellis2/href-counter:build . -f Dockerfile.build
|
||||
|
||||
docker container create --name extract alexellis2/href-counter:build
|
||||
docker container cp extract:/go/src/github.com/alexellis/href-counter/app ./app
|
||||
docker container rm -f extract
|
||||
|
||||
echo Building alexellis2/href-counter:latest
|
||||
|
||||
docker build --no-cache -t alexellis2/href-counter:latest .
|
||||
rm ./app
|
||||
```
|
||||
|
||||
When you run the `build.sh` script, it needs to build the first image, create
|
||||
a container from it to copy the artifact out, then build the second
|
||||
image. Both images take up room on your system and you still have the `app`
|
||||
artifact on your local disk as well.
|
||||
|
||||
Multi-stage builds vastly simplify this situation!
|
||||
|
||||
## Use multi-stage builds
|
||||
|
||||
With multi-stage builds, you use multiple `FROM` statements in your Dockerfile.
|
||||
Each `FROM` instruction can use a different base, and each of them begins a new
|
||||
stage of the build. You can selectively copy artifacts from one stage to
|
||||
another, leaving behind everything you don't want in the final image. To show
|
||||
how this works, let's adapt the Dockerfile from the previous section to use
|
||||
multi-stage builds.
|
||||
|
||||
**`Dockerfile`**:
|
||||
|
||||
```dockerfile
|
||||
FROM golang:1.7.3
|
||||
WORKDIR /go/src/github.com/alexellis/href-counter/
|
||||
RUN go get -d -v golang.org/x/net/html
|
||||
COPY app.go .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk --no-cache add ca-certificates
|
||||
WORKDIR /root/
|
||||
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
|
||||
CMD ["./app"]
|
||||
```
|
||||
|
||||
You only need the single Dockerfile. You don't need a separate build script,
|
||||
either. Just run `docker build`.
|
||||
|
||||
```bash
|
||||
$ docker build -t alexellis2/href-counter:latest .
|
||||
```
|
||||
|
||||
The end result is the same tiny production image as before, with a
|
||||
significant reduction in complexity. You don't need to create any intermediate
|
||||
images and you don't need to extract any artifacts to your local system at all.
|
||||
|
||||
How does it work? The second `FROM` instruction starts a new build stage with
|
||||
the `alpine:latest` image as its base. The `COPY --from=0` line copies just the
|
||||
built artifact from the previous stage into this new stage. The Go SDK and any
|
||||
intermediate artifacts are left behind, and not saved in the final image.
|
||||
|
||||
## Name your build stages
|
||||
|
||||
By default, the stages are not named, and you refer to them by their integer
|
||||
number, starting with 0 for the first `FROM` instruction. However, you can
|
||||
name your stages, by adding an `AS <NAME>` to the `FROM` instruction. This
|
||||
example improves the previous one by naming the stages and using the name in
|
||||
the `COPY` instruction. This means that even if the instructions in your
|
||||
Dockerfile are re-ordered later, the `COPY` doesn't break.
|
||||
|
||||
```dockerfile
|
||||
FROM golang:1.7.3 AS builder
|
||||
WORKDIR /go/src/github.com/alexellis/href-counter/
|
||||
RUN go get -d -v golang.org/x/net/html
|
||||
COPY app.go .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk --no-cache add ca-certificates
|
||||
WORKDIR /root/
|
||||
COPY --from=builder /go/src/github.com/alexellis/href-counter/app .
|
||||
CMD ["./app"]
|
||||
```
|
||||
|
||||
## Stop at a specific build stage
|
||||
|
||||
When you build your image, you don't necessarily need to build the entire
|
||||
Dockerfile including every stage. You can specify a target build stage. The
|
||||
following command assumes you are using the previous `Dockerfile` but stops at
|
||||
the stage named `builder`:
|
||||
|
||||
```bash
|
||||
$ docker build --target builder -t alexellis2/href-counter:latest .
|
||||
```
|
||||
|
||||
A few scenarios where this might be very powerful are:
|
||||
|
||||
- Debugging a specific build stage
|
||||
- Using a `debug` stage with all debugging symbols or tools enabled, and a
|
||||
lean `production` stage
|
||||
- Using a `testing` stage in which your app gets populated with test data, but
|
||||
building for production using a different stage which uses real data
|
||||
|
||||
## Use an external image as a "stage"
|
||||
|
||||
When using multi-stage builds, you are not limited to copying from stages you
|
||||
created earlier in your Dockerfile. You can use the `COPY --from` instruction to
|
||||
copy from a separate image, either using the local image name, a tag available
|
||||
locally or on a Docker registry, or a tag ID. The Docker client pulls the image
|
||||
if necessary and copies the artifact from there. The syntax is:
|
||||
|
||||
```dockerfile
|
||||
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
|
||||
```
|
||||
|
||||
## Use a previous stage as a new stage
|
||||
|
||||
You can pick up where a previous stage left off by referring to it when using the `FROM` directive. For example:
|
||||
|
||||
```dockerfile
|
||||
FROM alpine:latest as builder
|
||||
RUN apk --no-cache add build-base
|
||||
|
||||
FROM builder as build1
|
||||
COPY source1.cpp source.cpp
|
||||
RUN g++ -o /binary source.cpp
|
||||
|
||||
FROM builder as build2
|
||||
COPY source2.cpp source.cpp
|
||||
RUN g++ -o /binary source.cpp
|
||||
```
|
||||
Reference in New Issue
Block a user