首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >DockerFile

DockerFile

作者头像
看、未来
发布2022-05-17 14:13:30
发布2022-05-17 14:13:30
1.2K0
举报

文章目录
  • 有 docker commit,为什么还要 DockerFile ?
    • docker commit 的弊端:
    • docker build 方式镜像生成新的镜像:
    • Dockerfile的优点:
    • Dockerfile的缺点:
  • DockerFile 怎么写?
    • FROM && RUN
    • 开始构建镜像
    • 上下文路径
  • 其他指令详解
    • COPY
    • ADD
    • CMD
    • ENTRYPOINT
    • ENV
    • ARG
    • VOLUME
    • EXPOSE
    • WORKDIR
    • USER
    • HEALTHCHECK
    • ONBUILD

有 docker commit,为什么还要 DockerFile ?

默认你已经知道什么是 DockerFile 了。如果不知道的话:DockerFile 是用来构建镜像的一个脚本文件。

此前我构建镜像都是使用 docker file,简单又明确。但是后来我就犯迷糊了,commit 出来的镜像都是什么啊,那个描述信息真的会有人很详细的去写?弄多了自己都记不住了。而且,commit 到底打包了些什么东西啊?我后来突然意识到。是像虚拟机快照那样吗?会把当时的容器状态全都打包进去吗?还是说只是单纯的打包一下当时的文件?

docker commit 一个很不方便的地方就在于,难以回顾它是怎么来的,比方说我这里使用 commit 构建了一个 CentOS + vim 镜像,查看它的构建历史发现:

代码语言:javascript
复制
[root@centos7 ~]# docker history centos-vim:v1.0
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
8df43092cfd1        6 minutes ago       /bin/bash                                       140MB               
67591570dd29        4 years ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
<missing>           4 years ago         /bin/sh -c #(nop)  LABEL name=CentOS Base Im…   0B                  
<missing>           4 years ago         /bin/sh -c #(nop) ADD file:940c77b6724c00d42…   192MB               
<missing>           4 years ago         /bin/sh -c #(nop)  MAINTAINER https://github…   0B          

说真的,这要不是我自己创建的,我还真不知道它有些什么。而且,就算是我自己创建的,我也仅是知道它有 CentOS + vim,至于还有没有点别的什么,不知道啊!!!

docker commit 的弊端:

如果是安装软件包、编译构建,那会有大量的无关内容被添加进来,如果不小心清理,将会导致镜像极为臃肿。

此外,使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为 黑箱镜像,换句话说,就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体在操作的。虽然 docker diff 或许可以告诉得到一些线索,但是远远不到可以确保生成一致镜像的地步。这种黑箱镜像的后期维护工作是非常痛苦的。

而且,镜像所使用的分层存储,除当前层外,之前的每一层都是不会发生改变的,换句话说,任何修改的结果仅仅是在当前层进行标记、添加、修改,而不会改动上一层。如果使用 docker commit 制作镜像,以及后期修改的话,每一次修改都会让镜像更加臃肿一次,所删除的上一层的东西并不会丢失,会一直如影随形的跟着这个镜像,即使根本无法访问到。这会让镜像更加臃肿。

docker build 方式镜像生成新的镜像:

docker build的方式生成新镜像的前提条件是有一个旧的基础镜像,在此基础上通过docker build 命令执行dockerfile 文件从而生成一个新的镜像,不同于docker commit,是镜像–> 镜像的转化。当然,是否转化正确是需要将镜像 docker run起来的哦。

Dockerfile的优点:

能够自由灵活的与宿主机联系,比如,某些配置文件在宿主机验证并使用过后很好用,那么,可以将文件copy到镜像中,(这个动作是写在dockerfile里),add 远程主机的配置文件到镜像中,定义onbuild动作等等各种灵活的功能。docker commit不能做到这些事情,因为是在一个封闭的在运行中的容器中,无法做复制拷贝宿主机文件的事情。

dockerfile本身就是一个比较详细的构建文档,有这个文档就可以清楚的知道新构建的镜像经历了怎样的变化。没有黑箱操作的困扰了,后期的维护更为方便了。

后期可扩展性强,一个文件就可以在哪都可以运行镜像了。(前提有网,有安装docker环境)

Dockerfile的缺点:

编写不容易,因为需要对脚本这些比较了解,有Linux基础的人才可以编写出好用的dockerfile,上手难度大。

