Docker - Dockerfile之FROM、ARG、LABEL、MAINTAINER、RUN、CMD指令详解

Docker - Dockerfile之FROM、ARG、LABEL、MAINTAINER、RUN、CMD指令详解

Dockerfile是什么

Dockerfile是一个包含用于组装镜像的所有指令的文本文档。Docker可以使用docker build命令读取Dockerfile中的指令自动生成镜像。

Dockerfile由一行行指令组成,支持以#开头的注释行。一般的,Dockerfile分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。

FROM

构建所需要的镜像,就是一个定制化的过程,那么就需要以一个镜像为基础,在其基础上进行修改定制。而FROM指令就是用来指定基础镜像,因此在Dockerfile中,FROM指令是必备指定,并且必需是第一条指令!

格式

FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

FROM指令在Dockerfile中可以出现多次,这样可以创建多个镜像。每个FROM指令会清除由先前指令创建的任何状态。

通过添加可选的[AS <name>]可以给予一个新的构建阶段FROM指令进行命名。该名称可以在后续的FROM指令和COPY --from=<name>中使用,以引用此阶段中构建的镜像。

[:<tag>][@<digest>]也都是可选的。如果两个都不选择,那么构建器默认情况下将使用latest标签。如果构建器找不到该tagdigest版本,命令则会返回错误。

示例

FROM centos
FROM centos:8.3.2011

除了指定现有的基础镜像以外,Dockerfile还存在一个特殊的镜像srcatch,这个镜像是一个虚拟的概念,并不实际存在,它表示一个空白的镜像:

FROM scratch

如果以scratch作为基础镜像,意味着将不使用任何镜像为基础,接下来所写的指令将作为第一层开始存在。不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见。对Linux下静态编译的程序来说,并不需要其他操作提供其运行时支持,所需的一切库都在可执行文件里了,因此使用scratch作为基础镜像,可以使镜像的体积更加小巧,之前介绍Docker中关于Image的build命令时,就使用过scratch作为基础镜像,将主机上编译好的c语言程序放入镜像中运行:Docker - Docker Image及Image命令详解

FROM scratch
ADD hello /
CMD ["/hello"]

ARG

Dockerfile中的ARG指令用以定义构建镜像时需要的参数。

格式

ARG <name>[=<default value>]

ARG指令定义了一个参数,用户可以通过docker build命令的--build-arg <varname>=<value>选项将其值传递给构建器(如果ARG指令定义的参数具有默认值,此时默认值会被覆盖)。

默认值

如果ARG指令定义的参数具有默认值(通过设置可选项[=<default value>]来实现),并且在构建镜像时未传递该参数的值,则构建器将使用默认值。

范围

ARG指令定义的参数从Dockerfile中定义的行开始生效,而不是从参数使用处开始生效。

FROM centos:7
USER ${user:-kaven}
ARG user
USER $user

使用该Dockerfile来构建image,通过-t选项来对image设置nametag

docker build --build-arg user=kaven_centos -t centos:kaven .
[root@izoq008ryseuupz ~]# docker build --build-arg user=kaven_centos -t centos:kaven .
Sending build context to Docker daemon  1.316GB
Step 1/4 : FROM centos:7
 ---> 8652b9f0cb4c
Step 2/4 : USER ${user:-kaven}
 ---> Running in 0db31a9b2ba2
Removing intermediate container 0db31a9b2ba2
 ---> b9cd1bab4371
Step 3/4 : ARG user
 ---> Running in 68370ca04def
Removing intermediate container 68370ca04def
 ---> e85d5f280c22
Step 4/4 : USER $user
 ---> Running in 357cc35e19fa
Removing intermediate container 357cc35e19fa
 ---> 94891bfd473b
Successfully built 94891bfd473b
Successfully tagged centos:kaven

查看USER是否设置成功。

docker image inspect centos:kaven

在这里插入图片描述

2行的USERkaven,因为在随后的第3行中定义了user参数,并且通过选项--build-arg传递该参数的值为kaven_centos,所以第4行的USER为kaven_centos

