Java 8 重复注解 类型注解

一、Dockerfile概述

A、Docker制作镜像方式

  • 基于容器制作镜像:
    • 每次都需要启动容器,然后在容器内部执行相关命令,才能制作容器(比较麻烦)。
    • 制作后的容器变得很庞大,用户拷贝也可能成为问题。
  • 基于Dockerfile制作镜像:
    • Dockerfile是制作镜像的源码文件、是构建容器过程中的指令。Docker能够读取Dockerfile的指令进行自动构建容器。
    • 基于Dockerfile制作镜像,每一个指令都会创建一个镜像层(即镜像都是多层叠加而成)。
    • 层越多、效率越低。创建镜像,层越少越好(能在一个指令完成的动作尽量通过一个指令)

B、Docker镜像制作过程

  • 首先需要有一个制作镜像的目录,该目录下有个文件名称必须为Dockerfile
  • docker build读取Dockerfile是按顺序依次读取Dockerfile里的配置,且第一条非注释指令必须是FROM开头,表示基于哪个基础镜像来构建新镜像。
  • Dockerfile有指定的格式:#号开头为注释、指定默认用大写字母来表示以区分指令和参数。

二、Dockerfile指令

组成部分命令
基础镜像信息FROM
维护者信息MAINTAINER
镜像操作指令RUNCOPYADDEXPOSEWORKDIRONBUILDUSERVOLUME
容器启动时执行指令CMDENTRYPOINT

A、FROM

  • FROM指令是最重要一个且必须为Dockerfile文件开篇的第一个非注释行。用于指定映像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境。
  • 基准镜像可以是任何可用镜像文件。
  • 默认情况下,docker build会在Docker主机上查找指定的镜像文件。当不存在时,则会从Docker Hub Registry上拉取所需的镜像文件。如果找不到指定的镜像文件, docker build会返回一个错误信息。
  • 除了指定现有的基础镜像以外,还存在一个特殊的镜像srcatch,这个镜像是一个虚拟的概念,并不实际存在,它表示一个空白的镜像。如果以scratch作为基础镜像,意味着将不使用任何镜像为基础,接下来你所写的指令将作为第一层开始存在。
    • 不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见。如swarmcoreos/etcd。对Linux下静态编译的程序来说,并不需要其他操作提供其运行时支持,所需的一切库都在可执行文件里了。因此使用scratch作为基础,可以使镜像的体积更加小巧。
# <repository>:指定作为 base image 的名称
# <tag>:base image 的标签,为可选项,省略时默认为 latest
# <digest>:校验码
FROM <repository>[:<tag>]
FROM <repository>@<digest>

B、MAINTANIER

  • 用于让镜像制作者提供本人的详细信息。
  • Dockerfile并不限制MAINTAINER指令可在出现的位置,但推荐放置于FROM指令之后。
# 可以是任何文本信息,但约定俗成地使用作者名称及邮件地址
# MAINTAINER "hjyang <17826****@qq.com>
MAINTAINER  <authtor's detail> l <author's detail>

C、COPY

  • Docker宿主机复制文件至目标镜像的文件系统
# <src>:要复制的源文件或目录,支持使用通配符
# <dest>:目标路径,即正在创建的image的文件系统路径
# 建议为<dest>使用绝对路径(镜像中的路径)。否则COPY指令则以WORKDIR为其起始路径
COPY <src> ... <dest>

# 如果路径中有空格,建议使用该方式
COPY ["<src>",... "<dest>"]

COPY准则:

  • <src>必须是build上下文中的路径,不能是其父目录中的文件。
  • 如果<src>是目录,则再内部文件或者子目录会被递归复制,但是<src>目录本身不被复制。
  • 如果<dest>事先不存在,它会被自动创建,包括其父目录。但是它只是单纯的复制,并不会做文件提取和解压工作。
  • 需要复制的目录一定要放在Dockerfile文件的同级目录下。

因为构建环境会上传到Docker守护进程,而复制是在Docker守护进程中进行的。任何位于构建环境之外的东西都是不可用的。COPY指令的目的的位置则必须是容器内部的一个绝对路径。

