Dockerfile 是用于构建 Docker 镜像的脚本文件,由一系列指令构成。通过 docker build 命令构建镜像时,Dockerfile 中的指令由上到下依次执行,每条命令都将会构建出一个镜像。这就是镜像分层。因此,指令越多,层次就越多,创建的镜像就越多,效率就越低。所以在定义 Dockerfile 时,能在一个指令完成的动作就不要分为两条。
- 指令时大小写不敏感的,但是规范时全大写
- 指令后至少携带一个参数
- # 号开头的行是注释
FROM
语法:FROM <image>[:<tag>]
解析:用于指定基础镜像,且必须是第一条指令,若省略了 tag,则默认为 latest。
MAINTAINER
语法:MAINTAINER <name>
解析:MAINTAINER 指令的参数一般是维护者姓名和邮箱。不过,该指令官方已不建议使用,而是使用 LABEL 指令代替。
LABEL
语法:LABEL <key>=<value> <key>=<value>…
解析:LABEL 指令中可以键值对的方式包含任意镜像的元数据信息,用于代替 MAINTAINER 指令。通过 docker inspect 可以查看到 LABEL 与 MAINTAINER 的内容。
ENV
语法:ENV <key> <value>
解析:用于指定环境变量,这些环境变量,后续可以被 RUN 指令使用,容器运行起来之后,也可以在容器中获得这些环境变量。
语法2:ENV <key1>=<value1> <key2>=<value2> …
解析:可以设置多个变量,每个变量为一对<key>=<value>指定。
WORKDIR
语法:WORKDIR path
解析:容器打开后默认进入的目录,一般在后续的 RUN、CMD、ENTRYPOINT、ADD 等指令中会引用该目录。可以设置多个 WORKDIR 指令。后续 WORKDIR 指令若用的是相对路径,则会基于之前 WORKDIR 指定的路径。在使用 docker run 运行容器时,可以通过 -w 参数覆盖构建时所设置的工作目录。
RUN
语法1:RUN <command>
解析:这里的 <command> 就是 shell 命令。docker build 执行过程中,会使用 shell 运行指定的 command。
语法2:RUN [“EXECUTABLE”, “PARAM1”, “PARAM2”, …]
解析:在 docker build 执行过程中,会调用一个参数 “EXECUTABLE” 指定应用程序运行,并使用后面第二、第三参数作为应用程序的运行参数。
CMD
语法1:CMD [“EXECUTABLE”, “PARAM1”, “PARAM2”, …]
解析:在容器启动后,即在执行完 docker run 后立即调用执行 “EXECUTABLE” 指定的可执行文件,并使用后面第二、三等参数哦作为应用程序的运行参数。
语法2:CMD command param1 param2 …
解析:这里的 command 就是 shell 命令。在容器启动后会立即运行指定的 shell 命令。
语法3:CMD [“PARAM1”, “PARAM2”, …]
解析:提供给 ENTERPOINT 的默认参数。
ENTRYPOINT
语法1:ENTRYPOINT [“EXECUTABLE”, “PARAM1”, “PARAM2”, …]
解析:在容器启动过程中,即在执行 docker run 时,会调用执行 “EXECUTABLE” 指定的应用程序,并使用后面第二、三等参数作为应用程序的运行参数。
语法2:ENTRYPOINT command param1 param2 …
解析:这里的 command 就是 shell 命令。在容器启动过程中,即执行 docker run 时,会运行指定 shell 命令。
EXPOSE
语法:EXPOSE <port> [<port>…]
解析:指定容器准备对外暴露的端口号,但该端口号并不会真正的对外暴露。若要真正暴露,则需要在执行 docker run 命令时使用 -p 来指定说要真正暴露的端口号。
ARG
语法:ARG <varname>[=<default value>]
解析:定义一个变量,该变量将会使用于镜像构建运行时。若要定义多个变量,则需要定义多个 ARG 指令。
ADD
语法1:ADD <src> <dest>
语法2:ADD [“<src>”, “<dest>”] # 路径中存在空格时需要用双引号引起来
解析:该指令将复制到当前宿主机中指定文件 src 到容器中指定目录 dest 中。src 可以时宿主机中的绝对路径,也可以是相对路径。但相对路径时相对于 docker build 命令所指定的路径。src 指定的文件可以时一个压缩文件,压缩文件复制到容器后会自动解压为目录。src 也可以是一个 URL,此时 ADD 指令相当于 wget 命令。src 最好不要是目录,其会将该目录中所有内容复制到容器的指定目录中。dest 是一个绝对路径,其最后面的路径必须要加上斜杠,否则系统会将最后的目录名称当作是文件名的。
COPY
说明:功能与 ADD 指令相同,只不过 src 不能是 URL。若 src 为压缩文件,复制到到容器后不会自动解压。
ONBUILD
语法:onBUILD [INSTRUCTION]
解析:该指令用于指定当前镜像的子镜像进行构建时要执行的指令。
VOLUME
语法:VOLUME [“dir1”, “dir2”, …]
解析:在容器创建可以挂载的数据卷。
使用 docker build 命令构建镜像
docker build [OPTIONS] PATH | URL | -
- -t 用于要生成镜像的 <repository>与<tag>。若省略 tag,则默认为 latest。
- 最后的 点(.)是宿主机的 URL 路径,构建镜像时会从该路径中查找 Dockerfile 文件。同时该路径也是在 Dockerfile 中 ADD、COPY 指令中若使用的相对路径,那个相对路径就相对这个路径。不过需要注意,即使 ADD、COPY 指令中使用绝对路径指定源文件,该源文件所在路径也必须要在这个 URL 指定目录或子目录内,否则将无法找到该文件
- -f 用于指定本次构建所要使用的 Dockerfile 文件。如果文件名不是 docker build 默认加载的 Dockerfile 这个文件名。
自己的 hello world 程序镜像
首先到docker hub上查看我们原先测试docker是否安装成功的 hello world 镜像的Dockerfile,我们先简单模仿这个镜像来写一个我们自己的。
上面就是 hello-world 镜像的Dockerfile
其中 FROM 指令前面介绍过了,时指定一个基础镜像。这里的 scratch 就是一个基础镜像,它是一个空镜像,是所有镜像的 base Image (相当于面向对象编程中的 Object类)scratch 镜像只能在 Dockerfile 中被继承,不能通过 pull 命令拉取,不能 run,也没有 tag。并且它也不会生成镜像中的文件系统层。在 Docker 中,scratch 是一个保留字,用户不能作为自己的镜像名称使用。
首先,我们先在Linux系统下安装 gcc 相关编译器,用于编译 c 语言代码(仅作为本次实验,后续不会用到 c 语言相关带代码)
安装完成后,创建一个 hello.c 的文件,并写入如下内容:
编写完成后,编译 hello.c 文件
在该目录下创建 Dockerfile 文件。内容如下:
执行 docker build 命令来构建我们自己的 hello-world
运行这个构建好的镜像查看结果,会发现,与我们自己所编写的输出格式一致。成功的构建了第一个镜像。
实际Java web项目构建镜像
构建目标:使用 centos:7 镜像作为基础镜像运行一个 Java web 项目,并成功运行以及可以请求其接口。
-
创建项目
创建完成后,pom文件中注释掉下面这句(<skip>true</skip> 如果不注释,编译为jar后运行会报错,找不到主类)
修改 application.yaml 文件,设置端口为 8080
添加 controller 并编写一个简单的接口并启动测试
-
所需文件整理
测试完成后,使用 maven 打包为jar,将打包后的jar文件复制另一个目录(这里是我个人习惯,为了区分每次构建的东西,所以专门建立了一个DockerSpaces的目录,下面是每次所要构建具体镜像的目录)
将所需要的 jdk-1.8 也拷贝到该目录下(jdk是Oracle官网下载的)
-
编写Dockerfile
在下面建立 Dockerfile 文件。内容如下:
-
构建并启动容器
构建为镜像并查看
查看log日志
同样,访问该接口也是没有问题的