mirror of https://github.com/docker/docs.git
freshness: update top pages in the build section
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
This commit is contained in:
parent
e29944ad49
commit
2a6f7eac80
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
title: Multi-platform images
|
title: Multi-platform images
|
||||||
description: Different strategies for building multi-platform images
|
description: Introduction to multi-platform images and how to build them
|
||||||
keywords: build, buildx, buildkit, multi-platform images
|
keywords: build, buildx, buildkit, multi-platform images
|
||||||
redirect_from:
|
redirect_from:
|
||||||
- /build/buildx/multiplatform-images/
|
- /build/buildx/multiplatform-images/
|
||||||
|
@ -13,8 +13,8 @@ Docker images can support multiple platforms, which means that a single image
|
||||||
may contain variants for different architectures, and sometimes for different
|
may contain variants for different architectures, and sometimes for different
|
||||||
operating systems, such as Windows.
|
operating systems, such as Windows.
|
||||||
|
|
||||||
When running an image with multi-platform support, `docker` automatically
|
When you run an image with multi-platform support, Docker automatically selects
|
||||||
selects the image that matches your OS and architecture.
|
the image that matches your OS and architecture.
|
||||||
|
|
||||||
Most of the Docker Official Images on Docker Hub provide a [variety of architectures](https://github.com/docker-library/official-images#architectures-other-than-amd64){:target="blank" rel="noopener" class=""}.
|
Most of the Docker Official Images on Docker Hub provide a [variety of architectures](https://github.com/docker-library/official-images#architectures-other-than-amd64){:target="blank" rel="noopener" class=""}.
|
||||||
For example, the `busybox` image supports `amd64`, `arm32v5`, `arm32v6`,
|
For example, the `busybox` image supports `amd64`, `arm32v5`, `arm32v6`,
|
||||||
|
@ -23,55 +23,61 @@ on an `x86_64` / `amd64` machine, the `amd64` variant is pulled and run.
|
||||||
|
|
||||||
## Building multi-platform images
|
## Building multi-platform images
|
||||||
|
|
||||||
Docker is now making it easier than ever to develop containers on, and for Arm
|
|
||||||
servers and devices. Using the standard Docker tooling and processes, you can
|
|
||||||
start to build, push, pull, and run images seamlessly on different compute
|
|
||||||
architectures. In most cases, you don't have to make any changes to Dockerfiles
|
|
||||||
or source code to start building for Arm.
|
|
||||||
|
|
||||||
BuildKit with Buildx is designed to work well for building for multiple
|
|
||||||
platforms and not only for the architecture and operating system that the user
|
|
||||||
invoking the build happens to run.
|
|
||||||
|
|
||||||
When you invoke a build, you can set the `--platform` flag to specify the target
|
When you invoke a build, you can set the `--platform` flag to specify the target
|
||||||
platform for the build output, (for example, `linux/amd64`, `linux/arm64`, or
|
platform for the build output. For example, `linux/amd64`, `linux/arm64`, or
|
||||||
`darwin/amd64`).
|
`darwin/amd64`.
|
||||||
|
|
||||||
When the current builder instance is backed by the `docker-container` driver,
|
By default, you can only build for a single platform at a time. If you want to
|
||||||
you can specify multiple platforms together. In this case, it builds a manifest
|
build for multiple platforms at once, you can:
|
||||||
list which contains images for all specified architectures. When you use this
|
|
||||||
image in [`docker run`](../../engine/reference/commandline/run.md) or
|
|
||||||
[`docker service`](../../engine/reference/commandline/service.md), Docker picks
|
|
||||||
the correct image based on the node's platform.
|
|
||||||
|
|
||||||
You can build multi-platform images using three different strategies that are
|
- Create a new builder that uses the [`docker-container` driver](../drivers/docker-container.md)
|
||||||
supported by Buildx and Dockerfiles:
|
- Turn on the [containerd snapshotter storage](../../desktop/containerd/index.md)
|
||||||
|
|
||||||
1. Using the QEMU emulation support in the kernel
|
## Strategies
|
||||||
2. Building on multiple native nodes using the same builder instance
|
|
||||||
3. Using a stage in Dockerfile to cross-compile to different architectures
|
|
||||||
|
|
||||||
QEMU is the easiest way to get started if your node already supports it (for
|
You can build multi-platform images using three different strategies,
|
||||||
example. if you are using Docker Desktop). It requires no changes to your
|
depending on your use case:
|
||||||
Dockerfile and BuildKit automatically detects the secondary architectures that
|
|
||||||
are available. When BuildKit needs to run a binary for a different architecture,
|
1. Using the [QEMU emulation](#qemu) support in the kernel
|
||||||
it automatically loads it through a binary registered in the `binfmt_misc`
|
2. Building on [multiple native nodes](#multiple-native-nodes) using the same
|
||||||
handler.
|
builder instance
|
||||||
|
3. Using a stage in your Dockerfile to [cross-compile](#cross-compilation) to
|
||||||
|
different architectures
|
||||||
|
|
||||||
|
### QEMU
|
||||||
|
|
||||||
|
Building multi-platform images under emulation with QEMU is the easiest way to
|
||||||
|
get started if your builder already supports it. Docker Desktop supports it out
|
||||||
|
of the box. It requires no changes to your Dockerfile, and BuildKit
|
||||||
|
automatically detects the secondary architectures that are available. When
|
||||||
|
BuildKit needs to run a binary for a different architecture, it automatically
|
||||||
|
loads it through a binary registered in the `binfmt_misc` handler.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> QEMU performs full-system emulation of non-native platforms, which is much
|
||||||
|
> slower than native builds. Compute-heavy tasks like compilation and
|
||||||
|
> compression or decompression likely results in a large performance hit.
|
||||||
|
>
|
||||||
|
> Use [cross-compilation](#cross-compilation) instead, if possible.
|
||||||
|
|
||||||
For QEMU binaries registered with `binfmt_misc` on the host OS to work
|
For QEMU binaries registered with `binfmt_misc` on the host OS to work
|
||||||
transparently inside containers, they must be statically compiled and registered
|
transparently inside containers, they must be statically compiled and
|
||||||
with the `fix_binary` flag. This requires a kernel >= 4.8 and
|
registered with the `fix_binary` flag. This requires a kernel version 4.8 or
|
||||||
binfmt-support >= 2.1.7. You can check for proper registration by checking if
|
later, and `binfmt-support` version 2.1.7 or later.
|
||||||
`F` is among the flags in `/proc/sys/fs/binfmt_misc/qemu-*`. While Docker
|
|
||||||
Desktop comes preconfigured with `binfmt_misc` support for additional platforms,
|
You can verify your registration by checking if `F` is among the flags in
|
||||||
for other installations it likely needs to be installed using
|
`/proc/sys/fs/binfmt_misc/qemu-*`. While Docker Desktop comes preconfigured
|
||||||
[`tonistiigi/binfmt`](https://github.com/tonistiigi/binfmt){:target="blank" rel="noopener" class=""}
|
with `binfmt_misc` support for additional platforms, for other installations it
|
||||||
image.
|
likely needs to be installed using
|
||||||
|
[`tonistiigi/binfmt`](https://github.com/tonistiigi/binfmt) image:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker run --privileged --rm tonistiigi/binfmt --install all
|
$ docker run --privileged --rm tonistiigi/binfmt --install all
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Multiple native nodes
|
||||||
|
|
||||||
Using multiple native nodes provide better support for more complicated cases
|
Using multiple native nodes provide better support for more complicated cases
|
||||||
that are not handled by QEMU and generally have better performance. You can
|
that are not handled by QEMU and generally have better performance. You can
|
||||||
add additional nodes to the builder instance using the `--append` flag.
|
add additional nodes to the builder instance using the `--append` flag.
|
||||||
|
@ -85,13 +91,18 @@ $ docker buildx create --append --name mybuild node-arm64
|
||||||
$ docker buildx build --platform linux/amd64,linux/arm64 .
|
$ docker buildx build --platform linux/amd64,linux/arm64 .
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, depending on your project, the language that you use may have good
|
For information on using multiple native nodes in CI, with GitHub Actions,
|
||||||
support for cross-compilation. In that case, multi-stage builds in Dockerfiles
|
refer to
|
||||||
can be effectively used to build binaries for the platform specified with
|
[Configure your GitHub Actions builder](../ci/github-actions/configure-builder.md#append-additional-nodes-to-the-builder).
|
||||||
`--platform` using the native architecture of the build node. A list of build
|
|
||||||
arguments like `BUILDPLATFORM` and `TARGETPLATFORM` is available automatically
|
### Cross-compilation
|
||||||
inside your Dockerfile and can be leveraged by the processes running as part
|
|
||||||
of your build.
|
Depending on your project, if the programming language you use has good support
|
||||||
|
for cross-compilation, multi-stage builds in Dockerfiles can be effectively
|
||||||
|
used to build binaries for target platforms using the native architecture of
|
||||||
|
the build node. Build arguments such as `BUILDPLATFORM` and `TARGETPLATFORM`
|
||||||
|
are automatically available for use in your Dockerfile, and can be leveraged by
|
||||||
|
the processes running as part of your build.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
@ -124,34 +135,7 @@ and the more advanced cache exporters, which are currently unsupported in the
|
||||||
default `docker` driver:
|
default `docker` driver:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx create --name mybuilder --driver docker-container --bootstrap
|
$ docker buildx create --name mybuilder --bootstrap --use
|
||||||
mybuilder
|
|
||||||
```
|
|
||||||
|
|
||||||
Switch to the new builder:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ docker buildx use mybuilder
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Note**
|
|
||||||
>
|
|
||||||
> Alternatively, run `docker buildx create --name mybuilder --driver docker-container --bootstrap --use`
|
|
||||||
> to create a new builder and switch to it using a single command.
|
|
||||||
|
|
||||||
And inspect it:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ docker buildx inspect
|
|
||||||
Name: mybuilder
|
|
||||||
Driver: docker-container
|
|
||||||
|
|
||||||
Nodes:
|
|
||||||
Name: mybuilder0
|
|
||||||
Endpoint: unix:///var/run/docker.sock
|
|
||||||
Status: running
|
|
||||||
Buildkit: v0.10.4
|
|
||||||
Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Now listing the existing builders again, we can see our new builder is
|
Now listing the existing builders again, we can see our new builder is
|
||||||
|
@ -160,10 +144,10 @@ registered:
|
||||||
```console
|
```console
|
||||||
$ docker buildx ls
|
$ docker buildx ls
|
||||||
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
|
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
|
||||||
mybuilder docker-container
|
mybuilder * docker-container
|
||||||
mybuilder0 unix:///var/run/docker.sock running v0.10.4 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
|
mybuilder0 unix:///var/run/docker.sock running v0.12.1 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
|
||||||
default * docker
|
default docker
|
||||||
default default running v0.11.6 linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6
|
default default running v{{ site.buildkit_version }} linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
@ -272,5 +256,5 @@ Linux architectures such as `arm`, `mips`, `ppc64le`, and even `s390x`.
|
||||||
|
|
||||||
This does not require any special configuration in the container itself as it
|
This does not require any special configuration in the container itself as it
|
||||||
uses [qemu-static](https://wiki.qemu.org/Main_Page){:target="blank" rel="noopener" class=""}
|
uses [qemu-static](https://wiki.qemu.org/Main_Page){:target="blank" rel="noopener" class=""}
|
||||||
from the **Docker for Mac VM**. Because of this, you can run an ARM container,
|
from the Docker Desktop VM. Because of this, you can run an ARM container,
|
||||||
like the `arm32v7` or `ppc64le` variants of the busybox image.
|
like the `arm32v7` or `ppc64le` variants of the busybox image.
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
title: Multi-stage builds
|
title: Multi-stage builds
|
||||||
description: Keeping your images small with multi-stage builds
|
description: |
|
||||||
|
Learn about multi-stage builds and how you can use
|
||||||
|
them to improve your builds and get smaller images
|
||||||
keywords: build, best practices
|
keywords: build, best practices
|
||||||
redirect_from:
|
redirect_from:
|
||||||
- /engine/userguide/eng-image/multistage-build/
|
- /engine/userguide/eng-image/multistage-build/
|
||||||
|
@ -10,125 +12,46 @@ redirect_from:
|
||||||
Multi-stage builds are useful to anyone who has struggled to optimize
|
Multi-stage builds are useful to anyone who has struggled to optimize
|
||||||
Dockerfiles while keeping them easy to read and maintain.
|
Dockerfiles while keeping them easy to read and maintain.
|
||||||
|
|
||||||
> **Acknowledgment**
|
|
||||||
>
|
|
||||||
> Special thanks to [Alex Ellis](https://twitter.com/alexellisuk){:target="blank" rel="noopener" class=""}
|
|
||||||
> for granting permission to use his blog post [Builder pattern vs. Multi-stage builds in Docker](https://blog.alexellis.io/mutli-stage-docker-builds/){:target="blank" rel="noopener" class=""}
|
|
||||||
> as the basis of the examples on this page.
|
|
||||||
|
|
||||||
## Before multi-stage builds
|
|
||||||
|
|
||||||
One problem you may face as you build and publish images, is that the size of
|
|
||||||
those images can sometimes grow quite large. Traditionally, before multi-stage
|
|
||||||
builds were a thing, keeping the size of images down would require you to
|
|
||||||
manually clean up resources from the image, so as to keep it small.
|
|
||||||
|
|
||||||
In the past, it was common practice to have one Dockerfile for development,
|
|
||||||
and another, slimmed-down one to use for production.
|
|
||||||
The development version contained everything needed to build your application.
|
|
||||||
The production version only contained your application
|
|
||||||
and the dependencies needed to run it.
|
|
||||||
|
|
||||||
To write a truly efficient Dockerfile, you had to come up with shell tricks and
|
|
||||||
arcane solutions to keep the layers as small as possible.
|
|
||||||
All to ensure that each layer contained only the artifacts it needed,
|
|
||||||
and nothing else.
|
|
||||||
|
|
||||||
This has been referred to as the _builder pattern_.
|
|
||||||
The following examples show two Dockerfiles that adhere to this pattern:
|
|
||||||
|
|
||||||
- `build.Dockerfile`, for development builds
|
|
||||||
- `Dockerfile`, for slimmed-down production builds
|
|
||||||
|
|
||||||
**`build.Dockerfile`**:
|
|
||||||
|
|
||||||
```dockerfile
|
|
||||||
# syntax=docker/dockerfile:1
|
|
||||||
FROM golang:1.16
|
|
||||||
WORKDIR /go/src/github.com/alexellis/href-counter/
|
|
||||||
COPY app.go ./
|
|
||||||
RUN go get -d -v golang.org/x/net/html \
|
|
||||||
&& CGO_ENABLED=0 go build -a -installsuffix cgo -o app .
|
|
||||||
```
|
|
||||||
|
|
||||||
Notice how this example artificially compresses two `RUN` commands together
|
|
||||||
using the Bash `&&` operator. This is done to avoid creating an additional
|
|
||||||
layer in the image. Writing Dockerfiles like 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
|
|
||||||
# syntax=docker/dockerfile:1
|
|
||||||
FROM alpine:latest
|
|
||||||
RUN apk --no-cache add ca-certificates
|
|
||||||
WORKDIR /root/
|
|
||||||
COPY app ./
|
|
||||||
CMD ["./app"]
|
|
||||||
```
|
|
||||||
|
|
||||||
The following example is a utility script that:
|
|
||||||
|
|
||||||
1. Builds the first image.
|
|
||||||
2. Creates a container from it to copy the artifact out.
|
|
||||||
3. Builds the second image.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/bin/sh
|
|
||||||
echo Building alexellis2/href-counter:build
|
|
||||||
docker build -t alexellis2/href-counter:build . -f build.Dockerfile
|
|
||||||
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
Both images take up room on your system and you still end up with the `app`
|
|
||||||
artifact on your local disk as well.
|
|
||||||
|
|
||||||
Multi-stage builds simplifies this situation!
|
|
||||||
|
|
||||||
## Use multi-stage builds
|
## Use multi-stage builds
|
||||||
|
|
||||||
With multi-stage builds, you use multiple `FROM` statements in your Dockerfile.
|
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
|
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
|
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
|
another, leaving behind everything you don't want in the final image.
|
||||||
how this works, you can adapt the `Dockerfile` from the previous section to use
|
|
||||||
multi-stage builds.
|
The following Dockerfile has two separate stages: one for building a binary,
|
||||||
|
and another where we copy the binary into.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM golang:1.21
|
||||||
|
WORKDIR /src
|
||||||
|
COPY <<EOF ./main.go
|
||||||
|
package main
|
||||||
|
|
||||||
FROM golang:1.16
|
import "fmt"
|
||||||
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 go build -a -installsuffix cgo -o app .
|
|
||||||
|
|
||||||
FROM alpine:latest
|
func main() {
|
||||||
RUN apk --no-cache add ca-certificates
|
fmt.Println("hello, world")
|
||||||
WORKDIR /root/
|
}
|
||||||
COPY --from=0 /go/src/github.com/alexellis/href-counter/app ./
|
EOF
|
||||||
CMD ["./app"]
|
RUN go build -o /bin/hello ./main.go
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
COPY --from=0 /bin/hello /bin/hello
|
||||||
|
CMD ["/bin/hello"]
|
||||||
```
|
```
|
||||||
|
|
||||||
You only need the single Dockerfile.
|
You only need the single Dockerfile. No need for a separate build script. Just
|
||||||
No need for a separate build script.
|
run `docker build`.
|
||||||
Just run `docker build`.
|
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker build -t alexellis2/href-counter:latest .
|
$ docker build -t hello .
|
||||||
```
|
```
|
||||||
|
|
||||||
The end result is the same tiny production image as before, with a
|
The end result is a tiny production image with nothing but the binary inside.
|
||||||
significant reduction in complexity. You don't need to create any intermediate
|
None of the build tools required to build the application are included in the
|
||||||
images, and you don't need to extract any artifacts to your local system at all.
|
resulting image.
|
||||||
|
|
||||||
How does it work? The second `FROM` instruction starts a new build stage with
|
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
|
the `alpine:latest` image as its base. The `COPY --from=0` line copies just the
|
||||||
|
@ -146,18 +69,22 @@ Dockerfile are re-ordered later, the `COPY` doesn't break.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM golang:1.21 as build
|
||||||
|
WORKDIR /src
|
||||||
|
COPY <<EOF /src/main.go
|
||||||
|
package main
|
||||||
|
|
||||||
FROM golang:1.16 AS builder
|
import "fmt"
|
||||||
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 go build -a -installsuffix cgo -o app .
|
|
||||||
|
|
||||||
FROM alpine:latest
|
func main() {
|
||||||
RUN apk --no-cache add ca-certificates
|
fmt.Println("hello, world")
|
||||||
WORKDIR /root/
|
}
|
||||||
COPY --from=builder /go/src/github.com/alexellis/href-counter/app ./
|
EOF
|
||||||
CMD ["./app"]
|
RUN go build -o /bin/hello ./main.go
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
COPY --from=build /bin/hello /bin/hello
|
||||||
|
CMD ["/bin/hello"]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Stop at a specific build stage
|
## Stop at a specific build stage
|
||||||
|
@ -168,7 +95,7 @@ following command assumes you are using the previous `Dockerfile` but stops at
|
||||||
the stage named `builder`:
|
the stage named `builder`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker build --target builder -t alexellis2/href-counter:latest .
|
$ docker build --target build -t hello .
|
||||||
```
|
```
|
||||||
|
|
||||||
A few scenarios where this might be useful are:
|
A few scenarios where this might be useful are:
|
||||||
|
@ -179,7 +106,7 @@ A few scenarios where this might be useful are:
|
||||||
- Using a `testing` stage in which your app gets populated with test data, but
|
- 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
|
building for production using a different stage which uses real data
|
||||||
|
|
||||||
## Use an external image as a "stage"
|
## Use an external image as a stage
|
||||||
|
|
||||||
When using multi-stage builds, you aren't limited to copying from stages you
|
When using multi-stage builds, you aren't limited to copying from stages you
|
||||||
created earlier in your Dockerfile. You can use the `COPY --from` instruction to
|
created earlier in your Dockerfile. You can use the `COPY --from` instruction to
|
||||||
|
@ -284,5 +211,4 @@ Removing intermediate container bbc025b93175
|
||||||
Successfully built 09fc3770a9c4
|
Successfully built 09fc3770a9c4
|
||||||
```
|
```
|
||||||
|
|
||||||
The legacy builder processes `stage1`,
|
The legacy builder processes `stage1`, even if `stage2` doesn't depend on it.
|
||||||
even if `stage2` doesn't depend on it.
|
|
||||||
|
|
|
@ -9,15 +9,15 @@ redirect_from:
|
||||||
|
|
||||||
It all starts with a Dockerfile.
|
It all starts with a Dockerfile.
|
||||||
|
|
||||||
Docker builds images by reading the instructions from a Dockerfile. This is a
|
Docker builds images by reading the instructions from a Dockerfile. A
|
||||||
text file containing instructions that adhere to a specific format needed to
|
Dockerfile is a text file containing instructions for building your source
|
||||||
assemble your application into a container image and for which you can find
|
code. The Dockerfile instruction syntax is defined by the specification
|
||||||
its specification reference in the [Dockerfile reference](../../engine/reference/builder.md).
|
reference in the [Dockerfile reference](../../engine/reference/builder.md).
|
||||||
|
|
||||||
Here are the most common types of instructions:
|
Here are the most common types of instructions:
|
||||||
|
|
||||||
| Instruction | Description |
|
| Instruction | Description |
|
||||||
|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
| ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [`FROM <image>`](../../engine/reference/builder.md#from) | Defines a base for your image. |
|
| [`FROM <image>`](../../engine/reference/builder.md#from) | Defines a base for your image. |
|
||||||
| [`RUN <command>`](../../engine/reference/builder.md#run) | Executes any commands in a new layer on top of the current image and commits the result. `RUN` also has a shell form for running commands. |
|
| [`RUN <command>`](../../engine/reference/builder.md#run) | Executes any commands in a new layer on top of the current image and commits the result. `RUN` also has a shell form for running commands. |
|
||||||
| [`WORKDIR <directory>`](../../engine/reference/builder.md#workdir) | Sets the working directory for any `RUN`, `CMD`, `ENTRYPOINT`, `COPY`, and `ADD` instructions that follow it in the Dockerfile. |
|
| [`WORKDIR <directory>`](../../engine/reference/builder.md#workdir) | Sets the working directory for any `RUN`, `CMD`, `ENTRYPOINT`, `COPY`, and `ADD` instructions that follow it in the Dockerfile. |
|
||||||
|
@ -26,35 +26,38 @@ Here are the most common types of instructions:
|
||||||
|
|
||||||
Dockerfiles are crucial inputs for image builds and can facilitate automated,
|
Dockerfiles are crucial inputs for image builds and can facilitate automated,
|
||||||
multi-layer image builds based on your unique configurations. Dockerfiles can
|
multi-layer image builds based on your unique configurations. Dockerfiles can
|
||||||
start simple and grow with your needs and support images that require complex
|
start simple and grow with your needs to support more complex scenarios.
|
||||||
instructions. For all the possible instructions, see the [Dockerfile reference](../../engine/reference/builder.md).
|
|
||||||
|
### Filename
|
||||||
|
|
||||||
The default filename to use for a Dockerfile is `Dockerfile`, without a file
|
The default filename to use for a Dockerfile is `Dockerfile`, without a file
|
||||||
extension. Using the default name allows you to run the `docker build` command
|
extension. Using the default name allows you to run the `docker build` command
|
||||||
without having to specify additional command flags.
|
without having to specify additional command flags.
|
||||||
|
|
||||||
Some projects may need distinct Dockerfiles for specific purposes. A common
|
Some projects may need distinct Dockerfiles for specific purposes. A common
|
||||||
convention is to name these `<something>.Dockerfile`. Such Dockerfiles can then
|
convention is to name these `<something>.Dockerfile`. You can specify the
|
||||||
be used through the `--file` (or `-f` shorthand) option on the `docker build` command.
|
Dockerfile filename using the `--file` flag for the `docker build` command.
|
||||||
Refer to the ["Specify a Dockerfile" section](../../engine/reference/commandline/build.md#file)
|
Refer to the
|
||||||
in the `docker build` reference to learn about the `--file` option.
|
[`docker build` CLI reference](../../engine/reference/commandline/build.md#file)
|
||||||
|
to learn about the `--file` flag.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> We recommend using the default (`Dockerfile`) for your project's primary
|
> We recommend using the default (`Dockerfile`) for your project's primary
|
||||||
> Dockerfile.
|
> Dockerfile.
|
||||||
|
|
||||||
Docker images consist of **read-only layers**, each resulting from an
|
## Docker images
|
||||||
instruction in the Dockerfile. Layers are stacked sequentially and each one is
|
|
||||||
|
Docker images consist of layers. Each layer is the result of a build
|
||||||
|
instruction in the Dockerfile. Layers are stacked sequentially, and each one is
|
||||||
a delta representing the changes applied to the previous layer.
|
a delta representing the changes applied to the previous layer.
|
||||||
|
|
||||||
## Example
|
### Example
|
||||||
|
|
||||||
Here's a simple Dockerfile example to get you started with building images.
|
Here's what a typical workflow for building applications with Docker looks like.
|
||||||
We'll take a simple "Hello World" Python Flask application, and bundle it into
|
|
||||||
a Docker image that can test locally or deploy anywhere!
|
|
||||||
|
|
||||||
Let's say we have a `hello.py` file with the following content:
|
The following example code shows a small "Hello World" application written in
|
||||||
|
Python, using the Flask framework.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
@ -65,18 +68,15 @@ def hello():
|
||||||
return "Hello World!"
|
return "Hello World!"
|
||||||
```
|
```
|
||||||
|
|
||||||
Don't worry about understanding the full example if you're not familiar with
|
In order to ship and deploy this application without Docker Build, you would
|
||||||
Python, it's just a simple web server that will contain a single page that
|
need to make sure that:
|
||||||
says "Hello World".
|
|
||||||
|
|
||||||
> **Note**
|
- The required runtime dependencies are installed on the server
|
||||||
>
|
- The Python code gets uploaded to the server's filesystem
|
||||||
> If you test the example, make sure to copy over the indentation as well! For
|
- The server starts your application, using the necessary parameters
|
||||||
> more information about this sample Flask application, check the
|
|
||||||
> [Flask Quickstart](https://flask.palletsprojects.com/en/2.1.x/quickstart/){:target="blank" rel="noopener" class=""}
|
|
||||||
> page.
|
|
||||||
|
|
||||||
Here's the Dockerfile that will be used to create an image for our application:
|
The following Dockerfile creates a container image, which has all the
|
||||||
|
dependencies installed and that automatically starts your application.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
@ -95,6 +95,20 @@ EXPOSE 8000
|
||||||
CMD flask run --host 0.0.0.0 --port 8000
|
CMD flask run --host 0.0.0.0 --port 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Here's a breakdown of what this Dockerfile does:
|
||||||
|
|
||||||
|
- [Dockerfile syntax](#dockerfile-syntax)
|
||||||
|
- [Base image](#base-image)
|
||||||
|
- [Environment setup](#environment-setup)
|
||||||
|
- [Comments](#comments)
|
||||||
|
- [Installing dependencies](#installing-dependencies)
|
||||||
|
- [Copying files](#copying-files)
|
||||||
|
- [Setting environment variables](#setting-environment-variables)
|
||||||
|
- [Exposed ports](#exposed-ports)
|
||||||
|
- [Starting the application](#starting-the-application)
|
||||||
|
|
||||||
|
### Dockerfile syntax
|
||||||
|
|
||||||
The first line to add to a Dockerfile is a [`# syntax` parser directive](../../engine/reference/builder.md#syntax).
|
The first line to add to a Dockerfile is a [`# syntax` parser directive](../../engine/reference/builder.md#syntax).
|
||||||
While optional, this directive instructs the Docker builder what syntax to use
|
While optional, this directive instructs the Docker builder what syntax to use
|
||||||
when parsing the Dockerfile, and allows older Docker versions with [BuildKit enabled](../buildkit/index.md#getting-started)
|
when parsing the Dockerfile, and allows older Docker versions with [BuildKit enabled](../buildkit/index.md#getting-started)
|
||||||
|
@ -107,128 +121,156 @@ your Dockerfile, and should be the first line in Dockerfiles.
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**
|
> **Tip**
|
||||||
>
|
>
|
||||||
> We recommend using `docker/dockerfile:1`, which always points to the latest
|
> We recommend using `docker/dockerfile:1`, which always points to the latest
|
||||||
> release of the version 1 syntax. BuildKit automatically checks for updates of
|
> release of the version 1 syntax. BuildKit automatically checks for updates of
|
||||||
> the syntax before building, making sure you are using the most current version.
|
> the syntax before building, making sure you are using the most current version.
|
||||||
|
{: .tip }
|
||||||
|
|
||||||
Next we define the first instruction:
|
### Base image
|
||||||
|
|
||||||
|
The line following the syntax directive defines what base image to use:
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM ubuntu:22.04
|
FROM ubuntu:22.04
|
||||||
```
|
```
|
||||||
|
|
||||||
Here the [`FROM` instruction](../../engine/reference/builder.md#from) sets our
|
The [`FROM` instruction](../../engine/reference/builder.md#from) sets your base
|
||||||
base image to the 22.04 release of Ubuntu. All following instructions are
|
image to the 22.04 release of Ubuntu. All instructions that follow are executed
|
||||||
executed on this base image, in this case, an Ubuntu environment. The notation
|
in this base image: an Ubuntu environment. The notation `ubuntu:22.04`, follows
|
||||||
`ubuntu:22.04`, follows the `name:tag` standard for naming docker images. When
|
the `name:tag` standard for naming Docker images. When you build images, you
|
||||||
you build your image you use this notation to name your images and use it to
|
use this notation to name your images. There are many public images you can
|
||||||
specify any existing Docker image. There are many public images you can
|
leverage in your projects, by importing them into your build steps using the
|
||||||
leverage in your projects. Explore [Docker Hub](https://hub.docker.com/search?image_filter=official&q=&type=image){:target="blank" rel="noopener" class=""}
|
Dockerfile `FROM` instruction.
|
||||||
to find out.
|
|
||||||
|
[Docker Hub](https://hub.docker.com/search?image_filter=official&q=&type=image)
|
||||||
|
contains a large set of official images that you can use for this purpose.
|
||||||
|
|
||||||
|
### Environment setup
|
||||||
|
|
||||||
|
The following line executes a build command inside the base image.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
# install app dependencies
|
# install app dependencies
|
||||||
RUN apt-get update && apt-get install -y python3 python3-pip
|
RUN apt-get update && apt-get install -y python3 python3-pip
|
||||||
```
|
```
|
||||||
|
|
||||||
This [`RUN` instruction](../../engine/reference/builder.md#run) executes a shell
|
This [`RUN` instruction](../../engine/reference/builder.md#run) executes a
|
||||||
command in the [build context](context.md).
|
shell in Ubuntu that updates the APT package index and installs Python tools in
|
||||||
|
the container.
|
||||||
|
|
||||||
In this example, our context is a full Ubuntu operating system, so we have
|
### Comments
|
||||||
access to its package manager, apt. The provided commands update our package
|
|
||||||
lists and then, after that succeeds, installs `python3` and `pip`, the package
|
|
||||||
manager for Python.
|
|
||||||
|
|
||||||
Also note `# install app dependencies` line. This is a comment. Comments in
|
Note the `# install app dependencies` line. This is a comment. Comments in
|
||||||
Dockerfiles begin with the `#` symbol. As your Dockerfile evolves, comments can
|
Dockerfiles begin with the `#` symbol. As your Dockerfile evolves, comments can
|
||||||
be instrumental to document how your dockerfile works for any future readers
|
be instrumental to document how your Dockerfile works for any future readers
|
||||||
and editors of the file.
|
and editors of the file, including your future self!
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> Starting your Dockerfile by a `#` like regular comments is treated as a
|
> You might've noticed that comments are denoted using the same symbol as the
|
||||||
> directive when you are using BuildKit (default), otherwise it is ignored.
|
> [syntax directive](#dockerfile-syntax) on the first line of the file.
|
||||||
|
> The symbol is only interpreted as a directive if the pattern matches a
|
||||||
|
> directive and appears at the beginning of the Dockerfile. Otherwise, it's
|
||||||
|
> treated as a comment.
|
||||||
|
|
||||||
|
### Installing dependencies
|
||||||
|
|
||||||
|
The second `RUN` instruction installs the `flask` dependency required by the
|
||||||
|
Python application.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
RUN pip install flask==2.1.*
|
RUN pip install flask==2.1.*
|
||||||
```
|
```
|
||||||
|
|
||||||
This second `RUN` instruction requires that we've installed pip in the layer
|
A prerequisite for this instruction is that `pip` is installed into the build
|
||||||
before. After applying the previous directive, we can use the pip command to
|
container. The first `RUN` command installs `pip`, which ensures that we can
|
||||||
install the flask web framework. This is the framework we've used to write
|
use the command to install the flask web framework.
|
||||||
our basic "Hello World" application from above, so to run it in Docker, we'll
|
|
||||||
need to make sure it's installed.
|
### Copying files
|
||||||
|
|
||||||
|
The next instruction uses the
|
||||||
|
[`COPY` instruction](../../engine/reference/builder.md#copy) to copy the
|
||||||
|
`hello.py` file from the local build context into the root directory of our image.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
COPY hello.py /
|
COPY hello.py /
|
||||||
```
|
```
|
||||||
|
|
||||||
Now we use the [`COPY` instruction](../../engine/reference/builder.md#copy) to
|
A [build context](context.md) is the set of files that you can access
|
||||||
copy our `hello.py` file from the local [build context](context.md) into the
|
in Dockerfile instructions such as `COPY` and `ADD`.
|
||||||
root directory of our image. After being executed, we'll end up with a file
|
|
||||||
called `/hello.py` inside the image.
|
After the `COPY` instruction, the `hello.py` file is added to the filesystem
|
||||||
|
of the build container.
|
||||||
|
|
||||||
|
### Setting environment variables
|
||||||
|
|
||||||
|
If your application uses environment variables, you can set environment variables
|
||||||
|
in your Docker build using the [`ENV` instruction](../../engine/reference/builder.md#env).
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
ENV FLASK_APP=hello
|
ENV FLASK_APP=hello
|
||||||
```
|
```
|
||||||
|
|
||||||
This [`ENV` instruction](../../engine/reference/builder.md#env) sets a Linux
|
This sets a Linux environment variable we'll need later. Flask, the framework
|
||||||
environment variable we'll need later. This is a flask-specific variable,
|
used in this example, uses this variable to start the application. Without this,
|
||||||
that configures the command later used to run our `hello.py` application.
|
flask wouldn't know where to find our application to be able to run it.
|
||||||
Without this, flask wouldn't know where to find our application to be able to
|
|
||||||
run it.
|
### Exposed ports
|
||||||
|
|
||||||
|
The [`EXPOSE` instruction](../../engine/reference/builder.md#expose) marks that
|
||||||
|
our final image has a service listening on port `8000`.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
This [`EXPOSE` instruction](../../engine/reference/builder.md#expose) marks that
|
This instruction isn't required, but it is a good practice and helps tools and
|
||||||
our final image has a service listening on port `8000`. This isn't required,
|
team members understand what this application is doing.
|
||||||
but it is a good practice, as users and tools can use this to understand what
|
|
||||||
your image does.
|
### Starting the application
|
||||||
|
|
||||||
|
Finally, [`CMD` instruction](../../engine/reference/builder.md#cmd) sets the
|
||||||
|
command that is run when the user starts a container based on this image.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
CMD flask run --host 0.0.0.0 --port 8000
|
CMD flask run --host 0.0.0.0 --port 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, [`CMD` instruction](../../engine/reference/builder.md#cmd) sets the
|
In this case we'll start the flask development server listening on all addresses
|
||||||
command that is run when the user starts a container based on this image. In
|
|
||||||
this case we'll start the flask development server listening on all addresses
|
|
||||||
on port `8000`.
|
on port `8000`.
|
||||||
|
|
||||||
## Testing
|
## Building
|
||||||
|
|
||||||
To test our Dockerfile, we'll first build it using the [`docker build` command](../../engine/reference/commandline/build.md):
|
To build a container image using the Dockerfile example from the
|
||||||
|
[previous section](#example), you use the `docker build` command:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker build -t test:latest .
|
$ docker build -t test:latest .
|
||||||
```
|
```
|
||||||
|
|
||||||
Here `-t test:latest` option specifies the name (required) and tag (optional)
|
The `-t test:latest` option specifies the name and tag of the image.
|
||||||
of the image we're building. `.` specifies the [build context](context.md) as
|
|
||||||
the current directory. In this example, this is where build expects to find the
|
|
||||||
Dockerfile and the local files the Dockerfile needs to access, in this case
|
|
||||||
your Python application.
|
|
||||||
|
|
||||||
So, in accordance with the build command issued and how [build context](context.md)
|
The single dot (`.`) at the end of the command sets the
|
||||||
works, your Dockerfile and python app need to be in the same directory.
|
[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
|
||||||
|
where the command is invoked. If those files aren't there, the build fails.
|
||||||
|
|
||||||
Now run your newly built image:
|
After the image has been built, you can run the application as a container with
|
||||||
|
`docker run`, specifying the image name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker run -p 8000:8000 test:latest
|
$ docker run -p 127.0.0.1:8000:8000 test:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
From your computer, open a browser and navigate to `http://localhost:8000`
|
This publishes the container's port 8000 to `http://localhost:8000` on the
|
||||||
|
Docker host.
|
||||||
> **Note**
|
|
||||||
>
|
|
||||||
> You can also build and run using [Play with Docker](https://labs.play-with-docker.com){:target="blank" rel="noopener" class=""}
|
|
||||||
> that provides you with a temporary Docker instance in the cloud.
|
|
||||||
|
|
||||||
## Other resources
|
## Other resources
|
||||||
|
|
||||||
If you are interested in examples in other languages, such as Go, check out
|
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,
|
||||||
|
refer to the [Build with Docker](../guide/index.md) guide.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
title: Configuring your builder
|
title: Configuring your GitHub Actions builder
|
||||||
description: Configuring BuildKit instances with GitHub Actions.
|
description: Configuring BuildKit instances for building in CI with GitHub Actions
|
||||||
keywords: ci, github actions, gha, buildkit, buildx
|
keywords: ci, github actions, gha, buildkit, buildx
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -7,15 +7,14 @@ redirect_from:
|
||||||
- /develop/develop-images/build_enhancements/
|
- /develop/develop-images/build_enhancements/
|
||||||
---
|
---
|
||||||
|
|
||||||
Docker Build is one of Docker Engine's most used features. Whenever you are
|
Docker Build is one of Docker Engine's most used features. Whenever you're
|
||||||
creating an image you are using Docker Build. Build is a key part of your
|
creating an image, you are using Docker Build. Build is a key part of your
|
||||||
software development life cycle allowing you to package and bundle your code and
|
software development life cycle allowing you to package and bundle your code and
|
||||||
ship it anywhere.
|
ship it anywhere.
|
||||||
|
|
||||||
Docker Build is more than a command for building images, and it's not only about
|
Docker Build is more than a command for building images, and it's not only about
|
||||||
packaging your code. It's a whole ecosystem of tools and features that support
|
packaging your code. It's a whole ecosystem of tools and features that support
|
||||||
not only common workflow tasks but also provides support for more complex and
|
both common workflow tasks and more complex and advanced scenarios.
|
||||||
advanced scenarios.
|
|
||||||
|
|
||||||
<div class="component-container">
|
<div class="component-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
Loading…
Reference in New Issue