今日内容概述
Dockerfile构建镜像
今日内容详细
Dockerfile构建镜像
Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。一般来说,Dockerfile主体内容分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行的指令。
Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。一个声明以#字符开头则被视为注释。可以在Docker文件中使用RUN,CMD,FROM,EXPOSE,ENV等指令。
下面我们来看看具体的指令
FROM:指定基础镜像,必须为第一个命令
FROM 指定基础镜像,目的是为了给构建镜像提供一个基础环境
# 格式:
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
示例: FROM mysql:5.7
注: tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
MAINTAINER::维护者信息
指定维护者信息 # 没什么好说的
RUN:构建镜像时执行的命令
基于FROM指定的docker镜像运行一个指令,将结果反映到新生成的镜像。RUN指令后面执行的命令必须是镜像中已经存在了的命令。
# RUN有两种命令执行的方式
shell执行:
格式:
RUN <command>
exec执行
格式:
RUN ["executable", "param1", "param2"]
示例:
RUN ["executable", "param1", "param2"]
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]
注: RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache
CMD:构建容器后调用(在容器启动时才进行调用)
CMD指令用于指定一个容器启动时要运行的命令,这有点类似于RUN指令,只是RUN指令是指定镜像被构建时要运行的命令;而CMD是指定容器被启动时要运行的命令。这和使用docker run 命令时指定要运行的命令非常类似
# CDM可以为要运行的命令指定参数
CMD ["/bin/bash,"-l"] 这里将-l标志传递给了/bin/bash命令
CMD指令也有两种格式:
exec格式
["nginx", "-g", "daemon off;"]
shell格式
nginx -g 'daemon off;'
# 需要注意的是,要运行的命令是存放在一个数组结构中的,这将告诉Docker按指定的样子来运行该命令,当然也可以不使用数组指定CMD指令,这时候Docker会在指定的命令前加上/bin/sh -c。这在执行该命令的时候可能会导致意料之外的行为,所以Docker推荐使用数组语法来设置要执行的命令。
最后一点,使用docker run 命令可以覆盖CMD指令,如果我们在Dockerfile里指定了CMD指令,而同时在docker run 命令中也指定了要运行的命令,命令行中指定的命令会覆盖Dockerfile中的CMD指令。
在Dockerfile中只能指定一条CMD指令,如果指定了多条CMD指令,也只有最后一条CMD指令会被使用。
ENTRYPOINT
ENTRYPOINT指令与CMD指令非常类似,也很容易和CMD指令弄混,它们有什么区别呢?
我们已经知道,docker run 命令行会覆盖CMD指令,但有时我们希望容器按我们希望的方式去工作,那么CMD就不够合适。
而ENTRYPOINT指令提供的命令不容易在启动容器时被覆盖,实际上docker run 命令行中指定的任何参数都会被当做参数再次传递给ENTRYPOINT指令中指定的命令。
例子:
ENTRYPOINT ["/usr/sbin/nginx"]
类似于CMD指令,我们也可以在该指令中通过数组的方式为命令行指定相应的参数
ENTRYPOINT ["/usr/sbin/nginx,"-g","daemon off;"]
# 如果ENTRYPOINT和CMD指令同时存在,则CMD的相关内容会被设置成ENTRYPOINT的参数
ADD和COPY
ADD : 将本地文件添加到镜像
ADD支持自动解压,但是仅仅支持解压tar包
ADD支持远程下载,但是不会解压网络资源
示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件
ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"
ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/
# ADD指令会使得构建缓存变得无效,这一点非常重要,如果通过ADD指令向镜像添加一个文件过目录,那么将使Dockerfile中的后续指令都不能继续使用之间的构建缓存。
COPY : 将文件复制到镜像
语法:COPY < src>… < dest>|[“< src>”,… “< dest>”]
指令逻辑与ADD十分相似,同样Docker Daemon会从编译目录寻找文件或目录,dest为镜像中的绝对路径或者相对于WORKDIR的路径
WORKDIR
WORKDIR用来从镜像创建一个新容器时,在容器内部设置一个工作目录,ENTRYPOINT或/CMD指定的程序会在这个目录下执行
我们可以使用该指令为Dockerfile中后续到的一系列指令设置工作目录,也可以为最终的容器设置工作目录
实例:
WORKDIR /opt/webapp/db
RUN bundle install
WORKDIR /opt/webapp
ENTRYPOINT ["rackup"]
# 这里我们将工作目录切换为/opt/webapp/db后运行了bundle install命令,之后又将工作目录设置为/opt/webapp,最后设置了ENTRYPOINT指令来启动rackup命令
可以通过-w标志在运行时覆盖工作目录
docker run -it -w /var/log ubuntu pwd /var/log
该命令会将容器内的工作目录设置为/var/log
ENV:设置环境变量
设置一个容器的环境变量
格式:
ENV <key> <value> #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
ENV <key>=<value> ... #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
示例:
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat=fluffy
新的环境变量可以在后续的任何RUN指令中使用;也可以使用docker run 命令行的-e参数来传递变量,这些变量只会在运行时有效。
USER
USER指令用来指定该镜像会以什么样的用户去运行
示例:
USER www
基于该镜像启动的容器会以www用户的身份来运行,我们可以指定用户名或UID以及组或GID,甚至是两者的组合
USER www
USER www:group
USER www:gid
我们也可以在docker run 命令中通过-u选项来覆盖该指令指定的值
# 如果不通过USER指令指定用户,默认用户为root
VOLUME:用于持久化目录
VOLUME指令用来向基于镜像创建的容器添加卷,一个卷是可以存在与一个或者多个容器内的特定的目录,这个目录可以绕过联合文件系统,并提供如下共享数据或者对数据进行持久化的功能。
1.卷可以在容器内共享和复用
2.一个容器可以不是必须和其他容器共享卷
3.对卷的修改不会对更新镜像产生影响
4.卷会一直保存直到没有任何容器再使用它。
卷功能让我们可以将数据(代码)、数据库或者其他内容添加到镜像中而不是将这些内容提交到镜像中,并且允许我们在多个容器间共享这些内容。
格式:
VOLUME ["/path/to/dir"]
示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ARG:用于指定传递给构建运行时的变量
格式:
ARG <name>[=<default value>]
示例:
ARG site
ARG build_user=www
ONBUILD:用于设置镜像触发器
ONBUILD指令能为镜像添加触发器(triggger),当一个镜像被用作其他镜像的基础镜像时,该镜像中的触发器将会被执行。
触发器会在构建过程中插入新的指令,我们可以认为这些指令是紧跟在FROM之后指定的,触发器可以是任何构建指令。
# 触发器,ONBUILD后面跟指令,在构建时不会执行,只有在当前镜像作为基础镜像构建时才会执行。
格式: ONBUILD [INSTRUCTION]
示例:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
EXPOSE:指定于外界交互的端口
格式:
EXPOSE <port> [<port>...]
示例:
EXPOSE 80 443
EXPOSE 8080
EXPOSE 11211/tcp 11211/udp
注:
EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出所有的端口
LABEL:用于为镜像添加元数据
格式:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
注:
使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
构建镜像
1.Dockerfile
Dockerfile命名必须D大写其他必须小写
Dockerfile中所有的指令必须大写
2.构建镜像的命令
docker build -t 镜像名称
参数:
-t : 指定构建镜像的名称