不要用ARG指令来保存密码之类的信息,因为通过docker history命令是能够看到这些信息的。

[root@izoq008ryseuupz ~]# docker history centos:kaven
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
94891bfd473b        2 days ago          /bin/sh -c #(nop)  USER kaven_centos            0B                  
e85d5f280c22        2 days ago          /bin/sh -c #(nop)  ARG user                     0B                  
b9cd1bab4371        2 days ago          /bin/sh -c #(nop)  USER kaven                   0B                  
8652b9f0cb4c        4 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
<missing>           4 weeks ago         /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B                  
<missing>           4 weeks ago         /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB 

Dockerfile的每一条指令都会新构建一层,从上面docker history命令产生的输出也可以看出来。

在通过ARG指令对参数进行定义之前或者没有通过--build-arg <varname>=<value>选项给定义的参数传递值,对参数的任何使用都会导致一个空字符串。

通过--build-arg <varname>=<value>选项给未定义的参数传递值,很显然这里并没有给user参数传递值。

docker build --build-arg xxx=kaven -t kaven .
[root@izoq008ryseuupz ~]#  docker build --build-arg xxx=kaven -t kaven .
Sending build context to Docker daemon  1.317GB
Step 1/4 : FROM centos:7
 ---> 8652b9f0cb4c
Step 2/4 : USER ${user:-kaven}
 ---> Using cache
 ---> b9cd1bab4371
Step 3/4 : ARG user
 ---> Using cache
 ---> e85d5f280c22
Step 4/4 : USER $user
 ---> Running in 20022b5eb237
Removing intermediate container 20022b5eb237
 ---> 0dbfbc335abb
[Warning] One or more build-args [xxx] were not consumed
Successfully built 0dbfbc335abb
Successfully tagged kaven:latest

如果通过--build-arg <varname>=<value>选项传递了未在Dockerfile中定义的参数,则构建过程中会输出警告。

[Warning] One or more build-args [xxx] were not consumed

查看刚刚构建的镜像信息。

docker image inspect kaven

确实是空字符串。
在这里插入图片描述

LABEL

LABEL指令将一些元数据添加到镜像中。LABEL指令对应一个或多个键值对。

格式

LABEL <key>=<value> <key>=<value> <key>=<value> ...

LABEL <key>=<value> 
LABEL <key>=<value> 
LABEL <key>=<value> 
...

Dockerfile的每一条指令都会新构建一层,所以,上面的多条LABEL指令可以写成一条指令,使用\符号进行换行操作:

LABEL <key>=<value> \
 <key>=<value> \
 <key>=<value> 
...

示例

LABEL maintainer="kaven"
LABEL version="1.0"
LABEL description="This is Kaven's blog."
LABEL maintainer="kaven" version="1.0" description="This is Kaven's blog."
LABEL maintainer="kaven" \
      version="1.0" \
      description="This is Kaven's blog."

所以LABEL指令的作用也很明显了,就是给需要构建的镜像添加一些元数据,用来描述这个镜像的元数据信息。

MAINTAINER (Deprecated)

已弃用。

MAINTAINER <name>

MAINTAINER指令用于设置创建镜像的作者的标识。但LABEL指令比MAINTAINER指令灵活得多,应该使用LABEL指令,因为LABEL指令可以设置所需的任何元数据,并且可以很容易查看这些元数据,例如使用docker inspect命令。

比如:

MAINTAINER "kaven"

可以换成:

LABEL maintainer="kaven"

RUN

构建镜像时执行的命令。

格式

  1. RUN <command>shell格式)
  2. RUN ["executable", "param1", "param2"]exec格式)

RUN指令将在当前镜像顶部的新层中执行任何命令并提交结果。生成的镜像将用于Dockerfile的下一步。

分层运行指令和生成提交符合Docker的核心概念,在Docker中提交是很轻量的,可以从镜像历史的任何一点来创建容器,就像源代码管理一样。

