Dockerfile语法自定义镜像构建详解

Posted 流水武qin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dockerfile语法自定义镜像构建详解相关的知识,希望对你有一定的参考价值。

Dockerfile语法、自定义镜像构建详解

简单的说Dockerfile就是一个文本文件。

Docker使用它就可以帮助我们构建镜像。

大部分镜像都可以在DockerHub上找到。

但是以后自己写的微服务,想要发布到Docker上运行,就需要自己来构建镜像了。

一、镜像的结构

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

可以大致把这些层分为三部分:

1.1 基础镜像层(BaseImage)

应用依赖的函数库、环境变量、配置、文件系统等。

最底层的Layer

1.2 中间层(Layer)

BaseImage的基础上,添加安装包、依赖、配置等。

中间层并不是只单独的一层,而是基础镜像层和入口层之间的所有Layer

1.3 入口层(Entrypoint)

指镜像的运行入口,可以是程序的启动脚本。

是最顶层的Layer

1.4 镜像分层的好处

最直接的好处就是节省磁盘空间和共享资源。

比如有多个镜像都是从相同的BaseImage构建来的。

那么Docker只需要在磁盘上保持一份BaseImage,并且内存也只需加载一份BaseImage

这样就实现了BaseImage的复用。

1.5 注意点

Docker镜像一旦制作完成,层级就不能够再去更改,这也是从安全性和可维护可拓展性考虑。

如果想要修改镜像,比如拓展镜像的功能,只能够在原来的层级上加一层,再统一打包成镜像。

如果不了解这个过程,自己制作镜像时,也可以从头开始打包。

1.6 镜像的概念

镜像就是在系统函数库、运行环境基础上,添加应用程序文件、配置文件、依赖文件等组合。

然后编写好启动脚本和上面的文件组合统统打包在一起形成的文件。

要自定义构建镜像,就是实现上述打包的过程。

二、Dockerfile及其相关命令

自己构建自定义的镜像时,并不需要把所有文件一个个拷贝,打包。

只要告诉Docker,镜像的组成,需要哪些BaseImage、需要拷贝什么文件、需要安装什么依赖、以及启动脚本。

Docker会帮助我们构建镜像。

而描述上述信息的文件就是Dockerfile文件,它相当于就是构建镜像的说明书。

因此,Dockerfile就是一个文本文件,它提供了一种可以通过描述文件来构建镜像的一种方式

用指令来说明Docker要执行什么操作去构建镜像。

每一个指令都会形成一层Layer

2.1 Dockerfile常用命令

指令名称说明示例
FROM指定基础镜像是什么FROM centos:7
ENV设置环境变量,可在后面指令使用ENV key value
COPY拷贝本地文件到镜像的指定目录COPY ./nginx.tar /tmp/nginx
RUN执行Linux的shell命令,一般是当前应用安装过程的命令RUN yum install gcc
EXPOSE指定容器运行时监听的端口EXPOSE 80
ENTRYPOINT镜像中应用的启动命令,容器运行时调用ENTRYPOINT java -jar xx.jar

EXPOSE 监听的端口,一般也是在docker run 运行镜像生成容器时,需要把容器和宿主机相关联的端口。

如果上面的命令满足不了构建镜像的需要时。

可以查阅官方文档 :

https://docs.docker.com/engine/reference/builder/

文档里什么命令都有,但是有相当一部分是不常用的

三、使用Dockerfile一个JavaWeb程序构建为镜像

3.1 文件准备

  • docker-demo.jar:需要制作成镜像的SpringBoot项目。
  • Dockerfile:包含了镜像构建的全部步骤。
  • jdk-8u171-linux-x64.tar.gz:jdk安装包。

先解压jdk-8u171-linux-x64.tar.gz,是因为我想知道解压出来的目录叫什么名字,在Dockerfile中有用。

3.2 编写Dockerfile文件

# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录
ENV JAVA_DIR=/usr/local

