Docker(2)——构建镜像命令解析

Posted

tags:

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

参考技术A

Dockerfile 中包括 FROM 、 MAINTAINER 、 RUN 、 CMD 、 EXPOSE 、 ENV 、 ADD 、 COPY 、 ENTRYPOINT 、 VOLUME 、 USER 、 WORKDIR 、 ONBUILD 、 LABEL 等14个指令。

1.FROM
格式: FROM image 或 FROM image:tag
含义:Dockerfile中第一条指令必须是FROM指令,且在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令。

docker17.05版本开始,dockerfile中允许使用多个FROM指令,主要是解决编译环境和运行环境分开的问题。 https://www.cnblogs.com/leoyang63/articles/13733967.html

2.MAINTAINER
格式: MAINTAINER user_name user_email
含义:指定维护者信息,作者以及作者的邮箱地址

3.RUN
支持两种格式:
RUN command
RUN ["EXECUTABLE","PARAM1","PARAM2".....]
含义:前者在shell终端中运行命令, /bin/sh -c command ,例如: /bin/sh -c "echo hello" ;后者使用 exec 执行,指定其他运行终端使用 RUN["/bin/bash","-c","echo hello"] 。每条RUN指令将当前的镜像基础上执行指令,并提交为新的镜像,命令较长的时候可以使用 \\ 来换行。

4.CMD
支持三种格式:
CMD ["executable","param1","param2"] ,使用exec执行,这是推荐的方式。
CMD command param1 param2 , 在 /bin/sh 中执行。
CMD ["param1","param2"] ,提供给 ENTERYPOINT 的默认参数。

含义: CMD 用于指定容器启动时执行的命令,每个 Dockerfile 只能有一个 CMD 命令,多个 CMD 命令只执行最后一个。若容器启动时指定了运行的命令,则会覆盖掉 CMD 中指定的命令。

5.EXPOSE
格式: EXPOSE port [port2,port3,...]
含义:例如 EXPOSE 80 这条指令告诉Docker服务器暴露80端口,供容器外部连接使用。在启动容器的使用使用-P,Docker会自动分配一个端口和转发指定的端口,使用-p可以具体指定使用哪个本地的端口来映射对外开放的端口。

6.ENV
格式: EVN key value
含义:用于指定环境变量,这些环境变量,后续可以被 RUN 指令使用,容器运行起来之后,也可以在容器中获取这些环境变量,例如:
ENV word hello
RUN echo $word

7.ADD
格式: ADD src dest
含义:该命令将复制指定本地目录中的文件到容器中的 dest 中, src 可以是是一个绝对路径,也可以是一个 URL 或一个 tar 文件, tar 文件会自动解压为目录。

8.COPY
格式为: COPY src desc
含义:复制本地主机src目录或文件到容器的desc目录,desc不存在时会自动创建。

9.ENTRYPOINT
支持两种格式:
ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT command param1,param2

含义:后者会在shell中执行。用于配置容器启动后执行的命令,这些命令不能被 docker run 提供的参数覆盖。和 CMD 一样,每个Dockerfile中只能有一个 ENTRYPOINT ,当有多个时最后一个生效。

10.VOLUME
格式: VOLUME ["/data"]
含义:作用是创建在本地主机或其他容器可以挂载的数据卷,用来存放数据。

11.USER
格式: USER username
含义:指定容器运行时的用户名或UID,后续的RUN也会使用指定的用户。要临时使用管理员权限可以使用sudo。在USER命令之前可以使用RUN命令创建需要的用户。
例如: RUN groupadd -r docker && useradd -r -g docker docker

12.WORKDIR
格式: WORKDIR /path
含义:为后续的 RUN CMD ENTRYPOINT 指定配置工作目录,可以使用多个 WORKDIR 指令,若后续指令用得是相对路径,则会基于之前的命令指定路径。

