freshness: update top pages in the build section

Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
This commit is contained in:
David Karlsson 2023-08-09 17:23:19 +02:00
parent e29944ad49
commit 2a6f7eac80
5 changed files with 242 additions and 291 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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
---

View File

@ -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">