mirror of https://github.com/docker/docs.git
build: editorial suggestions for cache docs
Co-authored-by: CrazyMax <github@crazymax.dev> Co-authored-by: Justin Chadwell <github@jedevc.com>
This commit is contained in:
parent
c42962dc87
commit
fdfcea0035
|
@ -1,58 +1,58 @@
|
||||||
---
|
---
|
||||||
title: Optimizing builds with cache management
|
title: Optimizing builds with cache management
|
||||||
description: Improve your build speeds by taking advantage of the builtin cache
|
description: Improve your build speeds by taking advantage of the builtin cache
|
||||||
keywords: build, buildx, buildkit, dockerfile, image layers, build instructions, build context
|
keywords: >
|
||||||
|
build, buildx, buildkit, dockerfile, image layers, build instructions, build
|
||||||
|
context
|
||||||
---
|
---
|
||||||
|
|
||||||
It's very unlikely you end up just building a docker image once - most of the
|
You will likely find yourself rebuilding the same Docker image over and over
|
||||||
time, you'll want to build it again at some point, whether that's for the next
|
again. Whether it's for the next release of your software, or locally during
|
||||||
release of your software, or, more likely, on your local development machine
|
development. Because building images is a common task, Docker provides several
|
||||||
for testing. Because building images is a frequent operation, docker provides
|
tools that speed up builds.
|
||||||
several tools to speed up your builds for when you inevitably need to run them
|
|
||||||
again.
|
|
||||||
|
|
||||||
The main approach to improving your build's speed is to take advantage of
|
The most important feature for improving build speeds is Docker's build cache.
|
||||||
docker's build cache.
|
|
||||||
|
|
||||||
## How does the build cache work?
|
## How does the build cache work?
|
||||||
|
|
||||||
Docker's build cache is quite simple to understand - first, remember the
|
Understanding Docker's build cache helps you write better Dockerfiles that
|
||||||
instructions that make up your Dockerfile, for example, in this build which
|
result in faster builds.
|
||||||
might be used to create a C/C++ program:
|
|
||||||
|
Have a look at the following example, which shows a simple Dockerfile for a
|
||||||
|
program written in C.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM ubuntu:latest
|
FROM ubuntu:latest
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y build-essentials
|
RUN apt-get update && apt-get install -y build-essentials
|
||||||
COPY . /src/
|
COPY main.c /src/
|
||||||
WORKDIR /src/
|
WORKDIR /src/
|
||||||
RUN make build
|
RUN make build
|
||||||
```
|
```
|
||||||
|
|
||||||
Each instruction in this Dockerfile (roughly) translates into a layer in your
|
Each instruction in this Dockerfile translates (roughly) to a layer in your
|
||||||
final image. You can think of layers in a stack, with each layer adding more
|
final image. You can think of image layers as a stack, with each layer adding
|
||||||
content to the filesystem on top of the layer before it:
|
more content on top of the layers that came before it:
|
||||||
|
|
||||||
{:.invertible}
|
{:.invertible}
|
||||||
|
|
||||||
|
Whenever a layer changes, that layer will need to be re-built. For example,
|
||||||
Now, if one of the layers changes, somewhere - for example, suppose you make a
|
suppose you make a change to your program in the `main.c` file. After this
|
||||||
change to your C/C++ program in `main.c`. After this change, the `COPY` command
|
change, the `COPY` command will have to run again in order for those changes to
|
||||||
will have to run again, so that the layer changes, so the cache for that layer
|
appear in the image. In other words, Docker will invalidate the cache for this
|
||||||
has been invalidated.
|
layer.
|
||||||
|
|
||||||
{:.invertible}
|
{:.invertible}
|
||||||
|
|
||||||
But since we have a change to that file, we now need to run our `make build`
|
If a layer changes, all other layers that come after it are also affected. When
|
||||||
step again, so that those changes are built into our program. So since our
|
the layer with the `COPY` command gets invalidated, all layers that follow will
|
||||||
cache for `COPY` was invalidated, we also have to invalidate the cache for all
|
need to run again, too:
|
||||||
the layers after it, including our `RUN make build`, so that it will run again:
|
|
||||||
|
|
||||||
{:.invertible}
|
{:.invertible}
|
||||||
|
|
||||||
That's pretty much all there is to understand the cache - once there's a change
|
And that's the Docker build cache in a nutshell. Once a layer changes, then all
|
||||||
in a layer, then all the layers after it will need to be rebuilt as well (even
|
downstream layers need to be rebuilt as well. Even if they wouldn't build
|
||||||
if they wouldn't build anything differently, they still need to re-run).
|
anything differently, they still need to re-run.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
|
@ -60,214 +60,230 @@ if they wouldn't build anything differently, they still need to re-run).
|
||||||
> Dockerfile to upgrade all the software packages in your Debian-based image to
|
> Dockerfile to upgrade all the software packages in your Debian-based image to
|
||||||
> the latest version.
|
> the latest version.
|
||||||
>
|
>
|
||||||
> Unfortunately, this doesn't mean that the images you build are *always* up to
|
> This doesn't mean that the images you build are always up to date. Rebuilding
|
||||||
> date! If you built the image a week ago, then the results of your `apt-get`
|
> the image on the same host one week later will still get you the same packages
|
||||||
> will get cached, and re-used if you re-run it now! The only way to force a
|
> as before. The only way to force a rebuild is by making sure that a layer
|
||||||
> re-run is to make sure that a layer before it has changed, for example, by
|
> before it has changed, or by clearing the build cache using
|
||||||
> making sure you have the latest version of the image used in `FROM`.
|
> [`docker builder prune`](/engine/reference/commandline/builder_build/).
|
||||||
|
|
||||||
## How can I use the cache efficiently?
|
## How can I use the cache efficiently?
|
||||||
|
|
||||||
Now that we've seen how the cache works, we can look at how to best take
|
Now that you understand how the cache works, you can begin to use the cache to
|
||||||
advantage of the cache to get the best results. While the cache will
|
your advantage. While the cache will automatically work on any `docker build`
|
||||||
automatically work on any docker build that you run, you can often refactor
|
that you run, you can often refactor your Dockerfile to get even better
|
||||||
your Dockerfile to get even better performance and save precious seconds (or
|
performance. These optimizations can save precious seconds (or even minutes) off
|
||||||
even minutes) off of your builds!
|
of your builds.
|
||||||
|
|
||||||
### Order your layers
|
### Order your layers
|
||||||
|
|
||||||
Putting the commands in your Dockerfile into a logical order is a great place
|
Putting the commands in your Dockerfile into a logical order is a great place to
|
||||||
to start. Because a change in an earlier step will rebuild all the later steps,
|
start. Because a change causes a rebuild for steps that follow, try to make
|
||||||
we want to make sure that we put our most expensive steps near the beginning,
|
expensive steps appear near the beginning of the Dockerfile. Steps that change
|
||||||
and our most frequently changing steps near the end, to avoid unnecessarily
|
often should appear near the end of the Dockerfile, to avoid triggering rebuilds
|
||||||
rebuilding layers that haven't changed much.
|
of layers that haven't changed.
|
||||||
|
|
||||||
Let's take a simple example, a Dockerfile snippet that runs a javascript build
|
Consider the following example. A Dockerfile snippet that runs a JavaScript
|
||||||
from the source files in the current directory:
|
build from the source files in the current directory:
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM node
|
FROM node
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . . # Copy over all files in the current directory
|
||||||
RUN npm install
|
RUN npm install # Install dependencies
|
||||||
RUN npm build
|
RUN npm build # Run build
|
||||||
```
|
```
|
||||||
|
|
||||||
We can examine why this isn't very efficient. If we update our `package.json`
|
This Dockerfile is rather inefficient. Updating any file causes a reinstall of
|
||||||
file, we'll install all of our dependencies and run the build from scratch, as
|
all dependencies every time you build the Docker image &emdash; even if the
|
||||||
intended. But, if we update `src/main.js`, then we'll install all of our
|
dependencies didn't change since last time!
|
||||||
dependencies again - even if nothing has changed!
|
|
||||||
|
|
||||||
We can improve this, to only install dependencies the relevant files have
|
Instead, the `COPY` command can be split in two. First, copy over the package
|
||||||
changed:
|
management files (in this case, `package.json` and `yarn.lock`). Then, install
|
||||||
|
the dependencies. Finally, copy over the project source code, which is subject
|
||||||
|
to frequent change.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM node
|
FROM node
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package.json yarn.lock .
|
COPY package.json yarn.lock . # Copy package management files
|
||||||
RUN npm install
|
RUN npm install # Install dependencies
|
||||||
COPY . .
|
COPY . . # Copy over project files
|
||||||
RUN npm build
|
RUN npm build # Run build
|
||||||
```
|
```
|
||||||
|
|
||||||
What we've done is to divide up our `COPY` command to only copy over our
|
By installing dependencies in earlier layers of the Dockerfile, there is no need
|
||||||
`package.json` and `yarn.lock` before the `npm install` - this means that we'll
|
to rebuild those layers when a project file has changed.
|
||||||
only re-run `npm install` if those files change, instead of any of the files
|
|
||||||
in our local directory!
|
|
||||||
|
|
||||||
### Keep layers small
|
### Keep layers small
|
||||||
|
|
||||||
One of the easiest things you can do to keep your images building quickly is to
|
One of the best things you can do to speed up image building is to just put less
|
||||||
just put less stuff into your build! This keeps your image layers thin and
|
stuff into your build. Fewer parts means the cache stay smaller, but also that
|
||||||
lean, which means that not only will your cache stay smaller, but there should
|
there should be fewer things that could be out-of-date and need rebuilding.
|
||||||
be fewer things that could be out-of-date and need rebuilding!
|
|
||||||
|
|
||||||
To get started, here are a few tips and tricks:
|
To get started, here are a few tips and tricks:
|
||||||
|
|
||||||
- Don't `COPY` unnecessary files into your build environment!
|
#### Don't include unnecessary files
|
||||||
|
|
||||||
Running a command like `COPY . /src` will `COPY` your entire build context
|
Be considerate of what files you add to the image.
|
||||||
into the image! If you've got logs, package manager artifacts, or even
|
|
||||||
previous build results in your current directory, those will also be copied
|
|
||||||
over, which will make your image larger than it needs to be (especially as
|
|
||||||
those files are usually not helpful)!
|
|
||||||
|
|
||||||
You can avoid copying these files over by `COPY`ing only the files and
|
|
||||||
directories that you want, for example, you might only just want a `Makefile`
|
|
||||||
and your `src` directory - if that's all you need, then you can split up your
|
|
||||||
`COPY` into `COPY ./Makefile /src` and `COPY ./src /src`. If you do want the
|
|
||||||
entire current directory, but want to ignore the unnecessary files in it, you
|
|
||||||
can setup your [`.dockerignore` file](https://docs.docker.com/engine/reference/builder/#dockerignore-file),
|
|
||||||
to make sure that those files won't be copied over!
|
|
||||||
|
|
||||||
- Use your package manager wisely!
|
Running a command like `COPY . /src` will `COPY` your entire build context into
|
||||||
|
the image. If you've got logs, package manager artifacts, or even previous build
|
||||||
|
results in your current directory, those will also be copied over. This could
|
||||||
|
make your image larger than it needs to be, especially as those files are
|
||||||
|
usually not useful.
|
||||||
|
|
||||||
No matter what operating system or programming language you choose to use as
|
Avoid adding unnecessary files to your builds by explicitly stating the files or
|
||||||
your build's base image, most docker images have some sort of package manager
|
directories you intend to copy over. For example, you might only want to add a
|
||||||
to help install software into your image. For example, `debian` has `apt`,
|
`Makefile` and your `src` directory to the image filesystem. In that case,
|
||||||
`alpine` has `apk`, `python` has `pip`, `node` has `npm`, etc, etc.
|
consider adding this to your Dockerfile:
|
||||||
|
|
||||||
When installing packages be careful! Make sure to only install the packages
|
```dockerfile
|
||||||
that you need - if you're not going to use them, don't install them. Remember
|
COPY ./src ./Makefile /src
|
||||||
that this might be a different list for your local development environment
|
```
|
||||||
and your production environment. You can use multi-stage builds (which we'll
|
|
||||||
cover later) to split these up efficiently.
|
|
||||||
|
|
||||||
- Try using the `RUN` command dedicated cache!
|
As opposed to this:
|
||||||
|
|
||||||
The `RUN` command supports a specialized cache, which can be used when you
|
```dockerfile
|
||||||
need a more fine-grained cache between runs. For example, when installing
|
COPY . /src
|
||||||
packages, you don't always need to fetch all of your packages from the
|
```
|
||||||
internet each time, you only need the ones that have changed!
|
|
||||||
|
|
||||||
To solve this problem, you can use `RUN --mount type=cache`. For example, for
|
You can also create a
|
||||||
your `debian`-based image you might use the following:
|
[`.dockerignore` file](https://docs.docker.com/engine/reference/builder/#dockerignore-file),
|
||||||
|
and use that to specify which files and directories to exclude from the build
|
||||||
|
context.
|
||||||
|
|
||||||
```dockerfile
|
#### Use your package manager wisely
|
||||||
RUN \
|
|
||||||
--mount=type=cache,target=/var/cache/apt \
|
|
||||||
apt-get update && apt-get install -y git
|
|
||||||
```
|
|
||||||
|
|
||||||
The use of the explicit cache with the `--mount` flag keeps the contents of
|
Most Docker image builds involve using a package manager to help install
|
||||||
the `target` directory preserved between builds - so when this layer needs to
|
software into the image. Debian has `apt`, Alpine has `apk`, Python has `pip`,
|
||||||
be rebuilt, then it'll be able to use `apt`'s own cache in `/var/cache/apt`.
|
NodeJS has `npm`, and so on.
|
||||||
|
|
||||||
|
When installing packages, be considerate. Make sure to only install the packages
|
||||||
|
that you need. If you're not going to use them, don't install them. Remember
|
||||||
|
that this might be a different list for your local development environment and
|
||||||
|
your production environment. You can use multi-stage builds to split these up
|
||||||
|
efficiently.
|
||||||
|
|
||||||
|
#### Use the dedicated `RUN` cache
|
||||||
|
|
||||||
|
The `RUN` command supports a specialized cache, which you can use when you need
|
||||||
|
a more fine-grained cache between runs. For example, when installing packages,
|
||||||
|
you don't always need to fetch all of your packages from the internet each time.
|
||||||
|
You only need the ones that have changed.
|
||||||
|
|
||||||
|
To solve this problem, you can use `RUN --mount type=cache`. For example, for
|
||||||
|
your Debian-based image you might use the following:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
RUN \
|
||||||
|
--mount=type=cache,target=/var/cache/apt \
|
||||||
|
apt-get update && apt-get install -y git
|
||||||
|
```
|
||||||
|
|
||||||
|
Using the explicit cache with the `--mount` flag keeps the contents of the
|
||||||
|
`target` directory preserved between builds. When this layer needs to be
|
||||||
|
rebuilt, then it'll use the `apt` cache in `/var/cache/apt`.
|
||||||
|
|
||||||
### Minimize the number of layers
|
### Minimize the number of layers
|
||||||
|
|
||||||
Keeping your layers small is a good step to getting quick builds - the logical
|
Keeping your layers small is a good first step, and the logical next step is to
|
||||||
next step is to reduce the number of layers that you have! Fewer layers mean
|
reduce the number of layers that you have. Fewer layers mean that you have less
|
||||||
that you have less to rebuild, when something in your Dockerfile changes, so
|
to rebuild, when something in your Dockerfile changes, so your build will
|
||||||
your build will complete faster!
|
complete faster.
|
||||||
|
|
||||||
Here are some more tips you can use:
|
The following sections outline some tips you can use to keep the number of
|
||||||
|
layers to a minimum.
|
||||||
|
|
||||||
- Use an appropriate base image!
|
#### Use an appropriate base image
|
||||||
|
|
||||||
Docker provides over 170 pre-built [official images](https://hub.docker.com/search?q=&image_filter=official)
|
Docker provides over 170 pre-built
|
||||||
for almost every common development scenario! For example, if you're building
|
[official images](https://hub.docker.com/search?q=&image_filter=official) for
|
||||||
a Java web server, then while you could install `java` into any image you
|
almost every common development scenario. For example, if you're building a Java
|
||||||
like, it's much quicker (and easier to manage updates) if you use a dedicated
|
web server, use a dedicated image such as
|
||||||
image, for example, [`openjdk`](https://hub.docker.com/_/openjdk/). Even if
|
[`openjdk`](https://hub.docker.com/_/openjdk/). Even when there's not an
|
||||||
there's not an official image for what you might want, Docker provides images
|
official image for what you might want, Docker provides images from
|
||||||
from [verified publishers](https://hub.docker.com/search?q=&image_filter=store)
|
[verified publishers](https://hub.docker.com/search?q=&image_filter=store) and
|
||||||
and [open source partners](https://hub.docker.com/search?q=&image_filter=open_source)
|
[open source partners](https://hub.docker.com/search?q=&image_filter=open_source)
|
||||||
that can help you on your way, and the community often produces third-party
|
that can help you on your way. The Docker community often produces third-party
|
||||||
images to use as well.
|
images to use as well.
|
||||||
|
|
||||||
These pre-built stop you from needing to manually install and manage the
|
|
||||||
software, which allows you to save valuable build time as well as disk space.
|
|
||||||
|
|
||||||
- Use multi-stage builds to run builds in parallel!
|
Using official images saves you time and ensures you stay up to date and secure
|
||||||
|
by default.
|
||||||
|
|
||||||
<!-- x-link to multi-stage builds once we have some reworked content for that -->
|
#### Use multi-stage builds
|
||||||
|
|
||||||
Multi-stage builds let you split up your Dockerfile into multiple distinct
|
<!-- x-link to multi-stage builds once we have some reworked content for that -->
|
||||||
stages, and then provide the tools to combine them all back together again.
|
|
||||||
The docker builder will work out dependencies between the stages and run them
|
|
||||||
using the most efficient strategy, even allowing you to run multiple commands at the
|
|
||||||
same time in this way!
|
|
||||||
|
|
||||||
To use a multi-stage build, you can simply use multiple `FROM` commands. For
|
|
||||||
example, suppose you want to build a simple web server that serves HTML from
|
|
||||||
your `docs` directory in Git:
|
|
||||||
|
|
||||||
```dockerfile
|
|
||||||
FROM alpine as git
|
|
||||||
RUN apk add git
|
|
||||||
|
|
||||||
FROM git as fetch
|
|
||||||
WORKDIR /repo
|
|
||||||
RUN git clone https://github.com/your/repository.git .
|
|
||||||
|
|
||||||
FROM nginx as site
|
|
||||||
COPY --from=fetch /repo/docs/ /usr/share/nginx/html
|
|
||||||
```
|
|
||||||
|
|
||||||
This build has 3 stages - `git`, `fetch` and `site`. In this example, we've
|
|
||||||
used `git` as the base for the `fetch` stage, and also used `COPY`'s `--from`
|
|
||||||
flag to copy the data from the `docs/` directory into the NGINX server
|
|
||||||
directory.
|
|
||||||
|
|
||||||
Each stage has only a few instructions, and when possible, docker will run
|
|
||||||
these stages in parallel. Additionally, only the final instructions in the
|
|
||||||
`site` stage will end up as layers in our image, so we won't have our entire
|
|
||||||
`git` history embedded into the final result, which helps keep our images
|
|
||||||
small and secure.
|
|
||||||
|
|
||||||
- Combine your commands together wherever possible!
|
Multi-stage builds let you split up your Dockerfile into multiple distinct
|
||||||
|
stages. Each stage completes a step in the build process, and you can bridge the
|
||||||
|
different stages to create your final image at the end. The Docker builder will
|
||||||
|
work out dependencies between the stages and run them using the most efficient
|
||||||
|
strategy. This even allows you to run multiple builds concurrently.
|
||||||
|
|
||||||
Most commands in your Dockerfile support being joined together, so that they
|
Multi-stage builds use two or more `FROM` commands. The following example
|
||||||
can do multiple things all at once! For example, it's fairly common to see
|
illustrates building a simple web server that serves HTML from your `docs`
|
||||||
`RUN` commands being used like this:
|
directory in Git:
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
RUN echo "the first command"
|
# stage 1
|
||||||
RUN echo "the second command"
|
FROM alpine as git
|
||||||
```
|
RUN apk add git
|
||||||
|
|
||||||
But actually, we can run both of these commands inside a single `RUN`, which
|
# stage 2
|
||||||
means that they will share the same cache! We can do this by using the `&&`
|
FROM git as fetch
|
||||||
shell operator to run one command after another:
|
WORKDIR /repo
|
||||||
|
RUN git clone https://github.com/your/repository.git .
|
||||||
|
|
||||||
```dockerfile
|
# stage 3
|
||||||
RUN echo "the first command" && echo "the second command"
|
FROM nginx as site
|
||||||
# or to split to multiple lines
|
COPY --from=fetch /repo/docs/ /usr/share/nginx/html
|
||||||
RUN echo "the first command" && \
|
```
|
||||||
echo "the second command"
|
|
||||||
```
|
|
||||||
|
|
||||||
We can also use [heredocs]() to simplify complex multiline scripts (note the
|
This build has 3 stages: `git`, `fetch` and `site`. In this example, `git` is
|
||||||
`set -e` command to exit immediately after any command fails, instead of
|
the base for the `fetch` stage. It uses the `COPY --from` flag to copy the data
|
||||||
continuing):
|
from the `docs/` directory into the Nginx server directory.
|
||||||
|
|
||||||
```dockerfile
|
Each stage has only a few instructions, and when possible, Docker will run these
|
||||||
RUN <<EOF
|
stages in parallel. Only the instructions in the `site` stage will end up as
|
||||||
set -e
|
layers in the final image. The entire `git` history doesn't get embedded into
|
||||||
echo "the first command"
|
the final result, which helps keep the image small and secure.
|
||||||
echo "the second command"
|
|
||||||
EOF
|
#### Combine commands together wherever possible.
|
||||||
```
|
|
||||||
|
Most Dockerfile commands, and `RUN` commands in particular, can often be joined
|
||||||
|
together. For example, instead of using `RUN` like this:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
RUN echo "the first command"
|
||||||
|
RUN echo "the second command"
|
||||||
|
```
|
||||||
|
|
||||||
|
It's possible to run both of these commands inside a single `RUN`, which means
|
||||||
|
that they will share the same cache! This can is achievable using the `&&` shell
|
||||||
|
operator to run one command after another:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
RUN echo "the first command" && echo "the second command"
|
||||||
|
# or to split to multiple lines
|
||||||
|
RUN echo "the first command" && \
|
||||||
|
echo "the second command"
|
||||||
|
```
|
||||||
|
|
||||||
|
Another shell feature that allows you to simplify and concatenate commands in a
|
||||||
|
neat way are [`heredocs`](https://en.wikipedia.org/wiki/Here_document){:
|
||||||
|
target="blank" rel="noopener" class="\_"}. It enables you to create multi-line
|
||||||
|
scripts with good readability:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
RUN <<EOF
|
||||||
|
set -e
|
||||||
|
echo "the first command"
|
||||||
|
echo "the second command"
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
(Note the `set -e` command to exit immediately after any command fails, instead
|
||||||
|
of continuing.)
|
||||||
|
|
||||||
## Other resources
|
## Other resources
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ digraph {
|
||||||
|
|
||||||
from [ label = <<B>FROM </B>ubuntu:latest> ];
|
from [ label = <<B>FROM </B>ubuntu:latest> ];
|
||||||
deps [ label = <<B>RUN </B>apt-get update && \\<br/>apt-get install -y build-essentials> ];
|
deps [ label = <<B>RUN </B>apt-get update && \\<br/>apt-get install -y build-essentials> ];
|
||||||
copy [ label = <<B>COPY </B>. /src/>, color = "red" ];
|
copy [ label = <<B>COPY </B>main.c /src/>, color = "red" ];
|
||||||
workdir [ label = <<B>WORKDIR </B>/src/> ];
|
workdir [ label = <<B>WORKDIR </B>/src/> ];
|
||||||
build [ label = <<B>RUN </B>make build> ];
|
build [ label = <<B>RUN </B>make build> ];
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
<!-- Generated by graphviz version 5.0.0 (0)
|
<!-- Generated by graphviz version 6.0.1 (20220911.1526)
|
||||||
-->
|
-->
|
||||||
<!-- Pages: 1 -->
|
<!-- Pages: 1 -->
|
||||||
<svg width="368pt" height="256pt"
|
<svg width="368pt" height="256pt"
|
||||||
viewBox="0.00 0.00 368.00 256.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
viewBox="0.00 0.00 368.00 256.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 252)">
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 252)">
|
||||||
<polygon fill="transparent" stroke="transparent" points="-4,4 -4,-252 364,-252 364,4 -4,4"/>
|
<polygon fill="none" stroke="none" points="-4,4 -4,-252 364,-252 364,4 -4,4"/>
|
||||||
<!-- from -->
|
<!-- from -->
|
||||||
<g id="node1" class="node">
|
<g id="node1" class="node">
|
||||||
<title>from</title>
|
<title>from</title>
|
||||||
|
@ -33,8 +33,8 @@
|
||||||
<g id="node3" class="node">
|
<g id="node3" class="node">
|
||||||
<title>copy</title>
|
<title>copy</title>
|
||||||
<polygon fill="none" stroke="red" points="360,-146 0,-146 0,-117 360,-117 360,-146"/>
|
<polygon fill="none" stroke="red" points="360,-146 0,-146 0,-117 360,-117 360,-146"/>
|
||||||
<text text-anchor="start" x="143" y="-130" font-family="monospace" font-weight="bold" font-size="10.00">COPY </text>
|
<text text-anchor="start" x="128" y="-130" font-family="monospace" font-weight="bold" font-size="10.00">COPY </text>
|
||||||
<text text-anchor="start" x="174" y="-130" font-family="monospace" font-size="10.00">. /src/</text>
|
<text text-anchor="start" x="159" y="-130" font-family="monospace" font-size="10.00">main.c /src/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- deps->copy -->
|
<!-- deps->copy -->
|
||||||
<g id="edge2" class="edge">
|
<g id="edge2" class="edge">
|
||||||
|
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
@ -8,7 +8,7 @@ digraph {
|
||||||
|
|
||||||
from [ label = <<B>FROM </B>ubuntu:latest> ];
|
from [ label = <<B>FROM </B>ubuntu:latest> ];
|
||||||
deps [ label = <<B>RUN </B>apt-get update && \\<br/>apt-get install -y build-essentials> ];
|
deps [ label = <<B>RUN </B>apt-get update && \\<br/>apt-get install -y build-essentials> ];
|
||||||
copy [ label = <<B>COPY </B>. /src/>, color = "red" ];
|
copy [ label = <<B>COPY </B>main.c /src/>, color = "red" ];
|
||||||
workdir [ label = <<B>WORKDIR </B>/src/>, color = "red" ];
|
workdir [ label = <<B>WORKDIR </B>/src/>, color = "red" ];
|
||||||
build [ label = <<B>RUN </B>make build>, color = "red" ];
|
build [ label = <<B>RUN </B>make build>, color = "red" ];
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
<!-- Generated by graphviz version 5.0.0 (0)
|
<!-- Generated by graphviz version 6.0.1 (20220911.1526)
|
||||||
-->
|
-->
|
||||||
<!-- Pages: 1 -->
|
<!-- Pages: 1 -->
|
||||||
<svg width="368pt" height="271pt"
|
<svg width="368pt" height="271pt"
|
||||||
viewBox="0.00 0.00 368.00 271.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
viewBox="0.00 0.00 368.00 271.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 267)">
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 267)">
|
||||||
<polygon fill="transparent" stroke="transparent" points="-4,4 -4,-267 364,-267 364,4 -4,4"/>
|
<polygon fill="none" stroke="none" points="-4,4 -4,-267 364,-267 364,4 -4,4"/>
|
||||||
<!-- from -->
|
<!-- from -->
|
||||||
<g id="node1" class="node">
|
<g id="node1" class="node">
|
||||||
<title>from</title>
|
<title>from</title>
|
||||||
|
@ -33,8 +33,8 @@
|
||||||
<g id="node3" class="node">
|
<g id="node3" class="node">
|
||||||
<title>copy</title>
|
<title>copy</title>
|
||||||
<polygon fill="none" stroke="red" points="360,-161 0,-161 0,-132 360,-132 360,-161"/>
|
<polygon fill="none" stroke="red" points="360,-161 0,-161 0,-132 360,-132 360,-161"/>
|
||||||
<text text-anchor="start" x="143" y="-145" font-family="monospace" font-weight="bold" font-size="10.00">COPY </text>
|
<text text-anchor="start" x="128" y="-145" font-family="monospace" font-weight="bold" font-size="10.00">COPY </text>
|
||||||
<text text-anchor="start" x="174" y="-145" font-family="monospace" font-size="10.00">. /src/</text>
|
<text text-anchor="start" x="159" y="-145" font-family="monospace" font-size="10.00">main.c /src/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- deps->copy -->
|
<!-- deps->copy -->
|
||||||
<g id="edge2" class="edge">
|
<g id="edge2" class="edge">
|
||||||
|
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
@ -8,7 +8,7 @@ digraph {
|
||||||
|
|
||||||
from [ label = <<B>FROM </B>ubuntu:latest> ];
|
from [ label = <<B>FROM </B>ubuntu:latest> ];
|
||||||
deps [ label = <<B>RUN </B>apt-get update && \\<br/>apt-get install -y build-essentials> ];
|
deps [ label = <<B>RUN </B>apt-get update && \\<br/>apt-get install -y build-essentials> ];
|
||||||
copy [ label = <<B>COPY </B>. /src/> ];
|
copy [ label = <<B>COPY </B>main.c /src/> ];
|
||||||
workdir [ label = <<B>WORKDIR </B>/src/> ];
|
workdir [ label = <<B>WORKDIR </B>/src/> ];
|
||||||
build [ label = <<B>RUN </B>make build> ];
|
build [ label = <<B>RUN </B>make build> ];
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
<!-- Generated by graphviz version 5.0.0 (0)
|
<!-- Generated by graphviz version 6.0.1 (20220911.1526)
|
||||||
-->
|
-->
|
||||||
<!-- Pages: 1 -->
|
<!-- Pages: 1 -->
|
||||||
<svg width="368pt" height="241pt"
|
<svg width="368pt" height="241pt"
|
||||||
viewBox="0.00 0.00 368.00 241.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
viewBox="0.00 0.00 368.00 241.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 237)">
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 237)">
|
||||||
<polygon fill="transparent" stroke="transparent" points="-4,4 -4,-237 364,-237 364,4 -4,4"/>
|
<polygon fill="none" stroke="none" points="-4,4 -4,-237 364,-237 364,4 -4,4"/>
|
||||||
<!-- from -->
|
<!-- from -->
|
||||||
<g id="node1" class="node">
|
<g id="node1" class="node">
|
||||||
<title>from</title>
|
<title>from</title>
|
||||||
|
@ -33,8 +33,8 @@
|
||||||
<g id="node3" class="node">
|
<g id="node3" class="node">
|
||||||
<title>copy</title>
|
<title>copy</title>
|
||||||
<polygon fill="none" stroke="black" points="360,-131 0,-131 0,-102 360,-102 360,-131"/>
|
<polygon fill="none" stroke="black" points="360,-131 0,-131 0,-102 360,-102 360,-131"/>
|
||||||
<text text-anchor="start" x="143" y="-115" font-family="monospace" font-weight="bold" font-size="10.00">COPY </text>
|
<text text-anchor="start" x="128" y="-115" font-family="monospace" font-weight="bold" font-size="10.00">COPY </text>
|
||||||
<text text-anchor="start" x="174" y="-115" font-family="monospace" font-size="10.00">. /src/</text>
|
<text text-anchor="start" x="159" y="-115" font-family="monospace" font-size="10.00">main.c /src/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- deps->copy -->
|
<!-- deps->copy -->
|
||||||
<g id="edge2" class="edge">
|
<g id="edge2" class="edge">
|
||||||
|
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Loading…
Reference in New Issue