目录
1、Dockerfile简介
2、Dockerfile编写注意项
3、 Dockerfile文件中的 指令
3.1、FROM(指定基础镜像)
3.2、MAINTAINER(用来指定镜像创建者信息)
3.3、LABEL(设定一些元数据)
3.4、ADD(将本地文件添加到镜像中)
3.5、COPY(将文件复制到所做镜像的文件系统中)
3.6、WORKDIR(切换目录,类似于cd命令 )
3.7、VOLUME(指定持久化目录)
3.8、EXPOSE(指定与外界交互的端口)
3.9、ENV(设置环境变量)
3.10、RUN(构建镜像时执行的命令)
3.11、CMD(容器启动以后要默认运行的程序)
3.12、ENTRYPOINT(配置容器,使其可执行化)
3.13、 ARG(指定传递给构建镜像时的变量)
3.13.1、Dockerfile中ENV 和 ARG的区别
3.14、USER(指定运行容器时的用户名和UID)
3.15、HEALTHCHECK(检查docker容器是否正常)
3.16、SHELL(指定系统中默认的shell类型)
3.17、STOPSIGNAL
3.18、ONBULID(用于设置镜像触发器)
4、Dokcerfile完整演示创建nginx镜像
镜像的定制,实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么哪些无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
Dockerfile的指令根据作用可以分为两种:构建指令和设置指令。
构建指令用于构建image,其指定的操作不会在运行image的容器上执行;
设置指令用于设置image的属性,其指定的操作将在运行image的容器中执行。
- # 为 Dockerfile 中的注释。
- 指令参数,指令的大小写不敏感。
- 第一个非注释行必须是FROM指令。
- 编写Dockerfile必须在一个目录下进行,这个目录称之为 工作目录(WORKSPACE)。
- Dockerfile文件命令的首字母必须大写。
- 制作镜像所要用的文件必须放在工作目录或者工作目录的子目录之下,不能放在父目录。
- 可以通过隐藏文件 .dockeringnore 来指定不要放入到镜像中的文件,一行是一个文件,可以用通配符。
- 基于dockerfile做镜像,本质上还是基于一个现有的镜像做新镜像。
指定基础镜像,必须为第一个命令。
构建指令。必须指定且需要在Dockerfile其他指令的前面。后续的指令都依赖于该指令指定的image。FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库的tag版本。
格式: FROM
FROM : FROM @ 示例: FROM mysql:5.6 注: tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像。
构建指令,用于将image的制作者相关的信息写入到image中。当我们对该image执行docker inspect命令时,输出中有相应的字段记录该信息。
MAINTAINER
已经过时,在新版本已不推荐使用,如果允许的尽可能使用LABEL
完成元数据设置。
格式: MAINTAINER
示例: MAINTAINER Jasper Xu MAINTAINER [email protected] MAINTAINER Jasper Xu
LABEL
为镜像增加元数据,一个LABEL
是键值对,多个键值对之间使用空格分开,命令换行时是使用反斜杠 \
。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
基础镜像或父镜像中包含的元数据由当前镜像继承。如果元数据已经存在,但具有不同的值,则最近应用的值将覆盖以前设置的任何值。
格式: LABEL= = = ... 示例: LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget。
格式: ADD... ADD [" ",... " "] 用于支持包含空格的路径 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url; 是container中的绝对路径。 所有拷贝到container中的文件和文件夹权限为755,uid和gid为0; 如果是一个目录,那么会将该目录下的所有文件添加到container中,不包括目录; 如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式); 如果 是文件且 ; 如果中不使用斜杠结束,则会将 视为文件, 的内容会写入 是文件且 中使用斜杠结束,则会 文件拷贝到 目录下。 示例: ADD hom* /mydir/ # 添加所有以"hom"开头的文件 ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt" ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/ ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/
功能类似ADD,但是是不会自动解压文件,也不能访问网络资源。
格式:
复制单个文件:COPY
复制多个文件:COPY [
… ] 示例:
COPY passwd /data/
注意:
格式: WORKDIR /path/to/workdir (容器目录) 示例: WORKDIR /a (这时工作目录为/a) WORKDIR b (这时工作目录为/a/b) WORKDIR c (这时工作目录为/a/b/c) WORKDIR /p1 WORKDIR p2 RUN vim a.txt
注:
docker run
运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。可以多次切换(相当于cd命令)。
使容器中的目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。
我们容器使用AUFS时,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。容器使用OverlayFS时(Overlay是Linux内核3.18后支持的,也是一种Union FS,和AUFS的多层不同的是Overlay只有两层:一个upper文件系统和一个lower文件系统,分别代表Docker的镜像层和容器层。当需要修改一个文件时,使用CoW将文件从只读的lower复制到可写的upper进行修改,结果也保存在upper层。在Docker中,底下的只读层就是image,可写层就是Container。目前最新的OverlayFS为Overlay2。),当容器删除后,所有的更改都会丢失。所以当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。
格式:
VOLUME ["/path/to/dir"] (容器目录)
示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
注:
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
设置Docker容器内部暴露的端口号,如果需要外部访问,还需要启动容器时增加-p或者-P参数进行分配。
格式: EXPOSE[ ...] 示例: EXPOSE 80 443 # 暴露多个端口; EXPOSE 8080 EXPOSE 11211/tcp 11211/udp
注: EXPOSE 仅仅是暴露一个端口,一个标识,在没有定义任何端口映射时,外部是无法访问到容器提供的服务。而端口映射(-p)是 docker 比较重要的一个功能,原因在于我们每次运行容器的时候容器的IP地址不能指定,而是在桥接网卡的地址范围内随机生成的。宿主机器的IP地址是固定的,我们可以将容器的端口的映射到宿主机器上的一个端口,免去每次访问容器中的某个服务时都要查看容器的IP的地址。对于一个运行的容器,可以使用 docker port 加上容器ID 和 EXPOSE 暴露的端口来查看该端口号在宿主机器上的映射端口。如下所示:
运行容器的命令:
# 如果想代理 EXPOSE 端口, 相应的运行容器使用的命令
# 此时,端口被随机映射到宿主机
docker run -p 8001 image# 可以指定映射到宿主机的端口
docker run -p 8002:8001 image
格式: #之后的所有内容均会被视为其 的组成部分,因此,一次只能设置一个变量 ENV <key> #可以设置多个变量,每个变量为一个" = "的键值对,如果 中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行。 ENV = ... 示例: ENV myName John Doe ENV myDog Rex The Dog ENV myCat=fluffy ENV pkgname=nginx-1.14.0.tar.gz root=/data/mysql/mysql3306/data
注意:
通过ENV所定义的变量是可以传递到容器之中,但是,在创建容器的时候,如果手动指定了变量的值,那么这个值会覆盖掉镜像中原有的值。
作用:基于镜像构建容器时候要执行命令。
RUN 会在现有的基础上新添一层layer,创建一个新的image。(一般用来安装软件包)
RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:
shell执行
格式: RUN
# 运行可执行文件
格式: RUN ["executable", "param1", "param2"]
示例:
RUN apk update
RUN ["/etc/execfile", "arg1", "arg2"]
注: RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache
作用:定义容器启动以后要默认运行的程序,pid为1的程序。
格式: CMD ["executable","param1","param2"] (执行可执行文件,优先) CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数) CMD command param1 param2 (执行shell内部命令) 示例: CMD echo "This is a test." | wc - CMD ["/usr/bin/wc","--help"]
注:CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
作用:定义容器启动以后要默认运行的程序,pid为1的程序。
配合CMD可省去"application",只使用参数。
注意:
在运行RUN的时候所执行的命令无法覆盖ENTRYPOINT中的命令。
RUN 后面的命令会被以参数的方式追加到原本要执行的命令的末尾,而不是替换。
基于一个镜像,在创建容器的时候,通过传递不同的参数实现创建不同的容器。
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。
格式: ENTRYPOINT ["执行命令", "参数1", "参数2"] (可执行文件, 优先) ENTRYPOINT command 参数1 参数2 (shell内部命令) 示例: ENTRYPOINT [ "curl", "-s", "http://10.220.5.138" ] 注: ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
例如:CMD和ENTRYPOINT的结合
FROM nginx
label auther=ken
ARG name=ken
ENV path=/ken/
COPY test /data/
ADD https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/audiocd-kio-devel-4.10.5-3.el7.i686.rpm $path
WORKDIR $path
RUN mkdir $name
VOLUME $path
EXPOSE 80
RUN mkdir /test1
CMD ["-g","daemon off;"]
ENTRYPOINT ["nginx"]
作用:定义变量,这个变量是用在第一阶段(构建镜像——build)
格式:
ARG 变量名=变量值示例:
ARG name=ken
在指定docker build 过程中传参数,要用ARG;
在执行docker run的过程中传参数,要用ENV;
ARG构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是, ARG 所设置的是构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。
指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用 用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户。
格式:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group示例:
USER www注:
使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
作用:docker daemon检查docker容器是否正常,如果异常会将该容器stop。
将容器stop的条件
1)主进程停止了。
2)主进程工作在了后台。
格式:
HEALTHCHECK [options] CMD
options
–interval=#s|m 指定健康检查的时间间隔(例如:30s,30m)
–timeout=#s|m 指定等待响应的超时时间
–start-period=#s|m 指定容器启动多久以后才可以做监控检查
–retries=# 指定重试次数
返回值
0:success
1:unhealth
HEALTHCHECK示例:
HEALTHCHECK --interval=5m --timeout=1s --retries=3 CMD curl http://10.220.5.138/ken.html || exit 1
可以用来指定系统中默认的shell类型。
格式:
SHELL [“/bin/sh”, “-c”] (linux系统中)
SHELL示例:
SHELL ["/bin/sh","-c"]
向容器中pid为1的进程发送一个信号,通过这个信号来关闭这个主进程。默认是15信号。
格式:
STOPSIGNAL 数值
STOPSIGNAL示例:
STOPSIGNAL 9
作用:定义一个触发器,指定的命令在构建镜像时并不执行,用来实现当基于这个这个镜像做新镜像的时候要执行的命令。
格式: ONBUILD 其他指令 示例: ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src 注: 当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发。
FROM docker.io/nginx:latest
LABEL author "lys"
COPY ./passwd /data/
WORKDIR /pack/nginx/
ENV pkgname=nginx-1.14.0.tar.gz root=/data/mysql/mysql3306/data/
COPY nginx-1.14.0.tar.gz $root
VOLUME $root
EXPOSE 80/tcp
RUN tar xf $root$pkgname
CMD nginx -g "daemon off;"
build:是指根据dockerfile制作镜像
-t:指定一个tag标签
.:表示上下文。你也可以理解为dockfile所在的目录,但是并不是准确的。
如果下方出现successfully就表示镜像已经构建成功了
[root@localhost lys]# docker build -t lys:v1.0 .
Sending build context to Docker daemon 1.019MB
Step 1/10 : FROM docker.io/nginx:latest
---> d1a364dc548d
Step 2/10 : LABEL author "lys"
---> Using cache
---> 2ffd54ac6e08
Step 3/10 : COPY ./passwd /data/
---> a41c70cd7c9a
Step 4/10 : WORKDIR /pack/nginx/
---> Running in 935c76237194
Removing intermediate container 935c76237194
---> 0f4342766cc0
Step 5/10 : ENV pkgname=nginx-1.14.0.tar.gz root=/data/mysql/mysql3306/data/
---> Running in 302b61253868
Removing intermediate container 302b61253868
---> bf018e71c8f3
Step 6/10 : COPY nginx-1.14.0.tar.gz $root
---> c1d411d47551
Step 7/10 : VOLUME $root
---> Running in 9d4709eb00fa
Removing intermediate container 9d4709eb00fa
---> d80f86757545
Step 8/10 : EXPOSE 80/tcp
---> Running in dad02c434aab
Removing intermediate container dad02c434aab
---> e4488ab2b88b
Step 9/10 : RUN tar xf $root$pkgname
---> Running in 326b801420f0
Removing intermediate container 326b801420f0
---> 817c07e27adf
Step 10/10 : CMD nginx -g "daemon off;"
---> Running in 9f11bd563d17
Removing intermediate container 9f11bd563d17
---> 9b1b4112e98a
Successfully built 9b1b4112e98a
Successfully tagged lys:v1.0
可以发现构建的名为lys标签为v1.0的镜像已经存在了.
[root@localhost lys]# docker image ls lys
REPOSITORY TAG IMAGE ID CREATED SIZE
lys v1.0 9b1b4112e98a 3 minutes ago 140MB
可以发现基于我们刚才的创建的镜像的容器已经顺利跑起来了。
[root@localhost lys]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@localhost lys]# docker run -d --name lysv1.0 lys:v1.0
fb09b0225bba10297dbae886a3c09eb1d439743e56166dd65945cd8c0cdb7ffa
[root@localhost lys]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fb09b0225bba lys:v1.0 "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 80/tcp lysv1.0
可以发现我们这个启动的容器里面已经有我们指定的工作目录
复制过来的passwd文件
已经下载并传送到/data下了。
[root@localhost lys]# docker exec -it lysv1.0 bash
root@fb09b0225bba:/pack/nginx# ls
nginx-1.14.0
root@fb09b0225bba:/pack/nginx# ls /data
mysql
root@fb09b0225bba:/pack/nginx# ls /data/mysql/mysql3306/data/nginx-1.14.0.tar.gz
/data/mysql/mysql3306/data/nginx-1.14.0.tar.gz