一文详解Dockerfile自定义镜像

简介: 一文详解Dockerfile自定义镜像

镜像概念

镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包组成。

镜像是分层结构,每一层称为一个Layer:

  • BaseImage: 包含基本的系统函数库、环境变量、文件系统等
  • Entrypoint: 入口,是镜像中应用启动的命令
  • 其他:在BaseImage 基础上添加依赖、安装程序、完成整个应用的安装和配置

镜像就是在系统函数库、运行环境基础上,添加应用程序文件、配置文件、依赖文件等组合,然后编写好启动脚本打包在一起形成的文件。

Dockerfile概念

  • Dockerfile使用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
  • Dockerfile是自定义镜像的一套规则
  • Dockerfile由多条指令构成,Dockerfile中的每一条指令都会对应于Docker镜像中的每一层
  • Dockerfile每行支持一条指令,每条指令可携带多个参数,一条指令可以用&&方式,去写多条指令。
  • Dockerfile支持以“#”为开头的注释

构建三步骤

1、编写Dockerfile文件

2、docker build命令构建镜像

3、docker run 依镜像运行容器实例

Dockerfile执行流程

  1. docker 从基础镜像运行一个容器
  2. 执行一条 指令并对容器做出修改
  3. 执行类似docker commit的操作提交一个新的镜像层
  4. docker 再基于刚提交的镜像运行一个新容器
  5. 执行dockerfile中的下一条指令,直到所有的指令都执行完成

Dockerfile关键字

FROM关键字

       指定基础镜像,并且必须是第一条指令。如果不以任何镜像为基础,那么写法为:FROM scratch。同时意味着接下来所写的指令将作为镜像的第一层开始,语法:

FROM <image>

FROM <image>:<tag>

FROM <image>:<digest>

       三种写法,其中<tag>和<digest> 是可选项,如果没有选择,那么默认值为latest,为了安全,尽量使用官方image作为base image 例:

FROM scratch #制作base image

FROM centos #以centos作为base image

LABEL关键字

为镜像指定标签,语法:LABEL <key>=<value> <key>=<value> <key>=<value> ...

一个Dockerfile种可以有多个LABEL,如下:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

但是并不建议这样写,最好就写成一行,如太长需要换行的话则使用\符号, 如下:

LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"

说明:LABEL会继承基础镜像种的LABEL,如遇到key相同,则值覆盖,例:

LABEL maintainer="asd@163.com"  #维护者信息
LABEL version="1.0"             #版本
LABEL description="这是描述"     #镜像描述信息
RUN关键字

   功能为运行指定的命令,每运行一次RUN对image而言都生成新的一层,RUN命令有两种格式

RUN <command>
RUN ["executable", "param1", "param2"]

第一种后边直接跟shell命令

  • 在linux操作系统上默认 /bin/sh -c
  • 在windows操作系统上默认 cmd /S /C

第二种是类似于函数调用。可将executable理解成为可执行文件,后面就是两个参数。两种写法比对:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME
RUN ["/bin/bash", "-c", "echo hello"]

注意:多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层.多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。

当命令较多,或较长时,建议将命令换行,RUN书写时的换行符是 \,例:

RUN yum update && yum install -y vim \
    python-dev
