dockerfile文件解析

什么是 Dockerfile

用户通过 docker client 客户端去操作 docker daemon 进程对 docker 服务的管理,例如 docker 容器如何从仓库中获取 docker 镜像,这些镜像间依赖关系如何组织等等。

docker 镜像实际上是一种特殊的文件系统,它提供了容器运行时所需的程序、库、资源、配置等文件,以及运行时的配置参数。镜像是静态的,存储在远程仓库中。定制镜像的过程就是向容器中叠加镜像,每个镜像占据一层,为了方便安装镜像,我们设计了 dockerfile,它可以理解为安装、定制镜像的脚本。

dockerfile 中包含许多条指令,每一条指令构建一层镜像。最上层为可读写层,其余层为镜像层,只读。

Dockerfile 介绍及配置解析

  • 首先在一个目录下创建 Dockerfile 文件,该文件有独特的文件结构,指令必须大写(与参数区分),且第一条非注释指令必须以 FROM 开头,表示基于哪个镜像来构建新镜像。
  • .dockerignore 中对应路径不会打包到新镜像;
  • docker build -f filePath 命令用于从 Dockerfile 中构建新镜像。

以构建 ubuntu 系统为例:

# 第一非注释行必须指定基础镜像
FROM ubuntu

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

# 镜像操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

# 容器启动指令
CMD /usr/sbin/nginx

Docker 守护进程会一条条执行 Dockerfile 中的指令,并且每一步提交并生成一个新镜像,最后输出镜像ID。Docker 会重用中间已生成的镜像,加速 docker build 的速度,如果不想使用本地缓存的镜像,可以通过 --cache-from 指定缓存,指定后将不再使用本地生成的镜像链,而是从镜像仓库中下载。

Docker 寻找缓存的逻辑就是树型结构根据 Dockerfile 指令遍历子节点的过程,如下:

     FROM base_image:version           Dockerfile:
           +----------+                FROM base_image:version
           |base image|                RUN cmd1  --> use cache because we found base image
           +-----X----+                RUN cmd11 --> use cache because we found cmd1
                / \
               /   \
       RUN cmd1     RUN cmd2           Dockerfile:
       +------+     +------+           FROM base_image:version
       |image1|     |image2|           RUN cmd2  --> use cache because we found base image
       +---X--+     +------+           RUN cmd21 --> not use cache because there's no child node
          / \                                        running cmd21, so we build a new image here
         /   \
RUN cmd11     RUN cmd12
+-------+     +-------+
|image11|     |image12|
+-------+     +-------+

绝大部分指令按照上述逻辑查找缓存,除了 ADD、COPY 指令会直接复制内容到镜像内,其余会首先检查缓存。比如 RUN apt-get udpate xxx,每次执行时可能文件内容不一样,但是 Docker 认为命令一致会继续使用缓存的命令。

Docker 指令详解

FROM

FROM 指令指定基础镜像,后续镜像构建都是基于该镜像,FROM 位于 Dockerfile 文件的首条命令:

FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>

RUN

RUN 指令用于镜像构建过程中执行特定的命令,生成一个中间镜像,格式为:

# shell
RUN <command>
# exec
RUN ["executable", "param1", "param2"]
  • RUN 命令会在当前镜像中执行任意合法命令并提交结果,命令提交后自动执行 Dockerfile 中下一个指令;
  • RUN 指令创建的中间镜像会缓存,并在下次构建中使用,若不想使用缓存,可以指定 --no-cache
  • Dockerfile 中的指令每执行一次就会在 docker 上新建一层,为了避免镜像无意义扩大,应尽量减少 RUN 命令执行次数;
# 会构建三层镜像
FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
# 构建一层镜像
FROM centos
RUN apt -y install wget \
	&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && tar -xvf redis.tar.gz

COPY

COPY 命令用于从宿主机复制文件到容器内,格式为:

COPY <源路径> ... <目标路径>
COPY ["<源路径>", ..., "<目标路径>"]

其中目标路径可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作路径通过 WORKDIR 指令指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

COPY hom* /mydir/
COPY hom?.txt /mydir/

ADD

ADD 指令类似于 COPY,区别在于源路径可以为 URL,Docker 引擎会尝试去这个链接下下载文件到目标路径下。

ENV

ENV 用于配置环境变量:

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

举例如下:

ENV VERSION=1.0 DEBUG=on NAME="Happy Feet"

