DockerFile简介

官网:https://docs.docker.com/engine/reference/builder/

概述

Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

1.构建三步骤

  编写Dockerfile文件 - docker build命令构建镜像 - docker run依镜像运行容器实例

2.Dockerfile内容基础知识

  1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数

  2:指令按照从上到下,顺序执行

  3:#表示注释

  4:每条指令都会创建一个新的镜像层并对镜像进行提交

DockerFile构建过程解析

  Docker执行Dockerfile的大致流程

    (1)docker从基础镜像运行一个容器

    (2)执行一条指令并对容器作出修改

    (3)执行类似docker commit的操作提交一个新的镜像层

    (4)docker再基于刚提交的镜像运行一个新容器

    (5)执行dockerfile中的下一条指令直到所有指令都执行完成

  从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,

    *  Dockerfile是软件的原材料

    *  Docker镜像是软件的交付品

    *  Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例

 

  Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

 

    1 Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;

    2 Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;

    3 Docker容器,容器是直接提供服务的。

 DockerFile常用保留字指令

FROM 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from(最好挑一些aplineslim之类的基础小镜像
LABEL
标注镜像的一些说明信息
LABEL multi.label1="value1" multi.label2="value2" other="value3"
MAINTAINER 镜像维护者的姓名和邮箱地址
RUN

容器构建时需要运行的命令

RUN指令在当前镜像层顶部的新层执行任何命令,并提交结果,生成新的镜像层

生成的提交映像将用于Dockerfile中的下一步。 分层运行RUN指令并生成提交符合Docker的核心概念,就像源代码控制一样

exec形式可以避免破坏shell字符串,并使用不包含指定shell可执行文件的基本映像运行RUN命令。可以使用SHELL命令更改shell形式的默认shell。 在shell形式中,您可以使用\(反斜杠)将一条RUN指令继续到下一行。

两种格式

shell格式

/bin/sh -c <command>的方式,

# 测试案例
FROM alpine
LABEL maintainer=leifengyang xx=aa
ENV msg='hello atguigu itdachang'
RUN echo $msg
RUN ["echo","$msg"]
RUN /bin/sh -c 'echo $msg'
RUN ["/bin/sh","-c","echo $msg"]
CMD sleep 10000


#总结; 由于[]不是shell形式,所以不能输出变量信息,而是输出$msg。其他任何/bin/sh -c 的形式都
可以输出变量信息

exec格式

["/bin/sh","-c",command] 的方式== shell方式
也就是exec 默认方式不会进行变量替换

RUN是在 docker build时运行
EXPOSE EXPOSE指令通知Docker容器在运行时在指定的网络端口上进行侦听。 可以指定端口是侦听TCP还是UDP,如果未指定协议,则默认值为TCP
EXPOSE指令实际上不会发布端口。 它充当构建映像的人员和运行容器的人员之间的一种文档,即有关打算发布哪些端口的信息。 要在运行容器时实际发布端口,请在docker run上使用-p标志发布并映射一个或多个端口,或使用-P标志发布所有公开的端口并将其映射到高阶端口
EXPOSE <port> [<port>/<protocol>...]
EXPOSE [80,443]
EXPOSE 80/tcp
EXPOSE 80/udp
WORKDIR WORKDIR指令为Dockerfile中跟随它的所有 RUNCMDENTRYPOINTCOPYADD 指令设置工作目
录。 如果WORKDIR不存在,即使以后的Dockerfile指令中未使用它也将被创建。
WORKDIR指令可在Dockerfile中多次使用。 如果提供了相对路径,则它将相对于上一个WORKDIR
令的路径

例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
#结果 /a/b/c

例如:

ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
#结果 /path/$DIRNAME

USER USER指令设置运行映像时要使用的用户名(或UID)以及可选的用户组(或GID),以及DockerfileUSER后面所有RUNCMDENTRYPOINT指令 USER <user>[:<group>]
USER <UID>[:<GID>]
ARG

ARG指令定义了一个变量,用户可以在构建时使用--build-arg = 传递,docker build命令会将其传递
给构建器。
--build-arg 指定参数会覆盖Dockerfile 中指定的同名参数
如果用户指定了 未在Dockerfile中定义的构建参数 ,则构建会输出 警告
ARG只在构建期有效,运行期无效
不建议使用构建时变量来传递诸如github密钥,用户凭据等机密。因为构建时变量值使用docker
history是可见的。
ARG变量定义从Dockerfile中定义的行开始生效。
使用ENV指令定义的环境变量始终会覆盖同名的ARG指令

ENV 在构建阶段中所有后续指令的环境中使用,并且在许多情况下也可以内联替换。
引号和反斜杠可用于在值中包含空格。
ENV 可以使用key value的写法,但是这种不建议使用了,后续版本可能会删除 参照右侧示例

ENV MY_MSG hello
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
#多行写法如下
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy

docker run --env 可以修改这些值
容器运行时ENV值可以生效
ENVimage阶段就会被解析并持久化(docker inspect image查看),参照右侧示例
FROM alpine
ENV arg=1111111
ENV runcmd=$arg
RUN echo $runcmd
CMD echo $runcmd
#ENV的固化问题: 改变arg,会不会改变 echo的值,会改变哪些值,如何修改这些值?
ADD COPY用法,不过 ADD拥有自动下载远程文件和解压的功能

 注意:

src 路径必须在构建的上下文中; 不能使用 ../something /something 这种方式,因为docker构建的第一步是将上下文目录(和子目录)发送到docker守护程序。
如果 src URL,并且 dest 不以斜杠结尾,则从URL下载文件并将其复制到 dest
  如果 dest 以斜杠结尾,将自动推断出url的名字(保留最后一部分),保存到 dest
如果 src 是目录,则将复制目录的整个内容,包括文件系统元数据。

COPY

类似ADD,拷贝文件和目录到镜像中。

将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置

 

COPY指令从 src 复制新文件或目录,并将它们添加到容器的文件系统中,路径为 dest
可以指定多个 src 资源,但是文件和目录的路径将被解释为相对于构建上下文的源。
每个 src 都可以包含通配符,并且匹配将使用Gofilepath.Match规则进行

COPY [--chown=<user>:<group>] <src>... <dest> COPY hom* /mydir/ #当前上下文,以home开始的所有资源
COPY hom?.txt /mydir/ # ?匹配单个字符
COPY test.txt relativeDir/ # 目标路径如果设置为相对路径,则相对与 WORKDIR 开始
# “test.txt” 添加到 <WORKDIR>/relativeDir/
COPY test.txt /absoluteDir/ #也可以使用绝对路径,复制到容器指定位置
#所有复制的新文件都是uid(0)/gid(0)的用户,可以使用--chown改变
COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
--chown=<user>:<group> 用户:用户组权限(--chown功能仅在用于构建Linux容器的Dockerfiles上受支持,而在Windows容器上不起作用
<src源路径>:源文件或者源目录
<dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
VOLUME

容器数据卷,用于数据保存和持久化工作

作用:把容器的某些文件夹映射到主机外部

VOLUME ["/var/log/"] #可以是JSON数组
VOLUME /var/log #可以直接写
VOLUME /var/log /var/db #可以空格分割多个

VOLUME 声明了卷,那么以后对于卷内容的修改会被丢弃,所以, 一定在volume声明之前修改内容 

CMD 指定容器启动后的要干的事情  
注意 Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
参考官网Tomcat的dockerfile演示讲解 官网最后一行命令
我们演示自己的覆盖操作
它和前面RUN命令的区别 CMD是在docker run 时运行。
RUN是在 docker build时运行。
ENTRYPOINT 也是用来指定一个容器启动时要运行的命令

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

命令格式和案例说明   命令格式:

ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参。

当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变成

案例如下:假设已通过 Dockerfile 构建了 nginx:test 镜像:

是否传参 按照dockerfile编写执行 传参运行
Docker命令 docker run  nginx:test docker run  nginx:test -c /etc/nginx/new.conf
衍生出的实际命令 nginx -c /etc/nginx/nginx.conf nginx -c /etc/nginx/new.conf
优点 在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
注意 如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

 CMDENTRYPOINT

写法 CMD 的三种写法
CMD ["executable","param1","param2"] ( exec 方式首选方式)
  # 示例
FROM alpine
LABEL maintainer=leifengyang
CMD ["1111"]
CMD ["2222"]
ENTRYPOINT ["echo"]
#构建出如上镜像后测试
docker run xxxx:效果 echo 1111
 
CMD ["param1","param2"] (ENTRYPOINT提供默认参数)
CMD command param1 param2 ( shell 形式)
ENTRYPOINT 的两种写法:
ENTRYPOINT ["executable", "param1", "param2"] ( exec 方式首选方式)
ENTRYPOINT command param1 param2 (shell 形式)
只能有一个CMD

Dockerfile中只能有一条CMD指令。 如果您列出多个CMD,则只有最后一个CMD才会生效。

CMD的主要目的是为执行中的容器提供默认值。 这些默认值可以包含可执行文件,也可以省略可执行文件,在这种情况下,您还必须指定ENTRYPOINT指令。

CMDENTRYPOINT提供默认参数
如果使用CMDENTRYPOINT指令提供默认参数,则CMDENTRYPOINT指令均应使用JSON数组格式指定
组合最终效果
  无ENTRYPOINT

ENTRYPOINT  exec_entry  p1_entry

ENTRYPOINT [“exec_entry”, “p1_entry”]

无CMD 错误, 不允许的写法 ;容器没有启动命令 /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD ["exec_cmd","p1_cmd"] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry

exec_entry p1_entry
exec_cmd p1_cmd

CMD["p1_cmd","p2_cmd"] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd
    这条竖线,总是以ENTRYPOINT的为准 这条竖线,ENTRYPOINT和CMD共同作用
docker run启动参数会覆盖CMD内容
# 一个示例
FROM alpine
LABEL maintainer=leifengyang
CMD ["1111"]
ENTRYPOINT ["echo"]
#构建出如上镜像后测试
docker run xxxx:什么都不传则 echo 1111
docker run xxx arg1:传入arg1 echo arg1

 


 

posted @ 2022-10-20 08:23  Dabo丶  阅读(68)  评论(0编辑  收藏  举报