# 拷贝jdk和java项目的包
COPY ./jdk-8u171-linux-x64.tar.gz $JAVA_DIR/	# 把jdk压缩包复制到/usr/local目录下
COPY ./docker-demo.jar /soft/app.jar			# 把java程序移动到/soft目录下并重命令为app.jar

# 使用RUN命令执行Linux的shell命令
RUN cd $JAVA_DIR \\								# 跳转到 到/usr/local目录下
 && tar -xf ./jdk-8u171-linux-x64.tar.gz \\		# 解压缩jdk的安装包
 && mv ./jdk1.8.0_171 ./java8					# 把jdk解压出来的目录重命名为java8
										# 其实重命名操作都是非必须的,只是用更短的名字更好操作一些
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8			# 把jdk的安装目录配置成环境变量JAVA_HOME
ENV PATH=$PATH:$JAVA_HOME/bin			# 最后再配置PATH变量为jdk的安装目录

# 暴露需要被监听端口,就是让被完全隔离的容器暴露出一个可以被外界访问的端口
# 一般就是application.yml中配置的端口号
EXPOSE 8999
# 程序运行入口,就是java项目的启动命令
# 这句话也是容器成功运行后,第一个执行的命令
ENTRYPOINT java -jar /soft/app.jar

3.3 构建镜像

运行构建镜像命令

# 写法一:默认文件名称必须叫Dockerfile
# -t	代表以' Name:tag'格式命名和可选的标记 (相当于就是-tag)
# . 	代表构建镜像所需的文件都在Dockerfile文件所在的目录下
docker build -t javaapp:1.0 .	

# 写法二:自己执行Dockerfile文件是谁
# -f 手动指定Dockerfile的文件名称
docker build -f mydockerfile -t javaapp:1.0 


注意:

1)构建的镜像名称必须全部小写

2)没有特殊情况文件名称就用Dockerfile就行,容易记忆,更加直观,也符合习惯

可以看到Docker在一步步执行Dockerfile文件中的步骤。一共是9步。

最终构建成功!

构建成功后查看镜像:

docker images

确认镜像存在后运行镜像:

# --name myApp  定义容器名称为myApp
# -p 把主机的8999端口和容器的8999相关联
# -d 后台运行
# javaapp:1.0 需要运行的镜像名称
docker run --name myApp -p 8999:8999 -d javaapp:1.0

成功运行后查看正在运行的容器:

docker ps

确认java程序在容器中正常运行后,就可以在浏览器中访问了。

四、使用java:8-alpine镜像去优化Dockerfile文件的编写

在微服务项目中,肯定不止一个镜像需要我们去构建。

如果每个微服务都是使用java编写的话。

那么Dockerfile文件中,选择基础镜像、安装jdk、配置环境变量的操作都是一致的。

我们没必要对每个微服务的镜像构建都做一次上面的操作。java:8-alpine这个镜像就已经做了上面的操作。

所以我们只要选择java:8-alpine,作为我们的基础镜像,就可以避免上面的重复操作了。

这也是Docker镜像分层的体现。

如果对Docker镜像分层机制不了解,可以查看我Docker专栏下的Docker的概念、架构、安装详解这篇博文。

了解了java:8-alpine镜像的作用之后,就可以这么优化Dockerfile文件了:

# 指定java:8-alpine作为基础镜像,它包含了java程序部署的基本环境依赖
FROM java:8-alpine
# 暴露需要被监听端口(一般就是application.yml中配置的端口号)
EXPOSE 8999
# 程序运行入口,就是java项目的启动命令
ENTRYPOINT java -jar /soft/app.jar

这样以后构建别的微服务的Dockerfile文件就方便多了。

并且使用它构建镜像时,步骤也从9步变成了4步。

Dockerfile详解,以及构建自定义镜像

Dockerfile使用

前面的操作我们一直下载下载官方已经构建好的镜像,直接下载后就可以run,如果我们想要在镜像中添加自己的应用,比如在tomcat中添加自己的app,构建一个自定义的镜像,那么我们应该怎么做,这个时候就用到了Dockerfile。Dockerfile是由一系列命令和参数构成的脚本,Docker可以根据这个脚本基于某个基础镜像创建一个新的定制化的镜像,大大提高了我们部署的效率,使用Dockfile最终的结果是帮助我们定制化自己的镜像。

