Skip to content

Dockerfile 是一个文本格式的文件,用户可以使用 Dockerfile 来快速的自定义的构建自己的服务。

基本结构

Dockerfile 主要由四部分构成,基础镜像,维护者信息,镜像操作和容器启动时执行的指令。

shell
FROM ubuntu

RUN echo "deb http://archive.ubuntu.com/ubuntu/ raing main universe" >> /etc/apt/source.list

RUN apt-get update && apt-get install -y nginx

RUN echo "\ndeamon off;" >> /etc/nginx/nginx.conf

CMD /usr/sbin/nginx

RUN 指令将对镜像执行 linux 命令,每运行一条 RUN 指令,镜像将创建一个层,并提交。

  1. 构建一个 nginx 镜像
shell
FROM debian:jessie
MAINTAINER NGINX Docker Maintainers "[email protected]"
ENV NGINX_VERSION 1.10.1-1~jessie
RUN apt-key adv --keyserver hkp://pgd.mit.edu:80 --recv--keys 537BFD6B3DDFBC641079A6ABABF5BD827BD9BF62 \
    && echo "deb http://nginx.org/packages/debian/ jessie nginx" >> /etc/apt/sources.list \
    && apt-get update \
    && apt-get install --no-install-recommends --no-install-suggests -y \
    ca-certificates \
    nginx=${NGINX_VERSION} \
    nginx-module-xslt \
    nginx-module-geoip \
    nginx-module-image-filter \
    nginx-module-njs \
    gettext-base \
    && rm -rf /var/lib/apt/lists/*
RUN ln -sf /dev/stderr /var/log/nginx/error.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log
EXPOSE 80 443
CMD ["nginx","-g","deamon off;"]
  1. 安装 Golang 相关环境,制作 Go 语言的运行环境镜像。
shell
FROM buildpack-deps:jesssie-scm
RUN apt-get update && \
apt-get install -y --no-install-recommends \
 g++ \
 gcc \
 libc6-dev \
 make \
 && rm -rf /var/lib/apt/lists/\*
ENV GOLANG_VERSION 1.6.3
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLAOD_HASG256CDDE5E08530C0579255D153B08FDB3BE47CAABBE717BC7BCD756127A87AED
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \
    && echo "$GOLANG_DOWNLOAD_SHASH256 golang.tar.gz" | shash256sum -c - \
 && tar -C /usr/local -xzf golang.tar.gz \
 && rm golang.tar.gx
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin/$PATH
RUN mkdir -p $GOPATH/src $GOPATH/bin && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
COPY go-wrapper /usr/local/bin

指令说明

指令说明

  1. FROM

from 指令用以指定创建镜像的基础镜像,如果本地不存在,就会去远程 DOCKER HUB 下载指定镜像。格式为 FROM<image>,FROM <image>:<tag>或者 FROM<image>@<digest>。任何 Dockerfile 中的第一条指令必须为 FROM 指令,并且,如果在同一个 Dockerfile 中创建多个镜像,可以使用多个 FROM 指令(每个镜像一次)

  1. MAINTAINER

此命令用于指定维护者的信息,格式为 MAINTAINER<name>

shell

MAINTAINER [email protected]
  1. RUN 此命令用于运行指令,格式为 RUN<command> RUN ["excutable","parma1","param2"],需要指出的时第二条指令会被解析成 json 因此必须为双引号。命令的执行默认会使用 shell 命令执行,如果要指定指定的终端来执行命令,可以使用 RUN ["/bin/bash","param1","param2"],每一条指令的执行都将在当前镜像的基础上执行指定的指令,并提交为新的镜像。当命令较长时可以使用\来换行。
shell

RUN apt-get update \
 && apt-get install -y libsnappy-dev zliblg-dev libbz2-dev \
 && rm -rf /var/cache/apt
  1. CMD 此指令用于启动容器时默认执行的指令,其支持三种格式,需要注意的是每个 Dockerfile 只能执行一个 CMD 命令,如果指定了多个 CMD 命令那么只有最后一个命令会被执行。如果在启动容器的时候指定了运行命令,那么将会覆盖 CMD 命令。
shell

CMD ["executable","param1","param2"] # 使用 exec 执行,是推荐使用的方式。

CMD command param1 param2 # 在 /bin/sh 中执行,提供给需要交互的应用。

CMD ["param1","param2"] #提供给 ENTRYPOINT 的默认参数。
  1. LABEL 此指令用来指定生成镜像的元数据标签信息,格式为 LABEL <key>=<value><key>=<value>
shell

LABEL version="1.0"
LABEL description="This text illustrates \ that lable-value can span multipel lines"
  1. EXPOSE 此命令用于声明镜像内服务监听的端口,格式为 EXPOSE <port> [<port>...],需要注意的是此命令只是声明的作用,不会自动的完成容器的映射,具体的映射需要在启动容器的时候使用-p 参数来指定映射关系。
shell

EXPORT 22 80 443
  1. ENV 此命令用于指定环境变量,在镜像生成的过程中会被后续 RUN 指令使用,在镜像启动的容器中也会存在,格式为,ENV <key><value> 或 ENV <key>=<value>,使用此命令指定的环境变量可以在启动镜像时使用 docker --env 覆盖。
shell

ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && ...
RUN PATH /usr/local/postgress-$PG_MAJOR/bin:/bin/$PATH
  1. ADD 此命令将复制指定路径下的内容到 docker 的目标路径下,格式为 ADD <src><dest> 其中<src>可以是 Dockerfile 所在目录的相对路径(文件或者目录),也可以是一个 url,还可以是一个 tar 文件,如果时 tar 文件该文件将会被自动的解压。
shell

ADD \*.c /code/
  1. COPY 此指令是用于复制本机的文件或者文件夹至主机之中的,当目标文件夹不存时,目录将会被自动的创建,其格式为:COPY <src><dest>
  2. ENTRYPOINT 此命令用于指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入的至作为该命令的参数执行。其格式为:
shell

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

需要注意的时一个 Dockerfile 只能指定一个 ENTRYPOINT 指定多个时,只有最后一个生效,在运行时可以使用 -- entrypoint 参数覆盖掉。

  1. VOLUME 此命令用于创建一个数据挂载点,格式为 VOLUME ["/data"],可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保存的数据。
  2. USER 此命令用于指定容器运行时用户名或者 UID,后续的 RUN 等指令也会使用指定的用户身份,格式为 USER daemon ,当服务不需要管理员权限时,可以通过命令指定运行的用户,并且可以在之前创建所需要的用户。例如:RUN groupadd -r postgress && user add -r -g postgress 当需要临时使用管理员权限时,可以使用 gosu 或者 sudo。
  3. WORKDIR 为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录。格式为:WORKDIR /path/to/workdir。可以指定多个 WORKDIR,后续的命令如果参数时相对路径,则会基于之前命令指定的路径,例如:
shell

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
# 此时最终的路径是 /a/b/c

创建镜像

在 Dockerfile 编写完成之后就可以使用 docker build 命令来创建镜像了,该命令会读取目录下以及子目录下的 Dockerfile 文件,并将读取到的文件发送给 Docker 服务端然后由服务端来构建镜像。可以使用.dockerignore 文件来忽略匹配模式路径下的目录和文件。

最佳实践

最佳实践是指从需求触发,来制定合适自己,高效方便的构建镜像。做到做到这一点并不容易。可以从以下两个方面着手,一是尽量弄清楚每一个指令的含义和执行效果,自己多编写一些例子进行测试。二是阅读 docker hub 优秀镜像的构建文件进行学习。

实践经验:

  1. 精简镜像的用途,尽量让每个镜像的用途都比较单一,避免构建大的复杂的镜像。
  2. 选用合适的基础镜像,过大的基础镜像会造成生成臃肿的镜像。
  3. 提供清楚的命令注释和维护者信息。
  4. 正确的使用版本号,避免使用 latest 镜像,latest 镜像变化快往往不稳定,易造成构建不一致的情况。
  5. 减少镜像的层数,表现为尽量将多个 run 命令合并为一个。
  6. 及时删除临时文件和缓存文件,特别是执行 apt-get 之后 /var/cache/apt 下边会缓存一些安装包。
  7. 提高生成速度,合理的使用缓存,减少内容目录下的文件数量。
  8. 合理的使用指令的顺序,在开启缓存的情况下,内容不变指令尽量放在前边,这样可以尽量的复用。
  9. 减少外部的干扰,如果确实要从外部引入数据,需要指定持久地址,并带有版本信息,让他人可以复用而不至于出错。