13.ONBUILD
格式: ONBUILD [INSTRUCTION]
含义:该配置指定当所创建的镜像作为其他新建镜像的基础镜像时所执行的指令,例如下面的Dockerfile创建了镜像A:
ONBUILD ADD . /app
ONBUILD RUN python app.py

基于镜像A创建新的镜像时,新的Dockerfile中使用 from A 指定基镜像时,会自动执行 ONBBUILD 指令内容,等价于在新的要构建镜像的Dockerfile中增加了两条指令:
FROM A
ADD ./app
RUN python app.py

14.LABEL
格式: LABEL <label_name>="<label_value>"
含义:用来给镜像以键值对的形式添加一些元数据(metadata),如明镜像的作者、文档地址,commit ID。

Docker系列-第六篇DockerFile解析

1.手动编写一个dockerfile文件,当然必须要符合file的规则

2.有了这个文件,直接docker build命令执行,获得一个自定义的镜像

3.run

1.是什么

Dockerfle 是一个文本格式的配置文件, 用户可以使用 Dockerfle 来快速创建自定义的镜像。

Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。

1.1三步骤

  • 编写Dockerfile文件
  • docker build
  • docker run

2.DockerFile构建过程解析

2.1Dockerfile内容基础知识

1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数

2:指令按照从上到下,顺序执行

3:#表示注释

4:每条指令都会创建一个新的镜像层,并对镜像进行提交

2.2Docker执行Dockerfile的大致流程

(1)docker从基础镜像运行一个容器

(2)执行一条指令并对容器作出修改

(3)执行类似docker commit的操作提交一个新的镜像层

(4)docker再基于刚提交的镜像运行一个新容器

(5)执行dockerfile中的下一条指令直到所有指令都执行完成

2.3小总结

从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,

  • Dockerfile是软件的原材料
  • Docker镜像是软件的交付品
  • Docker容器则可以认为是软件的运行态。
    Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

技术图片
1、Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;

2、Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;

3、Docker容器,容器是直接提供服务的。

3.DockerFile体系结构(保留字指令)

3.1FROM

基础镜像,当前新镜像是基于哪个镜像的

每个Dockerfile的第一挑指令必须是FROM,FROM指令指定一个已存在的镜像,后续指令都继续该镜像进行,这个镜像也称为基础镜像

3.2MAINTAINER

MAINTAINER指令没有具体的格式,建议一般使用姓名和邮箱

3.3RUN

镜像构建时需要运行的命令(即镜像制作过程中需要执行的命令)

每条RUN指令都会创建一个新的镜像层,如果该指令执行成功,就会将此镜像层提交。

如果需要执行多条命令,可使用多行RUN命令,但经验告我,将多条指定通过命令换行合并成一条,这样将减少锁构建的体积。原因,上面也已经说了,在镜像中每执行一条命令,都会形成新的镜像层,需要尽可能的较少镜像层,从而减少镜像的提示

3.4EXPOSE

当前容器对外暴露出的端口

3.5WORKDIR

指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点

可以用过-w标志在运行时覆盖工作目录

3.6ENV

用来在构建镜像过程中设置环境变量

ENV MY_PATH /usr/mytest
这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;
也可以在其它指令中直接使用这些环境变量,

比如:WORKDIR $MY_PATH

3.7ADD

将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包

在ADD文件时,Docker通过目的地址参数末尾的字符来判断文件源是目录还是文件。如果目标地址以/结尾那么Docker就认为源位置指向的是一个目录。如果目的地址不是以/结尾,那么Docker就认为原文件指向的是文件。

ADD jdk-8u91-linux-x64.tar.gz /opt

是将宿主机当前目录下的 jdk-8u91-linux-x64.tar.gz 拷贝到容器/opt目录下 ,容器的目标路径必须的绝对路径。

一般将Dockerfile与需要添加到容器中的文件放在同一目录下,有助于编写来源路径

3.8COPY

类似ADD,拷贝文件和目录到镜像中。没有自动解压的功能
将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置

3.9VOLUME

容器数据卷,用于数据保存和持久化工作