Dockerfile初体验

下面就基于tomcat镜像简单部署一个属于我们自己的应用,选择一个合适的目录,这里我选择的目录是/usr/local/src,在/usr/local/src目录下创建一个文件夹docker-web,在里面创建一个index.html文件,写上下面内容

mkdir docker-web
vim index.html
<h1>I‘m Docker Test Page</h1>

然后创建一个没有扩展名的文件Dockerfile,开始编写相关命令

FROM tomcat 
MAINTAINER www.conly.top
WORKDIR /usr/local/tomcat/webapps
ADD docker-web ./docker-web

一个简单的Dockerfile就编写完成,其中命令具体是什么意思,下面会做详细说明,接下来开始构建镜像

[root@node2 docker-test]# docker build -t conly/mywebapp:1.0 ./
Sending build context to Docker daemon 3.584kB
Step 1/4 : FROM tomcat
---> 6408fdc94212
Step 2/4 : MAINTAINER www.conly.top
---> Running in 53e29f832089
Removing intermediate container 53e29f832089
---> b285ad91c35b
Step 3/4 : WORKDIR /usr/local/tomcat/webapps/
---> Running in ac5f64ef5e3c
Removing intermediate container ac5f64ef5e3c
---> f3eeee360833
Step 4/4 : ADD dockerweb ./dockerweb
---> 51a4c7e6ed10
Successfully built 51a4c7e6ed10
Successfully tagged conly/mywebapp:1.0

在构建的过程中,Docker根据Dockerfile中的内容进行了四个步骤,分别对应四个命令,这里要提到一个镜像分层的概念,每执行一步都会创建一个临时容器,并且可以看到临时容器的ID,临时容器是不可使用的,执行完成后,会展示构建镜像的镜像ID,镜像名称,tags等信息。

这时可以看到我们的Docker image已经多了一个自己创建的镜像conly/tomcat 的1.0版本

