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
|
||||
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
|
||||
redirect_from:
|
||||
- /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
|
||||
operating systems, such as Windows.
|
||||
|
||||
When running an image with multi-platform support, `docker` automatically
|
||||
selects the image that matches your OS and architecture.
|
||||
When you run an image with multi-platform support, Docker automatically selects
|
||||
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=""}.
|
||||
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
|
||||
|
||||
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
|
||||
platform for the build output, (for example, `linux/amd64`, `linux/arm64`, or
|
||||
`darwin/amd64`).
|
||||
platform for the build output. For example, `linux/amd64`, `linux/arm64`, or
|
||||
`darwin/amd64`.
|
||||
|
||||
When the current builder instance is backed by the `docker-container` driver,
|
||||
you can specify multiple platforms together. In this case, it builds a manifest
|
||||
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.
|
||||
By default, you can only build for a single platform at a time. If you want to
|
||||
build for multiple platforms at once, you can:
|
||||
|
||||
You can build multi-platform images using three different strategies that are
|
||||
supported by Buildx and Dockerfiles:
|
||||
- Create a new builder that uses the [`docker-container` driver](../drivers/docker-container.md)
|
||||
- Turn on the [containerd snapshotter storage](../../desktop/containerd/index.md)
|
||||
|
||||
1. Using the QEMU emulation support in the kernel
|
||||
2. Building on multiple native nodes using the same builder instance
|
||||
3. Using a stage in Dockerfile to cross-compile to different architectures
|
||||
## Strategies
|
||||
|
||||
QEMU is the easiest way to get started if your node already supports it (for
|
||||
example. if you are using Docker Desktop). 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.
|
||||
You can build multi-platform images using three different strategies,
|
||||
depending on your use case:
|
||||
|
||||
1. Using the [QEMU emulation](#qemu) support in the kernel
|
||||
2. Building on [multiple native nodes](#multiple-native-nodes) using the same
|
||||
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
|
||||
transparently inside containers, they must be statically compiled and registered
|
||||
with the `fix_binary` flag. This requires a kernel >= 4.8 and
|
||||
binfmt-support >= 2.1.7. You can check for proper registration by checking if
|
||||
`F` is among the flags in `/proc/sys/fs/binfmt_misc/qemu-*`. While Docker
|
||||
Desktop comes preconfigured with `binfmt_misc` support for additional platforms,
|
||||
for other installations it likely needs to be installed using
|
||||
[`tonistiigi/binfmt`](https://github.com/tonistiigi/binfmt){:target="blank" rel="noopener" class=""}
|
||||
image.
|
||||
transparently inside containers, they must be statically compiled and
|
||||
registered with the `fix_binary` flag. This requires a kernel version 4.8 or
|
||||
later, and `binfmt-support` version 2.1.7 or later.
|
||||
|
||||
You can verify your registration by checking if `F` is among the flags in
|
||||
`/proc/sys/fs/binfmt_misc/qemu-*`. While Docker Desktop comes preconfigured
|
||||
with `binfmt_misc` support for additional platforms, for other installations it
|
||||
likely needs to be installed using
|
||||
[`tonistiigi/binfmt`](https://github.com/tonistiigi/binfmt) image:
|
||||
|
||||
```console
|
||||
$ docker run --privileged --rm tonistiigi/binfmt --install all
|
||||
```
|
||||
|
||||
### Multiple native nodes
|
||||
|
||||
Using multiple native nodes provide better support for more complicated cases
|
||||
that are not handled by QEMU and generally have better performance. You can
|
||||
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 .
|
||||
```
|
||||
|
||||
Finally, depending on your project, the language that you use may have good
|
||||
support for cross-compilation. In that case, multi-stage builds in Dockerfiles
|
||||
can be effectively used to build binaries for the platform specified with
|
||||
`--platform` using the native architecture of the build node. A list of build
|
||||
arguments like `BUILDPLATFORM` and `TARGETPLATFORM` is available automatically
|
||||
inside your Dockerfile and can be leveraged by the processes running as part
|
||||
of your build.
|
||||
For information on using multiple native nodes in CI, with GitHub Actions,
|
||||
refer to
|
||||
[Configure your GitHub Actions builder](../ci/github-actions/configure-builder.md#append-additional-nodes-to-the-builder).
|
||||
|
||||
### Cross-compilation
|
||||
|
||||
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
|
||||
# syntax=docker/dockerfile:1
|
||||
|
@ -124,34 +135,7 @@ and the more advanced cache exporters, which are currently unsupported in the
|
|||
default `docker` driver:
|
||||
|
||||
```console
|
||||
$ docker buildx create --name mybuilder --driver docker-container --bootstrap
|
||||
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
|
||||
$ docker buildx create --name mybuilder --bootstrap --use
|
||||
```
|
||||
|
||||
Now listing the existing builders again, we can see our new builder is
|
||||
|
@ -160,10 +144,10 @@ registered:
|
|||
```console
|
||||
$ docker buildx ls
|
||||
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
|
||||
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
|
||||
default * docker
|
||||
default default running v0.11.6 linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6
|
||||
mybuilder * docker-container
|
||||
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 default running v{{ site.buildkit_version }} linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6
|
||||
```
|
||||
|
||||
## 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
|
||||
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.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
---
|
||||
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
|
||||
redirect_from:
|
||||
- /engine/userguide/eng-image/multistage-build/
|
||||
|
@ -10,125 +12,46 @@ redirect_from:
|
|||
Multi-stage 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){: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
|
||||
|
||||
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, you can adapt the `Dockerfile` from the previous section to use
|
||||
multi-stage builds.
|
||||
another, leaving behind everything you don't want in the final image.
|
||||
|
||||
The following Dockerfile has two separate stages: one for building a binary,
|
||||
and another where we copy the binary into.
|
||||
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM golang:1.21
|
||||
WORKDIR /src
|
||||
COPY <<EOF ./main.go
|
||||
package main
|
||||
|
||||
FROM golang:1.16
|
||||
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 .
|
||||
import "fmt"
|
||||
|
||||
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"]
|
||||
func main() {
|
||||
fmt.Println("hello, world")
|
||||
}
|
||||
EOF
|
||||
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.
|
||||
No need for a separate build script.
|
||||
Just run `docker build`.
|
||||
You only need the single Dockerfile. No need for a separate build script. Just
|
||||
run `docker build`.
|
||||
|
||||
```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
|
||||
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.
|
||||
The end result is a tiny production image with nothing but the binary inside.
|
||||
None of the build tools required to build the application are included in the
|
||||
resulting image.
|
||||
|
||||
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
|
||||
|
@ -146,18 +69,22 @@ Dockerfile are re-ordered later, the `COPY` doesn't break.
|
|||
|
||||
```dockerfile
|
||||
# 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
|
||||
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 .
|
||||
import "fmt"
|
||||
|
||||
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"]
|
||||
func main() {
|
||||
fmt.Println("hello, world")
|
||||
}
|
||||
EOF
|
||||
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
|
||||
|
@ -168,7 +95,7 @@ following command assumes you are using the previous `Dockerfile` but stops at
|
|||
the stage named `builder`:
|
||||
|
||||
```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:
|
||||
|
@ -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
|
||||
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
|
||||
created earlier in your Dockerfile. You can use the `COPY --from` instruction to
|
||||
|
@ -284,5 +211,4 @@ Removing intermediate container bbc025b93175
|
|||
Successfully built 09fc3770a9c4
|
||||
```
|
||||
|
||||
The legacy builder processes `stage1`,
|
||||
even if `stage2` doesn't depend on it.
|
||||
The legacy builder processes `stage1`, even if `stage2` doesn't depend on it.
|
||||
|
|
|
@ -9,15 +9,15 @@ redirect_from:
|
|||
|
||||
It all starts with a Dockerfile.
|
||||
|
||||
Docker builds images by reading the instructions from a Dockerfile. This is a
|
||||
text file containing instructions that adhere to a specific format needed to
|
||||
assemble your application into a container image and for which you can find
|
||||
its specification reference in the [Dockerfile reference](../../engine/reference/builder.md).
|
||||
Docker builds images by reading the instructions from a Dockerfile. A
|
||||
Dockerfile is a text file containing instructions for building your source
|
||||
code. The Dockerfile instruction syntax is defined by the specification
|
||||
reference in the [Dockerfile reference](../../engine/reference/builder.md).
|
||||
|
||||
Here are the most common types of instructions:
|
||||
|
||||
| Instruction | Description |
|
||||
|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`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. |
|
||||
| [`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,
|
||||
multi-layer image builds based on your unique configurations. Dockerfiles can
|
||||
start simple and grow with your needs and support images that require complex
|
||||
instructions. For all the possible instructions, see the [Dockerfile reference](../../engine/reference/builder.md).
|
||||
start simple and grow with your needs to support more complex scenarios.
|
||||
|
||||
### Filename
|
||||
|
||||
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
|
||||
without having to specify additional command flags.
|
||||
|
||||
Some projects may need distinct Dockerfiles for specific purposes. A common
|
||||
convention is to name these `<something>.Dockerfile`. Such Dockerfiles can then
|
||||
be used through the `--file` (or `-f` shorthand) option on the `docker build` command.
|
||||
Refer to the ["Specify a Dockerfile" section](../../engine/reference/commandline/build.md#file)
|
||||
in the `docker build` reference to learn about the `--file` option.
|
||||
convention is to name these `<something>.Dockerfile`. You can specify the
|
||||
Dockerfile filename using the `--file` flag for the `docker build` command.
|
||||
Refer to the
|
||||
[`docker build` CLI reference](../../engine/reference/commandline/build.md#file)
|
||||
to learn about the `--file` flag.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> We recommend using the default (`Dockerfile`) for your project's primary
|
||||
> Dockerfile.
|
||||
|
||||
Docker images consist of **read-only layers**, each resulting from an
|
||||
instruction in the Dockerfile. Layers are stacked sequentially and each one is
|
||||
## Docker images
|
||||
|
||||
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.
|
||||
|
||||
## Example
|
||||
### Example
|
||||
|
||||
Here's a simple Dockerfile example to get you started with building images.
|
||||
We'll take a simple "Hello World" Python Flask application, and bundle it into
|
||||
a Docker image that can test locally or deploy anywhere!
|
||||
Here's what a typical workflow for building applications with Docker looks like.
|
||||
|
||||
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
|
||||
from flask import Flask
|
||||
|
@ -65,18 +68,15 @@ def hello():
|
|||
return "Hello World!"
|
||||
```
|
||||
|
||||
Don't worry about understanding the full example if you're not familiar with
|
||||
Python, it's just a simple web server that will contain a single page that
|
||||
says "Hello World".
|
||||
In order to ship and deploy this application without Docker Build, you would
|
||||
need to make sure that:
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> If you test the example, make sure to copy over the indentation as well! For
|
||||
> 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.
|
||||
- The required runtime dependencies are installed on the server
|
||||
- The Python code gets uploaded to the server's filesystem
|
||||
- The server starts your application, using the necessary parameters
|
||||
|
||||
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
|
||||
# syntax=docker/dockerfile:1
|
||||
|
@ -95,6 +95,20 @@ EXPOSE 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).
|
||||
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)
|
||||
|
@ -107,128 +121,156 @@ your Dockerfile, and should be the first line in Dockerfiles.
|
|||
# syntax=docker/dockerfile:1
|
||||
```
|
||||
|
||||
> **Note**
|
||||
> **Tip**
|
||||
>
|
||||
> We recommend using `docker/dockerfile:1`, which always points to the latest
|
||||
> 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.
|
||||
{: .tip }
|
||||
|
||||
Next we define the first instruction:
|
||||
### Base image
|
||||
|
||||
The line following the syntax directive defines what base image to use:
|
||||
|
||||
```dockerfile
|
||||
FROM ubuntu:22.04
|
||||
```
|
||||
|
||||
Here the [`FROM` instruction](../../engine/reference/builder.md#from) sets our
|
||||
base image to the 22.04 release of Ubuntu. All following instructions are
|
||||
executed on this base image, in this case, an Ubuntu environment. The notation
|
||||
`ubuntu:22.04`, follows the `name:tag` standard for naming docker images. When
|
||||
you build your image you use this notation to name your images and use it to
|
||||
specify any existing Docker image. There are many public images you can
|
||||
leverage in your projects. Explore [Docker Hub](https://hub.docker.com/search?image_filter=official&q=&type=image){:target="blank" rel="noopener" class=""}
|
||||
to find out.
|
||||
The [`FROM` instruction](../../engine/reference/builder.md#from) sets your base
|
||||
image to the 22.04 release of Ubuntu. All instructions that follow are executed
|
||||
in this base image: an Ubuntu environment. The notation `ubuntu:22.04`, follows
|
||||
the `name:tag` standard for naming Docker images. When you build images, you
|
||||
use this notation to name your images. There are many public images you can
|
||||
leverage in your projects, by importing them into your build steps using the
|
||||
Dockerfile `FROM` instruction.
|
||||
|
||||
[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
|
||||
# install app dependencies
|
||||
RUN apt-get update && apt-get install -y python3 python3-pip
|
||||
```
|
||||
|
||||
This [`RUN` instruction](../../engine/reference/builder.md#run) executes a shell
|
||||
command in the [build context](context.md).
|
||||
This [`RUN` instruction](../../engine/reference/builder.md#run) executes a
|
||||
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
|
||||
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.
|
||||
### Comments
|
||||
|
||||
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
|
||||
be instrumental to document how your dockerfile works for any future readers
|
||||
and editors of the file.
|
||||
be instrumental to document how your Dockerfile works for any future readers
|
||||
and editors of the file, including your future self!
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> Starting your Dockerfile by a `#` like regular comments is treated as a
|
||||
> directive when you are using BuildKit (default), otherwise it is ignored.
|
||||
> You might've noticed that comments are denoted using the same symbol as the
|
||||
> [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
|
||||
RUN pip install flask==2.1.*
|
||||
```
|
||||
|
||||
This second `RUN` instruction requires that we've installed pip in the layer
|
||||
before. After applying the previous directive, we can use the pip command to
|
||||
install the flask web framework. This is the framework we've used to write
|
||||
our basic "Hello World" application from above, so to run it in Docker, we'll
|
||||
need to make sure it's installed.
|
||||
A prerequisite for this instruction is that `pip` is installed into the build
|
||||
container. The first `RUN` command installs `pip`, which ensures that we can
|
||||
use the command to install the flask web framework.
|
||||
|
||||
### 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
|
||||
COPY hello.py /
|
||||
```
|
||||
|
||||
Now we use the [`COPY` instruction](../../engine/reference/builder.md#copy) to
|
||||
copy our `hello.py` file from the local [build context](context.md) into the
|
||||
root directory of our image. After being executed, we'll end up with a file
|
||||
called `/hello.py` inside the image.
|
||||
A [build context](context.md) is the set of files that you can access
|
||||
in Dockerfile instructions such as `COPY` and `ADD`.
|
||||
|
||||
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
|
||||
ENV FLASK_APP=hello
|
||||
```
|
||||
|
||||
This [`ENV` instruction](../../engine/reference/builder.md#env) sets a Linux
|
||||
environment variable we'll need later. This is a flask-specific variable,
|
||||
that configures the command later used to run our `hello.py` application.
|
||||
Without this, flask wouldn't know where to find our application to be able to
|
||||
run it.
|
||||
This sets a Linux environment variable we'll need later. Flask, the framework
|
||||
used in this example, uses this variable to start the application. 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
|
||||
EXPOSE 8000
|
||||
```
|
||||
|
||||
This [`EXPOSE` instruction](../../engine/reference/builder.md#expose) marks that
|
||||
our final image has a service listening on port `8000`. This isn't required,
|
||||
but it is a good practice, as users and tools can use this to understand what
|
||||
your image does.
|
||||
This instruction isn't required, but it is a good practice and helps tools and
|
||||
team members understand what this application is doing.
|
||||
|
||||
### 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
|
||||
CMD flask run --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
Finally, [`CMD` instruction](../../engine/reference/builder.md#cmd) sets the
|
||||
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
|
||||
In this case we'll start the flask development server listening on all addresses
|
||||
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
|
||||
$ docker build -t test:latest .
|
||||
```
|
||||
|
||||
Here `-t test:latest` option specifies the name (required) and tag (optional)
|
||||
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.
|
||||
The `-t test:latest` option specifies the name and tag of the image.
|
||||
|
||||
So, in accordance with the build command issued and how [build context](context.md)
|
||||
works, your Dockerfile and python app need to be in the same directory.
|
||||
The single dot (`.`) at the end of the command sets 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
|
||||
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
|
||||
$ 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`
|
||||
|
||||
> **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.
|
||||
This publishes the container's port 8000 to `http://localhost:8000` on the
|
||||
Docker host.
|
||||
|
||||
## Other resources
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
description: Configuring BuildKit instances with GitHub Actions.
|
||||
title: Configuring your GitHub Actions builder
|
||||
description: Configuring BuildKit instances for building in CI with GitHub Actions
|
||||
keywords: ci, github actions, gha, buildkit, buildx
|
||||
---
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@ redirect_from:
|
|||
- /develop/develop-images/build_enhancements/
|
||||
---
|
||||
|
||||
Docker Build is one of Docker Engine's most used features. Whenever you are
|
||||
creating an image you are using Docker Build. Build is a key part of your
|
||||
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
|
||||
software development life cycle allowing you to package and bundle your code and
|
||||
ship it anywhere.
|
||||
|
||||
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
|
||||
not only common workflow tasks but also provides support for more complex and
|
||||
advanced scenarios.
|
||||
both common workflow tasks and more complex and advanced scenarios.
|
||||
|
||||
<div class="component-container">
|
||||
<div class="row">
|
||||
|
|
Loading…
Reference in New Issue