Torres-tao  

使用Dockerfile创建镜像

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

1、基本结构

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

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

2、指令说明

Dockerfile中指令的一般格式为:INSTRUCTION arguments,包括配置指令(配置镜像信息)和操作指令(具体执行操作)

分类 指令 说明
配置指令 ARG 定义创建镜像过程中使用的变量
FROM 指定所创建镜像的基础镜像
LABEL 为生成的镜像添加元数据标签信息
EXPOSE 声明镜像内服务监听的端口
ENV 指定环境变量
ENTRYPOINT 指定镜像的默认入口命令
VOLUME 创建一个数据卷挂载点
USER 指定运行容器时的用户名或UID
WORKDIR 配置工作目录
ONBUILD 创建子镜像时指定自动执行的操作指令
STOPSIGNAL 指定退出的信号值
HEALTHCHECK 配置所启动容器如何进行健康检查
SHELL 指定默认shell类型
操作指令 RUN 运行指定命令
CMD 启动容器时指定默认执行的命令
ADD 添加内容到镜像
COPY 复制内容到镜像

2.1、配置指令介绍

ARG

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

格式:

ARG <name>[=<default value>]

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

Docker内置了一些镜像创建变量,用户可以直接使用而无须声明,包括(不区分大小写)HTTP_PROXY、HTTPS_PROXY、FTP_PROXY、NO_PROXY。

FROM

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

格式:

FROM <image> [AS <name>] 或 FROM <image>:<tag> [AS <name>] 或 FROM <image>@<digest> [AS <name>]

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

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

LABEL

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

格式:

LABEL <key>=<value> <key>=<value> <key>=<value>...

EXPOSE

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

格式:

EXPOSE <port> [<port>/<protocol>...]

eg:

EXPOSE 22 80 8443

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

如果要映射端口出来,在启动容器时可以使用-P参数(Docker主机会自动分配一个宿主机的临时端口)或-p HOST_PORT:CONTAINER_PORT参数(具体指定所映射的本地端口)

ENV

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

格式:

ENV <key> <value> 或 ENV <key>=<value> 

eg:

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=${keys1}

ENTRYPOINT

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

支持以下两种格式:

#exec调用执行
ENTRYPOINT ["executable","param1","param2"]、
#shell中执行
ENTRYPOINT command param1 param2

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

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

在运行时,可以被--entrypoint参数覆盖掉,如:docker run --entrypoint(即覆盖Dockerfile文件中ENTRYPOINT指令)

VOLUME

创建一个数据挂载点

格式:

VOLUME ["/data"]

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

USER

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

格式:

USER daemon

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

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

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

WORKDIR

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

格式:

WORKDIR /path/to/workdir

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

WORKDIR /a
WORKDIR b
WORKDIR c
#最终路径为:/a/b/c

因此,为了避免出错,推荐WORKDIR指令中只使用绝对路径

ONBUILD

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

格式:

ONBUILD [INSTRUCYION]

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

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

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

#Dockerfile for ChildImage
FROM ParentImage

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

[...]
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
...

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

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

STOPSIGNAL

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

格式:

STOPSIGNAL signal

HEALTHCHECK

配置所启动容器如何进行健康检查(如何判断健康与否)。

格式有两种:

#根据所执行命令返回值是否为0来判断
HEALTHCHECK [OPTIONS] CMD command
#禁止基础镜像中的健康检查
HEALTHCHECK NONE

OPTION支持如下参数:

  • -interval=DURATION(default:30s):过多久检查一次
  • -timeout=DURATION(default:30s):每次检查等待结果的超时
  • -retries=N(default:3):如果失败了,重试几次才最终确定失败。

SHELL

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

格式:

SHELL ["executable","parameters"]

默认值为["/bin/sh","-C"]

注意:对于windows系统,shell路径中使用了“\”作为分隔符,建议在Dockerfile开头添加”#escape=“来指定转义符。

2.2、操作指令介绍

RUN

运行指定命令

格式:

RUN <command> 或 RUN ["executable","param1","param2"]

注意:后者指令会被解析为JSON数组,因此必须使用双引号。前者默认将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行,不会启动shell环境。

指定使用其他终端类型可以通过exec方式实现,如:

