This is the third day of my participation in the August More Text Challenge

Docker company put forward the idea of image layering in the development of container technology. It can be said that this revolutionary idea made the container, which was originally just the integration of Linux kernel features, start to grow wild.

Docker merges layers of images through UnionFS federated file system. Students who are interested in knowledge about images can refer to OverlayFS, the federated file system based on Docker container technology, in our previous article

This article is the docker official document Dockerfile reference learning and practice, in learning docker container related technology students do not light collection, you have to move! Practice!

Note: No one knows Docker better than Docker company. This essay contains some of my own understanding. If you have the habit of reading English, please read the official document directly.


docker build

Dockerfile is a set of image build command text file, the following is our most common Dockerfile build, if we have a file Dockerfile directory

[root@localhost nginx_project]# ls
Dockerfile
[root@localhost nginx_project]# docker build -t nginx:v1 .
Copy the code

Build specifies the tag of the target image as nginx:v1 and the context of the Dockerfile.

What is a Docker context?

A service-oriented directory folder structure, in which all of your build resources (except for dockerfiles) should be located (specified context).

Context is handled recursively. Therefore, if it is PATH it contains any subdirectories, and if it is a URL it contains the repository and its submodules.

The key point is that the build is run by the Docker daemon, not the CLI, so Docker packages the context resources and transmits them to the daemon for the build. To reduce unnecessary bloat, it is best to start with an empty directory as the context and save the Dockerfile in that directory. Add only the files needed to build the Dockerfile.

We can specify a dockerfile using the -f option

[root@localhost folder]# docker build -f .. /Dockerfile -t nginx:v1 .Copy the code

Use multiple -t options to hold multiple tags

[root@localhost folder]# docker build -t nginx:v1 -t dockerhub.com/nginx:v2 . Sending build context to Docker daemon Step 2: FROM nginx --> nginx Step 2: run echo 123 ---> Using cache ---> 3b636c79fbfa Successfully built 3b636c79fbfa Successfully tagged nginx:v1 Successfully tagged dockerhub.com/nginx:v2Copy the code

This builds mirror images of the same ID for two different tags

[root@localhost folder]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
dockerhub.com/nginx   v2        3b636c79fbfa   23 minutes ago   133MB
nginx                 v1        3b636c79fbfa   23 minutes ago   133MB
Copy the code

BuildKit

Buildkit turns DockerFiles into Docker images. It doesn’t just build Docker images; It can build OCI images and several other output formats.

As of version 18.09, Docker supports a new back end for performing builds provided by the Moby/BuildKit project. The BuildKit back end offers many benefits over older implementations. For example, BuildKit can:

  • Detect and skip the execution of unused build phases.
  • Build separate build phases in parallel.
  • Only the change files in the transfer build context are added during the different build processes.
  • Detects and skips transfer of unused files in the build context.
  • Many new features are implemented using external Dockerfiles.
  • Avoid side effects with other parts of the API (intermediate images and containers).
  • Prioritize your build cache for automatic pruning.

To use the BuildKit backend, simply set the environment variable DOCKER_BUILDKIT=1 on the CLI before calling docker build =1. Or enable /etc/docker-daemon. json.

[root@localhost folder]# DOCKER_BUILDKIT=1 docker build -f .. /Dockerfile -t nginx:v1 -t dockerhub.com/nginx:v2. [+] Building 5.2s (6/6) FINISHED => [internal] Load build definition From Dockerfile 0.7s => => dokerfile: 118B 0.9s => [internal] loading. Dockerignore 0.9s => => transferring-window context: 2 b 0.0 s = > (internal) load metadata for docker. IO/library/nginx: latest 0.0 s = > [1/2] FROM docker. IO/library/nginx 2.2 s => [2/2] RUN echo 123 1.3s => exporting to image 0.1s => => exporting layers 0.2s => => Writing Image Sha256:813 b09c58322dce98ee28e717baeb9f3593ce3e46a032488949250f761004495 0.0 s = > = > naming to docker. IO/library/nginx: v1 0.0s => => Naming to dockerhub.com/nginx:v2Copy the code

Dockerfile format

1, comments,

For a standard Dockerfile, comments are required.

CMD args, CMD args, CMD args...Copy the code

The first directive in a Dockerfile must be the FROM directive, which specifies the base image. Where does the base image’s parent come FROM? The answer is scratch and the Dockerfile with the FROM Scratch instruction creates a base image.

2. Parser instructions

