build: refresh building best practices

Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
This commit is contained in:
David Karlsson 2023-10-10 09:28:55 +02:00
parent e1db0099ae
commit 54e13c08d9
8 changed files with 369 additions and 386 deletions

View File

@ -4,48 +4,57 @@ description: Learn how to use the build context to access files from your Docker
keywords: build, buildx, buildkit, context, git, tarball, stdin keywords: build, buildx, buildkit, context, git, tarball, stdin
--- ---
The [`docker build`](../../engine/reference/commandline/build.md) or The `docker build` and `docker buildx build` commands build Docker images from
[`docker buildx build`](../../engine/reference/commandline/buildx_build.md) a [Dockerfile](../../engine/reference/builder.md) and a context.
commands build Docker images from a [Dockerfile](../../engine/reference/builder.md)
and a "context".
The build context is the argument that you pass to the build command: ## What is a build context?
The build context is the set of files that your build can access.
The positional argument that you pass to the build command specifies the
context that you want to use for the build:
```console ```console
$ docker build [OPTIONS] PATH | URL | - $ docker build [OPTIONS] PATH | URL | -
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
``` ```
## What is a build context?
You can pass any of the following inputs as the context for a build: You can pass any of the following inputs as the context for a build:
- The relative or absolute path to a local directory - The relative or absolute path to a local directory
- The address of a remote Git repository, tarball, or plain-text file - A remote URL of a Git repository, tarball, or plain-text file
- A piped plain-text file or a tarball using standard input - A plain-text file or tarball piped to the `docker build` command through standard input
### Filesystem contexts ### Filesystem contexts
When your build context is a local directory, a remote Git repository, or a tar file, When your build context is a local directory, a remote Git repository, or a tar
then that becomes the set of files that the builder can access during the build. file, then that becomes the set of files that the builder can access during the
Build instructions can refer to any of the files and directories in the context. build. Build instructions such as `COPY` and `ADD` can refer to any of the
For example, when you use a [`COPY` instruction](../../engine/reference/builder.md#copy), files and directories in the context.
the builder copies the file or directory from the build context, into the build container.
A filesystem build context is processed recursively: A filesystem build context is processed recursively:
- When you specify a local directory or a tarball, all subdirectories are included - When you specify a local directory or a tarball, all subdirectories are included
- When you specify a remote Git repository, the repository and all submodules are included - When you specify a remote Git repository, the repository and all submodules are included
For more information about the different types of filesystem contexts that you
can use with your builds, see:
- [Local files](#local-context)
- [Git repositories](#git-repositories)
- [Remote tarballs](#remote-tarballs)
### Text file contexts ### Text file contexts
When your build context is a plain-text file, the builder interprets the file When your build context is a plain-text file, the builder interprets the file
as a Dockerfile. With this approach, the builder doesn't receive a filesystem context. as a Dockerfile. With this approach, the build doesn't use a filesystem context.
For more information about building with a text file context, see [Text files](#text-files).
## Local directories and tarballs For more information, see [empty build context](#empty-context).
The following example shows a build command that uses the current directory ## Local context
(`.`) as a build context:
To use a local build context, you can specify a relative or absolute filepath
to the `docker build` command. The following example shows a build command that
uses the current directory (`.`) as a build context:
```console ```console
$ docker build . $ docker build .
@ -56,11 +65,16 @@ $ docker build .
... ...
``` ```
This makes files and directories in the current working directory available This makes files and directories in the current working directory available to
to the builder. The builder loads the files that it needs from the build context, the builder. The builder loads the files it needs from the build context when
when it needs them. needed.
For example, given the following directory structure: You can also use local tarballs as build context, by piping the tarball
contents to the `docker build` command. See [Tarballs](#local-tarballs).
### Local directories
Consider the following directory structure:
``` ```
. .
@ -71,8 +85,8 @@ For example, given the following directory structure:
└── package-lock.json └── package-lock.json
``` ```
Dockerfile instructions can reference and include these files in the build Dockerfile instructions can reference and include these files in the build if
if you pass the directory as a context. you pass this directory as a context.
```dockerfile ```dockerfile
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
@ -83,46 +97,93 @@ RUN npm ci
COPY index.ts src . COPY index.ts src .
``` ```
### `.dockerignore` ```console
$ docker build .
You can use a [`.dockerignore`](../../engine/reference/builder.md#dockerignore-file)
file to exclude some files or directories from being sent:
```gitignore
# .dockerignore
node_modules
bar
``` ```
A `.dockerignore` file located at the root of build context is automatically ### Local context with Dockerfile from stdin
detected and used.
If you use multiple Dockerfiles, you can use different ignore-files for each Use the following syntax to build an image using files on your local
Dockerfile. You do so using a special naming convention for the ignore-files. filesystem, while using a Dockerfile from stdin.
Place your ignore-file in the same directory as the Dockerfile, and prefix the
ignore-file with the name of the Dockerfile.
For example:
```console ```console
. $ docker build -f- <PATH>
├── index.ts
├── src/
├── docker
│   ├── build.Dockerfile
│   ├── build.Dockerfile.dockerignore
│   ├── lint.Dockerfile
│   ├── lint.Dockerfile.dockerignore
│   ├── test.Dockerfile
│   └── test.Dockerfile.dockerignore
├── package.json
└── package-lock.json
``` ```
A Dockerfile-specific ignore-file takes precedence over the `.dockerignore` The syntax uses the -f (or --file) option to specify the Dockerfile to use, and
file at the root of the build context if both exist. it uses a hyphen (-) as filename to instruct Docker to read the Dockerfile from
stdin.
## Git repositories The following example uses the current directory (.) as the build context, and
builds an image using a Dockerfile passed through stdin using a here-document.
```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
```
### Local tarballs
When you pipe a tarball to the build command, the build uses the contents of
the tarball as a filesystem context.
For example, given the following project directory:
```text
.
├── Dockerfile
├── Makefile
├── README.md
├── main.c
├── scripts
├── src
└── test.Dockerfile
```
You can create a tarball of the directory and pipe it to the build for use as
a context:
```console
$ tar czf foo.tar.gz *
$ docker build - < foo.tar.gz
```
The build resolves the Dockerfile from the tarball context. You can use the
`--file` flag to specify the name and location of the Dockerfile relative to
the root of the tarball. The following command builds using `test.Dockerfile`
in the tarball:
```console
$ docker build --file test.Dockerfile - < foo.tar.gz
```
## Remote context
You can specify the address of a remote Git repository, tarball, or plain-text
file as your build context.
- For Git repositories, the builder automatically clones the repository. See
[Git repositories](#git-repositories).
- For tarballs, the builder downloads and extracts the contents of the tarball.
See [Tarballs](#remote-tarballs).
If the remote tarball is a text file, the builder receives no [filesystem
context](#filesystem-contexts), and instead assumes that the remote
file is a Dockerfile. See [Empty build context](#empty-context).
### Git repositories
When you pass a URL pointing to the location of a Git repository as an argument When you pass a URL pointing to the location of a Git repository as an argument
to `docker build`, the builder uses the repository as the build context. to `docker build`, the builder uses the repository as the build context.
@ -139,7 +200,7 @@ $ docker build https://github.com/user/myrepo.git
By default, the builder clones the latest commit on the default branch of the By default, the builder clones the latest commit on the default branch of the
repository that you specify. repository that you specify.
### URL fragments #### URL fragments
You can append URL fragments to the Git repository address to make the builder You can append URL fragments to the Git repository address to make the builder
clone a specific branch, tag, and subdirectory of a repository. clone a specific branch, tag, and subdirectory of a repository.
@ -170,7 +231,7 @@ contexts:
| `myrepo.git#mytag:myfolder` | `refs/tags/mytag` | `/myfolder` | | `myrepo.git#mytag:myfolder` | `refs/tags/mytag` | `/myfolder` |
| `myrepo.git#mybranch:myfolder` | `refs/heads/mybranch` | `/myfolder` | | `myrepo.git#mybranch:myfolder` | `refs/heads/mybranch` | `/myfolder` |
### Keep `.git` directory #### Keep `.git` directory
By default, BuildKit doesn't keep the `.git` directory when using Git contexts. By default, BuildKit doesn't keep the `.git` directory when using Git contexts.
You can configure BuildKit to keep the directory by setting the You can configure BuildKit to keep the directory by setting the
@ -191,7 +252,7 @@ $ docker build \
https://github.com/user/myrepo.git#main https://github.com/user/myrepo.git#main
``` ```
### Private repositories #### Private repositories
When you specify a Git context that's also a private repository, the builder When you specify a Git context that's also a private repository, the builder
needs you to provide the necessary authentication credentials. You can use needs you to provide the necessary authentication credentials. You can use
@ -218,12 +279,39 @@ $ GIT_AUTH_TOKEN=<token> docker buildx build \
> **Note** > **Note**
> >
> Don't use `--build-arg` for secrets, except for > Don't use `--build-arg` for secrets.
> [HTTP proxies](../../network/proxy.md#set-proxy-using-the-cli)
### Remote context with Dockerfile from stdin
Use the following syntax to build an image using files on your local
filesystem, while using a Dockerfile from stdin.
```console
$ docker build -f- <URL>
```
The syntax uses the -f (or --file) option to specify the Dockerfile to use, and
it uses a hyphen (-) as filename to instruct Docker to read the Dockerfile from
stdin.
This can be useful in situations where you want to build an image from a
repository that doesn't contain a Dockerfile. Or if you want to build with a
custom Dockerfile, without maintaining your own fork of the repository.
The following example builds an image using a Dockerfile from stdin, and adds
the `hello.c` file from the [hello-world](https://github.com/docker-library/hello-world)
repository on GitHub.
```bash
docker build -t myimage:latest -f- https://github.com/docker-library/hello-world.git <<EOF
FROM busybox
COPY hello.c ./
EOF
```
### Remote tarballs ### Remote tarballs
If you pass the URL to a remote tarball, then the URL itself is sent to the builder. If you pass the URL to a remote tarball, the URL itself is sent to the builder.
```console ```console
$ docker build http://server/context.tar.gz $ docker build http://server/context.tar.gz
@ -235,98 +323,64 @@ $ docker build http://server/context.tar.gz
... ...
``` ```
The download operation will be performed on the host the daemon is running on, The download operation will be performed on the host where the BuildKit daemon
which is not necessarily the same host from which the build command is being is running. Note that if you're using a remote Docker context or a remote
issued. The daemon will fetch `context.tar.gz` and use it as the build context. builder, that's not necessarily the same machine as where you issue the build
Tarball contexts must be tar archives conforming to the standard `tar` Unix command. BuildKit fetches the `context.tar.gz` and uses it as the build
format and can be compressed with any one of the `xz`, `bzip2`, `gzip` or context. Tarball contexts must be tar archives conforming to the standard `tar`
Unix format and can be compressed with any one of the `xz`, `bzip2`, `gzip` or
`identity` (no compression) formats. `identity` (no compression) formats.
## Pipes ## Empty context
When you pass a single dash `-` as the argument to the build command, you can
pipe a plain-text file or a tarball as the context:
```console
$ docker build - PIPE
```
For example:
```console
$ docker build - < Dockerfile
$ docker build - < archive.tar
$ docker build - <<EOF
FROM node:alpine
COPY . .
RUN npm ci
EOF
```
### Tarballs
When you pipe a tarball to the build command, the build uses the contents of
the tarball as a filesystem context.
For example, given the following project directory:
```
.
├── Dockerfile
├── Makefile
├── README.md
├── main.c
├── scripts
├── src
└── test.Dockerfile
```
You can create a tarball of the directory and pipe it to the build for use as
a context:
```console
$ tar czf foo.tar.gz *
$ docker build - < foo.tar.gz
```
The build resolves the Dockerfile from the tarball context. You can use the
`--file` flag to specify the name and location of the Dockerfile relative to
the root of the tarball. The following command builds using `test.Dockerfile`
in the tarball:
```console
$ docker build --file test.Dockerfile - < foo.tar.gz
```
### Text files
When you use a text file as the build context, the builder interprets the file When you use a text file as the build context, the builder interprets the file
as a Dockerfile. Using a text file as context means that the build has no as a Dockerfile. Using a text file as context means that the build has no
filesystem context. This can be useful when your build doesn't require any filesystem context.
local files. This means there's no filesystem context when building.
You can build with an empty build context when your Dockerfile doesn't depend
on any local files.
### How to build without a context
You can pass the text file using a standard input stream, or by pointing at the You can pass the text file using a standard input stream, or by pointing at the
URL of a remote text file. URL of a remote text file.
{{< tabs >}}
{{< tab name="Unix pipe" >}}
```console ```console
$ docker build - < Dockerfile $ docker build - < Dockerfile
``` ```
With PowerShell on Windows, you can run: {{< /tab >}}
{{< tab name="PowerShell" >}}
```powershell ```powershell
Get-Content Dockerfile | docker build - Get-Content Dockerfile | docker build -
``` ```
To use a remote text file, pass the URL of the text file as the argument to the {{< /tab >}}
build command: {{< tab name="Heredocs" >}}
```bash
docker build -t myimage:latest - <<EOF
FROM busybox
RUN echo "hello world"
EOF
```
{{< /tab >}}
{{< tab name="Remote file" >}}
```console ```console
$ docker build https://raw.githubusercontent.com/dvdksn/clockbox/main/Dockerfile $ docker build https://raw.githubusercontent.com/dvdksn/clockbox/main/Dockerfile
``` ```
Again, this means that the build has no filesystem context, {{< /tab >}}
so Dockerfile commands such as `COPY` can't refer to local files: {{< /tabs >}}
When you build without a filesystem context, Dockerfile instructions such as
`COPY` can't refer to local files:
```console ```console
$ ls $ ls
@ -352,18 +406,143 @@ Dockerfile:2
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref 7ab2bb61-0c28-432e-abf5-a4c3440bc6b6::4lgfpdf54n5uqxnv9v6ymg7ih: "/main.c": not found ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref 7ab2bb61-0c28-432e-abf5-a4c3440bc6b6::4lgfpdf54n5uqxnv9v6ymg7ih: "/main.c": not found
``` ```
#### Build using heredocs ## .dockerignore files
The following example builds an image using a `Dockerfile` that is passed You can use a `.dockerignore` file to exclude files or directories from the
through standard input using build context.
[shell heredocs](https://en.wikipedia.org/wiki/Here_document):
```bash ```gitignore
docker build -t myimage:latest - <<EOF # .dockerignore
FROM busybox node_modules
RUN echo "hello world" bar
EOF
``` ```
This approach is useful when you want to quickly run a build command with a This helps avoid sending unwanted files and directories to the builder,
Dockerfile that's short and concise. improving build speed, especially when using a remote builder.
### Filename and location
When you run a build command, the build client looks for a file named
`.dockerignore` in the root directory of the context. If this file exists, the
files and directories that match patterns in the files are removed from the
build context before it's sent to the builder.
If you use multiple Dockerfiles, you can use different ignore-files for each
Dockerfile. You do so using a special naming convention for the ignore-files.
Place your ignore-file in the same directory as the Dockerfile, and prefix the
ignore-file with the name of the Dockerfile, as shown in the following example.
```text
.
├── index.ts
├── src/
├── docker
│   ├── build.Dockerfile
│   ├── build.Dockerfile.dockerignore
│   ├── lint.Dockerfile
│   ├── lint.Dockerfile.dockerignore
│   ├── test.Dockerfile
│   └── test.Dockerfile.dockerignore
├── package.json
└── package-lock.json
```
A Dockerfile-specific ignore-file takes precedence over the `.dockerignore`
file at the root of the build context if both exist.
### Syntax
The `.dockerignore` file is a newline-separated list of patterns similar to the
file globs of Unix shells. For the purposes of matching, the root of the
context is considered to be both the working and the root directory. For
example, the patterns `/foo/bar` and `foo/bar` both exclude a file or directory
named `bar` in the `foo` subdirectory of `PATH` or in the root of the Git
repository located at `URL`. Neither excludes anything else.
If a line in `.dockerignore` file starts with `#` in column 1, then this line
is considered as a comment and is ignored before interpreted by the CLI.
If you're interested in learning the precise details of the `.dockerignore`
pattern matching logic, check out the
[moby/patternmatcher repository](https://github.com/moby/patternmatcher/tree/main/ignorefile)
on GitHub, which contains the source code.
#### Matching
The following code snippet shows an example `.dockerignore` file.
```gitignore
# comment
*/temp*
*/*/temp*
temp?
```
This file causes the following build behavior:
| Rule | Behavior |
| :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `# comment` | Ignored. |
| `*/temp*` | Exclude files and directories whose names start with `temp` in any immediate subdirectory of the root. For example, the plain file `/somedir/temporary.txt` is excluded, as is the directory `/somedir/temp`. |
| `*/*/temp*` | Exclude files and directories starting with `temp` from any subdirectory that is two levels below the root. For example, `/somedir/subdir/temporary.txt` is excluded. |
| `temp?` | Exclude files and directories in the root directory whose names are a one-character extension of `temp`. For example, `/tempa` and `/tempb` are excluded. |
Matching is done using Go's
[`filepath.Match` function](https://golang.org/pkg/path/filepath#Match) rules.
A preprocessing step uses Go's
[`filepath.Clean` function](https://golang.org/pkg/path/filepath/#Clean)
to trim whitespace and remove `.` and `..`.
Lines that are blank after preprocessing are ignored.
> **Note**
>
> For historical reasons, the pattern `.` is ignored.
Beyond Go's `filepath.Match` rules, Docker also supports a special wildcard
string `**` that matches any number of directories (including zero). For
example, `**/*.go` excludes all files that end with `.go` found anywhere in the
build context.
You can use the `.dockerignore` file to exclude the `Dockerfile` and
`.dockerignore` files. These files are still sent to the builder as they're
needed for running the build. But you can't copy the files into the image using
`ADD`, `COPY`, or bind mounts.
#### Negating matches
You can prepend lines with a `!` (exclamation mark) to make exceptions to
exclusions. The following is an example `.dockerignore` file that uses this
mechanism:
```gitignore
*.md
!README.md
```
All markdown files right under the context directory _except_ `README.md` are
excluded from the context. Note that markdown files under subdirectories are
still included.
The placement of `!` exception rules influences the behavior: the last line of
the `.dockerignore` that matches a particular file determines whether it's
included or excluded. Consider the following example:
```gitignore
*.md
!README*.md
README-secret.md
```
No markdown files are included in the context except README files other than
`README-secret.md`.
Now consider this example:
```gitignore
*.md
README-secret.md
!README*.md
```
All of the README files are included. The middle line has no effect because
`!README*.md` matches `README-secret.md` and comes last.

View File

@ -198,7 +198,7 @@ The next instruction uses the
COPY hello.py / COPY hello.py /
``` ```
A [build context](context.md) is the set of files that you can access A [build context](./context.md) is the set of files that you can access
in Dockerfile instructions such as `COPY` and `ADD`. in Dockerfile instructions such as `COPY` and `ADD`.
After the `COPY` instruction, the `hello.py` file is added to the filesystem After the `COPY` instruction, the `hello.py` file is added to the filesystem
@ -253,7 +253,7 @@ $ docker build -t test:latest .
The `-t test:latest` option specifies the name and tag of the image. The `-t test:latest` option specifies the name and tag of the image.
The single dot (`.`) at the end of the command sets the The single dot (`.`) at the end of the command sets the
[build context](context.md) to the current directory. This means that the [build context](./context.md) to the current directory. This means that the
build expects to find the Dockerfile and the `hello.py` file in the directory build expects to find the Dockerfile and the `hello.py` file in the directory
where the command is invoked. If those files aren't there, the build fails. where the command is invoked. If those files aren't there, the build fails.
@ -273,4 +273,4 @@ If you are interested in examples in other languages, such as Go, check out
our [language-specific guides](../../language/index.md) in the Guides section. our [language-specific guides](../../language/index.md) in the Guides section.
For more information about building, including advanced use cases and patterns, For more information about building, including advanced use cases and patterns,
refer to the [Build with Docker](../guide/index.md) guide. refer to the [Build with Docker](../guide/index.md) guide.

View File

@ -144,7 +144,7 @@ COPY . /src
``` ```
You can also create a You can also create a
[`.dockerignore` file](../../engine/reference/builder.md#dockerignore-file), [`.dockerignore` file](../../build/building/context.md#dockerignore-files),
and use that to specify which files and directories to exclude from the build and use that to specify which files and directories to exclude from the build
context. context.

View File

@ -391,10 +391,10 @@ more efficient:
### Dockerignore files ### Dockerignore files
Using a [`.dockerignore` file](./building/context.md#dockerignore), you can be Using a [`.dockerignore` file](./building/context.md#dockerignore-files), you can be
explicit about which local files that you dont want to include in the build explicit about which local files that you dont want to include in the build
context. Files caught by the [glob patterns](../engine/reference/builder.md#dockerignore-file) context. Files caught by the glob patterns you specify in your ignore-file are
you specify in your ignore-file are not transferred to the remote builder. not transferred to the remote builder.
Some examples of things you might want to add to your `.dockerignore` file are: Some examples of things you might want to add to your `.dockerignore` file are:

View File

@ -1,9 +1,29 @@
--- ---
description: Hints, tips and guidelines for writing clean, reliable Dockerfiles description: Hints, tips and guidelines for writing clean, reliable Dockerfiles
keywords: parent image, images, dockerfile, best practices, hub, official image keywords: parent image, images, dockerfile, best practices, hub, official image
title: General best practices for writing Dockerfiles title: General best practices for writing Dockerfiles
--- ---
## Use multi-stage builds
Multi-stage builds let you reduce the size of your final image, by creating a
cleaner separation between the building of your image and the final output.
Split your Dockerfile instructions into distinct stages to make sure that the
resulting output only contains the files that's needed to run the application.
Using multiple stages can also let you build more efficiently by executing
build steps in parallel.
See [Multi-stage builds](../../build/building/multi-stage.md) for more
information.
## 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
[Dockerignore file](../../build/building/context.md#dockerignore-files).
## Create ephemeral containers ## Create ephemeral containers
The image defined by your Dockerfile should generate containers that are as The image defined by your Dockerfile should generate containers that are as
@ -15,13 +35,6 @@ Refer to [Processes](https://12factor.net/processes) under _The Twelve-factor Ap
methodology to get a feel for the motivations of running containers in such a methodology to get a feel for the motivations of running containers in such a
stateless fashion. stateless fashion.
## 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
[.dockerignore file](../../engine/reference/builder.md#dockerignore-file).
## Don't install unnecessary packages ## Don't install unnecessary packages
Avoid installing extra or unnecessary packages just because they might be nice to have. For example, you dont need to include a text editor in a database image. Avoid installing extra or unnecessary packages just because they might be nice to have. For example, you dont need to include a text editor in a database image.
@ -48,23 +61,9 @@ 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) containers depend on each other, you can use [Docker container networks](../../network/index.md)
to ensure that these containers can communicate. 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`, and `ADD` create layers. Other instructions
create temporary intermediate images, and don't increase the size of the build.
- Where possible, use [multi-stage builds](../../build/building/multi-stage.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 ## Sort multi-line arguments
Whenever possible, sort multi-line arguments alphanumerically to make maintenance easier. Whenever possible, sort multi-line arguments alphanumerically to make maintenance easier.
This helps to avoid duplication of packages and make the 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 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. review. Adding a space before a backslash (`\`) helps as well.
@ -81,213 +80,13 @@ RUN apt-get update && apt-get install -y \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
``` ```
## Understand build context
See [Build context](../../build/building/context.md) for more information.
## Pipe a Dockerfile through stdin
Docker has the ability to build images by piping a 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
afterward.
> **Note**
>
> The examples in the following sections 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 equal:
>
> ```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
doesn't 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**
>
> If you attempt to build an image using a Dockerfile from stdin, without sending a build context, then the build will fail if you use `COPY` or `ADD`.
> 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, and it uses a hyphen (`-`) as filename to instruct
Docker to read the Dockerfile from stdin:
```bash
docker build [OPTIONS] -f- PATH
```
The following example 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 doesn't contain a Dockerfile, or if you want to build with a custom
Dockerfile, without maintaining your own fork of the repository.
The following example builds an image using a Dockerfile from stdin, and adds
the `hello.c` file from the [hello-world](https://github.com/docker-library/hello-world) repository on GitHub.
```bash
docker build -t myimage:latest -f- https://github.com/docker-library/hello-world.git <<EOF
FROM busybox
COPY hello.c ./
EOF
```
> **Note**
>
> When building an image using a remote Git repository as the build context, Docker
> performs a `git clone` of the repository on the local machine, and sends
> those files as the build context to the daemon. This feature requires you to
> install Git on the host where you run the `docker build` command.
## Use multi-stage builds
[Multi-stage builds](../../build/building/multi-stage.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 and you want to ensure the build cache is reusable, you can order them from the less frequently changed to the more frequently changed. The following list is an example of the order of instructions:
1. Install tools you need to build your application
2. Install or update library dependencies
3. Generate your application
A Dockerfile for a Go application could look like:
```dockerfile
# syntax=docker/dockerfile:1
FROM golang:{{% param "example_go_version" %}}-alpine AS build
# Install tools required for project
# Run `docker build --no-cache .` to update dependencies
RUN apk add --no-cache git
# List project dependencies with go.mod and go.sum
# These layers are only re-built when Gopkg files are updated
WORKDIR /go/src/project/
COPY go.mod go.sum /go/src/project/
# Install library dependencies
RUN go mod download
# 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"]
```
### Leverage build cache ### Leverage build cache
When building an image, Docker steps through the instructions in your When building an image, Docker steps through the instructions in your
Dockerfile, executing each in the order specified. As each instruction is Dockerfile, executing each in the order specified. For each instruction, Docker
examined, Docker looks for an existing image in its cache, checks whether it can reuse the instruction from the build cache.
rather than creating a new, duplicate image.
If you don't want to use the cache at all, you can use the `--no-cache=true` The basic rules of build cache invalidation are as follows:
option on the `docker build` command. However, if you do let Docker use its
cache, it's important to understand when it can, and can't, find a matching
image. The basic rules that Docker follows are outlined below:
- Starting with a parent image that's already in the cache, the next - Starting with a parent image that's already in the cache, the next
instruction is compared against all child images derived from that base instruction is compared against all child images derived from that base
@ -298,12 +97,10 @@ image. The basic rules that Docker follows are outlined below:
of the child images is sufficient. However, certain instructions require more of the child images is sufficient. However, certain instructions require more
examination and explanation. examination and explanation.
- For the `ADD` and `COPY` instructions, the contents of each file - For the `ADD` and `COPY` instructions, the modification time and size file
in the image are examined and a checksum is calculated for each file. metadata is used to determine whether cache is valid. During cache lookup,
The last-modified and last-accessed times of each file aren't considered in cache is invalidated if the file metadata has changed for any of the files
these checksums. During the cache lookup, the checksum is compared against the involved.
checksum in the existing images. If anything has changed in any file, such
as the contents and metadata, then the cache is invalidated.
- Aside from the `ADD` and `COPY` commands, cache checking doesn't look at the - Aside from the `ADD` and `COPY` commands, cache checking doesn't look at the
files in the container to determine a cache match. For example, when processing files in the container to determine a cache match. For example, when processing
@ -313,3 +110,10 @@ image. The basic rules that Docker follows are outlined below:
Once the cache is invalidated, all subsequent Dockerfile commands generate new Once the cache is invalidated, all subsequent Dockerfile commands generate new
images and the cache isn't used. images and the cache isn't used.
If your build contains several layers and you want to ensure the build cache is
reusable, order the instructions from less frequently changed to more
frequently changed where possible.
For more information about the Docker build cache and how to optimize your
builds, see [cache management](../../build/cache/_index.md).

View File

@ -92,7 +92,7 @@ dependencies if there was a change to the `package.json`.
`.dockerignore` files are an easy way to selectively copy only image relevant files. `.dockerignore` files are an easy way to selectively copy only image relevant files.
You can read more about this You can read more about this
[here](../engine/reference/builder.md#dockerignore-file). [here](../build/building/context.md#dockerignore-files).
In this case, the `node_modules` folder should be omitted in the second `COPY` step because otherwise, In this case, the `node_modules` folder should be omitted in the second `COPY` step because otherwise,
it would possibly overwrite files which were created by the command in the `RUN` step. it would possibly overwrite files which were created by the command in the `RUN` step.
For further details on why this is recommended for Node.js applications and other best practices, For further details on why this is recommended for Node.js applications and other best practices,
@ -212,7 +212,7 @@ into an nginx container.
In this section, you learned a few image building best practices, including layer caching and multi-stage builds. In this section, you learned a few image building best practices, including layer caching and multi-stage builds.
Related information: Related information:
- [.dockerignore](../engine/reference/builder.md#dockerignore-file) - [.dockerignore](../build/building/context.md#dockerignore-files)
- [Dockerfile reference](../engine/reference/builder.md) - [Dockerfile reference](../engine/reference/builder.md)
- [Build with Docker guide](../build/guide/index.md) - [Build with Docker guide](../build/guide/index.md)
- [Dockerfile best practices](../develop/develop-images/dockerfile_best-practices.md) - [Dockerfile best practices](../develop/develop-images/dockerfile_best-practices.md)

View File

@ -188,4 +188,4 @@ If the proxy is an internal proxy, it might not be accessible for containers
created from that image. created from that image.
Embedding proxy settings in images also poses a security risk, as the values Embedding proxy settings in images also poses a security risk, as the values
may include sensitive information. may include sensitive information.

View File

@ -1784,7 +1784,7 @@ Manuals:
- path: /build/building/packaging/ - path: /build/building/packaging/
title: Packaging your software title: Packaging your software
- path: /build/building/context/ - path: /build/building/context/
title: Build context title: Context
- path: /build/building/multi-stage/ - path: /build/building/multi-stage/
title: Multi-stage builds title: Multi-stage builds
- path: /build/building/multi-platform/ - path: /build/building/multi-platform/