Dockerfile
Dockerfile称为:镜像构建文件,用来帮助我们构建一个自定义镜像。
Dockerfile作用
在Docker Hub中官方提供的镜像已经能满足我们的所有服务了,为什么还需要自定义镜像?
日后用户可以将自己应用构建成镜像,这样就可以让我们的应用在容器中运行了。
Dockerfile构建原理
我们需要在宿主机中创建一个空目录。
在该目录中创建名为Dockerfile的镜像构建文件。
当我们执行build指令时,Docker Server就会把build指令之后加载的Dockerfile所在的目录作为本次构建的上下文目录(context)。
宿主机会将上下文目录中所有文件进行打包,发送给Docker Server。(上下文目录中不要放与本次构建无关的文件)
Docker Server接收到打包文件后,根据Dockerfile中的指令逐行进行构建。假设Dockerfile中有三条指令,Docker Server读取第一行指令后,构建第一个镜像层,并将第一个镜像层存入Docker Cache中;Docker Server读取第二行指令后,基于第一个镜像层构建第二个镜像层,并将第二个镜像层存入Docker Cache中;Docker Server读取第三行指令后,基于第二个镜像层构建成最终镜像。最终给我们看到的只有最终镜像这一个镜像。
Docker Server将镜像层存入Docker Cache中的原因是,防止在Docker Server读取指令过程中出错,修改错误后,如果Docker Server继续构建镜像的话,就可以利用Docker Cache中存储的镜像层接着构建,而不需要从第一行指令开始构建了。
也可以设置Docker Server在构建镜像时不借助Docker Cache中缓存的镜像层而是从第一行指令开始构建,只需要在build指令中添加
--no-cache
即可。
Dockerfile保留指令
1. FROM
作用:设置当前镜像基于的哪一个镜像。
意思就是,当我们构建自己的镜像时,不可能重头写。因为Docker是系统层面上的隔离,镜像中必须包含启动、引导操作系统的文件和操作系统内核。所以我们都是基于一个带有启动、引导操作系统的文件和操作系统内核的镜像去构建自己的镜像,比如基于CentOS 7、Alpine构建镜像。
Dockerfile的第一个指令必须是FROM。
因为我们通常构建自定义镜像的对象都是我们做的项目,如果该项目是一个jar包,那么我们需要基于带有JDK的镜像构建;如果该项目是一个war包,那么我们需要基于带有Tomcat的镜像构建,以此类推。
基于的镜像必须在当前宿主机中存在,没有需要去Docker Hub下载。
FROM 基础镜像名:基础镜像版本号
复制代码
例如:
FROM centos:7
复制代码
2. RUN
作用:设置构建镜像时需要运行的指令。
比如说,我基于centos:7这个镜像构建,但是CentOS 7本身没有vim,需要另外安装。由于该镜像是一个裸操作系统,没有进程阻塞,导致我们在宿主机中打不开,手动安装不了vim。所以我们就可以使用RUN命令让centos:7镜像在构建自定义镜像时自动执行指令安装vim。
RUN shell脚本
复制代码
例如:
RUN yum install -y vim
复制代码
如果要运行多个指令,多次使用该命令即可。
3. EXPOSE
作用:设置镜像运行后的容器允许对宿主机暴露哪些端口。
该暴露是指宿主机可以通过某个端口去映射容器暴露的端口。比方说,MySQL在容器内占用的端口为3306,意味着MySQL镜像对宿主机暴露了3306端口,宿主机可以使用 -p
让宿主机内的端口去映射容器内的3306端口,从而实现通信。
EXPOSE 端口号
复制代码
例如:
EXPOSE 8080
复制代码
如果要暴露多个端口,多次使用该命令即可。
4. WORKDIR
作用:设置从宿主机进入容器后的落脚目录。
因为落脚目录可以是绝对路径,也可以是相对路径。
落脚目录如果是绝对路径的话,例如:
WORKDIR /data
复制代码
此时落脚目录是绝对路径 /data
。
落脚目录如果是相对路径的话,可以书写该命令多次,Dockerfile会将所有WORKDIR的相对路径集合到一起构建成一个绝对路径,例如:
WORKDIR /data
WORKDIR my
复制代码
此时落脚目录是绝对路径 /data/my
。
如果落脚目录中有目录不存在,会自动创建。
该指令下的所有相对路径的当前目录都是WORKDIR设置的目录。
该命令可以在Dockerfile中使用多次。
5. ENV
作用:设置镜像的环境变量。
有两个好处,一个可复用,还有就是在允许镜像构建容器时可以给环境变量设置其他值。
ENV key(大写) value
复制代码
还可以写成
ENV key(大写)=value
复制代码
例如:
ENV BASE_DIR /data
ADD a.zip $BASE_DIR
VOLUME $BASE_DIR/tomcat/webapps
复制代码
设置的key建议全部大写。
ENV指令下面如果有指令需要引用ENV设置的环境变量,必须加 “$” 。
6. ADD
作用:将宿主机中的文件拷贝至镜像中,如果该文件是压缩包(tar,zip等),还能先解压缩再拷贝至镜像中。还能给ADD提供一个URL,让其根据URL下载文件之后,再拷贝至镜像中。
和COPY用法相同,但是功能比COPY强大的多。
日后,我们需要构建自己项目的镜像时,往往都需要把jar包或者war包拷贝到上下文目录中。
ADD 文件在宿主机中的地址 拷贝到容器中的地址
复制代码
地址可以时绝路径,也可以时相对路径,相对路径的当前目录为上下文目录。
例如:
ADD a.zip /data/my
复制代码
把存放在上下文目录中的 a.zip
解压后拷贝到容器中的 /data/my
中。前面地址为相对路径,后面地址为绝对路径。
ADD还可以从URL下载文件后直接添加入镜像中。
ADD URL 拷贝到容器中的地址
复制代码
例如:
ADD https://mirrors.bfsu.edu.cn/apache/tomcat/tomcat-8/v8.5.61/bin/apache-tomcat-8.5.61.tar.gz /data/my
复制代码
从URL下载的文件不能解压,如果想要解压,只有在宿主机中解压(wget),然后将解压后的文件添加入镜像中。
该命令可以在Dockerfile中使用多次。
7. COPY
作用:将宿主机中的文件拷贝至镜像中。
COPY 文件在宿主机中的地址 拷贝到容器中的地址
复制代码
地址可以时绝路径,也可以时相对路径,相对路径的当前目录为上下文目录。
例如:
COPY a.txt /data/my
复制代码
把存放在上下文目录中的 a.txt
拷贝到容器中的 /data/my
中。前面地址为相对路径,后面地址为绝对路径。
该命令可以在Dockerfile中使用多次。
8. VOLUME
作用:设置镜像运行后的容器允许被宿主机挂载哪些目录。
假设我们在启动MySQL时,使用 -v
挂载了 /var/lib/mysql
这个目录作为数据卷,就说明了MySQL镜像允许 /var/lib/mysql
路径被挂载到宿主机,否则即使使用 -v
也挂载不了。
VOLUME 容器内可以挂载的路径
复制代码
该路径必须是绝对路径。
例如:
VOLUME /data/tomcat/webapps
复制代码
表示 /data/tomcat/webapps
这个目录运行被宿主机挂载。
9. CMD
作用:设置镜像启动需要执行的shell命令。Dockerfile中可以写N多个CMD指令,但最后只有最后一个生效。
例如Tomcat镜像在启动时,内部就调用了 “startup.sh” 命令。
CMD shell脚本
复制代码
例如:
CMD ls /data
复制代码
表示在该镜像启动时,将容器内 /data
目录中的所有文件打印到控制台。
CMD设置的shell脚本会被 docker run
指令后面追加的shell脚本所覆盖。
例如在Dockerfile设置了CMD的基础上执行:
docker run centos:7 ls /tomcat/data
复制代码
此时运行该镜像,控制台上打印是 ls /tomcat/data
的执行结果。
10. ENRTYPOINT
作用:设置镜像启动需要执行的shell命令。
ENRTYPOINT shell脚本
复制代码
例如:
ENRTYPOINT ls /data
复制代码
表示在该镜像启动时,将容器内 /data
目录中的所有文件打印到控制台。
ENRTYPOINT设置的shell脚本不会被 docker run
指令后面追加的shell脚本所覆盖。
例如在Dockerfile设置了ENRTYPOINT的基础上执行:
docker run centos:7 ls /tomcat/data
复制代码
此时运行该镜像,控制台上打印还是 ls /data
的执行结果。
如果在Dockerfile设置了ENRTYPOINT的基础上还是想覆盖:
docker run --entrypoint=ls centos:7 /tomcat/data
复制代码
此时运行该镜像,控制台上打印就是 ls /tomcat/data
的执行结果了。
11. CMD和ENRTYPOINT配合使用
由上可见,ENRTYPOINT如果想覆盖Dockerfile中原先配置的内容太麻烦了,但是CMD覆盖Dockerfile中原先配置的内容很方便,所以ENRTYPOINT一般和CMD配合使用。
但是ENRTYPOINT和CMD配合使用的前提是必须都是用JSON形式,而不是命令形式。
JSON形式就是将命令中的所有单词以空格分开,然后逐一放入数组中 。
例如:java -jar postilhub.jar ——> [“java”,”-jar”,”postilhub.jar”]
一般在启动时,指令不会变,但是传递的参数会有变化。
比如说我就要在容器启动时查看某一个目录的列表,但是我每一次启动查看的目录都不一样。所以查看这个指令不变,哪一个目录我们当作参数传递进来。
我们在Dockerfile中配置:
ENRTYPOINT ["ls","/data"]
CMD ["/tomcat/data"]
复制代码
ENRTYPOINT设置指令(ls
),并给参数一个默认值(/data
),CMD设置动态参数(/tomcat/data
)
不穿参数运行:
docker run centos:7
复制代码
那么会执行两条命令:ls /data
,ls /tomcat/data
传参数运行:
docker run centos:7 /mysql/data
复制代码
那么会执行两条命令:ls /data
,ls /mysql/data
,将原先CMD设置的ls /tomcat/data
覆盖掉了。
如果不想每次运行时都执行 ls /data
,完全按照CMD设置的运行,那么修改Dockerfile:
ENRTYPOINT ["ls"]
CMD ["/tomcat/data"]
复制代码
docker build命令
在Dockerfile设置完毕后,需要使用docker build来根据Dockerfile的设置打包成自定义镜像。
docker build -t 自定义镜像名:自定义镜像版本号 context目录的相对路径
复制代码
如果自定义镜像名和自定义镜像版本号和宿主机中另一个镜像完全一样,则会覆盖。
Dockerfile构建SpringBoot项目
-
打包项目(本文以jar包为例)
-
在宿主机中创建context目录
mkdir demo 复制代码
-
进入context目录创建Dockerfile
cd demo touch Dockerfile 复制代码
-
上传项目jar包到context目录
-
去Docker Hub查找JDK基础镜像
docker pull openjdk:8-jdk 复制代码
当前Oracle提供的开源免费的JDK就是open-jdk,如果使用oracle-jdk是需要付费的。
-
编辑Dockerfile
vim Dockerfile 复制代码
FROM openjdk:8-jdk // 基于JDK8的镜像 WORKDIR /app // 设置落脚目录为/app ADD xxx.jar app.jar // 将xxx.jar拷贝到镜像中/app下,并且重命名为app.jar EXPOSE 8080 // 默认SpringBoot中Application.yml中server.port=8080 ENTRYPOINT ["java","-jar"] CMD ["app.jar"] 复制代码
-
执行构建
假设容器名为demo,容器版本为:01。
docker build -t demo:01 复制代码
-
运行镜像
假设容器映射宿主机端口:8080。
docker run -d -p 8080:8080 --name demo:01 复制代码
IDEA安装Docker插件
-
在 File ——> Settings ——> Plugins 中搜索Docker。
新版IDEA默认绑定Docker插件,无需下载。
-
创建Dockerfile文件
写入Dockerfile命令时就会有提示了。
-
进入 Tools ——> Deployment ——> Configuration
-
填入服务器名,
一般使用宿主机IP来标识服务器。
-
选择SSH连接的服务器
-
设置SSH连接参数
-
进入 Tools ——> Deployment ——> Browse Remote Host
显示远程宿主机文件系统操作界面。
-
在宿主机中创建context目录
-
在context目录中创建Dockerfile
-
编辑Dockerfile内容
-
更新Dockerfile内容
-
直接将项目打包生成的jar包拖入context文件夹
-
在Shell处执行docker build命令即可完成镜像构建
如果在build过程中出现错误,可以在IDEA中直接修改Dockerfile的内容,然后更新,再docker build即可。