示例:
创建一个目录/data/data/docker,在该目录下新建index.html文件用于镜像制作的素材文件,在/data/data/docker下新建Dockerfile文件,把index.html拷贝到新镜像里。

mkdir -p /data/data/docker

touch /data/data/docker/index.html
touch /data/data/docker/Dockerfile

Dockerfile

# 设置继承自哪个镜像
FROM ubuntu:14.04
# 下面是创建者的基本信息
MAINTAINER hjyang (17826xxxx@qq.com)

COPY index.html  /data/html/

Dockerfile制作完成后,用docker build命令基于Dockerfile制作新镜像

cd /data/data/docker

docker build -t copytest:v1 ./

docker images

在这里插入图片描述
基于新镜像启动容器,在容器内部有目录/data/html/有文件index.html

docker run -it --rm --name copytest01 copytest:v1

ls /data/html/index.html

在这里插入图片描述


D、ADD

  • ADD指令类似于COPY指令,ADD支持使用TAR文件URL路径
    ADD <src> ... <dest>
    ADD ["<src>",... "<dest>"]
    

ADD操作准则:

  • 如果<src>URL(不能是FTP格式的URL):
    • <dest>不以/结尾,则<src>指定的文件将被下载并直接被创建为<dest>
    • <dest>/结尾,则URL指定的文件将被直接下载,并保存为<dest>/<filename>
  • 如果<src>是宿主机上的压缩格式的tar文件,它将被展开为一个目录。其行为类似于tar -x命令(通过URL获取到的tar文件将不会自动展开)。
  • 如果<src>有多个:或间接或直接使用了通配符,则<dest>必须是一个以/结尾的目录路径。如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内容将被直接写入到<dest>

示例:
创建一个目录/data/data/docker,在该目录有apache-tomcat-8.5.45.tar.gz

mkdir -p /data/data/docker

touch /data/data/docker/index.html
touch /data/data/docker/Dockerfile

Dockerfile

# 设置继承自哪个镜像
FROM ubuntu:14.04
# 下面是创建者的基本信息
MAINTAINER hjyang (17826xxxx@qq.com)

COPY index.html  /data/html/
ADD http://nginx.org/download/nginx-1.14.0.tar.gz /data/nginx/
ADD apache-tomcat-8.5.45.tar.gz /data/tomcat/

Dockerfile制作完成后,用docker build命令基于Dockerfile制作新镜像

cd /data/data/docker

docker build -t addtest:v1 ./

docker images

在这里插入图片描述
基于新镜像启动容器,并检查

docker run -it --rm --name addtest01 addtest:v1

ls /data/nginx/

ls /data/tomcat/apache-tomcat-8.5.45/

在这里插入图片描述
注意:此时URL对应的Nginx已经被下载到/data/nginx/下,且tar包不会被展开。同时/data/tomcat/目录下有个展开的目录。


E、WORKDIR

  • WORKDIR为工作目录,指当前容器环境的工作目录。用于为Dockerfile中所有的RUNCMDENTRYPOINTCOPYADD指定工作目录。
  • Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,不过相对此前一个WORKDIR指令指定的路径。另外,WORKDIR也可调用由 ENV指定定义的变量。
WORKDIR <dirpath>

示例一:
WORKDIR使用绝对路径或相对路径

WORKDIR /a
WORKDIR b
WORKDIR c

# 执行结果 /a/b/c
RUN pwd

WORKDIR也可以解析环境变量

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME

# 执行结果 /path/$DIRNAME
RUN pwd

示例二:
指定WORKDIR/usr/local,相当于是容器启动后,会把工作目录切换到/usr/local下,而不是默认的根目录。如下例子:相对路径./src/的绝对路径为容器的/usr/local/src,制作镜像时Nginx包拷贝到/usr/local/src,把Tomcat包解压到/usr/local/src下。

Dockerfile

# 设置继承自哪个镜像
FROM ubuntu:14.04
# 下面是创建者的基本信息
MAINTAINER hjyang (17826xxxx@qq.com)