DockerFile 怎么写?

FROM && RUN

先来看一个最简单的示例:

代码语言:javascript
复制
FROM  ubuntu:latest
RUN apt update \
    && aptinstall -y vim \
    && apt clean all

FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。

RUN:用于执行后面跟着的命令行命令。有以下俩种格式:

shell 格式:

代码语言:javascript
复制
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。

exec 格式:

代码语言:javascript
复制
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline

注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

代码语言:javascript
复制
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

以上执行会创建 3 层镜像。可简化为以下格式:

代码语言:javascript
复制
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

如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。

开始构建镜像

1、新建一个目录,将 Dockerfile 文件存放在目录下。

2、在 Dockerfile 文件的存放目录下,执行构建动作。

注:最后的 . 代表本次执行的上下文路径,后面会介绍。

代码语言:javascript
复制
$ docker build -t testbuild .

该命令会寻找当前路径下名为 Dockerfile 的文件。

注:apt update 搞一次要好久,建议直接存一个 update 过的系统包。。。

上下文路径

上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。

解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。

如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。

注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。

比方说:

代码语言:javascript
复制
ending build context to Docker daemon 1.38GB

我就觉着纳闷儿…

其他指令详解

COPY

复制指令,从上下文目录中复制文件或者目录到容器里指定路径。

格式:

代码语言:javascript
复制
COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]

[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。

<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

代码语言:javascript
复制
COPY hom* /mydir/
COPY hom?.txt /mydir/

<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

ADD

ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。 ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

CMD

类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

代码语言:javascript
复制
CMD 在docker run 时运行。
RUN 是在 docker build。

作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

格式:

代码语言:javascript
复制
CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...] 
CMD ["<param1>","<param2>",...]  # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

(哦,所以如果我要构建 redis 集群节点的镜像可以用这个)

ENTRYPOINT

类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

格式:

代码语言:javascript
复制
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

示例:

假设已通过 Dockerfile 构建了 nginx:test 镜像:

代码语言:javascript
复制
FROM nginx

ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参 

1、不传参运行

代码语言:javascript
复制
$ docker run  nginx:test

容器内会默认运行以下命令,启动主进程。

代码语言:javascript
复制
nginx -c /etc/nginx/nginx.conf

2、传参运行

代码语言:javascript
复制
$ docker run  nginx:test -c /etc/nginx/new.conf

容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

代码语言:javascript
复制
nginx -c /etc/nginx/new.conf

ENV

设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

格式:

代码语言:javascript
复制
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:

代码语言:javascript
复制
ENV NODE_VERSION 7.2.0
代码语言:javascript
复制
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"

ARG

构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。

格式:

代码语言:javascript
复制
ARG <参数名>[=<默认值>]

VOLUME

定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

作用:

代码语言:javascript
复制
避免重要的数据,因容器重启而丢失,这是非常致命的。
避免容器不断变大。

格式:

代码语言:javascript
复制
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

EXPOSE

仅仅只是声明端口。

作用:

代码语言:javascript
复制
帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

格式:

代码语言:javascript
复制
EXPOSE <端口1> [<端口2>...]

WORKDIR

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

格式:

代码语言:javascript
复制
WORKDIR <工作目录路径>

USER

用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

格式:

代码语言:javascript
复制
USER <用户名>[:<用户组>]

HEALTHCHECK

用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

格式:

代码语言:javascript
复制
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。

ONBUILD

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

格式:

代码语言:javascript
复制
ONBUILD <其它指令>

LABEL

LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:

代码语言:javascript
复制
LABEL <key>=<value> <key>=<value> <key>=<value> ...

比如我们可以添加镜像的作者:

代码语言:javascript
复制
LABEL org.opencontainers.image.authors="runoob"
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 有 docker commit,为什么还要 DockerFile ?
    • docker commit 的弊端:
    • docker build 方式镜像生成新的镜像:
    • Dockerfile的优点:
    • Dockerfile的缺点:
  • DockerFile 怎么写?
    • FROM && RUN
    • 开始构建镜像
    • 上下文路径
  • 其他指令详解
    • COPY
    • ADD
    • CMD
    • ENTRYPOINT
    • ENV
    • ARG
    • VOLUME
    • EXPOSE
    • WORKDIR
    • USER
    • HEALTHCHECK
    • ONBUILD
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档