Parser instructions are optional and affect how subsequent lines in aDockerfile are processed. Parser directives do not add layers to the build, nor do they appear as build steps, and a single directive can only be used once.

Dockerfile currently supports the following two parser directives:

  • syntax
  • escape
2.1 syntax

This feature is only available with the BuildKit back end and is ignored when using the classic builder back end.

We can specify the dockerfile syntax parser at the beginning of the dockerfile file as follows:

# syntax=docker/dockerfile:1
# syntax=docker.io/docker/dockerfile:1
# syntax=example.com/user/repo:tag@sha256:abcdef...
Copy the code

Custom Dockerfile syntax parser can be implemented as follows:

  • Automatically fixes errors without updating the Docker daemon
  • Make sure all users use the same parser to build your Dockerfile
  • You don’t need to update the Docker daemon to use the latest features
  • Try out new or third-party features before integrating them into the Docker daemon
  • Use alternative build definitions, or create your own

Official Dockerfile parser:

  • docker/dockerfile:1Constantly updated with the latest1.x.xsecondaryandThe patch version
  • Docker/dockerfile: 1.2Keep up to dateX 1.2.Patch version, once version1.3.0Publish and stop receiving updates.
  • Docker/dockerfile: 1.2.1Immutable: never updates version 1.2

For example, if we use the latest patch version 1.2, our Dockerfile is as follows:

#syntax=docker/dockerfile:1.2
FROM busybox
run echo 123
Copy the code

We enable the BuildKit build

[+] Building 5.8s (8/8) FINISHED => [internal] Build definition From Dockerfile 0.1s => => dokerfile: Dockerignore 0.4s => => transferring context: 2 b 0.0 s = > resolve image config for docker. IO/docker/dockerfile: 1.2 2.6 s = > CACHED Docker - image: / / docker. IO/docker/dockerfile: @ sha256 1.2:0.0 s = > e2a8561e419ab1ba6b2fe6cbdf49fd92b95 internal load The metadata for docker. IO/library/busybox: latest 0.0 s = > [1/2] FROM docker. IO/library/busybox 0.3 s = > [2/2] RUN echo 123 1.1s => exporting to image 0.1s => => exporting layers 0.1s => => Writing image Sha256: bd66a3db9598d942b68450a7ac08117830b4d66b68180b6e9d63599d01bc8a04 0.0 s = > = > naming the to docker.io/library/busybox:v1Copy the code
2.2 the escape

Define a newline concatenation escape for a dockerfile through escape

# escape=\   
Copy the code

This is useful if you want to build a window image, so let’s look at dockerFile

FROM microsoft/nanoserver
COPY testfile.txt c:\
RUN dir c:\
Copy the code

Since the default escape character is’ ‘, the second step in the build would be COPY testfile.txt c:\RUN dir c: obviously not what we expected.

Let’s replace the escape character with a ‘sign