[root@node2 docker-test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
conly/mywebapp      1.0                 51a4c7e6ed10        3 minutes ago       507MB
tomcat              latest              6408fdc94212        2 weeks ago         507MB

如果此时基于原来的Dockerfile构建2.0版本

[root@node2 docker-test]# docker build -t conly/mywebapp:2.0 ./
Sending build context to Docker daemon  3.584kB
Step 1/4 : FROM tomcat
 ---> 6408fdc94212
Step 2/4 : MAINTAINER www.conly.top
 ---> Using cache
 ---> b285ad91c35b
Step 3/4 : WORKDIR /usr/local/tomcat/webapps/
 ---> Using cache
 ---> f3eeee360833
Step 4/4 : ADD dockerweb ./dockerweb
 ---> Using cache
 ---> 51a4c7e6ed10
Successfully built 51a4c7e6ed10
Successfully tagged conly/mywebapp:2.0

Dcoker在根据Dockerfile构建镜像时没有变动的 部分会使用缓存Using cache不会重新构建,只会对我们变更的部分进行构建,由于镜像分层的和使用缓存的机制使得Docker在构建镜像的效率大大提升。

构建镜像后执行run来运行我们的镜像,这个时候就可以在外部浏览器访问自定义的app应用了。

docker run -p 80:8080 -d conly/mywebapp:3.0

访问页面

技术图片

Dockerfile常用指令详解

基本指令

下面介绍Docker常用的指令:

  • FROM 指定基础镜像
    • 指令格式 
      • FROM <image>
      • FROM <image>:<tag>
      • FROM <image>@<digest>
    • 说明 
      • 指定基准镜像,类似JAVA的继承,FROM使用在其他指令之前,其他指令的操作依赖于FROM指令;如果不依赖于其他镜像,构建初始镜像可使用FROM  scratch。
  • LABEL 为镜像添加元数据
    • 指令格式
      • LABEL <key>=<value> <key>=<value> ...
    • 说明
      • LABEL指令给镜像添加元数据,也可以看作镜像的标签,对于镜像信息的描述。
      • LABEL指令是键值对形式的如果value中有空格,可以使用引号和,例:LABEL desc="This is a test lable"。
      • 一个镜像可以有多个LABEL,但是LABEL是分层的,每个LABELL都会构建一层镜像,可以使用合并写法,例子:
        LABEL multi.label1="value1"       multi.label2="value2"       other="value3"


        LABEL multi.label1="value1" multi.label2="value2" other="value3"
      • 新添加LABEL会覆盖原有重名LABEL。
      • 镜像的LABEL信息可以使用 docker inspect image:<tag>来查看。
  • MAINTAINER 指定镜像维护者信息
    • 指令格式
      • MAINTAINER <name>
    • 说明 
      • 该指令现在已经被废弃,建议使用LABEL来指定,例:LABEL maintainer="www.conly.top"。
  • ADD 复制文件
    • 指令格式
      • ADD <src> <dest>
      • ADD ["<src>","<dest>"]
    • 说明
      • 从src路径复制指定内容到dest路径,src可以是Dockfile相对路径,也可以是一个URL,还可以是一个压缩包。
      • 拷贝文件时可识别压缩包格式,docker会自动解压。
      • 若src是一个URL,dest不以斜杠结尾,dest将会被视为文件,src对应内容将会被下载到dest文件。
      • 若src是一个URL,dest以斜杠结尾,dest将会被视为目录,src对应内容将会被下载到dest目录。
      • 若src是一个目录,整个目录下的内容,包括文件系统元数据将会被拷贝至dest目录。
  • WORKDIR 指定工作目录
    • 指令格式
      • WORKDIR /path
    • 说明
      • 指定工作目录,相当于cd /path,path不存在可以自动创建,为指令RUN,CMD,ENTRYPOINT指定工作目录,以WORKDIR目录为当前目录。
  • ARG 设置构建参数
    • 指令格式
      • ARG <name>[=<default value>]
    • 说明
      • 定义构建镜像时需要的参数,可用于FROM指令前。
      • ARG指令定义的参数,在docker build命令中以--build-arg a_name=a_value形式赋值。
      • Dockerfile中可以使用ARG定义一个变量,也可以定义多个变量,变量定义时可设置默认值,在build时传递参数则使用参数,未传递参数则使用默认值。
      • ARG变量定义从在Dockerfile定义的行生效,而不是从在命令行参数的使用或其它地方。
      • RUN指令可运行使用ARG或ENV指令定义的变量。使用ENV定义的环境变量会覆盖ARG指令定义的同名变量。
      • Dcoker中预设的一组ARG变量不需要预设即可使用,在执行docker --build-arg a_name=a_value即可使用。 
        HTTP_PROXY
        http_proxy
        HTTPS_PROXY
        https_proxy
        FTP_PROXY
        ftp_proxy
        NO_PROXY
        no_proxy
      • 在构建镜像过程中如果ARG传递的参数未定义会出现警告。
        [root@conly webapps]# docker build --build-arg xxccx=conly -t conly .
        Sending build context to Docker daemon  4.608kB
        Step 1/5 : from tomcat:latest
         ---> 6408fdc94212
        Step 2/5 : MAINTAINER www.conly.top
         ---> Using cache
         ---> 79180381b68d
        Step 3/5 : WORKDIR /opt/tomcat/webapps
         ---> Using cache
         ---> 9735f116f248
        Step 4/5 : EXPOSE 8080 8081 8082
         ---> Using cache
         ---> 8b140733df33
        Step 5/5 : ADD https://images.cnblogs.com/cnblogs_com/conly/1600508/o_191211120217min.png ./docker-web
        Downloading [==================================================>]  230.1kB/230.1kB
         ---> Using cache
         ---> 61e9f6346096
        [Warning] One or more build-args [xxccx] were not consumed
        Successfully built 61e9f6346096
        Successfully tagged conly:latest

        关于ARG的更多使用可以参考https://www.centos.bz/2016/12/dockerfile-arg-instruction/

  • CMD 容器启动指令
    • 指令格式xiang
      • CMD ["executable", "param1", "param2"] (推荐使用)
      • CMD ["param1", "param2"] 为[ENTRYPOINT]指令提供预设参数
      • CMD command param1 param2 在shell中执行
    • 说明
      • 用于在Docker容器创建时执行默认的命令,CMD命令可以有多个,但只会执行最后一个,CMD命令可以被覆盖。
      • 如果使用docker run 创建容器时附加了其他命令则默认的CMD命令不会被执行,执行附加命令。
  • RUN 执行命令
    • 指令格式
      • RUN <command> shell命令格式
      • RUN ["executable", "param1", "param2"] exec命令格式
    • 说明
      • 用于在Docker镜像构建时执行命令,镜像构建结束,RUN命令也就结束执行。
  • COPY 复制文件
    • 指令格式
      • COPY <src> <dest>
      • COPY ["<src>", "<dest>"]
    • 说明
      • 复制本地的src文件到dest目录,功能类似于ADD,COPY不支持URL和压缩包。
  • ENTRYPOINT 入口点
    • 指令格式
      • ENTRYPOINT ["executable", "param1", "param2"]
      • ENTRYPOINT command param1 param2
    • 说明
      • 用于在Docker容器创建时执行命令,ENTRYPOINT 可以存在多个,但只会执行最后一个,且ENTRYPOINT运行的命令不可被覆盖。
  • ENV 设置环境变量
    • 指令格式
      • ENV <key> <value>
      • ENV <key>=<value> ...
    • 说明
      • 设置环境变量,会被RUN指令使用,并在容器运行时保持。例:ENV JAVA_HOME /path/to/java。
  • EXPOSE 声明暴漏的端口
    • 指令格式
      • EXPOSE <port> [<port>...]
    • 说明
      • 用于声明容器运行时提供服务的端口,便于镜像使用者查看该镜像服务的守护端口,运行时并不会因为声明就打开相应端口。
      • 当运行时使用随机映射时,会自动映射EXPOSE的端口。例:docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 -d image:<tag>。
  • USER 设置用户
    • 指令格式
      • USER <daemon>
    • 说明
      • 该指令用于指定容器运行时的用户或者UID,RUN、CMD以及ENTRYPOINT指令都将使用该用户执行命令。例:
        RUN groupadd -r postgres && useradd -r -g postgres postgres

相似指令区别

  •  RUN,CMD,ENTRYPOINT的区别
    • 执行时机不同,RUN指令在镜像构建时使用,CMD | ENTRYPOINT在容器创建时使用。
    • CMD是默认执行命令,可以被覆盖,原有命令不一定执行,ENTRYPOINT不可以被覆盖,一定会被执行。
    • ENTRYPOINT和CMD命令可以组合使用,将CMD命令当作ENTRYPOINT命令的参数来执行,例:
      ENTRYPINT ["ps"]
      CMD ["-ef"]

      镜像构建完成,如果使用docker run image -aux,则原有CMD命令在执行时会被替换为ps -aux,这种方式实现了动态传参,不用修改Dockerfile重新构建镜像就可以在创建容器上执行自定义命令。

  • ARG和ENV的区别
    • 从语义上看ARG是用来设置构建镜像时参数的,设置参数仅在构建时期有用,ENV用来设置环境变量,可以保存在容器运行时。
    • Dockerfile中声明ARG后可以设定默认值,也可以构建时传参设置,ENV设置的环境变量可以覆盖ARG声明的同名参数。
    • Dockerfile中ARG和ENV可以配合使用,类似于ENTRYPOINT和CMD指令。例:
      # use the value to set the ENV var default
      ARG A_VARIABLE
      ENV an_env_var=$A_VARIABLE
    • 需要注意的是虽然使用ARG设置的参数仅在构建时有效,但是使用docker history <image>:<tag>还是可以查看构建记录,尽量避免传递密钥,password等敏感信息。
      [root@conly webapps]# docker build -t tomcat:0.1 .
      Sending build context to Docker daemon  4.608kB
      Step 1/7 : ARG user=test_user
      Step 2/7 : ARG password=test_password
      Step 3/7 : from tomcat:latest
       ---> 6408fdc94212
      Step 4/7 : MAINTAINER www.conly.top
       ---> Using cache
       ---> 79180381b68d
      Step 5/7 : WORKDIR /opt/tomcat/webapps
       ---> Using cache
       ---> 9735f116f248
      Step 6/7 : EXPOSE 8080 8081 8082
       ---> Using cache
       ---> 8b140733df33
      Step 7/7 : ADD https://images.cnblogs.com/cnblogs_com/conly/1600508/o_191211120217min.png ./docker-web
      Downloading [==================================================>]  230.1kB/230.1kB
       ---> Using cache
       ---> 61e9f6346096
      Successfully built 61e9f6346096
      Successfully tagged tomcat:0.1
      [root@conly webapps]# docker history tomcat:0.1   
      IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
      61e9f6346096        5 hours ago         /bin/sh -c #(nop) ADD 394a0073236e50f2867f4a…   230kB               
      8b140733df33        5 hours ago         /bin/sh -c #(nop)  EXPOSE 8080 8081 8082        0B                  
      9735f116f248        2 days ago          /bin/sh -c #(nop) WORKDIR /opt/tomcat/webapps   0B                  
      79180381b68d        2 days ago          /bin/sh -c #(nop)  MAINTAINER www.conly.top     0B                  
      6408fdc94212        2 weeks ago         /bin/sh -c #(nop)  CMD ["catalina.sh" "run"]    0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  EXPOSE 8080                  0B                  
      <missing>           2 weeks ago         /bin/sh -c set -e  && nativeLines="$(catalin…   0B                  
      <missing>           2 weeks ago         /bin/sh -c set -eux;   savedAptMark="$(apt-m…   18.6MB              
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV TOMCAT_SHA512=263480a…   0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV TOMCAT_VERSION=8.5.49    0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV TOMCAT_MAJOR=8           0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV GPG_KEYS=05AB33110949…   0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV LD_LIBRARY_PATH=/usr/…   0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV TOMCAT_NATIVE_LIBDIR=…   0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop) WORKDIR /usr/local/tomcat     0B                  
      <missing>           2 weeks ago         /bin/sh -c mkdir -p "$CATALINA_HOME"            0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV PATH=/usr/local/tomca…   0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV CATALINA_HOME=/usr/lo…   0B                  
      <missing>           2 weeks ago         /bin/sh -c set -eux;   dpkgArch="$(dpkg --pr…   205MB               
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV JAVA_URL_VERSION=8u23…   0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV JAVA_BASE_URL=https:/…   0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV JAVA_VERSION=8u232       0B                  
      <missing>           2 weeks ago         /bin/sh -c { echo #/bin/sh; echo echo "$J…   27B                 
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV PATH=/usr/local/openj…   0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV JAVA_HOME=/usr/local/…   0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop)  ENV LANG=C.UTF-8             0B                  
      <missing>           2 weeks ago         /bin/sh -c set -eux;  apt-get update;  apt-g…   9.68MB              
      <missing>           2 weeks ago         /bin/sh -c apt-get update && apt-get install…   142MB               
      <missing>           2 weeks ago         /bin/sh -c set -ex;  if ! command -v gpg > /…   7.81MB              
      <missing>           2 weeks ago         /bin/sh -c apt-get update && apt-get install23.2MB              
      <missing>           2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B                  
      <missing>           2 weeks ago         /bin/sh -c #(nop) ADD file:152359c10cf61d800…   101MB  

      完整信息命令

       docker history --format "table {{.ID}}	{{.CreatedBy}}" --no-trunc image:<tag>
  • ADD和COPY的区别
    • ADD和COPY都可以用来拷贝源文件到指定目录,在这点上用法一致。
    • ADD的源可以是本地也可以是远程的,COPY只能是本地文件。
    • 使用ADD来拷贝可识别的压缩文件时,如.tar,.war可以自动解压,COPY则不具备。
    • COPY可用于multi-stage中,复制上一阶段的镜像,笔者水平有限,详细内容看参考use multi-stage builds此功能在Docker17.05以后才添加,极大方便了Dockerfilr的维护者。