WORKDIR "/usr/local"
ADD http://nginx.org/download/nginx-1.14.0.tar.gz ./src/
ADD apache-tomcat-8.5.45.tar.gz ./

Dockerfile制作完成后,用docker build命令基于Dockerfile制作新镜像

docker build -t workdirtest:v1 ./

docker images

在这里插入图片描述
基于新镜像启动容器,容器启动后工作路径直接切换为/usr/local

docker run -it --rm --name workdirtest workdirtest:v1

ls
ls ./src

在这里插入图片描述


F、VOLUME

VOLUME <mountpoint>

VOLUME ["<mountpoint>"]
  • 定义卷:只能是Docker管理的卷。VOLUME为容器上的目录,用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其它容器上的卷。
  • 如果挂载点目录路径下此前存在文件,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中。
  • 实现挂载功能:可以将内地文件夹或者其他容器种得文件夹挂在到这个容器中。
    • VOLUME ["/data"]["/data"]可以是JsonArray ,也可以是多个值。如下几种写法都是正确的:
      VOLUME ["/var/log/"]
      VOLUME /var/log
      VOLUME /var/log /var/db
      
    • 使用场景为需要持久化存储数据。容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。

示例:
Dockerfile

# 设置继承自哪个镜像
FROM ubuntu:14.04
# 下面是创建者的基本信息
MAINTAINER hjyang (17826xxxx@qq.com)

VOLUME "/data/docker/volume"
COPY  index.html  /data/docker/volume/

Dockerfile制作完成后,用docker build命令基于Dockerfile制作新镜像

docker build -t volumetest:v1 ./

docker images

在这里插入图片描述
基于新镜像启动容器:

docker run -it --rm --name volumetest volumetest:v1

ls /data/docker/volume/

在这里插入图片描述
查看容器挂载的卷:

docker inspect -f {{.Mounts}} volumetest

# 本地默认保存位置
cd /var/lib/docker/volumes/c4cb5b268ce41e48ccf366d7bf6f7c356e292703faf8adea980df3abc5358a6b/_data

在这里插入图片描述


G、EXPOSE

# <protocol>用于指定传输层协议(tcp或udp二者之一,默认为TCP协议)
EXPOSE <port>[/<protocol>] [<port>[/<protocol>] ...] l
  • 暴露指定端口:用于为容器打开指定要监听的端口以实现与外部通信。
  • EXPOSE指令可一次指定多个端口,但是不能指定暴露为宿主机的指定端口。因为指定的宿主机端口可能已经被占用,因此这里使用随机端口(EXPOSE 11211/udp 11211/tcp)。
  • EXPOSE指令是声明运行时容器服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在Dockerfile中这样声明有两个好处:
    • 一个是帮助镜像使用者更好的理解这个镜像服务的守护端口。
    • 另一个作用则是在运行时使用随机端口映射时,也就是docker run -p命令时,会自动随机映射EXPOSE端口。
  • 要将EXPOSE和在运行时使用-p <宿主端口>:<容器端口>区分开来:
    • -p是映射宿主端口和容器端口,就是将容器的对应端口服务公开给外界访问。
    • EXPOSE仅仅是声明端口使用什么端口而已,并不会自动在宿主进行端口映射。
      示例:
      Dockerfile
# 设置继承自哪个镜像
FROM ubuntu:14.04
# 下面是创建者的基本信息
MAINTAINER hjyang (17826xxxx@qq.com)

VOLUME "/data/docker/volume"
COPY  index.html  /data/docker/volume/

EXPOSE 80/tcp

Dockerfile制作完成后,用docker build命令基于Dockerfile制作新镜像

docker build -t exposetest:v1 ./

docker images

在这里插入图片描述
基于新镜像启动容器(启动容器要跟选项-P来暴露端口):

docker run -it -P --rm --name exposetest exposetest:v1

ls /data/docker/volume/

在这里插入图片描述
查看80端口是否暴露

docker port exposetest

在这里插入图片描述