3.10CMD

指定一个容器启动时要运行的命令

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数

CMD指令用于执行容器提供默认值。每个Dockerfile只有一个CMD命令,如果指定了多个CMD命令,那么只有最后一个会被执行。

Docker run 命令可以覆盖CMD指令。如果在Dockerfile里指定了CMD指令,而同时在docker run命令行中也指定的要运行的命令,命令行中指定的命令会覆盖Dockerfile中的CMD指令。

如 CMD java app.jar 容器启动时启动app.jar应用

3.11ENTRYPOINT

指定一个容器启动时要运行的命令

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数

区别:

可以在docker run 命令中覆盖CMD命令。

ENTRYPOINT指令提供的命令则不容易在启动容器时被覆盖。实际上docker run命令中指定的任何参数会被当做参数再次传递给ENTRYPOINT指令中指定的命令。

3.12ONBUILD

当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发

3.13USER

指定该镜像会以什么用户运行

3.13小结

技术图片

4.案例

使用Dockerfile构建Java镜像入门1

  • step 1

    新建Dockerfile文件

    touch Dokcerfile
  • step 2

    编写Dockerfile脚本

    FROM centos:latest
    MAINTAINER "NIU GANG"<863263957@qq.com>
    # 在opt目录下新建apps目录
    RUN  mkdir -p /opt/apps
    # 在当前目录下及和Dockerfile在一个目录下,将jdk安装包增加到镜像的opt/apps目录下
    # ADD目录会自动将 .tar.gz包进行解压
    ADD jdk-8u211-linux-x64.tar.gz /opt/apps
    # 在启动容器是执行命令
    CMD /opt/apps/jdk1.8.0_211/bin/java -version
  • step 3 构建镜像

    [root@localhost tools]# docker build -t niugang/java .
    Sending build context to Docker daemon  197.8MB
    Step 1/5 : FROM centos:latest
     ---> 9f38484d220f
    Step 2/5 : MAINTAINER "NIU GANG"<863263957@qq.com>
     ---> Running in e4a4a0c1ffa9
    Removing intermediate container e4a4a0c1ffa9
     ---> a7f400aae1a7
    Step 3/5 : RUN  mkdir -p /opt/apps
     ---> Running in 49f2c1f076c0
    Removing intermediate container 49f2c1f076c0
     ---> 287c44707477
    Step 4/5 : ADD jdk-8u211-linux-x64.tar.gz /opt/apps
     ---> cf2dfbb373c8
    Step 5/5 : CMD /opt/apps/jdk1.8.0_211/bin/java -version
     ---> Running in 83d41700285a
    Removing intermediate container 83d41700285a
     ---> 79bf24642eb4
    Successfully built 79bf24642eb4
    Successfully tagged niugang/java:latest

对于 docker build -t niugang/java . 这个命令

-t 选项指定镜像名称 并读取当前(即.)目录中的Dockerfile文件

  • step 4 验证

    [root@localhost tools]# docker run --rm niugang/java
    java version "1.8.0_211"
    Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
    Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

    --rm 是启动并删除容器

    注意:

    最开始在启动docker run --rm niugang/java 会报

    /bin/sh: /opt/apps/jdk-8u211/bin/java: No such file or directory

    是因为当初认为ADD 增加 jdk-8u211-linux-x64.tar.gz 后解压的名称叫 jdk-8u211(感觉犯例了一个常识性的错误),但其实解压完成后的文件夹名称为1.8.0_211

使用Dockerfile构建Java镜像入门2

一般在安装JDK后需要设置JAVA_HOME 与PATH 这样就可以直接在命令中使用Java命令了,而须带路径参数

使用Dockerfile中的ENV指令来设置所需的环境变量

前提:

为了二次生成的镜像于之前的不重名,修改之前生成镜像的tag

docker tag 79bf24642eb4 niugang/java:1.0

修改之前的Dockerfile文件,修改后的文件内容如下