RUN apt-get update && apt-get install -y perl \
    pwgen --no-install-recommends && rm -rf \
    /var/lib/apt/list/*  
WORKDIR关键字

     设置工作目录,对RUN,CMD,ENTRYPOINT,COPY,ADD生效。相当于 cd,如果不存在要打开的目录则会创建,可以设置多次。语法:WORKDIR /path/to/workdir例:

WORKDIR /ROOT  #将工作目录切换到root下
WORKDIR /test  #将工作目录切换到test目录  没有则创建
WORKDIR demo   #结合上一句 此时工作目录被切换到/test/demo目录下

 尽量使用WORKDIR,而不使用RUN cd,尽量使用局对目录。

ADD关键字

      一个复制命令,把文件复制到镜像中。如果把宿主机与容器想象成两台linux服务器的话,那么这个命令就类似于scp,只是scp需要加用户名和密码的权限验证,而ADD不用。语法如下:

ADD <src>... <dest>
ADD ["<src>",... "<dest>"]

<dest>路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径

<src>可以是一个本地文件或者是一个本地压缩文件,还可以是一个url,如果把<src>写成一个url,那么ADD就类似于wget命令,ADD不仅可以添加一个文件到指定目录,而且还可以将添加的压缩文件解压缩,

如以下写法都是可以的:

ADD test relativeDir/   #将test复制到容器内,相对于当前工作目录下的relativeDir目录中
ADD test /relativeDir  #将test复制到容器内根目录下relativeDir目录中
ADD http://example.com/foobar /   #将网络文件下载到根目录下

   尽量不要把<scr>写成一个文件夹,如果<src>是一个文件夹了,将复制整个目录的内容,包括文件系统元数据

   有如下注意事项:

   1、如果源路径是个文件,且目标路径是以 / 结尾, 则docker会把目标路径当作一个目录,会把源文件拷贝到该目录下。如果目标路径不存在,则会自动创建目标路径。

   2、如果源路径是个文件,且目标路径是不是以 / 结尾,则docker会把目标路径当作一个文件。如果目标路径不存在,会以目标路径为名创建一个文件,内容同源文件;如果目标文件是个存在的文件,会用源文件覆盖它,当然只是内容覆盖,文件名还是目标文件名。如果目标文件实际是个存在的目录,则会源文件拷贝到该目录下。 注意,这种情况下,最好显示的以 / 结尾,以避免混淆。

   3、如果源路径是个目录,且目标路径不存在,则docker会自动以目标路径创建一个目录,把源路径目录下的文件拷贝进来。如果目标路径是个已经存在的目录,则docker会把源路径目录下的文件拷贝到该目录下。

   4、如果源文件是个归档文件(压缩文件),则docker会自动帮解压。

COPY关键字

   看这个名字就知道,又是一个复制命令,与ADD用法基本相同,COPY的<src>只能是本地文件,语法如下:

COPY <src>... <dest>
COPY ["<src>",... "<dest>"]

   例:

ADD hello /  #将hello文件复制到容器内根目录下
ADD test.tar.gz /   #将压缩文件添加到容器内根目录下并解压
WORKDIR /root  #将工作目录切换到root目录下
ADD hello test/   #将hello文件添加到/root/test目录下
WORKDIR /root  #将工作目录切换到root目录下
copy hello test/ #将hello文件复制到/root/test
ENV关键字

   功能为设置环境变量设置常量,语法有两种:  

ENV <key> <value>
ENV <key>=<value> ...

   两者的区别就是第一种是一次设置一个,第二种是一次设置多个。

例:

ENV MYSQL_VERSION 5.6 #设置常量
RUN apt-get install -y mysql-server="${MYSQL_VERSION}" \   #使用常量
    && rm -rf /var/lib/apt/list/* 
CMD关键字

   功能为容器启动时要运行的命令,语法有三种写法

CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2

   第三种比较好理解了,就时shell这种执行方式和写法,第一种和第二种其实都是可执行文件加上参数的形式,举例说明两种写法:

CMD [ "sh", "-c", "echo $HOME" 
CMD [ "echo", "$HOME" ]

   补充细节:这里边包括参数的一定要用双引号,就是",不能是单引号。千万不能写成单引号,原因是参数传递后,docker解析的是一个JSON array

   注意事项:

容器启动时默认执行的命令 如果docker run 指定了其他命令,CMD命令被忽略 如果定义了多个CMD,只有最后一个会执行    RUN & CMD

   不要把RUN和CMD搞混了。RUN是构件容器时就运行的命令以及提交运行结果,CMD是容器启动时执行的命令,在构件时并不运行,构件时紧紧指定了这个命令到底是个什么样子

ENTRYPOINT关键字

       功能是启动时的默认命令,语法如下:

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

   与CMD比较说明(这俩命令太像了,而且还可以配合使用):

   1. 相同点:

只能写一条,如果写了多条,那么只有最后一条生效

容器启动时才运行,运行时机相同

   2. 不同点:

ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖

如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数

shell格式:即把要运行的命令当做shell执行

RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"

Exec格式:即是 命令,参数格式

RUN ["apt-get", "install", "-y", "vim"]
CMD ["/bin/echo", "hello docker"]
ENTRYPOINT ["/bin/echo", "hello docker"]

   例:以下两个dockerfile结果相同

FROM centos  #指定基础镜像为centos
EVN name Docker   #设定常量name 值为Docker
ENTRYPOINT echo "hello $name"  #执行acho命令

以上dockerfile生成的镜像运行容器时输出 hello Docker

FROM centos  #指定基础镜像为centos
EVN name Docker   #设定常量name 值为Docker
ENTRYPOINT ["/bin/echo", "hello $name"]  #执行acho命令

以上dockerfile生成的镜像运行容器时输出 hello $name,因为 ENTRYPOINT ["/bin/echo", "hello $name"] 指定容器启动时运行的就是echo命令  不会识别$为变量,做如下修改:

FROM centos  #指定基础镜像为centos
EVN name Docker   #设定常量name 值为Docker
ENTRYPOINT ["/bin/bash", "-c", "echo", "hello $name"]  #在shell中执行acho命令

容器启动时输出 hello Docker


相关文章
|
Java Linux 程序员
maven构建docker镜像三部曲之二:编码和构建镜像
用docker-maven-plugin插件来构建本地的docker镜像
875 0
maven构建docker镜像三部曲之二:编码和构建镜像
|
6月前
|
Java 持续交付 Docker
Docker 项目如何使用 Dockerfile 构建镜像?
Docker 简介:讲述 Docker 的起源、它是如何革新现代软件开发的,以及它为开发者和运维团队带来的好处。重点强调 Docker 的轻量级特性和它在提高应用部署、扩展和隔离方面的优势。
180 0
|
6月前
|
应用服务中间件 Shell nginx
制作docker镜像的dockerfile编写规则汇总
制作docker镜像的dockerfile编写规则汇总
116 0
|
6月前
|
Java 网络安全 开发者
【Docker】5、Dockerfile 自定义镜像(镜像结构、Dockerfile 语法、把 Java 项目弄成镜像)
【Docker】5、Dockerfile 自定义镜像(镜像结构、Dockerfile 语法、把 Java 项目弄成镜像)
108 0
|
6月前
|
缓存 Ubuntu JavaScript
Docker自定义镜像-构建镜像-Dockerfile语法
Docker自定义镜像-构建镜像-Dockerfile语法
109 0
|
运维 Cloud Native 网络协议
【云原生】Docker—Dockerfile写法与用法以及dockerfile简介与构建镜像详解【附加实战】
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令(Instruction)和操作命令;每一条指令构建一层镜像,因此每一条指令的内容,就是描述该层镜像应当如何构建(也就是你要执行的操作命令)。
522 0
【云原生】Docker—Dockerfile写法与用法以及dockerfile简介与构建镜像详解【附加实战】
|
存储 SpringCloudAlibaba 运维
docker高级篇:镜像原理和Dockerfile
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件
213 0
docker高级篇:镜像原理和Dockerfile
|
Linux 开发工具 Docker
Docker Review - dockerfile 实战_给基础镜像增加功能
Docker Review - dockerfile 实战_给基础镜像增加功能
148 0
|
Oracle Java 关系型数据库
|
Java Linux Shell
DockerFile 案例-自定义镜像 mycentos|学习笔记
快速学习 DockerFile 案例-自定义镜像 mycentos
DockerFile 案例-自定义镜像 mycentos|学习笔记