使用Dockerfile创建镜像


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

基本结构

Dockerfile一般分为四部分:基础镜像信息,维护者信息,镜像操作指令,容器启动时执行指令。

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

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#第一行必须指令基于的基础镜像
From ubutu

#维护者信息
MAINTAINER docker_user docker_user@mail.com

#镜像的操作指令
apt/sourcelist.list

RUN apt update && apt install -y ngnix
RUN echo "\ndaemon off;">>/etc/ngnix/nignix.conf

#容器启动时执行指令
CMD /usr/sbin/ngnix

指令说明

FROM

指定所创建镜像的基础镜像,如果本地不存在,则默认从Docker Hub下载

格式为:FROM <image>FROM <image>:<tag>FROM <image>@<digest>

任何Dockerfile中第一条指令必须为FROM指令

若在同一个Dockerfile文件中创建多个镜像,可以使用多个FROM指令(每一个创建镜像使用一次)

MAINTAINER

指定维护者信息

格式:MAINTAINER <name>

该信息会写入生成镜像的Author属性域中

RUN

运行指定命令

格式:RUN <command>RUN ["executable","param1","param2"]

前者在shell终端上运行,即/bin/sh -c

后者使用exec运行 ,不会启动shell环境。会被解析为json数组,必须使用双引号。可使用此方法指定使用其他终端类型,例:RUN ["/bin/bash", "-c","echo hello"]

每运行一条RUN指令,镜像就会添加新的一层,并提交

每条run指令在当前基础镜像执行,并且提交新镜像。当命令比较长时,可以使用\换行。 例:

1
2
3
RUN apt update \
&& apt install -y libbz2-dev \
&& rm -rf /var/cache/apt

CMD

指定启动容器时默认执行的命令

格式:

  1. CMD ["executable","param1","param2"] 使用exec执行,推荐
  2. CMD command param1 param2/bin/sh上执行 ,提供给需要交互的应用
  3. CMD ["Param1","param2"] 提供给ENTRYPOINT做默认参数

每个Dockerfile只能执行一条CMD命令,多个CMD命令时,只最后一条被执行。

LABEL

指定生成镜像的元数据标签信息

格式:LABEL <key>=<value> <key>=<value>...

EXPOSE

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

格式:EXPOSE <port> [<port>...]

该命令只起到声明作用,并不会自动完成端口映射。在启动容器时,指定-P-p参数进行端口映射。

ENV

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

格式:ENV <key> <value>ENV <key>=<value>...

此指令所指定的环境变量在容器运行时可被覆盖掉。如:

1
docker run --env <key>=<value> image_name

ADD

复制指定路径下的内容到容器中的指定路径下

格式:ADD <src> <dest>

<src>可以是Dockerfile所在目录的相对路径(文件或目录)或URLtar文件(tar文件会自动解压到<dest>路径下)

<dest>可以是镜像内绝对路径,或相对于工作目录(WORKDIR)的相对路径

路径格式支持正则表达式

COPY

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

路径格式支持正则表达式

ENTRYPOINT

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

格式:

  1. ENTRYPOINT ["executable", "param1", "param2"] (exec调用执行)
  2. ENTRYPOINT command param1 param2(shell中执行)

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

每个Dockerfile只能执行一条ENTRYPOINT命令,多个ENTRYPOINT命令时,只最后一条被执行。

在运行容器时,此指令可被--entrypoint参数覆盖掉

VOLUME

创建一个数据卷挂载点

格式:VOLUME ["/data"]

创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保存的数据等

USER

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

格式:USER daemon

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

1
RUN groupadd -r postgres  && useradd -r -g postgres postgres

要临时获取管理员权限可以使用 gosusudo

WORKDIR

为后续的 RUNCMDENTRYPOINT 指令配置工作目录

格式为 WORKDIR /path/to/workdir

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

1
2
3
4
WORKDIR /a 
WORKDIR b
WORKDIR c
RUN pwd

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

ARG

指定一些镜像内使用的参数,这些参数在执行docker build命令时才以--build-arg <varname>=<value>格式传入

格式:ARG <name> [=<default value>]

ONBUILD

配置当所创建的镜像作为其他镜像的基础镜像时,所执行的创建操作指令

格式:ONBUILD [INSTRUCTION]

例:

  1. Dockerfile1创建镜像A
1
2
3
4
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
  1. Dockerfile2创建镜像B
1
FROM A

使用上方指令,会自动执行ONBUILD指令的内容,即FROM A指令等价于执行指令

1
2
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src

STOPSIGNAL

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

格式:STOPSIGNAL signal

HEALTHCHECK

配置所启动容器如何进行健康检查

格式:

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

OPTIONS支持:

  1. --interval=DURATION:检查的时间间隔(默认30s)
  2. --timeout=DURATION:每次检查等待结果的超时时间(默认30s)
  3. --retries=N:失败重试次数(默认3次)

SHELL

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

格式:SHELL ["executable","parameters"]

默认值:["/bin/sh","-c"]


在Dockerfile中使用multi-stage

1
2
3
4
5
6
7
8
9
10
11
FROM golang:1.7.3 as builder
WORKDIR /go/src/github.com/sparkdevo/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/sparkdevo/href-counter/app .
CMD ["./app"]

这个Dockerfile文件的特点是同时存在多个FROM指令,每个FROM指令代表一个stage的开始部分。我们可以把一个stage的产物拷贝到另一个stage中。

把第一个stage使用as语法命名为builder,然后在后面的stage中通过名称builder进行引用--from=builder


创建镜像

编写Dockerfile完成后,使用docker build命令创建镜像

格式:docker build [options] dir

过程:读取指定路径下(包括子目录)的Dockerfile,并将该目录下所有内容发送给Docker服务端,由服务端创建镜像。所以,除非特殊需要,一般建议放置Dockerfile的目录为空目录。

1
2
docker build -t re/fi /tmp/docker_build/
-t:指定生成镜像的标签信息

使用.dockerignore文件

此文件用于让Docker忽略匹配路径下的目录和文件

1
2
3
4
5
# comment
*/temp*
*/*/temp*
tmp?
~*

实践经验

  1. 精简镜像用途
  2. 选用合适的基础镜像
  3. 提供足够清晰的命令注释和维护者信息
  4. 正确使用版本号
  5. 减少镜像层数
  6. 及时删除临时文件和缓存文件
  7. 提高生成速度
  8. 调整合理的指令顺序
  9. 减少外部源的干扰
---------------The End---------------
0%