H、ENV

  • ENV用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如 ENVADDCOPY等)所调用 (即先定义后调用)。
  • 调用格式为$variable_name${variable_name}
#  <key>之后所有内容均会被视作其<value>的组成部分,因此一次只能设置一个变量
ENV <key> <value>

# 可用一次设置多个变量,每个变量为一个“<key>=<value>”的键值对。
# 如果<value>包含空格,以反斜线(\)进行转义,也可通过对<value>加引号进行标识,另外反斜线也可以用于续行。
# 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能
ENV <key>=<value> ...

示例:
下载Nginx包,其中Nginx的版本和Nginx包的路径用变量替换。

Dockerfile

# 设置继承自哪个镜像
FROM ubuntu:14.04
# 下面是创建者的基本信息
MAINTAINER hjyang (17826xxxx@qq.com)

ENV nginx_version=1.14.0
ENV nginx_url=http://nginx.org/download/nginx-${nginx_version}.tar.gz

ADD ${nginx_url} /data/nginx/

Dockerfile制作完成后,用docker build命令基于Dockerfile制作新镜像

docker build -t envtest:v1 ./

docker images

在这里插入图片描述
基于新镜像启动容器:

docker run -it --rm --name envtest envtest:v1

ls /data/nginx/

在这里插入图片描述

I、RUN

  • RUN用于指定docker build过程中运行的程序,其可以是任何命令。但是有个限定,一般为基础镜像可以运行的命令,如基础镜像为CentOS,安装软件命令为yum而不是ubuntu里的apt-get命令。
  • RUNCMD都可以改变容器运行的命令程序,但是运行的时间节点有区别:
    • RUN表示在docker build运行的命令。
    • CMD是将镜像启动为容器运行的命令。
    • 因为一个容器正常只用来运行一个程序,因此CMD一般只有一条命令。如果CMD配置多个,则只有最后一条命令生效,而RUN可以有多个。
  • 如果RUN的命令很多,就用&&符号连接多个命令,少构建镜像层,提高容器的效率。
# <command>通常是一个shell命令,且以“/bin/sh -c”作为父进程来运行它。
# 这意味着此进程在容器中的PID不为1,不能接收Unix信号。
# 因此:当使用docker stop <container>命令停止容器时,此进程接收不到SIGTERM信号。
RUN <command>

# 参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或参数。
# 此种格式指定的命令不会以“/bin/sh -c”来发起,表示这种命令在容器中直接运行,不会作为shell的子进程。
# 因此:常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行。
RUN ["<executable>", "<param1>", "<param2>"]

示例一:
下载Nginx包,用RUN命令来解压。

Dockerfile

# 设置继承自哪个镜像
FROM ubuntu:14.04
# 下面是创建者的基本信息
MAINTAINER hjyang (17826xxxx@qq.com)

ENV nginx_version=1.14.0
ENV nginx_url=http://nginx.org/download/nginx-${nginx_version}.tar.gz

ADD ${nginx_url} /data/nginx/

RUN tar -xf /data/nginx/nginx-${nginx_version}.tar.gz -C /data/nginx/

Dockerfile制作完成后,用docker build命令基于Dockerfile制作新镜像

docker build -t runtest:v1 ./

docker images

在这里插入图片描述
基于新镜像启动容器:

docker run -it --rm --name runtest runtest:v1

ls /data/nginx/

在这里插入图片描述


J、CMD

  • 类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过二者的运行时间点不同(见上面RUN指令)。
# 语法格式的意义同 RUN
CMD <command>

# 语法格式的意义同 RUN
CMD ["<executable>","<param1>","<param2>"]

# 用于为ENTRYPOINT指令提供默认参数
CMD["<param1>","<param2>"]

示例一:
编译安装Nginx,并将镜像的默认命令修改为Nginx启动于前台,暴露80端口

Dockerfile

# 设置继承自哪个镜像
FROM centos:7.3.1611
# 下面是创建者的基本信息
MAINTAINER hjyang (17826xxxx@qq.com)

ENV nginx_version=1.14.0
ENV nginx_url=http://nginx.org/download/nginx-${nginx_version}.tar.gz