首次使用 COPY 和 ADD 命令时也没有考虑过太多二者的区别,随着对Docker的使用会发现 COPY 命令的设计是简单,概念清晰的。而 ADD 命令是在COPY命令上的扩展,提高了使用的复杂度,尤其在使用ADD添加源为URL的情况,要注意dest路径的结尾有没有/,但这些设计在我们熟悉Docker后也会方便操作。

shell和exec区别

  • shell 在Linux系统中,使用shell执行时脚本时,当前shell为父进程,会生成一个子进程来执行脚本,执行完毕后会退出子进程回到当前shell。
  • exec 使用exec执行时,exec进程会替换当前进程,进程PID保持不变执行结束直接退出,不会退出到进程执行之前的环境。

  在Docker中推荐使用exec方式执行命令,方便于我们的操作,这也是官方推荐的方式。

使用Dockerfile构建Redis镜像

在了解完Dockerfile中的一些常见命令后,接下来就进行一个简单的应用吧,创建一个Dockerfile基于CentOS来构建自定义Redis镜像。这里切换到/usr/local/redis_dockertest目录来进行操作,Redis作为一个优秀的NoSQL数据库,Docker Hub自然有官方镜像,这里用来练习Dockerfile的常用指令。

基于CentOS7构建Redis镜像

