DockerFile build process practice

Dockerfile

1 DockerFile

Build process

dockerfile is used to build docker image files! command parameter script

Build steps

  1. dockerfile
  2. docker build builds an image
  3. docker run runs the image
  4. docker push publishes an image

The official dockerhub image will correspond to the Dockerfile in a warehouse on github.

instruction

FROM 基础镜像
MAINTAINER 镜像的维护者信息
RUN Docker镜像构建的时候需要的命令
ADD 步骤:tomcat的镜像中,tomcat的压缩包
WORKDIR 镜像的工作目录
VOLUME -v挂载的目录位置
EXPOSE -p暴露端口


CMD 指定这个容器启动的时候运行的命令,只有最后一个会生效,而且可悲替代
ENTRYPOINT 指定这个容器启动的时候运行的命令,可以追加命令
ONBUILD 当构建一个被继承的DockerfileFile,就会影响ONBUILD指令。触发指令
COPY 类似ADD命令,将文件COPY到镜像中。
ENV 构建的时候设置环境变量
  1. Each reserved keyword directive is capitalized
  2. #Indicates comments
  3. Each command will create and submit a new image layer and submit

The role of DockFile

The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly.

Dockerfile is development-oriented. To publish a project and make a mirror, you need to write a dockerfile.

  • DockerFile: Build file, which defines all steps and source code
  • DockerImages: The image generated by DockerFile build, the final released and running product
  • Docker container: A container is an image that runs and provides a server

Practice: Create your own centos

99% of the images in docker hub are from FROM scratch

  1. Write the dockerfile file
➜  dockerfile git:(master) ✗ cat mydockerfile        
FROM centos
MAINTAINER yinkanglong<yinkanglong.163.com>


ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools


EXPOSE 80

CMD echo $MYPATH
CMD echo "----end----"

CMD /bin/bash
  1. docker builid run image
dockerfile git:(master) ✗ docker build -f mydockerfile -t mycentos:0.1 .
[+] Building 64.0s (8/8) FINISHED                                                                                                
 => [internal] load build definition from mydockerfile                                                                      0.2s
 => => transferring dockerfile: 265B                                                                                        0.1s
 => [internal] load .dockerignore                                                                                           0.1s
 => => transferring context: 2B                                                                                             0.0s
 => [internal] load metadata for docker.io/library/centos:7                                                                 4.5s
 => [1/4] FROM docker.io/library/centos:7@sha256:c73f515d06b0fa07bb18d8202035e739a494ce760aa73129f60f4bf2bd22b407          20.6s
 => => resolve docker.io/library/centos:7@sha256:c73f515d06b0fa07bb18d8202035e739a494ce760aa73129f60f4bf2bd22b407           0.0s
 => => sha256:c73f515d06b0fa07bb18d8202035e739a494ce760aa73129f60f4bf2bd22b407 1.20kB / 1.20kB                              0.0s
 => => sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f 529B / 529B                                  0.0s
 => => sha256:eeb6ee3f44bd0b5103bb561b4c16bcb82328cfe5809ab675bb17ab3a16c517c9 2.75kB / 2.75kB                              0.0s
 => => sha256:2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3bc 76.10MB / 76.10MB                           15.0s
 => => extracting sha256:2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3bc                                   5.3s
 => [2/4] WORKDIR /usr/local                                                                                                0.6s
 => [3/4] RUN yum -y install vim                                                                                           21.9s
 => [4/4] RUN yum -y install net-tools                                                                                      9.3s
 => exporting to image                                                                                                      6.1s 
 => => exporting layers                                                                                                     6.1s 
 => => writing image sha256:87b7be8e41c9cc237c733930df0513f40a708fb0944f5ef48e815979e6880ee2                                0.0s 
 => => naming to docker.io/library/mycentos:0.1                                                                             0.0s 
                                                                                                                                 
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them                             
  1. Test running docker run to verify that vim and ifconfig commands are feasible