WORKDIR "/data/nginx/"

EXPOSE 80/tcp

ADD ${nginx_url} /data/nginx/
RUN tar xf nginx-${nginx_version}.tar.gz -C /data/nginx/ && yum -y install gcc pcre-devel openssl-devel make \
    && cd nginx-${nginx_version} && ./configure && make && make install

CMD ["/data/nginx/sbin/nginx","-g","daemon off;"]

Dockerfile制作完成后,用docker build命令基于Dockerfile制作新镜像

docker build -t cmdtest:v1 ./

docker images

基于新镜像启动容器:

docker run -it --rm --name cmdtest cmdtest:v1

ls /data/nginx/

测试,容器的ip 为 172.17.0.2,得到nginx的测试页
[root@docker yum.repos.d]# curl 172.17.0.2
查看容器80口被暴露为哪个口
[root@docker yum.repos.d]# docker port nginxv3
80/tcp -> 0.0.0.0:32772
[root@docker yum.repos.d]# curl 10.10.10.72:32772

注意,CMD在dockerfile里写的命令,如果启动容器的命令行里执行命令,则会把dockerfile里的命令覆盖掉,如下,容器启动后,执行/bin/bash,而不是启动nginx于前台
[root@docker workshop]# docker run -it --rm -P --name nginxv3 nginx:v3 /bin/bash
[root@5f2f4b930df3 src]# ss -ntlp

如果dockerfile指定的CMD不允许覆盖,则使用ENTRYPOINT

K、ENTRYPOINT

  • 类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序。
  • CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖。而且这些命令行参数会被当作参数传递给ENTRYPOINT指定指定的程序。
  • 不过docker run命令的--entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序。
ENTRYPOINT <command>

ENTRYPOINT ["<excutable>","<param1>","<param2>"]

docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用 。Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效。

例子
把上例中的CMD执行命令,改成ENTRYPOINT
vim Dockerfile
FROM centos:7.3.1611
MAINTAINER “sunny sunny@ghbsunny.cn”
ENV nginx_ver=1.14.0
ENV nginx_url=http://nginx.org/download/nginx-${nginx_ver}.tar.gz
WORKDIR “/usr/local/src”
EXPOSE 80/tcp
ADD n g i n x u r l / u s r / l o c a l / s r c / R U N t a r x f n g i n x − {nginx_url} /usr/local/src/ RUN tar xf nginx- nginxurl/usr/local/src/RUNtarxfnginx{nginx_ver}.tar.gz && yum -y install gcc pcre-devel openssl-devel make
&& cd nginx-${nginx_ver} && ./configure && make && make install
ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g",“daemon off;”]

制作镜像
[root@docker workshop]# docker build -t nginx:v5 ./
由于这次镜像修改相比上次很少,只差了一层CMD,构建过程直接使用缓存,所以速度很快,dockerfile里,建议CMD和ENTRYPOINT不用复用,二者选其一,除非明确指定CMD里的命令参数会被ENTRYPOINT当做参数执行

启动容器
run命令不带其他命令
[root@docker workshop]# docker run -it --rm -P --name nginxv3 nginx:v5
直接启动,可以正常启动nginx,并暴露端口
run命令修改默认命令如/bin/bash,与上例CMD不一样,此时报选项错误,因为此时会把 /bin/bash当做参数传递给ENTRYPOINT指定的指令,此时ENTRYPOINT指定的指令为启动nginx,不能识别/bin/bash
[root@docker workshop]# docker run -it --rm -P --name nginxv3 nginx:v5 /bin/bash
nginx: invalid option: “/bin/bash”
[root@docker workshop]#
但是,如果一定要覆盖dockerfile里指定的ENTRYPOINT命令,那么在run命令使用参数–entrypoint来覆盖,如下
[root@docker workshop]# docker run -it --rm -P --name nginxv3 --entrypoint /bin/bash nginx:v5
[root@4c940d422f20 src]# pwd
/usr/local/src
[root@4c940d422f20 src]#
成功以进程/bin/bash启动了容器,覆盖了dockerfile里设定的nginx启动命令

