Docker 学习笔记之使用Dockerfile创建镜像

in Linux with 0 comment

Dockerfile是一个文本的配置文件,可以使用Dockerfile来快速创建自定义的镜像

1、基本结构

Dockerfile有一行行命令语句组成,并且支持以#开头的注释行

Dockerfile主体内容分为四部分:基础镜像、维护者信息、镜像操作指令和容器启动是执行指令

FROM java:8
MAINTAINER wayne<[email protected]>
EXPOSE 80
ENTRYPOINT ["java","-jar","/root/cms/hjc_cms-1.0-SNAPSHOT.jar"]
# escape=\ (backslash)
# This dockerfile uses 七he ubuntu:xeniel image
# VERS工ON 2 - EDITION 1
# Author: docker_user
# Command format: Ins七ruction [arguments / command]
# Base image to use, this must be set as the first line
FROM ubuntu:xeniel
# Maintainer: docker user <docker user at email.com> ( @docker user )
LABEL maintainer docker user<docker [email protected]>
# Commands to update the image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ xeniel main universe">> /etc/
apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaernon off;" >> /etc/nginx/nginx.conf
# Commands when creating a new container
CMD /usr/sbin/nginx

首先可以通过注释来指定解析器的名称,后续通过注释说明镜像的相关信息。主体部分首先是要FROM指令指明所基于的镜像名称,接下来一般是使用LABEL指令说明维护者信息。后面则是镜像操作指令,例如RUN指令将对镜像执行跟随的命令,每运行一条RUN指令,镜像添加新的一层,并提交,最后CMD指令,来指定运行容器时的操作命令。

2、指令说明

Dockerfile中指令的一般格式为INSTRUCTION arguments,包括“配置指令”(配置镜像信息)和“操作指令”
image20200419005858356.png

image20200419005916348.png

2.1配置指令

1、ARG

定义创建镜像过程中使用的变量

格式为ARG [= value]

在执行docker build时,可以通过-build-arg=[=]来为变量赋值。当镜像编译成功后,ARG指定的变量将不再存在(ENV指定的变量将在镜像中保存)

Docker内置了一些镜像创建变量,用户可以直接使用而无需声明,包括(不区分大小写)http_proxy、https_proxy、ftp_proxy、no_proxy。

2、FROM

指定所创建镜像的基础镜像

格式为FROM [AS ]或者 FROM : [AS ]或者FROM @ [AS ]

任何Dockerfile中第一条指令必须为FROM指令,并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每一个镜像一次)。

为了保证镜像精简,可以选用体积较小的镜像如Alpine或Debian作为基础镜像,例如:

ARG VERSION=9.3
FROM debian:${VERSION}
3、LABEL

LABEL指令可以为生成的镜像添加元素数据标签信息,这些信息可以用来辅助过滤特定镜像。

格式为LABEL = = ……。

例如:

LABEL version="1.0.0-rc3"
LABEL author="wayne" date="2020-01-01"
LABEL description="This text illustrates \
    that label-value can span multiple lines."
4、EXPOSE

声明镜像内服务监听的端口

格式为EXPOSE [/…]。

例如:

EXPOSE 22 80 8443 443

注意该指令只是起到声明作用,并不会自动完成端口映射

如果要映射端口出来,在启动容器是可以使用-P参数或者使用-p HOST_PORT:CONTAINER_PORT参数

5、ENV

指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在。

格式为:ENV = ……。

例如:

ENV APP_VERSION=1.0.0
ENV APP_HOME=/usr/local/app
ENV PATH $PATH:/usr/local/bin

指令指定的环境变量在运行时可以被覆盖掉,如docker run --env = built_image

当一条ENV指令中同时为多个环境变量赋值并且值也是从环境变量读取时,会为变量都赋值后在更新。如下面的指令,最终结果为key1=value1 key2=value2:

ENV key1=value2
ENV key1=value1 key2=${key1}
6.ENTRYPOINT

指定镜像的默认入口命令,该入口命令会在启动容器时作为跟命令执行,所有传入值做为该命令的参数。

支持两种格式:

ENTRYPOINT [“executable”,“param1”,”param2”]:exec调用执行;

ENTRYPOINT command param1 param2:shell中执行。

此时,CMD指令指定值将作为根命令的参数。

每个Dockerfile中只能有一个ENTRYPOINIT,当指定多个时,只有最后一个起效。

在运行时,可以被--entrypoint参数覆盖掉,如docker run --entrypoint。

7、VOLUME

创建一个数据卷挂载点。

格式为VOLUME [“/data”]。

运行容器时可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保持的数据等

8、USER

指定运行容器时的用户或UID,后续的RUN等指令也会使用指定的用户身份。

格式为USER deamon

当服务不需要管理员权限时,可以通过该命令指定运行用户,并且可以在Dockerfile中创建所需要的用户,例如:

RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres

要临时获取管理员权限可以使用gous命令

9、WORKDIR

为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。

格式为WORKDIR /path/to/workdir。

可以使用多个WORKDIR指令,后续命令如果参数相对路径,则会基于之前命令指定的路径,例如:

WORKDIR /a

WORKDIR b

WORKDIR c

RUN pwd

则最终路径为 /a/b/c

因此,为了避免出错,推荐WORKDIR指令中只是用聚堆路径。

10、ONBUILD

指定当基于所生成镜像创建紫晶想时,自动执行的操作命令。

格式为ONBUILD [INSTRUCTION]