dockerfile git:(master) ✗ docker run -it mycentos:0.1    
[root@f318e4ba01b3 local]# pwd
/usr/local
[root@f318e4ba01b3 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 10  bytes 876 (876.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@f318e4ba01b3 local]# vim where
[root@f318e4ba01b3 local]# which vim
/usr/bin/vim

Practice: CMD and ENTRYPOINT

  1. Write dockerfilefile
vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
  1. Build image
docker build -f dockerfile-cmd-test -t cmdtest
  1. Run image
docker run cmdtest
  1. test image
发现CMD追加命令报错,发现ENTRYPOINT命令追加的命令是可以执行的。
docker run cmtest  -l

Practice: Making a tomcat image

More complex, will be added later

2 Publish your own image

Publish your own image to dockerhub

DockeHub

  1. Create an account at https://hub.docker.com
  2. Submit your own image to the server
  3. 登录 docker login -u yinkanglong
  4. Push docker push yinkanglong/mycentos:01

Publish your own image to Alibaba Cloud

  1. Log in to Alibaba Cloud
  2. Apply for warehouse address
  3. Log in to the Alibaba Cloud warehouse
  4. docker push

Publish docker save & docker load locally

  1. Save the image into a compressed package

  2. Load compressed package as image

Summarize

The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly.

3 DockerFile command

Each instruction in the Dockerfile creates a layer.

Build image

$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM nginx
 ---> e43d811ce2f4
Step 2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 ---> Running in 9cdc27646c7b
 ---> 44aa4490ce2c
Removing intermediate container 9cdc27646c7b
Successfully built 44aa4490ce2c
  • Build directly with Git repo. Docker build also supports building from URL. For example, you can build directly from Git repo:
$ docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14
docker build https://github.com/twang2218/gitlab-ce-zh.git\#:8.14
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM gitlab/gitlab-ce:8.14.0-ce.0
8.14.0-ce.0: Pulling from gitlab/gitlab-ce
aed15891ba52: Already exists
773ae8583d14: Already exists
...
  • Build with the given tar archive
$ docker build http://server/context.tar.gz
  • Read Dockerfile from standard input to build
docker build - < Dockerfile
cat Dockerfile | docker build -
  • Read context archive from standard input to build
$ docker build - < context.tar.gz

Image build context (Context)

The docker build command has a... at the end. . represents the current directory, and Dockerfile is in the current directory, so many beginners think that this path is specifying the path where Dockerfile is located. This understanding is actually inaccurate. If you correspond to the above command format, you may find that this is specifying the context path.

First we need to understand how docker build works. Docker is divided into Docker engine (that is, server-side daemon) and client-side tools at runtime. The Docker engine provides a set of REST APIs, called Docker Remote API, and client tools such as docker commands interact with the Docker engine through this set of APIs to complete various functions.

When we build an image, not all customization will be completed through the RUN command. We often need to copy some local files into the image, such as through the COPY command, ADD command, etc. The docker build command to build the image is not actually built locally, but on the server, that is, in the Docker engine. So in this client/server architecture, how can the server obtain local files?

This introduces the concept of context. When building, the user will specify the path to build the image context. After the docker build command learns this path, it will package all the content under the path and then upload it to the Docker engine. In this way, after the Docker engine receives the context package, it will expand and obtain all the files needed to build the image.

FROM

Specify a base image
. The so-called customized image must be based on an image and customized on top of it. Just like we previously ran a container with an nginx image and then modified it, the base image must be specified. FROM specifies the base image, so FROM is a necessary instruction in a Dockerfile and must be the first instruction.

There are many high-quality official images on Docker Hub (https://hub.docker.com/explore/), and there are service-type images that can be used directly, such as nginx, redis, mongo, mysql, httpd , php, tomcat, etc.

In addition to selecting an existing image as the base image, Docker also has a special image called scratch. This image is a virtual concept and does not actually exist. It represents a blank image.

For statically compiled programs under Linux, there is no need for an operating system to provide runtime support. All required libraries are already in the executable file, so directly FROM scratch will make the image size smaller. Many applications developed using the Go language use this method to create images, which is one of the reasons why some people think that Go is a language particularly suitable for container microservice architecture.

FROM scratch
...

RUN execution command

The RUN instruction is used to execute command line commands. Due to the powerful capabilities of the command line, the RUN command is one of the most commonly used commands when customizing images. There are two formats:

  • Shell format: RUN <command>, just like a command entered directly on the command line. The RUN instruction in the Dockrfile just written is in this format.
  • exec format: RUN ["executable file", "parameter 1", "parameter 2"], this is more like the format in function calls.
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

Like a shell script, map each command to a RUN

FROM debian:jessie

RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install

The above writing method creates a 7-layer image. This is completely meaningless, and many things that are not needed for runtime are installed in the image, such as the compilation environment, updated software packages, etc. The result is a very bloated, multi-layered image, which not only increases the time for building and deploying, but is also prone to errors.
Correct way to write Dockerfile

FROM debian:jessie

RUN buildDeps='gcc libc6-dev make' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

Line breaks are also performed here for formatting purposes. Dockerfile supports the command line wrapping method of adding \ at the end of the line of the Shell class, and the comment format of # at the beginning of the line. Good formatting, such as line breaks, indentation, comments, etc., will make maintenance and troubleshooting easier, which is a good habit.

In addition, you can also see that a cleanup command is added at the end of this set of commands, which deletes the software required for compilation and build, cleans up all downloaded and expanded files, and also cleans up the apt cache file. This is a very important step. As we said before, mirroring is a multi-layered storage. Things in each layer will not be deleted on the next layer, but will always follow the mirror. Therefore, when building an image, you must ensure that only what is really needed is added to each layer, and any irrelevant things should be cleaned up.

COPY Copy files

The COPY instruction will copy the files/directories at <source path> in the build context directory to the <target path> location within the new layer of the image.

COPY package.json /usr/src/app/

ADD Advanced File Copy

The format and properties of the ADD instruction and COPY are basically the same. But some functions are added based on COPY.

  • If <source path> can be a URL, in this case, the Docker engine will try to download the linked file and put it into <target path>. File permissions after downloading are automatically set to 600
  • If <source path> is a tar compressed file, and the compression format is gzip, bzip2 and xz, the ADD command will automatically decompress the compressed file to <destination path>.
FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
...

CMD container startup command

The CMD instruction is used to specify the default startup command of the container main process.

The format of the CMD instruction is similar to that of RUN, and there are two formats:

  • shell format: CMD <command>
  • exec format: CMD ["executable file", "parameter 1", "parameter 2"...]
  • Parameter list format: CMD ["Parameter 1", "Parameter 2"...]. After specifying the ENTRYPOINT command, use CMD to specify specific parameters.

When running, you can specify a new command to replace the default command in the image settings. For example, the default CMD of the ubuntu image is /bin/bash. If we directly docker run -it ubuntu, we will directly enter bash. We can also specify other commands to run at runtime, such as docker run -it ubuntu cat /etc/os-release. This means replacing the default /bin/bash command with the cat /etc/os-release command and outputting the system version information.

ENTRYPOINT

The format of ENTRYPOINT is the same as the RUN instruction format and is divided into exec format and shell format.

The purpose of ENTRYPOINT is the same as CMD, which is to specify the container startup program and parameters. ENTRYPOINT can also be replaced at runtime, but it is slightly more cumbersome than CMD and needs to be specified through the parameter --entrypoint of docker run.

  • The CMD command cannot add parameters, but the ENTRYPOINT command can add parameters.
FROM ubuntu:16.04
RUN apt-get update \
    && apt-get install -y curl \
    && rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
$ docker run myip
当前 IP:61.148.226.66 来自:北京市 联通

$ docker run myip -i
HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Tue, 22 Nov 2016 05:12:40 GMT
Content-Type: text/html; charset=UTF-8
Vary: Accept-Encoding
X-Powered-By: PHP/5.6.24-1~dotdeb+7.1
X-Cache: MISS from cache-2
X-Cache-Lookup: MISS from cache-2:80
X-Cache: MISS from proxy-2_6
Transfer-Encoding: chunked
Via: 1.1 cache-2:80, 1.1 proxy-2_6:8006
Connection: keep-alive

当前 IP:61.148.226.66 来自:北京市 联通
  • ENTRYPOINT and CMD are combined to add additional parameters. You can write a script and then put it into ENTRYPOINT for execution, and this script will use the received parameters (ie) as a command and execute it at the end of the script.
FROM alpine:3.4
...
RUN addgroup -S redis && adduser -S -G redis redis
...
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 6379
CMD [ "redis-server" ]

ENV sets environment variables

There are two formats:

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

This command is very simple, it just sets environment variables. Whether it is other subsequent commands, such as RUN, or runtime applications, you can directly use the environment variables defined here.

ENV VERSION=1.0 DEBUG=on \
    NAME="Happy Feet"
ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
  && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
  && grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
  && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
  && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
  && ln -s /usr/local/bin/node /usr/local/bin/nodejs

ARG build parameters

格式:ARG <参数名>[=<默认值>]

Build parameters have the same effect as ENV, setting environment variables. The difference is that the environment variables of the build environment set by ARG will not exist when the container is run in the future. But don't use ARG to save information such as passwords because docker history can still see all values.

The ARG directive in the Dockerfile defines parameter names and defines their default values. This default value can be overridden with --build-arg <argument name>=<value> in the build command docker build.

VOLUME defines an anonymous volume

The format is:

VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

We have said before that when the container is running, we should try to keep the container storage layer from writing operations. For database applications that need to save dynamic data, their database files should be stored in volumes. We will further introduce Docker volumes in the following chapters. the concept of. In order to prevent users from forgetting to mount the directory where dynamic files are saved as volumes during runtime, in the Dockerfile, we can specify certain directories to be mounted as anonymous volumes in advance, so that if the user does not specify mounting at runtime, the application can work normally. Run without writing large amounts of data to the container storage layer.

VOLUME /data

The /data directory here will be automatically mounted as an anonymous volume at runtime, and any information written to /data will not be recorded in the container storage layer, thus ensuring the statelessness of the container storage layer. Of course, this mount setting can be overridden at runtime. for example:

docker run -d -v mydata:/data xxxx

In this line of command, the named volume mydata is used to mount it to the location /data, replacing the mounting configuration of the anonymous volume defined in the Dockerfile.

EXPOSE expose port

格式为 EXPOSE <端口1> [<端口2>...]。

The EXPOSE directive declares that the runtime container provides a service port. This is just a statement. The application will not open the service of this port at runtime because of this statement. Writing such a statement in the Dockerfile has two benefits. One is to help image users understand the guard port of the image service to facilitate configuration mapping; the other is to use random port mapping at runtime, that is, docker run -P, the EXPOSE port will be automatically and randomly mapped.

WORKDIR specifies the working directory

格式为 WORKDIR <工作目录路径>。

You can use the WORKDIR command to specify the working directory (or current directory). In the future, the current directory of each layer will be changed to the specified directory. If the directory does not exist, WORKDIR will help you create the directory.

As mentioned before, a common mistake made by some beginners is to write Dockerfile as a Shell script. This wrong understanding may also lead to the following errors:

RUN cd /app
RUN echo "hello" > world.txt

If you run this Dockerfile to build the image, you will find that the /app/world.txt file cannot be found, or its content is not hello. The reason is actually very simple. In Shell, two consecutive lines represent the same process execution environment, so the memory state modified by the previous command will directly affect the subsequent command; in Dockerfile, the execution environments of these two lines of RUN commands are fundamentally different. , are two completely different containers. This is a mistake caused by not understanding the concept of building hierarchical storage in Dokerfile.

USER specifies the current user

格式:USER <用户名>

The USER command is similar to WORKDIR in that it changes the environment state and affects subsequent layers. WORKDIR is to change the working directory, USER is to change the identity of the subsequent layer to execute commands such as RUN, CMD and ENTRYPOINT.

Of course, like WORKDIR, USER only helps you switch to the specified user. This user must be created in advance, otherwise you cannot switch.

RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]

If you want to change the identity of a script executed as root during execution, for example, if you want to run a service process as an already established user, do not use su or sudo. These require more troublesome configuration, and the TTY is missing. The environment often goes wrong. It is recommended to use gosu, further information can be seen from its project website: https://github.com/tianon/gosu

# 建立 redis 用户,并使用 gosu 换另一个用户执行命令
RUN groupadd -r redis && useradd -r -g redis redis
# 下载 gosu
RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" \
    && chmod +x /usr/local/bin/gosu \
    && gosu nobody true
# 设置 CMD,并以另外的用户执行
CMD [ "exec", "gosu", "redis", "redis-server" ]

Supongo que te gusta

Origin blog.csdn.net/DeepLearning_/article/details/132714237
Recomendado
Clasificación