L、USER

  • USER用于指定运行image时的或运行Dockerfile中任何RUNCMDENTRYPOINT指令指定的程序时的用户名或UID ,即改变容器中运行程序的身份。
  • 默认情况下,container的运行身份为root用户。
#  <UID>可以为任意数字,但实践中其必须为/etc/passwd中某用户的有效UID,否则docker run命令将运行失败
USER  <UID>|<UserName>

M、ONBUILD

  • ONBUILD用于在Dockerfile中定义一个触发器,用来指定运行docker指令。
  • Dockerfile用于build映像文件,此映像文件亦可作为base image被另一个Dockerfile用作FROM指令的参数,并以之构建新的映像文件。在后面的这个Dockerfile中的FROM指令在build过程中被执行时,将会 “触发 ”创建其base imageDockerfile文件中的ONBUILD指令定义的触发器。
ONBUILD <INSTRUCTION>

尽管任何指令都可注册成为触发器指令,但是ONBUILD不能自我嵌套,且不会触发FROMMAINTAINER指令
使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,例如 ruby:2.0-onbuild
在ONBUILD指令中使用ADD或COPY指令应该格外小心,因为新构建过程的上下文在缺少指定的源文件时会失败
ONBUILD 在构建镜像时不会运行,是别人基于这个镜像作为基础镜像构建时,才会运行

如下例子
增加一个ONBUILD命令,执行RUN
FROM centos:7.3.1611
MAINTAINER “sunny sunny@ghbsunny.cn”
ENV nginx_ver=1.14.0
ENV nginx_url=http://nginx.org/download/nginx-${nginx_ver}.tar.gz
WORKDIR “/usr/local/src”
EXPOSE 80/tcp
ADD n g i n x u r l / u s r / l o c a l / s r c / R U N t a r x f n g i n x − {nginx_url} /usr/local/src/ RUN tar xf nginx- nginxurl/usr/local/src/RUNtarxfnginx{nginx_ver}.tar.gz && yum -y install gcc pcre-devel openssl-devel make
&& cd nginx-${nginx_ver} && ./configure && make && make install
CMD ["/usr/local/nginx/sbin/nginx","-g",“daemon off;”]
ONBUILD RUN echo -e “\nSunny do an onbuild~\n” >> /etc/issue

构建镜像
[root@docker workshop]# docker build -t nginx:v6 ./
基于nginx:v6启动容器,此时/etc/issue还没写入echo要插入的信息
[root@docker workshop]# docker run -it --rm -P --name nginxv3 nginx:v6 /bin/bash
[root@16e90f7a6460 src]# cat /etc/issue
\S
Kernel \r on an \m
[root@16e90f7a6460 src]#
然后基于这个nginx:v6镜像,再次制作一个新镜像,编辑一个新的Dockerfile
[root@docker ~]# mkdir nginxv7
[root@docker ~]# cd nginxv7/
[root@docker nginxv7]# vim Dockerfile
FROM nginx:v6
MAINTAINER “sunny sunny@ghbsunny.cn”
CMD “/bin/bash”
构建镜像,注意,会提示执行一个build trigger,如下Executing 1 build trigger
[root@docker nginxv7]# docker build -t nginx:v7 ./
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM nginx:v6
#Executing 1 build trigger
—> Running in 6bb18c52af99
Removing intermediate container 6bb18c52af99
基于新镜像nginx:v7启动新容器nginxv7
[root@docker nginxv7]# docker run -it --rm --name nginxv7 nginx:v7
[root@becc66948713 src]# cat /etc/issue
\S
Kernel \r on an \m
Sunny do an onbuild~
[root@becc66948713 src]#
此时,在旧的镜像中的dockerfile里的ONBUILD已经触发,把信息写入到/etc/issue里

N、LABEL

  • LABEL为磁盘映像文件添加元数据,可以基于这个LABEL调用这些元数据,一个LABEL就是一堆k/v值,一个镜像文件可以有多个LABEL
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页