RUN apt-get update
RUN ["/bin/bash", "-c", "echo hello"]

RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache选项,如:docker build --no-cache

对于一些编译、软件的安装和更新等操作,无需分成好几层来操作,这样会使得镜像非常臃肿,拥有非常多的层,不仅仅增加了构建部署的时间,也很容易出错。例如:

RUN buildDeps=apt-get update && mkdir -p /usr/src/redis && apt-get purge -y --auto-remove $buildDeps

这里仅仅使用了一条RUN指令,所以只会新建一层。可以使用&&符号将多个命令分割开,使其先后执行。此时,一条RUN指令有可能会变得非常长,可以使用\进行换行操作。

刚刚编写的RUN指令,会发现在指令的结尾处添加了清理工作的命令。镜像是多层存储,每一层存储的东西不会在下一层删除,会一直跟随着镜像。因此在镜像构建时,一定要确保每一层只添加真正需要的东西,任何无关的东西都应该被清理掉。

CMD

格式

  1. CMD ["executable","param1","param2"] (exec格式,官方推荐的方式)。
  2. CMD ["param1","param2"] (提供给ENTRYPOINT指令的默认参数)。
  3. CMD command param1 param2 (shell格式)。

Dockerfile中只会有一条有效的CMD指令。如果有多条CMD指令,则只有最后一条CMD指令生效。

Docker不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,就需要指定运行的程序及参数。

所以,CMD指令的主要用途是为启动容器时指定运行的程序及参数,而RUN指令用于指定镜像构建时所要执行的命令。

示例

CMD echo "This is kaven's blog." 
CMD ["/bin/bash", "-c", "echo This is kaven's blog."]

当使用了ENTRYPOINT指令时,CMD指令的性质将会发生改变:CMD指令中的内容将会以参数形式传递给ENTRYPOINT指令,如下:

FROM ubuntu
ENTRYPOINT ["rm", "docker"]
CMD ["-rf"]

其实,它真正执行的命令将会是:

rm docker -rf

Docker - Dockerfile之ENV、ENTRYPOINT、VOLUME、ONBUILD、STOPSIGNAL指令详解

例子

ARG CENTOS_VERSION=8.3.2011
FROM centos:$CENTOS_VERSION
LABEL  maintainer="kaven" \
    description="This is Kaven's blog." \
    version="centos.kaven.1.0" \
    name="CentOS Base Image" \
    date="20200-12-15"
CMD ["/bin/bash"]
RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
RUN yum update
RUN yum install -y mysql

在这里插入图片描述

使用Dockerfile来构建image,并且通过-t选项来对image设置nametag

docker build -t centos:kaven.1 .
[root@izoq008ryseuupz ~]# docker build -t centos:kaven.1 .
Sending build context to Docker daemon  1.308GB
Step 1/7 : ARG CENTOS_VERSION=8.3.2011
Step 2/7 : FROM centos:$CENTOS_VERSION
 ---> 300e315adb2f
Step 3/7 : LABEL  maintainer="kaven"     description="This is Kaven's blog."     version="centos.kaven.1.0"     name="CentOS Base Image"     date="20200-12-15"
 ---> Using cache
 ---> 72b4d13e9df0
Step 4/7 : CMD ["/bin/bash"]
 ---> Using cache
 ---> 69305c7a0a74
Step 5/7 : RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
 ---> Using cache
 ---> 2f0cb9c6f0ed
Step 6/7 : RUN yum update
 ---> Using cache
 ---> 473cf8a6416e
Step 7/7 : RUN yum install -y mysql
 ---> Running in 4e5e446fe864
Last metadata expiration check: 0:01:30 ago on Tue Dec 15 08:49:57 2020.
Dependencies resolved.
===========================================================================================
 Package                      Arch    Version                              Repo        Size
===========================================================================================
Installing:
 mysql                        x86_64  8.0.21-1.module_el8.2.0+493+63b41e36 appstream   12 M