基于CentOS7的镜像,添加Redis的安装包进去,添加配置文件来制作镜像,帮助我们熟悉Dockerfile的指令。

下载redis-5.0.5安装包

wget http://download.redis.io/releases/redis-5.0.5.tar.gz

下载redis.conf配置文件

wget http://download.redis.io/redis-stable/redis.conf

修改redis.conf

bind 127.0.0.1  -->  #bind 127.0.0.1
daemonize no    -->  daemonize yes
protected-mode yes -->   protected-mode no

创建Dockerfile

vim Dockerfile

编写Dockerfile

ARG desc
FROM centos
LABEL maintainer=www.cnblogs.com/conly/
RUN ["yum","-y","install","gcc","gcc-c++","net-tools","make"]
WORKDIR /usr/local
ADD redis-5.0.5.tar.gz .
WORKDIR /usr/local/redis-5.0.5/src/
RUN make && make install
WORKDIR /usr/local/redis-5.0.5
ADD redis.conf .
EXPOSE 6379
CMD ["redis-server","redis.conf"]

构建redis镜像

docker build --build-arg desc="this is a docker image build test" -t conly/redis:1.0 .

截取部分执行过程,看到Dockerfile的执行步骤

[root@conly redis_dockertest]# docker build --build-arg desc="this is a docker image build test" -t conly/redis:1.0 .
...
...
...
Removing intermediate container 528d15f50a03
 ---> 809289100143