RUN ["/bin/bsah","-c",“echo hello world"]

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

RUN apt-get update \
    && apt-get install -y python3 libbz2-dev \
    && rm -rf /var/cache/apt \
    && rm -rf /var/lib/apt/list/*

CMD

CMD指令用来指定启动容器时默认执行的命令。

支持三种格式:

#推荐方式
CMD ["executable","param1","param2"]
#在默认的shell中执行,提供给需要交互的应用
CMD command param1 param2
#提供给ENTRYPOINT的默认参数
CMD ["param1","param2"]

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

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

ADD

添加内容到镜像

格式:

ADD <src> <dest>
#该命令将复制指定的<src>路径下内容到容器中的<dest>路径下。

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

COPY

复制内容到镜像

格式:

COPY <src> <dest>

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

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

3、Dockerfile示例

FROM node
MAINTAINER Taolei
RUN git clone -q https://github.com/docker-in-practice/todo.git
WORKDIR todo
RUN npm install > /dev/null
EXPOSE 8000
CMD ["npm","start"]

构建过程如下:

[root@aliyun docker]# pwd
/home/docker
#构建一个镜像
[root@aliyun docker]# docker build .
Sending build context to Docker daemon  2.048kB
Step 1/7 : FROM node
latest: Pulling from library/node
0e29546d541c: Pull complete 
9b829c73b52b: Pull complete 
cb5b7ae36172: Pull complete 
6494e4811622: Pull complete 
6f9f74896dfa: Pull complete 
f2930ff7fb60: Pull complete 
c1d26179dd86: Pull complete 
1fa56dd41537: Pull complete 
321141c774e9: Pull complete 
Digest: sha256:36aca218a5eb57cb23bc790a030591382c7664c15a384e2ddc2075761ac7e701
Status: Downloaded newer image for node:latest
 ---> a283f62cb84b
Step 2/7 : MAINTAINER Taolei
 ---> Running in c367d3410334
Removing intermediate container c367d3410334
 ---> e7567eaaf35c
Step 3/7 : RUN git clone -q https://github.com/docker-in-practice/todo.git
 ---> Running in 9191275f23b1
Removing intermediate container 9191275f23b1
 ---> 5d80658a509b
Step 4/7 : WORKDIR todo
 ---> Running in f297028141cf
Removing intermediate container f297028141cf
 ---> a81464358a14
Step 5/7 : RUN npm install > /dev/null
 ---> Running in 19d637151604
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: 'minifyify@4.4.0',
npm WARN EBADENGINE   required: { node: '0.10.x' },
npm WARN EBADENGINE   current: { node: 'v17.3.0', npm: '8.3.0' }
npm WARN EBADENGINE }
npm WARN deprecated graceful-fs@2.0.3: please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js
npm WARN deprecated buffer-browserify@0.2.5: Package not maintained. Recent browserify uses https://github.com/feross/buffer
npm WARN deprecated mkdirp@0.3.5: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
npm WARN deprecated mkdirp@0.3.5: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated react-tools@0.11.2: react-tools is deprecated. For more information, visit https://fb.me/react-tools-deprecated
npm notice 
npm notice New minor version of npm available! 8.3.0 -> 8.6.0
npm notice Changelog: <https://github.com/npm/cli/releases/tag/v8.6.0>
npm notice Run `npm install -g npm@8.6.0` to update!
npm notice 
Removing intermediate container 19d637151604
 ---> d1b737e8b68f
Step 6/7 : EXPOSE 8000
 ---> Running in 27157638d7d6
Removing intermediate container 27157638d7d6
 ---> 6fafd82e1672
Step 7/7 : CMD ["npm","start"]
 ---> Running in fe6d70c5ec05
Removing intermediate container fe6d70c5ec05
 ---> eafa085c10fa
Successfully built eafa085c10fa

步骤说明:

  1. docker会上传docker build指定目录下的文件和目录
  2. 每个构建步骤从1开始按顺序编号,并与命令一起输出
  3. 每个命令会导致一个新镜像被创建出来,其镜像ID在此输出
  4. 为节省空间,在继续前每个中间容器会被移除
  5. 构建的调试信息在此输出
  6. 此次构建的最终镜像ID,可用于打标签

打标签

#打标签前
[root@aliyun docker]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
<none>       <none>    eafa085c10fa   7 minutes ago   1.1GB
busybox      latest    beae173ccac6   3 months ago    1.24MB
node         latest    a283f62cb84b   3 months ago    993MB
#打标签时
[root@aliyun docker]# docker tag eafa085c10fa todoapp
#打标签后
[root@aliyun docker]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
todoapp      latest    eafa085c10fa   8 minutes ago   1.1GB
busybox      latest    beae173ccac6   3 months ago    1.24MB
node         latest    a283f62cb84b   3 months ago    993MB

4、Dockerfile创建镜像过程

编写完Dockerfile之后,可使用docker build命令来创建镜像。基本格式为:

docker build [OPTIONS] PATH | URL | -

创建过程:

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

如果上下文过大,会导致发送大量数据给服务端,延缓创建过程。故而除非是生成镜像所必须的文件,不然不要放在上下文路径下。

posted on 2022-04-07 10:17  雷子锅  阅读(1885)  评论(0编辑  收藏  举报