Installing dependencies:
 libedit                      x86_64  3.1-23.20170329cvs.el8               baseos     102 k
 mariadb-connector-c-config   noarch  3.0.7-1.el8                          appstream   13 k
 mysql-common                 x86_64  8.0.21-1.module_el8.2.0+493+63b41e36 appstream  148 k
Enabling module streams:
 mysql                                8.0                                                  

Transaction Summary
===========================================================================================
Install  4 Packages

Total download size: 12 M
Installed size: 63 M
Downloading Packages:
(1/4): mariadb-connector-c-config-3.0.7-1.el8.n 440 kB/s |  13 kB     00:00    
(2/4): mysql-common-8.0.21-1.module_el8.2.0+493 3.1 MB/s | 148 kB     00:00    
(3/4): mysql-8.0.21-1.module_el8.2.0+493+63b41e  33 MB/s |  12 MB     00:00    
(4/4): libedit-3.1-23.20170329cvs.el8.x86_64.rp  60 kB/s | 102 kB     00:01    
--------------------------------------------------------------------------------
Total                                           2.9 MB/s |  12 MB     00:04     
warning: /var/cache/dnf/appstream-02e86d1c976ab532/packages/mariadb-connector-c-config-3.0.7-1.el8.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY
CentOS Linux 8 - AppStream                      1.6 MB/s | 1.6 kB     00:00    
Importing GPG key 0x8483C65D:
 Userid     : "CentOS (CentOS Official Signing Key) <security@centos.org>"
 Fingerprint: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1 
  Installing       : libedit-3.1-23.20170329cvs.el8.x86_64                  1/4 
  Installing       : mariadb-connector-c-config-3.0.7-1.el8.noarch          2/4 
  Installing       : mysql-common-8.0.21-1.module_el8.2.0+493+63b41e36.x8   3/4 
  Installing       : mysql-8.0.21-1.module_el8.2.0+493+63b41e36.x86_64      4/4 
  Running scriptlet: mysql-8.0.21-1.module_el8.2.0+493+63b41e36.x86_64      4/4 
  Verifying        : mariadb-connector-c-config-3.0.7-1.el8.noarch          1/4 
  Verifying        : mysql-8.0.21-1.module_el8.2.0+493+63b41e36.x86_64      2/4 
  Verifying        : mysql-common-8.0.21-1.module_el8.2.0+493+63b41e36.x8   3/4 
  Verifying        : libedit-3.1-23.20170329cvs.el8.x86_64                  4/4 

Installed:
  libedit-3.1-23.20170329cvs.el8.x86_64                                         
  mariadb-connector-c-config-3.0.7-1.el8.noarch                                 
  mysql-8.0.21-1.module_el8.2.0+493+63b41e36.x86_64                             
  mysql-common-8.0.21-1.module_el8.2.0+493+63b41e36.x86_64                      

Complete!
Removing intermediate container 4e5e446fe864
 ---> 5b689502d907
Successfully built 5b689502d907
Successfully tagged centos:kaven.1

查看镜像的详细信息。

docker image inspect centos:kaven.1

在这里插入图片描述

查看所有镜像,很明显镜像构建成功了。

docker images
[root@izoq008ryseuupz ~]# docker images
REPOSITORY                                                     TAG                 IMAGE ID            CREATED             SIZE
centos                                                         kaven.1             5b689502d907        4 minutes ago       347MB
centos                                                         8.3.2011            300e315adb2f        7 days ago          209MB

基于构建的镜像创建centos.test.1容器。

docker run -it --name centos.test.1 centos:kaven.1
[root@izoq008ryseuupz ~]# docker run -it --name centos.test.1 centos:kaven.1
[root@48ef31528900 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@48ef31528900 /]# exit  
exit

Dockerfile中的FROM、ARG、LABEL、MAINTAINER、RUN、CMD指令就介绍到这里。

写博客是博主记录自己的学习过程,如果有错误,请指正,谢谢!

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ITKaven

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值