FROM centos:latest
MAINTAINER "NIU GANG"<863263957@qq.com>
RUN  mkdir -p /opt/apps
ADD jdk-8u211-linux-x64.tar.gz /opt/apps
ENV JAVA_HOME /opt/apps/jdk1.8.0_211
ENV PATH $JAVA_HOME/bin:$PATH
CMD java -version

重新构建镜像

[root@localhost tools]# docker build -t niugang/java .
Sending build context to Docker daemon  197.8MB
Step 1/7 : FROM centos:latest
 ---> 9f38484d220f
Step 2/7 : MAINTAINER "NIU GANG"<863263957@qq.com>
 ---> Using cache
 ---> a7f400aae1a7
Step 3/7 : RUN  mkdir -p /opt/apps
 ---> Using cache
 ---> 287c44707477
Step 4/7 : ADD jdk-8u211-linux-x64.tar.gz /opt/apps
 ---> Using cache
 ---> cf2dfbb373c8
Step 5/7 : ENV JAVA_HOME /opt/apps/jdk1.8.0_211
 ---> Running in 6117528026ae
Removing intermediate container 6117528026ae
 ---> 1b9e9c656a8e
Step 6/7 : ENV PATH $JAVA_HOME/bin:$PATH
 ---> Running in 5711715ae4eb
Removing intermediate container 5711715ae4eb
 ---> 82f94b6f5211
Step 7/7 : CMD java -version
 ---> Running in fcb8b117a0c2
Removing intermediate container fcb8b117a0c2
 ---> 9a26c48936a4
Successfully built 9a26c48936a4
Successfully tagged niugang/java:latest

通过上面输出的信息可以观察到,step2 step3 step4 这三个步骤直接从缓存中获取之前构建的镜像,而不是重新构建镜像

Dockerfile和构建和缓存

由于每一步的构建都会将结果提交未镜像,所以Docker的构建过程就显得非常聪明。它会将之前的镜像层看作缓存。

要想忽略缓存功能,可以使用docker build --no-cache标志

如 docker build --no-cache -t niugang/java .

自定义mycentos镜像

  • 新建Dockerfile

    touch Dockerfile
  • 编写Dockerfile

    FROM centos
    MAINTAINER ng<863263957@qq.com>
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    RUN yum -y install vim
    RUN yum -y install net-tools
    
    EXPOSE 80
    
    CMD echo $MYPATH
    CMD echo "success--------------ok"
    CMD /bin/bash
  • 构建

    docker build -t 新镜像名:TAG .

    参数:

    -f :指定要使用的Dockerfile路径;

    --no-cache :创建镜像的过程不使用缓存;

    -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;

  • 运行

? docker run -it 新镜像名:TAG

  • 列出镜像变更历史

? docker history 镜像ID

CMD/ENTRYPOINT案例镜像

共同特点:都是指定一个容器启动时要运行的命令

CMD

Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换

列如:

以下是运行tomcat镜像的命令

docker run -it -p 8888:8080 tomcat

从docker.hub上查看tomcat镜像的Dockerfile文件会发现最后有 CMD ["catalina.sh", "run"]

现在以如下方式启动:

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH (CATALINA_HOME/bin:)PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME

在tomcat的Dockerfile中设置的WORKDIR为/usr/local/tomcat

docker run -it -p 8888:8080 tomcat ls -l

