描述
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像。
Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
具体命令
1. FROM 指定基础镜像
定制每一个镜像都必须指定基础镜像,每一个修改命令的修改都是在这个基础镜像上改动。FROM 必须是第一条指令。
FROM tomcat
有时候定制的镜像可能不需要依赖于其他镜像。可以使用scratch
这个镜像,表示一个空镜像
2. RUN 执行指令
RUN
分成两种格式,一种是shell 格式,一种是exec 格式
RUN <命令>
RUN ["可执行文件","参数1","参数2"]`
每一个RUN 指令就代表构建容器的一层,为了减少容器的臃肿,尽量使用&& 连接符来减少RUN的指令。
3. 将上下文文件复制到容器
docker文件复制命令有两个 COPY
和 ADD
。推荐使用COPY。
- COPY
COPY
将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。
COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
源路径可以是多个,也可以是一个通配符。
目标路径可以是一个绝对路径,也可以是一个相对于工作目录的相对路径。如果目标路径不存在会自动创建。
复制的文件,其中的元数据均会被保存,比如文件日期,大小等信息。可以使用--chown=<user>:<group>
来改变所属用户和组。
- ADD
ADD --chown=55:mygroup files* /mydir/
ADD
是一个比较高级的指令,是在COPY基础上新加了一些功能。
比如源路径是一个URL,ADD会自动去下载,并且设置文件权限为600。
如果源文件是一个压缩包,还会自动解压。
其实就是帮我们自动做了设置权限和自动解压工作,减少了一个RUN指令。
4. CMD 容器启动命令
容器就是一个进程,既然是一个进程,那就需要一个启动命令。比如想运行一个jar程序,需要Java -jar。CMD就是指定这样的启动命令的指令。若有多个CMD命令,则最后一个生效。
CMD <命令>
CMD ["可执行文件", "参数1", "参数2"...]
CMD指令可以在运行时被替换。比如ubuntu 默认指令是/bin/bash。可以这样替换掉默认命令docker run -it ubuntu cat /etc/os-release
5. 设置环境参数
EVN
和ARG
都可以设置环境参数,其后面的指令都可以应用这些参数。他们不同点就是ARG设置的环境变量,在容器运行时是不会保存的。
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
ARG <参数名>[=<默认值>]
6. EXPOSE 暴露端口
EXPOSE <端口1> [<端口2>...]
EXPOSE 只是声明端口而已,启动容器的时候并不会启用这些端口。
好处一时告诉使用者这个镜像的守护端口。好处二是在使用随机映射的时候会使用这里声明的端口,docker run -P
时,会自动随机映射 EXPOSE 的端口。
7. WORKDIR指定工作目录
WORKDIR <工作目录路径>
WORKDIR 指定工作目录之后,之后的指令都当前目录就是WORKDIR指定的目录。如果指定的目录不存在则会先创建。
RUN cd /app
RUN echo "hello" > world.txt
-------------WORKDIR使用
WORKDIR /app
RUN echo "hello" > world.txt
8. USER 指定用户
USER <用户名>[:<用户组>]
之后的命令都会以指定的用户执行。用户必须先创建好。
9. LABEL 为镜像添加元数据
LABEL <key>=<value> <key>=<value> <key>=<value> ...
10. VOLUME 定义数据挂载
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
VOLUME 可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
例如:VOLUME /data
,任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。也可以运行是进行一个覆盖docker run -d -v mydata:/data xxxx
例子
docker build [选项] <上下文路径/URL/->
在build之前,需要理解下上下文路径是什么。Docker是C/S模型,客户端发送指令给服务端,由服务端来执行相关操作。所以,当我们发送build指令的时候,实际上是由服务端来进行build的。那么build的时候,服务端所需要的文件是怎么获取呢?客户端执行build的时候,会把上下文目录所有内容都打包给服务端,服务端获取到这个目录之后就可以拿到所需要的文件。
通常会发现build 最后一个参数是 .
,这是代表当前目录的意思。如果不指定Dockerfile位置,会将上下文目录下的名为 Dockerfile 的文件作为 Dockerfile。可以使用-f
指定dockerfile。
一般来说,应该会将 Dockerfile 置于一个空目录下,或者项目根目录下。如果有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个 .dockerignore,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。
将一个spring boot项目通过dockerfile来构建container
- 构建一个简单的spring boot项目
@RestController
public class TestController {
@GetMapping("/hello")
public String sayHello(){
return "hello docker";
}
}
- 新建一个目录,将jar包放到当前目录下
- 在当前目录下新建一个dockerfile文件
FROM openjdk:8
MAINTAINER chihay
LABLE name="dockerfile-demo" version="V1.0" author="chihay"
COPY docker-demo-0.0.1-SNAPSHOT.jar docker-image.jar
CME ["java","-jar","docker-image.jar"]
- 创建镜像
- 使用镜像