# escape=`
​
FROM microsoft/nanoserver
COPY testfile.txt c:\ `
RUN dir c:\
Copy the code
Bash-like environment variables
FROM busybox
ENV FOO=/bar
WORKDIR ${FOO}   # WORKDIR /bar
ADD . $FOO       # ADD . /bar
COPY $FOO /quux # COPY $FOO /quux
Copy the code

The ${variable_name} syntax also supports some of the standard qualifiers specified by bash:

  • ${variable:-word}Said ifvariableThe variable is set (exists) and the result will be that value. ifvariableIs not set,wordWill be the result.
  • ${variable:+word}Said ifvariableIs set towordResult, otherwise empty string.
4. .dockerignore

Dockerignore Files or directories sent by the CLI to the docker daemon. Here is a.dockerignore file

#.dockerinGRE can have comments *.md! README.md temp? */temp* */*/temp*Copy the code
The rules behavior
*/temp* Exclude names bytempFiles and directories that begin with any direct subdirectory of the root directory. For example, pure files/somedir/temporary.txtExcluded, catalog/somedir/temp.
*/*/temp* To rule outtempFiles and directories starting from any subdirectory two levels below the root directory. For example,/somedir/subdir/temporary.txtLeft out.
temp? Exclude files and directories named with a one-character extension in the root directorytemp. For example,/tempaand/tempbLeft out.
! Do not exclude to file

Dockerfile command

1.FROM

Specifies the base image. The general format is as follows, [] parentheses can be omitted:

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
Copy the code

Of particular note is that FROM can appear multiple times in a dockerfile to enable a multi-phase build. And can interact with ARG parameters. As follows:

ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-app
​
FROM extras:${CODE_VERSION}
CMD  /code/run-extras
Copy the code

We loaded two different versions of the base images specified by the ARG parameter.

2.RUN

Two forms of RUN

  • RUN Preferred, (the command is RUN in the shell, that is, /bin/sh-c by default)
  • RUN [“exec”,param1,param2]

The RUN command is mainly executed during image construction to form a new layer. For example, we often see software installed during image building.

RUN yum install -y gcc 
Copy the code

When we do not want to use the default shell, we can use exec form implementation

RUN ["/bin/bash","-c","yum install -y gcc"]
Copy the code

Of course, the exec form can be done without the shell

RUN ["yum","install","-y","gcc"]
Copy the code

The EXEC form is parsed to a JSON array, so double quotes must be used

3.CMD

CMD directives come in three forms:

  • CMD ["executable","param1","param2"](execForm, this is the preferred form)
  • CMD ["param1","param2"](asDefault parameters for ENTRYPOINT)
  • CMD command param1 param2(Shell form)

In a dockerfile, only one CMD should be written, if there are more than one, only the last one will take effect. CMD is often used to provide default values for ENTRYPOINT when actually writing dockerfie, which we’ll cover later.

In contrast to RUN, CMD does nothing at build time and is mainly used to specify the startup commands for the image. The CMD start command can be replaced by the docker run argument.

We add the following CMD command to the dockerfile

CMD echo hello
Copy the code

After building the image, docker run starts the container without adding parameters

[root@localhost dockerfiles]# docker run centos:v1
hello
Copy the code

When we add parameters to docker run

[root@localhost dockerfiles]# docker run centos_env:v1 echo container
container 
Copy the code

The CMD echo hello command has been replaced by the docker run parameter echo container.

4. LABEL

Label Is used to add metadata of a mirror in the key-value format.

LABEL <key>=<value>
Copy the code

For example, we add the following LABEL

IO "LABEL "version"="v1.2" LABEL "author"="waterman&&iqsing"Copy the code

To prevent the creation of three layers, it is best to write through a tag.

IO "\ "version"="v1.2" \ "author"="waterman&&iqsing"Copy the code

We check the image label information through Docker inspect

#docker inspect centos_labels:v1 "Labels": { "author": "waterman&&iqsing", "miantainer": "iqsing.github.io", "org.label-schema.build-date": "20201204", "org.label-schema.license": "GPLv2", "org.label-schema.name": "CentOS Base Image", "org.label-schema.schema-version": "1.0", "org. Label - schema. Vendor" : "CentOS", "version" : "v1.2}"Copy the code
5.EXPOSE
EXPOSE 80/tcp
EXPOSE 161/udp
Copy the code

Note that EXPOSE simply tells the dockerfile reader which ports we’re building to EXPOSE, just a piece of information. In the container, you still need to expose the port with the -p option.

6.ENV
ENV <key>=<value> ... ENV <key> <value>Copy the code

ENV specifies the environment variable that will be applied to the environment of all subsequent directives during the build phase.

ENV username="iqsing"
Copy the code

So when we start the container, we can see that the container information has the ENV environment variable attached

"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"username=iqsing"
],
Copy the code

Of course, we can also add environment variables when we start the container

docker run --env <key>=<value>
Copy the code

In addition, if you only need to use environment variables during image build, it is better to use ARG parameters

7.ADD && COPY

The format of ADD is similar to that of COPY, which has two forms. Paths containing Spaces require the latter form:

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
​
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
Copy the code

On the Linux platform, you can set the user and group to which a file or file is added to a remote directory.


means to copy a new file, directory, or remote file URL. Each

can contain a wildcard, as follows:

ADD hom* /mydir/ ADD hom? .txt /mydir/Copy the code

Generally, ADD and COPY comply with the following rules:

  • <src>The path must be internalcontextThe building; You can’tCOPY .. /something /somethingBecause thedocker buildIs to send the context directory (and subdirectories) to the Docker daemon.
  • if<src>If yes, all contents of the directory, including file system metadata, are copied.
  • if<src>Is any other type of file, it is copied separately with its metadata. In this case, if<dest>End with a slash/It will be treated as a directory of its contents<src>Will be written to<dest>/base(<src>).
  • if<src>If multiple resources are specified directly, or because wildcards are used<dest>It must be a directory and must end with a slash/.
  • if<dest>If it does not end with a slash, it is treated as a regular file and its contents are passed<src>write<dest>.
  • if<dest>If not, all missing directories are created in their path.

In particular, if it is a tar package that can be recognized, such as gzip and bzip2, the package will be added to the image first and then automatically decompressed. This is arguably the biggest difference with the COPY command in use.

8.ENTRYPOINT

Exec preference and shell form:

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
Copy the code

ENTRYPOINT is similar to CMD in that it specifies the start command, except that the command specified by ENTRYPOINT cannot be replaced by the docker run parameter.

We add ENTRYPOINT to the Dockerfile

ENTRYPOINT echo hello container
Copy the code

Build the image and start the container, and you can see that the parameters in Docker Run do not replace ENTRYPOINT

[root@localhost dockerfiles]# docker run centos_entrtpoint:v1 echo hello docker
hello container
Copy the code

Another nice aspect of this directive is that it can interact with CMD directives. Let the container run as an application or service.

Classic operation: ENTRYPOINT + CMD = default container command parameter

ENTRYPOINT is a very important instruction in Dockerfile, so it is necessary to write another essay to learn more about it.

9.VOLUME
VOLUME ["/data"]
Copy the code

The volume command can be used to create a storage volume. Let’s look at an example:

FROM centos
RUN mkdir /volume
RUN echo "hello world" > /volume/greeting
VOLUME /volume
Copy the code

After building the image, create a container

[root@localhost dockerfiles]# docker create   --name centos_volume  centos_volue:v1
[root@localhost dockerfiles]# docker inspect centos_volume 
​
 "Mounts": [
            {
                "Type": "volume",
                "Name": "494cdb193984680045c36a16bbc2b759cf568b55c7e9b0852ccf6dff8bf79c46",
                "Source": "/var/lib/docker/volumes/494cdb193984680045c36a16bbc2b759cf568b55c7e9b0852ccf6dff8bf79c46/_data",
                "Destination": "/volume",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
​
Copy the code

You can use the “VOLUME” command to create a VOLUME. You can use the “–volumes-from” command to share the VOLUME

10.USER

Specifies the user and group to which the instruction set belongs. The default group is root. Can operate on directives following RUN, CMD, and ENTRYPOINT.

USER < USER >[:<group>] or USER <UID>[:<GID>]Copy the code
11.WORKDIR

Specifies the working directory in which the instruction set resides. If the directory does not exist, it will be created automatically. Works with RUN, CMD, ENTRYPOINT, COPY, and ADD

WORKDIR /path/to/workdir
Copy the code
12.ARG
ARG <name>[=<default value>]
Copy the code

The ARG directive defines a variable that we can pass to the builder at a Docker build using the –build-arg

=

flag.

  • ifARGThe builder uses default values when directives have default values and no values are passed at build time.
  • Multiple ARGs should be added in a multi-phase build
  • The ENV variable overrides the ARG variable
  • In contrast to ENV variables, ARG variables are mostly built and cannot reside in mirrors.
13.STOPSIGNAL

Configure the system call when the container exits

STOPSIGNAL signal
Copy the code
14.HEALTHCHECK

HEALTHCHECK directives come in two forms:

  • HEALTHCHECK [OPTIONS] CMD command(Check container health by running commands inside the container)
  • HEALTHCHECK NONE(Disable any health checks inherited from the underlying image)

OPTIONS Supports the following parameters:

  • --interval=DURATION(Default:30s)
  • --timeout=DURATION(Default:30s)
  • --start-period=DURATION(Default:0s)
  • --retries=N(Default:3)

For example, we can add the following parameters to check the Web service:

HEALTHCHECK --interval=5m --timeout=3s \
  CMD curl -f http://localhost/ || exit 1
Copy the code

Check every five minutes or so to see if the Web server can respond within three seconds. On failure, return status code 1

The exit status of the command indicates the health status of the container. Possible values are:

  • 0: successful – The container is healthy and ready to use
  • 1: Unhealthy – The container does not work properly
  • 2: reserved – Do not use this exit code

It is not easy to write a good Dockerfile. You need to consider the iteration of the image you are building, the stable operation of the service, start and stop, security and so on.

You are free to reprint, modify, publish this article, without my consent. Iqsing.github. IO


NEXT

  • Dockerfile understands ENTRYPOINT combined with CMD
  • Dockerfile multi-phase build practice
  • Dockerfile and Docker container security practices