一、Dockerfile文件介绍
1.1 什么是Dockerfile
Dockerfile 是构建docker镜像的构建文件,是由一系列命令和参数构成的脚本,即构建镜像的脚本文件。如下为centos的镜像Dockerfile内容:
FROM scratch
ADD centos-8-x86_64.tar.xz /
LABEL org.label-schema.schema-version="1.0" org.label-schema.name="CentOS Base Image" org.label-schema.vendor="CentOS" org.label-schema.license="GPLv2" org.label-schema.build-date="20200809"
CMD ["/bin/bash"]
构建命令:docker build -t 名称:[版本] .
1.2 编写语法
Dockerfile文件中每一行为一条指令;
每条指令由Dockerfile 关键词开头 并跟随至少一个参数;
# 来表示行注释;
Dockerfile文件执行由上往下逐行执行,每条指令都会创建一个镜像层,并对镜像进行提交。
1.3 构建流程
以以上1.1部分的Dockerfile文件为例,有四条语句。执行流程为:
1,使用第一层的镜像 创建一个容器A;
2,使用第二句的命令在第一层的容器A中进行修改,然后将修改后的容器 commit为一个第二层的镜像;再然后运行第二层的新的镜像生成容器B;
3,使用第三句的命令修改第二层的容器B;然后将容器commit为一个第三个镜像;并根据当前层镜像运行出一个容器C;
4,使用第四句的命令在第三层的容器C中修改,然后在把修改后的容器commit为一个新的镜像(最终镜像)。
然后没有下一条语句,流程结束。如下为Dockerfile与Docker镜像和docker容器之间关系
二、Dockerfile文件关键字介绍
FROM 基础镜像,当前镜像是基于那个镜像的。docker 大觉多数的镜像中最基础镜像都是来自scratch
MAINTAINER 镜像维护者的姓名和邮箱。
RUN 容器构建时需要运行的命令
EXPOSE 容器对外暴露的端口。
WORKDIR 创建容器后,默认登录进来的终端目录。
ENV 用来在构建过程中设置的环境变量,定义变量。
ADD 将宿主机目录下的文件在build时拷贝进镜像,并会自动处理URL及解压tar包。
COPY 类似ADD,拷贝文件和目录到镜像中,语法COPY src dest 或COPY ["src","dest"]。
VOLUME 容器数据卷,用于数据保存和数据持久化工作。
CMD 启动一个容器时,需要运行的命令。格式:CMD <命令> ;CMD["可执行文件","参数1","参数2"]
Dockerfile文件中可以有多个CMD指令,但只要最后一个生效,CMD 会被docker run 之后的参数替换掉
ENTEYPONT 指定一个容器启动时要运行的程序。
ENTEYPONT 和 CMD的作业一样 都是指定容器启动时的程序及参数,docker run 后面的参数会追加拼接到 该命令上。
OBBUILD 当构建一个被继承的Dockerfile时运行命令,父镜像在被子镜像继承后触发父镜像的onbuild
CMD与ENTEYPONT 差异测试:
FROM centos
CMD ["ls","-a"]
使用CMD 结尾的Dockerfile 在运行其镜像时 run 末尾跟随的参数会进行覆盖 CMD 后的命令。
通过 ls -lh 完整命令覆盖 CMD中的命令正常执行。通过 -lh 使用则会出错。
FROM centos
ENTRYPOINT ["ls","-a"]
使用ENTRYPOINT结尾的Dockerfile 在运行其镜像时 run 末尾跟随的参数会追加到 ENTRYPOINT 命令后。
使用命令 docker run -it centos_ls:1.1 ls -lh 启动容器后 ,实际在容器中执行的完整命令为 ls -a ls -lh,他会将 第二个ls当做目录来执行 故会报错如下图:
使用命令 docker run -it centos_ls:1.1 -lh 启动容器后 ,实际在容器中执行的完整命令为 ls -a -lh,不会报错。
三、编写Dockerfile文件示例
3.1 自定义centos (编写一个带有vim命令工具的centos,默认的centos镜像没有vim)
#基于centos 镜像创建
FROM centos
#指定作者名称邮箱
MAINTAINER huizi<625322503@qq.com>
#声明变量
ENV MY_WORKDIR /usr/local
#指定工作目录,进入容器时默认的目录
WORKDIR $MY_WORKDIR
#执行安装 vim 工具 -y表示安装过程中全部选是
RUN yum -y install vim
#设置对外暴露的端口 纯提示作用
EXPOSE 80
#打开一个终端
CMD echo $MY_WORKDIR
CMD echo "success---------ok"
CMD /bin/bash
在当前Dockerfile文件目录中执行打包镜像。执行命令:docker build -t centos_vim:1.0 .
执行完成后我们通过 docker images 查看我们打包的镜像。并使用run 运行查看是否正常使用vim命令,以为我们指定的工作目录是否正确。如下都符合我们Dockerfile文件中编写。
通过 docker history 镜像id 可以查看该镜像构建过程中的镜像组成
在上面的Dockerfile文件中我们有9行命令行,所以在查看构建过程中的历史镜像中会有9层镜像。镜像列表我们从下往上看其中missing的为基础镜像centos镜像Dockerfile中的命令。然后第一个镜像 0d120b6ccaa8为我们FROM的 centos 基础镜像id,通过上图蓝色划线可以看到。 然后每层语句都会生成一个镜像,最终的镜像 1a50ff6d9922 为我们打包后的最终镜像id 与 通过 images 查看的一致,如绿色箭头所指。
cmd与entrypoint
3.2 基于centos制作一个自己的tomcat镜像
分析:自定义tomcat需要 tomcat 安装包、jdk环境,centos镜像中不包含jdk和tomcat。所以我们需要在打包镜像时上传 jdk 与tomcat ,上传解压后,配置jdk和tomcat环境变量,最后再暴露端口并启动tomcat。
首先我们创建Dockerfile文件以及jdk与tomcat的安装包存放的目录
然后准备好安装包
接下来创建并编写Dockerfile
#基于centos镜像
FROM centos
#注明作者和邮箱
MAINTAINER huizi<625322503@qq.com>
#声明tomcat工作目录变量
ENV MYPATH /usr/local/tomcat
#创建jdk的安装解压命令
RUN mkdir -p /usr/local/java
#添加tomcat压缩文件到/usr/local目录下
ADD apache-tomcat-7.0.106.tar.gz /usr/local/
#添加jdk到 usr/local目录下
ADD jdk-8u261-linux-x64.tar.gz /usr/local/java
#打印/usr/local目录
RUN ls -lh /usr/local
#修改tomcat目录名称
RUN mv /usr/local/apache-tomcat-7.0.106 /usr/local/tomcat
#设置工作目录
WORKDIR $MYPATH
#配置java和tomcat环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_261
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tool.jar
ENV CATALINA_HOME /usr/local/tomcat
ENV CATALINA_BASE /usr/local/tomcat
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#设置对外暴露的端口
EXPOSE 8080
#打开一个终端 当前目录路径为工作路径
CMD bin/startup.sh && tail -F logs/catalina.out
由于ADD 命令会将tar文件自动解压,所以不需要做解压工作,我们在后续使用操作tomcat和jdk的目录时需要用解压之后的目录名称,不能用原始压缩包名。在Dockerfile 文件结尾与上面自定义centos不同的是,我们后台启动tomcat后 一般使用的 docker run -d -p port:8080 镜像名称:[版本] ,直接后台启动,为了避免启动后没有阻塞线程 如 top、tail 等,容器会立马退出,所以我们在添加启动startup.sh 之后在使用了tail 打印log日志进行保持容器一直处于运行状态。
编写完毕后,进行打包镜像 docker build -t mytomcat:1.0 . 完成后查看打包后镜像
启动容器运行访问tomcat
四、将java jar包打包发布到镜像中
本地打包好jar包后测试无问题上传到我们的新建目录下,并创建Dockerfile文件
编写Dockerfile文件,我们基于openjdk的镜像进行编写。
#基于openjdk的镜像编写
FROM adoptopenjdk/openjdk8
#定于工作目录变量
ENV MYDIR /usr/local/java
#创建目录,如果不存在逐个创建目录层级
RUN mkdir -p $MYDIR
#上传jar包到工作目录下
ADD docker.jar /usr/local/java/
#设置工作目录
WORKDIR $MYDIR
#对外暴露端口
EXPOSE 8080
#执行启动jar包
CMD java -jar docker.jar
打包镜像 : docker build -t hello-docker:1.2 .
运行启动:docker run -d -p 9999:8080 hello-docker:1.2
测试访问 :