[root@localhost mycmdip]# docker run -it -p 8888:8080 tomcat ls -l
total 124
-rw-r--r--. 1 root root  19534 Jul  4 20:56 BUILDING.txt
-rw-r--r--. 1 root root   5407 Jul  4 20:56 CONTRIBUTING.md
-rw-r--r--. 1 root root  57011 Jul  4 20:56 LICENSE
-rw-r--r--. 1 root root   1726 Jul  4 20:56 NOTICE
-rw-r--r--. 1 root root   3255 Jul  4 20:56 README.md
-rw-r--r--. 1 root root   7139 Jul  4 20:56 RELEASE-NOTES
-rw-r--r--. 1 root root  16262 Jul  4 20:56 RUNNING.txt
drwxr-xr-x. 2 root root   4096 Jul 18 02:55 bin
drwxr-sr-x. 2 root root    238 Jul  4 20:56 conf
drwxr-sr-x. 2 root staff    78 Jul 18 02:55 include
drwxr-xr-x. 2 root root   4096 Jul 18 02:54 lib
drwxrwxrwx. 2 root root      6 Jul  4 20:53 logs
drwxr-sr-x. 3 root staff   151 Jul 18 02:55 native-jni-lib
drwxr-xr-x. 2 root root     30 Jul 18 02:54 temp
drwxr-xr-x. 7 root root     81 Jul  4 20:53 webapps
drwxrwxrwx. 2 root root      6 Jul  4 20:53 work

以上说明:

ls -l 命令覆盖了Dockerfile中的catalina.sh run

NETRYPOINT

docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合

通过案列镜像对比

操作 1

执行CMD版查询IP信息的镜像

具体Dockerfile文件内容为:

FROM centos
RUN yum install -y curl
CMD [ "curl", "-s", "http://ip.cn" ]

构建镜像

运行镜像 会返回你当前的ip信息

问题:如果我们希望显示 HTTP 头信息,就需要加上 -i 参数
技术图片

为什么会出错:

我们可以看到可执行文件找不到的报错,executable file not found。

之前也提到过跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。

因此这里的 -i CMD而不是添加在原来的后面。而根本不是命令,所以自然找不到

操作2

制作ENTROYPOINT版查询IP信息的容器

具体Dockerfile文件内容为:

FROM centos
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]

这样制作出的镜像在运行过程就不会报错了 ,就会显示出http头信息了

自定义tomcat9镜像

step1 在根目录下新建mytomcat9文件夹

mkdir mytomcat9

step2 上传jdk tomcat安装包

step3 新建Dockerfile文件

touch Dockerfile

step4 编写Dockerfile 内容如下

FROM         centos
MAINTAINER    niugang<863263957@qq.com>
#把宿主机当前上下文的test.txt拷贝到容器/usr/local/路径下并重命名为test1.txt
COPY test.txt /usr/local/test1.txt
#把java与tomcat添加到容器中
ADD jdk-8u211-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.27.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#设置工作访问时候的WORKDIR路径,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_211
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.27
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.27
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE  8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.27/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.27/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.27/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.27/bin/logs/catalina.out

step5 构建镜像

docker build -t niugang/tomcat9 .

step6 运行容器

docker run -d -p 9080:8080 --name myt9  -v /mytomcat9/mywebapp/:/usr/local/apache-tomcat-9.0.27/webapps   -v /mytomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.27/logs niugang/tomcat9 --privileged=true

上述运行容器创建两个数据卷

第一个是将容器中的tomcat日志映射到宿主机上
第二个是 将tomcat中的webapps目录映射到宿主机上方便日后发布应用
也可以将容器中tomcat的配置conf文件夹映射到宿主机

step7 验证应用发布

在映射的/mytomcat9/mywebapp/ 新建test目录,test目录下新建index.html,写入helle world。

[root@localhost test]# pwd
/mytomcat9/mywebapp/test
[root@localhost test]# ll
总用量 4
-rw-r--r--. 1 root root 12 10月 23 21:30 index.html

技术图片

5.小总结

技术图片
微信公众号

技术图片
JAVA程序猿成长之路
分享资源,记录程序猿成长点滴。专注于Java,Spring,SpringBoot,SpringCloud,分布式,微服务。

以上是关于Docker(2)——构建镜像命令解析的主要内容,如果未能解决你的问题,请参考以下文章

docker镜像常用命令及解析

docker学习笔记 --- Dockerfile解析

docke--Dockerfile构建docker镜像

dockerfile解析过程

九Dockerfile

Docker重学系列之Dockerfile