例如,使用如下的Dockerfile创建父镜像ParentImage,指令ONBUILD指令:

# Dockerfile for ParentImage 
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

使用docker build命令创建子镜像ChindImage时(FROM ParentImage),会首先执行ParentImage中配置的ONBUILD指令:

# Dockerfile for ChindImage
FROM ParentImage

等价于在ChindImage的Dockerfile中添加了如下指令:

#Automatically run the following when building ChildImage
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
...

由于ONBUILD指令是隐式执行的,推荐在使用它的镜像便签中进行标注,例如ruby:2.1-onbuild。

ONBUILD指令在创建专门用于自动编译、检查等操作的基础镜像是,师范有用。

11、STOPSIGNAL

指定所创建镜像启动的容器接收退出的信号值

STOPSIGNAL signal

12、HEALTHCHECK

配置启动容器如何进行健康检查(如何判断与否),自Docker1.12开始支持。

格式有两种:

HEALTHCHECK [OPTIONS] CMD command:根据所执行命令返回值是否为0来判断

HEALTHCHECK NONE:禁止基础镜像中的健康检查。

OPTION 支持如下参数:

-interval=DURATION (deful:30s):过多久检查一次;

-timeout=DURATION(default:30s):每次检查等待结果的超时;

-retries=N(default:3):如果失败了,重试几次才最终取得失败

13、SHELL

指定其他命令使用shell时的默认shell类型:

SHELL [“executable”,“parameters”]

默认值为[“/bin/sh”,“-c”].

2.2操作指令

1、运行指令命令

格式为RUN 或RUN [“executable”,”param1”,“param2”]。注意后者指令会被解析为JSON数据,因此必须用双引号。前者默认将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行,不会启动shell环境

指定使用其他终端类型可以通过第二种方式实现,例如RUN [“/bin/bash”,“-c”,”echo hello”]。

每条RUN指令将在当前镜像基础上执行指令命令,并提交为新的镜像层,当命令较长时可以使用\来换行,例如:

RUN apt-get update \
     && apt-get install -y libsnappy-dev zliblg-dev libbz2-dev\
     && rm -rf /var/cache/apt \
     && rm -rf /var/lib/apt/lists/*
2、CMD

CMD指令也会指定启动容器是默认指向的命令。

支持三种格式:

CMD [“executable”,“param1”,”param2”]:相当于执行executable param1 param2,推荐方式;

CMD command param1 param2:在默认的Shell中执行,提供给需要交互的应用;

CMD [“param1”,“param2”]:提供给ENTRYPOINT的默认参数。

每个Dockerfile只能有一条CMD命令,如果指定了多条命令,只有最后一条会被执行。

如果用户启动容器时候手动指定了运行的命令(作为run命令的参数),则会覆盖掉CMD指令的命令。

3、ADD

添加内容到镜像。

格式:ADD

该命令将复制指定的路径下内容到容器中的路径下。

其中可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(自动解压为目录)可以是镜像内绝对路径,或者相对于工作目录(WORKDIR)的相对路径。

路径支持正则格式,例如:

ADD *.c /cade/

4、COPY

复制内容到镜像。

格式:COPY

复制本地主机的(为Dockerfile所在的相对路径,文件或目录)下内容到镜像中的。目标路径不存在是,会自动创建。

路径同样支持正则个格式

COPY与ADD指令功能类似,当使用本地目录为源目录时,推荐使用COPY。

2.3、创建镜像

编写完成Dockerfile之后,可以通过docker [image] build 命令类创建镜像。

基本的格式为docker build [OPTIONS] PATH |URL| -。

该命令将读取指定(包括子目录)的Dockerfile ,并将该路径下所有数据作为上下文( Context )发送给Docker 服务端。Docker 服务端在校验Dockerfile 格式通过后,逐条执行其中定义的指令,碰到ADD 、COPY 和RUN 指令会生成一层新的镜像。最终如果创建镜像成功,会返回最终镜像的ID 。

如果上下文过大, 会导致发送大量数据给服务端,延缓创建过程。因此除非是生成镜像所必需的文件,不然不要放到上下文路径下。如果使用非上下文路径下的Dockerfile ,可以通过“f选项来指定其路径。

要指定生成镜像的标签信息,可以通过-t 选项。该选项可以重复使用多次为镜像一次添加多个名称。
例如,上下文路径为/tmp/docker_builder/,并且希望生成镜像标签为builder/first_image: 1.0.0,
可以使用下面的命令:
$ docker build -t builder/first_image :1.0.0 /tmp/docker_builder/

命令选项

docker [image ] build 命令支持一系列的选项,可以调整创建镜像过程的行为。

image20200419223656228.png

image20200419223710241.png

我们在使用 docker build 命令去构建镜像时,往往会看到命令最后会有一个 . 号。如:

docker build -t xxx .

这里就有了一个 镜像构建上下文 的概念,当构建的时候,由用户指定构建镜像的上下文路径,而 docker build 会将这个路径下所有的文件都打包上传给 Docker 引擎,引擎内将这些内容展开后,就能获取到所有指定上下文中的文件了

比如说 dockerfile 中的 COPY ./package.json /project,其实拷贝的并不是本机目录下的 package.json 文件,而是 docker引擎 中展开的构建上下文中的文件,所以如果拷贝的文件超出了构建上下文的范围,Docker引擎 是找不到那些文件的。

所以 docker build 最后的 . 号,其实是在指定镜像构建过程中的上下文环境的目录。