Step 9/14 : WORKDIR /usr/local/redis-5.0.5
 ---> Running in 566b63100414
Removing intermediate container 566b63100414
 ---> 9cfce44318ee
Step 10/14 : ADD redis.conf .
 ---> dc8127dafb54
Step 11/14 : EXPOSE 6379
 ---> Running in eda8f77e9c83
Removing intermediate container eda8f77e9c83
 ---> 08f348a33ff6
Step 12/14 : WORKDIR /usr/local/redis-5.0.5/utils
 ---> Running in c7cd15701c85
Removing intermediate container c7cd15701c85
 ---> 1dcde04ee437
Step 13/14 : ENTRYPOINT ["./"]
 ---> Running in 152277e9979e
Removing intermediate container 152277e9979e
 ---> 1c9a7b9c6bae
Step 14/14 : CMD ["install_server.sh"]
 ---> Running in 065dc4a5ba65
Removing intermediate container 065dc4a5ba65
 ---> 8b1990aa9224
Successfully built 8b1990aa9224
Successfully tagged conly/redis:1.0

查看docker的镜像,可以看到除了我们构建的conly/redis:1.0版本意外,此外Dockerfile中的FROM centos也pull下来了

[root@conly redis_dockertest]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
conly/redis         1.0                 8b1990aa9224        3 minutes ago       587MB
centos              latest              0f3e07c0138f        2 months ago        220MB

