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
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步