EXPOSE

EXPOSE 声明可用端口,将当前容器内端口映射到外部宿主机某个端口,也就是 docker run -P port

EXPOSE <端口1> [<端口2>...]

VOLUME

VOLUME 定义了匿名数据卷,如果启动容器时忘记挂载数据卷,会自动挂载到匿名卷:

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

VOLUME <路径>

WORKDIR

指定工作目录,构建镜像的每一层中都存在。

CMD

CMD 指定容器在启动时需要执行的命令,有以下几种格式:

CMD ["executable", "param1", "param2"]
CMD ["param1", "param2"]
CMD command param1 param2

注意与 RUN 命令的区别,RUN 命令在构建镜像时执行,RUN 每执行一次会生成一层镜像;CMD 则是在容器运行时执行,在构建时不进行任何操作。

注意 docker run xxx param... 中的参数会直接替换 CMD 所有命令。

ENTRYPOINT

ENTRYPOINT 类似于 CMD 命令,都是在容器启动时执行一些命令,区别在于 ENTRYPOINT 中的可执行命令不会被 docker run xxx 的参数替换,它只会替换 ENTRYPOINT 的参数列表;CMD 的整体命令会被它所替换。

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

举个例子:

# dockerfile文件
# Version: 0.0.3
FROM ubuntu:16.04
MAINTAINER user "user.xxx@mail.com"
RUN apt-get update
RUN apt-get install -y nginx
RUN echo "Hello world" > /var/www/html/index.html
ENTRYPOINT ["/usr/sbin/nginx"]
EXPOSE 80


# docker build 构建镜像
docker build -t="itbilu/test" .

# 启动容器
docker run -i -t itbilu/test -g "daemon off;"

按上述命令构建并启动 docker 容器最终会执行如下命令:
/usr/sbin/nginx -g "daemon off;"

# dockerfile文件
FROM centos
CMD ["ls", "-a"]
# 构建镜像
docker build -f dockerfile-centos-test -t cmd-test:0.1 .
# 运行镜像
docker run cmd-test:0.1
# ls -a        容器启动时会执行
# 运行镜像
docker run cmd-test:0.1 -l
# 容器启动时会报错,因为执行 -l ,为无效命令

# dockerfile文件
FROM centos
ENTRYPOINT ["ls", "-a"]
# 构建镜像
docker build -f docker-test-entrypoint -t entrypoint-test:0.1 .
# 运行镜像
docker run entry-test:0.1 -l

# ls -l       容器启动时会执行

Dockerfile 示例

以构建 nginx 运行环境为例,编写 dockerfile:

# 基础镜像
FROM sameersbn/ubuntu:14.04.20161014

# 维护者
MAINTAINER sameer@damagehead.com

# 容器环境配置
ENV RTMP_VERSION=1.1.10 \
    NPS_VERSION=1.11.33.4 \
    LIBAV_VERSION=11.8 \
    NGINX_VERSION=1.10.1 \
    NGINX_USER=www-data \
    NGINX_SITECONF_DIR=/etc/nginx/sites-enabled \
    NGINX_LOG_DIR=/var/log/nginx \
    NGINX_TEMP_DIR=/var/lib/nginx \
    NGINX_SETUP_DIR=/var/cache/nginx

# 设置构建时变量,构建完毕失效
ARG BUILD_LIBAV=false
ARG WITH_DEBUG=false
ARG WITH_PAGESPEED=true
ARG WITH_RTMP=true

# 复制本地文件到容器目录中
COPY setup/ ${NGINX_SETUP_DIR}/
RUN bash ${NGINX_SETUP_DIR}/install.sh

# 复制本地配置文件到容器目录中
COPY nginx.conf /etc/nginx/nginx.conf
COPY entryporint.sh /sbin/entrypoint.sh

# 运行镜像构建命令
RUN chmod 755 /sbin/entrypoint.sh

# 映射端口
EXPOSE 80/tcp 433/tcp 1935/tcp

# 指定网站目录挂载点
VOLUME ["${NGINX_SITECONF_DIR}"]

# 启动容器时执行
ENTRYPOINT ["/sbin/entrypoint.sh"]
CMD ["/usr/sbin/nginx"]

参考

https://www.cnblogs.com/panwenbin-logs/p/8007348.html#autoid-0-0-0

https://cloud.tencent.com/developer/article/2035874

posted @   Stitches  阅读(111)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示