使用docker run运行redis镜像

[root@conly redis_dockertest]# docker run -p 6379:6379 conly/redis:1.0                                               
1:C 12 Dec 2019 13:27:00.599 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 12 Dec 2019 13:27:00.599 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 12 Dec 2019 13:27:00.599 # Configuration loaded
                _._                                                  
           _.-``__ ‘‘-._                                             
      _.-``    `.  `_.  ‘‘-._           Redis 5.0.5 (00000000/0) 64 bit
  .-`` .-```.  ```/    _.,_ ‘‘-._                                   
 (          ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|` _.-|     Port: 6379
 |    `-._   `._    /     _.-    |     PID: 1
  `-._    `-._  `-./  _.-    _.-                                   
 |`-._`-._    `-.__.-    _.-_.-|                                  
 |    `-._`-._        _.-_.-    |           http://redis.io        
  `-._    `-._`-.__.-_.-    _.-                                   
 |`-._`-._    `-.__.-    _.-_.-|                                  
 |    `-._`-._        _.-_.-    |                                  
  `-._    `-._`-.__.-_.-    _.-                                   
      `-._    `-.__.-    _.-                                       
          `-._        _.-                                           
              `-.__.-                                               

1:M 12 Dec 2019 13:27:00.601 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 12 Dec 2019 13:27:00.601 # Server initialized
1:M 12 Dec 2019 13:27:00.601 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add vm.overcommit_memory = 1 to /etc/sysctl.conf and then reboot or run the command sysctl vm.overcommit_memory=1 for this to take effect.
1:M 12 Dec 2019 13:27:00.601 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command echo never > /sys/kernel/mm/transparent_hugepage/enabled as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
1:M 12 Dec 2019 13:27:00.603 * Ready to accept connections

此时redis是阻塞状态运行,当然我们也可以重新编写Dockerfile来构建镜像让redis容器后台运行

ARG desc
FROM centos
LABEL maintainer=www.cnblogs.com/conly/
RUN ["yum","-y","install","gcc","gcc-c++","net-tools","make"]
WORKDIR /usr/local
ADD redis-5.0.5.tar.gz .
WORKDIR /usr/local/redis-5.0.5/src/
RUN make && make install
WORKDIR /usr/local/redis-5.0.5
ADD redis.conf .
RUN cd /usr/local/redis-5.0.5/utils  && echo | /bin/bash install_server.sh
ENTRYPOINT /usr/local/bin/redis-server /etc/redis/6379.conf && tail -f /var/log/redis_6379.log 

运行redis,可以看到我们自定义的redis已经运行了。

[root@conly redis_dockertest]# dockerun -p 6379:6379 -d conly/redis:1.0  .                                              
d3b1191ae2408d5025ba55e3b893300ca9438246a10feb2d7e02fa0f29801740
[root@conly redis_dockertest]# docker ps -s
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES               SIZE
d3b1191ae240        conly/redis:1.0     "/bin/sh -c ‘/usr/lo…"   8 seconds ago       Up 7 seconds        0.0.0.0:6379->6379/tcp   fervent_babbage     2.58kB (virtual 587MB)

Dockerfile中常用的指令总结完毕,并且进行了简单的练习,接下来开始学习Docker容器间的通信,Docker Compose的实战应用。

以上是关于Dockerfile语法自定义镜像构建详解的主要内容,如果未能解决你的问题,请参考以下文章

Docker:Dockerfile自定义镜像

Docker系列-第六篇DockerFile解析

docke--Dockerfile构建docker镜像

Docke--Dockerfile 构建LNMP环境

docker-4-Dockerfile配置文件详解

dockerfile 基本语法