Dockerfile是Docker用来构建镜像的文本文件,包含自定义的指令和格式。可以通过docker build命令利用Dockerfile构建镜像。Dockerfile提供了一系列统一的资源配置语法指令,开发人员可以根据需求定制Dockerfile,然后使用这份Dockerfile文件进行自动化镜像构建,简化了构建镜像的复杂过程,同时Dockerfile与镜像配合使用,使Docker在构建时可以充分利用镜像的功能进行缓存,大大提升了Docker的使用效率。

本文主要对Dockerfile指令和使用Dockerfile构建镜像进行简单总结。

一.Dockerfile基本结构

Dockerfile由一行行命令语句组成,支持以#开头的注释行。一般Dockerfile主体分为基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令四个部分。下面是从Docker Hub上拿来的nginx的一个Dockerfile的例子,可以对Dockerfile的基本结构有个大体的了解,我们在编写自己的Dockerfile时也可以参考Docker Hub上优秀镜像的Dockerfile,通过优秀镜像的Dockerfile来学习和总结经验来编写高效的Dockerfile文件。

#指定所构建镜像的基础镜像
FROM debian:buster-slim#指定生成镜像的元数据标签信息
LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>"#指定环境变量
ENV NGINX_VERSION   1.18.0
ENV NJS_VERSION     0.4.0
ENV PKG_RELEASE     1~buster#运行指定命令
RUN set -x \
# create nginx user/group first, to be consistent throughout docker variants&& addgroup --system --gid 101 nginx \&& adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx \&& apt-get update \&& apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates \&& \NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \found=''; \for server in \ha.pool.sks-keyservers.net \hkp://keyserver.ubuntu.com:80 \hkp://p80.pool.sks-keyservers.net:80 \pgp.mit.edu \; do \echo "Fetching GPG key $NGINX_GPGKEY from $server"; \apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \done; \test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \&& dpkgArch="$(dpkg --print-architecture)" \&& nginxPackages=" \nginx=${NGINX_VERSION}-${PKG_RELEASE} \nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} \nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} \nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} \nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-${PKG_RELEASE} \" \&& case "$dpkgArch" in \amd64|i386) \
# arches officialy built by upstreamecho "deb https://nginx.org/packages/debian/ buster nginx" >> /etc/apt/sources.list.d/nginx.list \&& apt-get update \;; \*) \
# we're on an architecture upstream doesn't officially build for
# let's build binaries from the published source packagesecho "deb-src https://nginx.org/packages/debian/ buster nginx" >> /etc/apt/sources.list.d/nginx.list \\
# new directory for storing sources and .deb files&& tempDir="$(mktemp -d)" \&& chmod 777 "$tempDir" \
# (777 to ensure APT's "_apt" user can access it too)\
# save list of currently-installed packages so build dependencies can be cleanly removed later&& savedAptMark="$(apt-mark showmanual)" \\
# build .deb files from upstream's source packages (which are verified by apt-get)&& apt-get update \&& apt-get build-dep -y $nginxPackages \&& ( \cd "$tempDir" \&& DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" \apt-get source --compile $nginxPackages \) \
# we don't remove APT lists here because they get re-downloaded and removed later\
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
# (which is done after we install the built packages so we don't have to redownload any overlapping dependencies)&& apt-mark showmanual | xargs apt-mark auto > /dev/null \&& { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \\
# create a temporary local APT repo to install from (so that dependency resolution can be handled by APT, as it should be)&& ls -lAFh "$tempDir" \&& ( cd "$tempDir" && dpkg-scanpackages . > Packages ) \&& grep '^Package: ' "$tempDir/Packages" \&& echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list \
# work around the following APT issue by using "Acquire::GzipIndexes=false" (overriding "/etc/apt/apt.conf.d/docker-gzip-indexes")
#   Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied)
#   ...
#   E: Failed to fetch store:/var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages  Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied)&& apt-get -o Acquire::GzipIndexes=false update \;; \esac \\&& apt-get install --no-install-recommends --no-install-suggests -y \$nginxPackages \gettext-base \curl \&& apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \\
# if we have leftovers from building, let's purge them (including extra, unnecessary build deps)&& if [ -n "$tempDir" ]; then \apt-get purge -y --auto-remove \&& rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \fi# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \&& ln -sf /dev/stderr /var/log/nginx/error.log# make default server listen on ipv6
RUN sed -i -E 's,listen       80;,listen       80;\n    listen  [::]:80;,' \/etc/nginx/conf.d/default.conf#指定镜像内服务所监听的端口
EXPOSE 80#指定所创建镜像启动的容器接收退出的信号值
STOPSIGNAL SIGTERM#指定启动容器时默认执行的命令
CMD ["nginx", "-g", "daemon off;"]

二.Dockerfile格式

Dockerfile的格式如下:

# Comment
INSTRUCTION arguments

其中指令(INSTRUCTION)不区分大小写,但是为了与参数区分,通常情况大写。Docker会按顺序运行Dockerfile中的指令。Dockerfile必须以FROM指令开头。它可以在解析器指令(parser directives),注释(comments)和全局范围参数(globally scoped ARGs)之后。FROM指令具体指定你想要构建的镜像的父镜像(Parent Image)。FROM指令只能在一个或多个声明在Dockerfile中的FROM行中使用的参数即ARG指令之前。
Docker将以开头的行视为注释,除非该行是有效的解析器指令(parser directive)。在一行中的任何其他位置使用标记都将被视为参数,它允许下面这样的语句。还有注释中不支持行连续字符(\)。

# Comment
RUN echo 'we are running some # of cool things'

三.解析器指令(Parser directives)

解析器指令是可选的,并且会影响Dockerfile中后续行的处理方式。解析器指令不会添加层到构建的镜像中,也不会显示为一个构建步骤。解析器指令以#directive = value的形式编写为特殊类型的注释,单个指令只能使用一次。
一旦一个注释,空行或者构建指令被执行。Docker就不会再寻找解析器指令。相反它会将任何符合解析器指令的格式视为注释,并且不会去尝试验证它是否是一个解析器指令,因此所有的解析器指令都必需位于Dockerfile的顶部。
解析器指令不区分大小写,但是它们通常是小写的并且在每个解析器指令后会使用空行分隔,解析器指令不支持行连续字符(\),解析器指令允许非断行空格字符,根据上述规则,以下示例均不是有效的解析器指令:
使用行连续字符(\)无效:

# direc \
tive=value

出现两次无效:

# directive=value1
# directive=value2
FROM ImageName

出现在构建器指令后被视为注释:

FROM ImageName
# directive=value

出现在注释后被视为注释而不是解析器指令:

# About my dockerfile
# directive=value
FROM ImageName

未被识别的未知指令会被视为注释,而出现在其后的有效指令也会被视为注释:

# unknowndirective=value
# knowndirective=value

解析器指令支持syntaxescape

1.syntax

格式

# syntax=[remote image reference]

示例
# syntax=docker/dockerfile
# syntax=docker/dockerfile:1.0
# syntax=docker.io/docker/dockerfile:1
# syntax=docker/dockerfile:1.0.0-experimental
# syntax=example.com/user/repo:tag@sha256:abcdef...

只有使用BuildKit后端时才启用此功能,syntax指令设定用于构建当前Dockerfile的Dockerfile构建器的位置。BuildKit后端允许无缝使用以Docker镜像的形式分发并在容器沙箱环境中执行的构建器的外部实现。
自定义的Dockerfile实现能够:

  • 自动获取错误修正而无需更新守护程序
  • 确保所有用户都使用相同的实现来构建Dockerfile
  • 使用最新功能而不更新守护程序
  • 试用新的测试性的或第三方的功能
正式发布(Official releases)

Docker分发了可用于docker/dockerfile在Docker Hub上的仓库下构建Dockerfile的镜像的正式版本。这里有稳定版(stable)和测试版(experimental)两个发布新镜像的渠道。
稳定版渠道遵循的版本控制示例如下:

  • docker/dockerfile:1.0.0 - 只允许不可变版本 1.0.0
  • docker/dockerfile:1.0 - 允许版本 1.0.*
  • docker/dockerfile:1 - 允许版本 1.*.*
  • docker/dockerfile:latest - 稳定渠道发布的最新版本

测试版渠道在正式发布时使用稳定版渠道中主要和次要组成部分的增量版本控制的示例如下:

  • docker/dockerfile:1.0.1-experimental - 只允许不可变版本
    1.0.1-experimental
  • docker/dockerfile:1.0-experimental - 1.0版本之后最新发布的测试版
  • docker/dockerfile:experimental - 测试渠道发布的最新版本

我们可以根据需求选择合适的发布渠道,如果只想修正错误,则应使用docker/dockerfile:1.0,如果想从测试功能中受益,则应使用测试版渠道,如果正在使用测试版渠道,则较新的版本可能无法向后兼容,因此建议使用不可变的完整版本。

2.escape

格式

# escape=\ (backslash)# escape=` (backtick)

escape指令设定在Dockerfile中作为转义字符的字符,如果未指定,默认转义字符为\
转义字符既用于转义行中的字符,也用于转义换行符,这允许Dockerfile指令跨越多行。注意,无论escape解析器指令是否包含在Dockerfile中,都不会在RUN命令中执行转义,除非在行尾。
将转义字符设置为`Windows上特别有用,其中\是目录路径分隔符。`与Windows PowerShell一致。
通过以下示例可以对escape指令做一个简单的了解,该示例在Windows系统环境中会运行失败,第二行末尾的第二个\将被解释为换行符的转义符,而不是第一个\的转义目标,类似的第三行结尾的 \ 将会被作为换行符处理,这个dockerfile的结果就是第二行和第三行被认为是单个指令:

FROM microsoft/nanoserver
COPY testfile.txt c:\\
RUN dir c:\

上面的一个解决方案是使用/作为COPY指令和dir的目标。但是这种语法对于Windows上的路径来说并不自然,并且最坏的情况是由于Windows上的所有命令都不支持/作为路径分隔符,因此容易出错。
但是通过添加escape解析器指令,以下Dockerfile会在Windows上按照预期的方式的成功使用自然路径执行,具体方式如下:

# escape=`FROM microsoft/nanoserver
COPY testfile.txt c:\
RUN dir c:\

四.环境替换(Environment replacement)

ENV声明的环境变量也可以在Dockerfile的某些指令中作为参数使用,还可以处理转义,将字符串中的类似变量的语法包含在语句中。
Dockerfile中使用$variable_name${variable_name}标注环境变量具有相同的效果,并且括号语法通常用来解决没有空格的变量名称的问题,例如${foo}_bar
${variable_name}语法还支持以下指定的一些标准bash修饰符,下面的word在所有情况下可以是包括其他环境变量的任何字符串:

  • ${variable:-word}:如果设置了variable,结果将是该值,如果未设置variable,结果将是word
  • ${variable:+word}:如果设置了variable,结果将是word,否则结果是空字符串 。

我们还可以通过在变量前添加\来进行转义。例如\$foo\${foo},将分别转换为$foo${foo}文字,下面是一个应用示例,之后显示的是解析后的表示:

FROM busybox
ENV foo /bar
WORKDIR ${foo}   # WORKDIR /bar
ADD . $foo       # ADD . /bar
COPY \$foo /quux # COPY $foo /quux

另外Dockerfile中支持环境变量的有以下指令:ADDCOPYENVEXPOSEFROMLABELSTOPSIGNALUSERVOLUMEWORKDIRONBUILD
注意:环境变量替换将在整个指令中为每个变量使用相同的值。例如:

ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc

def的值为hello不是bye,然而ghi的值为bye,这是因为它不是将abc设置为bye的相同指令的一部分。

五.构建指令

Dockerfile的格式上文已经总结过了,其中用于构建镜像的构建指令一般格式为INSTRUCTION arguments,而Dockerfile中一般有以下构建指令:FROMLABELMAINTAINEREXPOSEENVENTRYPOINTVOLUMEUSERWORKDIRARGONBUILDSTOPSIGNALHEALTHCHECKSHELLRUNCMDADDCOPY。下面将对这些指令进行简单总结。

1.FROM

格式

FROM [--platform=<platform>] <image> [AS <name>]

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

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

功能描述

FROM指令初始化一个新的构建阶段并为后续指令设置基础镜像。因此有效的Dockerfile必须以FROM指令开头,其中基础镜像可以是任何有效镜像,而通过从公有仓库中拉取镜像来启动它尤其容易。

Options

--platform选项在FROM引用了多平台镜像的情况下可以用于指定镜像所属的平台。例如linux/amd64linux/arm64windows/amd64,默认会使用发起构建请求的目标平台,也可以在该选项的值中使用全局构建参数。

注意

ARGDockerfile中唯一可以在FROM之前的指令。

FROM可以在单个Dockerfile中多次出现以创建多个镜像,或者使用一个构建阶段作为另一个构建阶段的依赖项。这只需在每个新的FROM指令之前记下提交输出的最后一个镜像ID。每个FROM指令会清除先前指令创建的任何状态。

通过将AS name添加到FROM指令可以将可选的名称赋予到新的构建阶段,该名称可以在后续的FROMCOPY --from=<name|index>指令中使用,以引用此阶段构建的镜像。

tagdigest的值是可选的,如果省略其中任何一个,构建器默认采用latest标签,如果找不到tag值,构建器将返回错误。

ARG与FROM间的相互作用

FROM指令支持在第一个FROM之前发生的任何ARG指令声明的变量。示例如下:

ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-appFROM extras:${CODE_VERSION}
CMD  /code/run-extras

FROM之前声明的ARG在构建阶段之外,因此在FROM之后的任何指令中都不能使用它。要使用在第一个FROM之前声明的ARG的默认值,需在构建阶段内使用没有值的ARG指令。示例如下:

ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version

2.LABEL

格式

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

功能描述

LABEL指令将元数据添加到生成的镜像中,采用键值对的形式。

注意

想要在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,可以在一行中指定多个label。在Docker 1.10之前,这减小了最终镜像的大小,但现在不再是这样了。我们仍然可以选择在单个指令中指定多个label,有以下两种方式:

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

基础或父镜像(FROM指定镜像)中包含的label将继承到新构建的镜像,如果label已存在但具有不同的值,则最近应用的值将覆盖任何之前设置的值。

使用docker image inspect命令可以查看镜像的label,使用--format选项可以只显示label,例如命令docker image inspect --format='' myimage

3.MAINTAINER[已弃用(deprecated)]

格式

MAINTAINER <name>

功能描述

MAINTAINER指令设置生成镜像的作者(Author)字段。不过LABEL指令使用起来比MAINTAINER更灵活,可以设置我们所需的任何元数据并且能够轻松查看这些元数据,所以比起MAINTAINER指令更推荐使用LABEL指令。要设置与MAINTAINER字段对应的label,可以使用下面示例中的LABEL指令:

LABEL maintainer="SvenDowideit@home.org.au"

MAINTAINER字段可以通过docker inspect与其他label一起显示出来。

4.EXPOSE

格式

EXPOSE <port> [<port>/<protocol>...]

功能描述

EXPOSE指令通知Docker容器在运行时监听指定的网络端口,可以指定端口是监听TCP还是UDP,如果未指定网络协议,默认监听TCP。

注意

EXPOSE指令只是起到声明作用,并不会自动完成端口映射,也就是实际上不会发布端口。

如果想要在运行容器时实际发布端口,即完成端口映射,需要在docker run即创建运行容器时使用-p具体指定一个或多个主机端口与容器端口间的映射,或者使用-P,对容器中被监听的每个端口,Docker都将自动分配一个主机临时端口与之完成映射。

默认情况EXPOSE指定端口是监听TCP,也可以指定为UDP,例如markup EXPOSE 80/udp。如果要指定端口是同时监听TCP和UDP,需要包括两行指令,下面是一个示例,在这种情况如果将-Pdocker run一起使用,则端口将对TCP和UDP各暴露一次,由于-P使用的是Docker自动分配的主机临时端口,所以在TCP和UDP上与EXPOSE指定端口映射的主机端口不相同。

EXPOSE 80/tcp
EXPOSE 80/udp

无论EXPOSE如何设置,在运行时都可以使用-p进行覆盖。示例如下:

docker run -p 80:80/tcp -p 80:80/udp ...

5.ENV

格式

ENV <key> <value>

ENV <key>=<value> ...

功能描述

ENV指令指定一个环境变量<key>的值<value>,该值将存在于构建阶段中所有后续指令的环境中,并且可以在许多时候进行内部替换。

注意

ENV指令有两种形式,第一种ENV <key> <value>设置单个变量的值,第一个空格后面的整个字符串包括空格字符都将被视为<value>,因为该值将针对其他环境变量进行解释,在未对其进行转义的情况下将删除引号字符。示例如下:

ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy

第二种形式ENV <key>=<value> ...允许一次设置多个变量,注意与第一种形式不同的是第二种形式在语法中使用等号(=)。与命令行解析一样,引号和反斜杠可用于在值内包含空格。示例如下,该例在最终生成的镜像中与上例一样会产生相同的结果。

ENV myName="John Doe" myDog=Rex\ The\ Dog \myCat=fluffy

从生成的镜像运行容器时使用ENV设置的环境变量将保持不变,可以使用docker inspect来查看环境变量的值,还可以使用docker run --env <key>=<value>来改变指定环境变量的值。

环境变量的持久性可能会导致意想不到的副作用。例如设置ENV DEBIAN_FRONTEND noninteractive可能会使基于Debian的镜像上的apt-get用户感到困惑。要为单个命令设置值,可以使用RUN <key>=<value> <command>

6.ENTRYPOINT

格式

ENTRYPOINT指令有两种形式:

  • ENTRYPOINT ["executable", "param1", "param2"](exec形式,推荐形式)
  • ENTRYPOINT command param1 param2(shell形式)
功能描述

ENTRYPOINT指令指定镜像的默认入口命令,,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。

注意

使用exec形式时docker run <image>传入的命令行参数会被附加到ENTRYPOINT所有元素之后,并将覆盖CMD指定的所有元素。这允许将参数传递给入口点,即docker run <image> -d-d参数传递给入口点。使用docker run --entrypoint可以覆盖ENTRYPOINT指令。

使用shell形式时ENTRYPOINT指令会防止任何CMDrun命令行参数被使用,但缺点是ENTRYPOINT将作为/bin/sh -c的子命令启动,它不传递信号。这意味着进程在容器中的PID不是1并且不会接收Unix信号,所以命令进程将不会从docker stop <container>中接收到SIGTERM信号,即在通过docker stop的形式停止容器的时候接收不到停止信号将会导致异常终止。

Dockerfile中只有最后一个ENTRYPOINT指令才会生效。

exec形式将被解析为JSON数组,所以必须使用"来包围单词而不是'

exec形式不会调用命令shell,也就不会发生正常的shell处理,例如ENTRYPOINT [ "echo", "$HOME" ]不会对$HOME进行变量替换。如果需要shell处理,可以使用shell形式或者直接执行shell,例如ENTRYPOINT [ "sh", "-c", "echo $HOME" ]。当使用exec形式并直接执行shell时,跟shell形式的情况一样是执行环境变量扩展的shell而不是docker。

如果CMD在基础镜像中被设置过,设置ENTRYPOINT将会重置CMD为一个空值,这种情况下CMD必须在当前镜像中设置一个值。

CMD与ENTRYPOINT间的相互作用

CMDENTRYPOINT指令都定义了运行容器时执行的命令,以下为它们之间协作的规则。

  1. Dockerfile应至少指定一个CMDENTRYPOINT命令。
  2. 使用容器作为可执行文件时应定义ENTRYPOINT
  3. CMD应该作为ENTRYPOINT命令定义默认参数或在容器中执行特定命令的方法。
  4. 使用备用参数运行容器时CMD将被覆盖。

下表展示了不同的ENTRYPOINTCMD组合执行的命令:

. No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

7.VOLUME

格式

VOLUME ["/data"]

功能描述

VOLUME指令创建一个具有指定名称的挂载点,并将其标记为从本机主机或其他容器保存的外部挂载卷,该值可以是JSON数组或具有多个参数的普通字符串。使用docker run命令会用任何存在于基础镜像内指定位置的数据初始化新创建的卷。

注意

以下是关于Dockerfile中的卷的注意事项:

基于Windows容器的卷:使用基于Windows的容器时,容器中卷的目标必须是一个不存在的或空目录和C:以外的驱动器这两者之一。

从Dockerfile中更改卷:如果任何构建步骤在声明后更改卷内的数据,那么这些更改将被丢弃。

JSON格式:将列表解析为JSON数组必须使用"而不是'

主机目录在容器运行时被声明:主机目录(挂载点)本质上是依赖于主机的。这是为了保持镜像的可移植性,因为不能保证给定的主机目录在所有主机上都可用,因此无法从Dockerfile中挂载主机目录。VOLUME指令不支持指定host-dir参数,在创建或运行容器时必须指定挂载点。

8.USER

格式

USER <user>[:<group>]

USER <UID>[:<GID>]

功能描述

USER指令设置用户名或UID以及可选的用户组或GID,当运行镜像以及在Dockerfile中紧接着的所有RUNCMDENTRYPOINT指令时会使用该指定用户。

注意

当为用户指定用户组时,用户将只有指定的用户组的成员身份,任何其他已配置的用户组的成员身份将被忽略。

当用户没有主用户组时将使用root组运行镜像或下一条指令。

在Windows上,如果用户不是内置帐户,则必须先创建用户,这可以通过作为Dockerfile一部分调用的net user命令来完成。示例如下:

FROM microsoft/windowsservercore
# 在容器中创建Windows用户
RUN net user /add patrick
# 为后续命令设置用户名
USER patrick

9.WORKDIR

格式

WORKDIR /path/to/workdir

功能描述

WORKDIR指令为Dockerfile中的任何RUNCMDENTRYPOINTCOPYADD指令设置工作目录。如果WORKDIR不存在,即使它没有在任何后续Dockerfile指令中被使用,也将创建它。

注意

WORKDIR指令可以在Dockerfile中多次使用,如果提供了相对路径,则这个工作目录会基于之前WORKDIR指令指定的路径。示例如下,该Dockerfile最终的pwd命令输出为/a/b/c

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

WORKDIR指令可以解析之前使用ENV设置的环境变量,并且只能使用Dockerfile中显式设置的环境变量。示例如下,该Dockerfile最终的pwd命令输出为/path/$DIRNAME

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd

10.ARG

格式

ARG <name>[=<default value>]

功能描述

ARG指令定义了一个变量,在使用docker build命令构建时通过--build-arg <varname>=<value>将该变量传递给构建器。

注意

如果指定了未在Dockerfile中定义的构建参数,构建时会输出以下警告:

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

一个Dockerfile可以包含一个或多个ARG指令。

不推荐使用构建时变量即ARG指令定义的变量来传递诸如github密钥,用户凭证等私密数据。使用docker history命令时任何镜像用户都能看到构建时变量。

ARG指令可以包含可选的默认值,如果ARG指令指定了默认值,并且在构建时没有传递值,则构建器将使用默认值。

ARG变量的定义从Dockerfile中定义的行开始生效,而不是从命令行或其他地方的参数使用时才生效。因此在ARG指令定义变量之前,对该变量的任何使用都将导致空字符串,即在ARG指令定义变量之前使用该变量,该变量的值为空字符串。例如以下示例,如果通过docker build --build-arg user=what_user .构建镜像,则第二行USER的值为some_user,第四行的USER在设置用户时的值为what_user,并在命令行上传递了what_user值。

FROM busybox
USER ${user:-some_user}
ARG user
USER $user
# ...

ARG指令在它所定义的构建阶段结束超出了作用域,则在多个阶段都要使用arg,即每个阶段必须包含ARG指令。示例如下:

FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGSFROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS

我们可以使用ARGENV指令指定RUN指令可用的变量,使用ENV指令定义的环境变量始终覆盖ARG指令定义的同名变量。例如以下示例,如果通过docker build --build-arg CONT_IMG_VER=v2.0.1 .构建镜像,在这种情况下RUN指令使用的是v1.0.0而不是用户传递的ARG设置值v2.0.1

FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER v1.0.0
RUN echo $CONT_IMG_VER

ARG指令不同的是ENV值将始终保留在构建的镜像中,而ARG定义的变量将在镜像编译完成后就不再存在。例如以下示例,如果通过docker build .不带--build-arg构建镜像,在这种情况下CONT_IMG_VER仍然保存在镜像中,但其值为v1.0.0,因为它是ENV指令在第3行中的默认设置。

FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER
预定义ARG变量

Docker有以下一组在Dockerfile中使用而无需相应的ARG指令的预定义的ARG变量:HTTP_PROXYhttp_proxyHTTPS_PROXYhttps_proxyFTP_PROXYftp_proxyNO_PROXYno_proxy。要使用这些预定义ARG变量,只需通过--build-arg <varname>=<value>在命令行上传递它们。默认情况下,这些预定义变量将从docker history的输出中排除,排除它们可降低在HTTP_PROXY变量中意外泄露敏感验证信息的风险。

11.ONBUILD

格式

ONBUILD <INSTRUCTION>

功能描述

ONBUILD指令向镜像添加将在稍后执行的触发器指令,当该镜像作为另一个镜像构建的基础时,触发器将在下游构建的上下文中执行,就好像是在下游Dockerfile中的FROM指令之后立即插入一样,换句话说,就是ONBUILD指令向镜像添加了触发器指令,当该镜像(父镜像)作为构建另一个镜像(子镜像)的基础镜像时,在构建另一个镜像(子镜像)时,这些触发器指令就在构建另一个镜像(子镜像)的DockerfileFROM指令执行时加入到构建过程,看起来就像是触发器指令在FROM指令之后执行。

注意

任何构建指令都可以注册为触发器,但是不允许使用ONBUILD ONBUILD这样的链状ONBUILD指令,即ONBUILD指令中不能包含ONBUILD指令,并且ONBUILD指令可能不会触发FROMMAINTAINER指令。当需要制作一个用来构建其他镜像的基础镜像时,ONBUILD指令会很有用。

ONBUILD指令的工作原理
  1. 当遇到ONBUILD指令时构建器会将触发器添加到正在构建的镜像的元数据中,该指令不会影响当前构建,即不会在当前构建流程中执行。
  2. 在构建结束时,所有触发器的列表都存储在镜像清单中的OnBuild键下,可以使用docker inspect查看。
  3. 之后可以使用FROM指令将该镜像作为新构建镜像的基础镜像。作为处理FROM指令的一部分,下游构建器查找ONBUILD触发器,并按照它们注册的顺序执行它们。如果任何触发器指令执行失败,FROM指令会被终止,导致构建失败。如果所有触发器指令执行成功,FROM指令成功执行完毕并且构建会继续正常进行。
  4. 在镜像构建完成之后,触发器指令会从最终镜像中清除,换句话说,它们不会被子孙镜像继承。

12.STOPSIGNAL

格式

STOPSIGNAL signal

功能描述

STOPSIGNAL指令设置将发送给容器退出的系统调用信号。此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如9或像SIGKILL这样的SIGNAME格式的信号名。

13.HEALTHCHECK

格式

HEALTHCHECK指令有两种形式:

  • HEALTHCHECK [OPTIONS] CMD command(通过在容器内运行命令来检查容器的健康状况)
  • HEALTHCHECK NONE(禁用从基础镜像继承的任何健康检查)
功能描述

HEALTHCHECK指令告诉Docker如何测试容器以检查它是否仍在工作。可以检测到陷入无限循环且无法处理新连接的Web服务器,即使服务器进程仍在运行等情况。当容器指定了健康检查时,除了正常状态外还有健康状态,此状态最初为starting,每当健康检查通过时,无论之前处于什么状态它都会变为healthy,在经过一定数量的连续失败后它会变成unhealthy

Options

OPTIONS支持的参数有:

  • --interval=DURATION(默认值:30s):启动容器到进行健康检查的间隔时间以及两次健康检查的间隔时间。
  • --timeout=DURATION(默认值:30s):单次健康检查的超时时间,超过该时间该次健康检查失败。
  • --start-period=DURATION(默认值:0s):为需要时间引导的容器提供的初始化时间,在此期间检查失败将不计入最大重试次数,但是如果在启动期间健康检查成功,则会将容器视为已启动,并且所有连续失败将计入最大重试次数。
  • --retries=N(默认值:3):健康检查失败后的最大重试次数,重试了最大次数依然失败,容器将被视为unhealthy
注意

Dockerfile中只能有一个HEALTHCHECK指令,如果超过一个那只有最后一个HEALTHCHECK会生效。

CMD关键字之后的命令可以是shell命令(例如HEALTHCHECK CMD /bin/check-running)或exec数组(与其他Dockerfile命令一样,详情参考ENTRYPOINT)。

命令的退出状态指示容器的运行状况,可能的值有:

  • 0:成功 - 容器健康可以使用
  • 1:不健康 - 容器不能正常工作
  • 2:保留 - 不要使用此退出码

为了帮助调试错误,命令在stdout或stderr上写入的任何输出文本(UTF-8编码)都将存储在健康状态中并可以使用docker inspect进行查询,此类输出应该保持简短(目前仅存储前4096个字节)。

当容器的健康状态改变时将使用新的状态生成health_status事件。

HEALTHCHECK指令是在Docker 1.12时添加的。

14.SHELL

格式

SHELL ["executable", "parameters"]

功能描述

SHELL指令允许用于命令的shell形式的默认shell被覆盖。Linux上的默认shell是["/bin/sh", "-c"],Windows上是["cmd", "/S", "/C"]。SHELL指令必须以JSON格式写入Dockerfile。

注意

SHELL指令在Windows上特别有用,其中有cmdpowershell这两个常用且相当不同的本机shell,以及包括sh的备用shell。

SHELL指令可以出现多次。每个SHELL指令覆盖以前的所有SHELL指令,并影响所有后续指令。示例如下:

FROM microsoft/windowsservercore# 以 cmd /S /C 执行 echo default
RUN echo default# 用 cmd /S /C 作为 powershell -command 执行 Write-Host default
RUN powershell -command Write-Host default# 以 powershell -command 执行 Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello# 以 cmd /S /C 执行 echo hello
SHELL ["cmd", "/S", "/C"]
RUN echo hello

当在Dockerfile中使用它们的shell形式时,RUNCMDENTRYPOINT可能会被SHELL指令影响,示例:
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
是在Windows上找到的常见模式,可以使用SHELL指令简化,docker调用的命令将是:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
由于调用一个不必要的cmd.exe命令处理器(也就是shell)并且shell形式的每个RUN指令都需要额外的powershell -command前缀命令,所以这种方式效率很低。为了提高效率,可以采用两种机制的其中之一,一种是使用RUN命令的JSON形式,例如:
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
虽然JSON格式是明确的且不使用不必要的cmd.exe,但它需要通过双引号和转义显得更加冗余。替代机制是使用SHELL指令和shell形式,为Windows用户提供更自然的语法,特别是与escape解析器指令结合使用时:

# escape=`FROM microsoft/nanoserver
SHELL ["powershell","-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'

SHELL指令也可用于修改shell的运行方式,例如在Windows上使用SHELL cmd /S /C /V:ON|OFF,可以修改延迟的环境变量扩展语义。如果需要例如zshcshtcsh等备用shell,也可以在Linux上使用SHELL指令。

SHELL指令是在Docker 1.12时添加的。

15.RUN

格式

RUN指令有两种形式:

  • RUN <command>(shell形式,命令在shell中运行,Linux上默认为/bin/sh -c,Windows上默认为cmd /S /C
  • RUN ["executable", "param1", "param2"](exec形式)
功能描述

RUN指令将在当前镜像之上的新的一层执行任何命令并提交结果为一个新镜像,这个新镜像将被Dockerfile的下一条指令使用。

注意

exec形式可以避免使用shell字符串,并使用不包含指定的shell可执行文件的基础镜像来运行RUN命令。

exec形式会被解析为JSON数组,因此必须使用"来包围单词而不是

exec形式不会调用命令shell,也就不会发生正常的shell处理,例如RUN [ "echo", "$HOME" ]不会对$HOME进行变量替换。如果需要shell处理,可以使用shell形式或者直接执行shell,例如RUN [ "sh", "-c", "echo $HOME" ]。当使用exec形式并直接执行shell时,跟shell形式的情况一样是执行环境变量扩展的shell而不是docker。

可以使用SHELL命令更改shell形式的默认shell。

在shell形式中可以使用\将单个RUN指令延续到下一行。以下示例相当于RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'这一行。

RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'

想使用除“/bin/sh”之外的其他shell,需使用传入所需shell的exec形式。例如RUN ["/bin/bash", "-c", "echo hello"]

在JSON格式中必须转义反斜杠,在以反斜杠为路径分隔符的Windows上尤其重要。例如RUN ["c:\windows\system32\tasklist.exe"]由于不是有效的JSON而被视为shell形式,并以一种意想不到的方式失败,而此例正确的语法应为RUN ["c:\\windows\\system32\\tasklist.exe"]

RUN指令的缓存在下一次​​构建期间不会自动失效。像RUN apt-get dist-upgrade -y这样的指令的缓存将在下一次构建期间被重新使用。可以使用--no-cache来使RUN指令的缓存无效,例如docker build --no-cache

RUN指令分层和生成提交符合Docker的核心概念,并且可以从镜像历史中的任何点创建容器,就像源代码控制一样,因此不必将所有的命令写在一个RUN指令中。

ADD指令可以使RUN指令的缓存无效。

16.CMD

格式

CMD指令有三种形式:

  • CMD ["executable","param1","param2"](exec形式,首选形式)
  • CMD ["param1","param2"](作为ENTRYPOINT的默认参数)
  • CMD command param1 param2(shell形式)
功能描述

CMD指令的主要目的是为正在执行的容器提供默认值,些默认值可以包括一个可执行文件,也可以省略可执行文件,在这种情况下必须指定一个ENTRYPOINT指令。简单来说CMD指令就是用来给容器启动时提供默认值,该值可以是一个命令,也可以是一个参数。

注意

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

如果使用CMDENTRYPOINT指令提供默认参数,则CMDENTRYPOINT指令都应被指定为JSON数组格式。

exec形式会被解析为JSON数组,因此必须使用"来包围单词而不是

exec形式不会调用命令shell,也就不会发生正常的shell处理。这跟RUNENTRYPOINT指令的exec形式一样。

在shell或exec形式中使用时,CMD指令指定容器启动时默认执行的命令。

如果使用CMD的shell形式,那么<command>将在/bin/sh -c中执行。如果要在没有shell的情况下运行<command>,则必须将该命令表示为JSON数组并提供可执行文件的完整路径。此数组形式是CMD的首选格式。任何其他参数必须在数组中单独表示为字符串。

如果用户在启动容器时指定了docker run的参数,CMD指定的默认命令将被覆盖。

如果希望容器每次都运行相同的可执行文件,那么建议ENTRYPOINTCMD结合使用。

注意不要将RUNCMD混淆。 RUN实际上运行一个命令并提交结果为一个新镜像,而CMD在构建镜像时不执行任何命令,但指定了镜像的预期命令,即在容器启动时默认执行的命令。

17.ADD

格式

ADD指令有两种形式:

  • ADD [--chown=<user>:<group>] <src>... <dest>
  • ADD [--chown=<user>:<group>] ["<src>",... "<dest>"](包含空格的路径必须使用这种格式)
功能描述

ADD指令从<src>复制新文件,目录或URL指向的远程文件并将它们添加到镜像的文件系统<dest>路径中。可以指定多个<src>资源,但是如果它们是文件或目录,则它们的路径将被解释为相对于构建上下文(context)(上下文就是docker build命令中指定位置的PATHURL处的文件集合,简单的说就是PATHURL中的所有内容)的源,简单来说就是相对于上下文路径的相对路径。

Options

--chown=<user>:<group>:指定给定用户名,组名或UID/GID组合以请求添加内容的特定所有权,如果没有指定,所有新创建的文件和目录的UID和GID都是0。

--chown的一些要点:

  • --chown的特性只在用于构建Linux容器的Dockerfiles上被支持,并不适用于Windows容器。由于用户和组所有权的概念不能在Linux和Windows之间转换,因此使用/etc/passwd/etc/group将用户名和组名转换为ID会限制此特性只适用于基于Linux OS的容器。
  • --chown的格式允许用户名和用户组名的字符串或直接整数UID和GID的任意组合。
  • 提供没有用户组名的用户名或没有GID的UID将使用与GID相同的数字UID。
  • 如果提供了用户名或组名,则容器的根文件系统/etc/passwd/etc/group文件将分别用于执行从名称到整数UID或GID的转换。
  • 如果容器根文件系统不包含/etc/passwd/etc/group文件,并且在--chown中使用了用户名或组名,则构建将在ADD操作上失败。而使用数字ID则不需要查找,因为数字ID不依赖于容器根文件系统内容。
注意

<src>可以包含通配符,匹配时将使用Go的filepath.Match规则完成。示例如下:

# 添加所有以hom开头的文件
ADD hom* /mydir/  
# ?可以替换单字符比如home.txt      
ADD hom?.txt /mydir/    

<dest>是绝对路径或相对于WORKDIR的路径,源文件将被复制到目标容器中,并且源文件的各种元数据都会保留。<dest>不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。示例如下:

# 添加 "test" 到 `WORKDIR`/relativeDir/
ADD test relativeDir/
# 添加 "test" 到 /absoluteDir/   
ADD test /absoluteDir/  

当添加包含诸如[]这种特殊字符的文件或目录时,需要按照Golang规则转义这些路径,以防止它们被视为匹配模式。例如要添加名为arr[0].txt的文件,需使用命令:ADD arr[[]0].txt /mydir/

<src>是远程文件URL的情况下,目标将具有600的权限。如果正在检索的远程文件具有HTTP的Last-Modified头,则该头的时间戳将用于在目标文件上设置mtime。但是与ADD期间处理的任何其他文件一样,在确定文件是否更改以及是否应该更新缓存时,并不包括mtime

如果通过将Dockerfile传递给STDIN(docker build - < somefile)来构建,则没有构建上下文(context),因此Dockerfile只能包含基于URL的ADD指令。还可以通过STDIN传递压缩存档(docker build - < archive.tar.gz),存档文件根目录下的Dockerfile和存档文件的其余部分将用作构建上下文使用。

ADD指令不支持身份验证,如果URL文件使用了身份验证进行保护,则需要使用RUN wgetRUN curl或使用容器内的其他工具。

ADD指令获取远程URL中的压缩包不是推荐的做法,因为需要额外的一层RUN指令进行解压缩,应该使用RUN wgetRUN curl代替,这样可以删除解压后不再需要的文件,并且不用在镜像中再添加一层。

如果<src>的内容已更改,则第一个遇到的ADD指令将使来自Dockerfile的包括RUN指令在内的所有后续指令的缓存无效。

ADD遵守的规则

ADD遵守以下规则:

  • <src>路径必须位于构建上下文(context)中,不能ADD ../something/something,因为docker build的第一步是将上下文目录(和子目录)发送给docker守护进程。
  • 如果<src>是URL且<dest>不以斜杠结尾,则从URL下载文件并将其复制到<dest>
  • 如果<src>是URL并且<dest>以斜杠结尾,则从URL推断文件名,并将文件下载到<dest>/<filename>。例如ADD http://example.com/foobar /将创建文件/foobar。URL必须具有一个有意义的路径,以便在这种情况下可以发现适当的文件名(http://example.com将不起作用)。
  • 如果<src>是目录,则复制目录包括文件系统元数据在内的全部内容,注意不复制目录本身,只复制其内容。
  • 如果<src>是可识别的压缩格式(identity,gzip,bzip2或xz)的本地tar存档,则将其解压缩为目录。远程URL中的资源则不解压。当目录被复制或解压缩时,它的行为与tar -x具相同。注意,文件是否被识别为可识别的压缩格式是完全基于文件的内容而不是文件的名称完成的。例如一个空文件以.tar.gz结尾,则不会将其识别为压缩文件,并且不会生成任何类型的解压缩错误消息,而是将文件简单复制到目标。
  • 如果<src>是任何其他类型的文件,它将与其元数据一起单独复制。在这种情况下,如果<dest>以斜杠/结尾,则将其视为目录,<src>的内容将写入<dest>/base(<src>)
  • 如果直接或由于使用通配符指定了多个<src>资源,则<dest>必须是目录并且以斜杠/结尾。
  • 如果<dest>不以尾部斜杠结束,则它将被视为常规文件,<src>的内容将写入<dest>
  • 如果<dest>不存在,则会在其路径中创建所有缺少的目录。

18.COPY

格式

COPY指令有两种形式:

  • COPY [--chown=<user>:<group>] <src>... <dest>
  • COPY [--chown=<user>:<group>] ["<src>",... "<dest>"](包含空格的路径必须使用这种格式)
功能描述

COPY指令从<src>复制新文件或目录,并将它们添加到容器的文件系统的<dest>路径中。可以指定多个<src>资源,但是如果它们是文件或目录,则它们的路径将被解释为相对于构建上下文(context)的源,简单来说就是相对于上下文路径的相对路径。

Options

--chown=<user>:<group>的含义和要点跟ADD中的一样,见ADD部分。

注意

<src>可以包含通配符,匹配时将使用Go的filepath.Match规则完成。

<dest>是绝对路径或相对于WORKDIR的路径,源文件将被复制到目标容器中,并且源文件的各种元数据都会保留。<dest>不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

当添加包含诸如[]这种特殊字符的文件或目录时,需要按照Golang规则转义这些路径,以防止它们被视为匹配模式。例如要添加名为arr[0].txt的文件,需使用命令:COPY arr[[]0].txt /mydir/

如果使用STDIN(docker build - < somefile)进行构建,则没有构建上下文(context),因此不能使用COPY

COPY接受一个可选标志--from=<name|index>,可用于将源位置设置为先前的构建阶段(使用FROM .. AS <name>创建)而不是由用户发送的构建上下文。该标志还接受使用FROM指令启动的所有先前构建阶段分配的数字索引。如果找不到具有指定名称的构建阶段,则尝试使用具有相同名称的镜像。

COPYADD指令的功能相似,但ADD的功能比COPY更复杂,当使用本地目录或文件为源时,推荐使用COPY。如果<src>为一个本地tar压缩文件,ADD会自动解压这个文件到<dest>,如果只是单纯希望复杂这个压缩文件而不解压缩,这时候只能使用COPY。推荐仅在需要自动解压缩或从URL指向的远程文件添加的情况下使用ADD

COPY遵守的规则

COPY遵守以下规则:

  • <src>路径必须位于构建上下文(context)中,不能COPY ../something /something,因为docker build的第一步是将上下文目录(和子目录)发送给docker守护进程。
  • 如果<src>是目录,则复制目录包括文件系统元数据在内的全部内容,注意不复制目录本身,只复制其内容。
  • 如果<src>是任何其他类型的文件,它将与其元数据一起单独复制。在这种情况下,如果<dest>以斜杠/结尾,则将其视为目录,<src>的内容将写入<dest>/base(<src>)
  • 如果直接或由于使用通配符指定了多个<src>资源,则<dest>必须是目录并且以斜杠/结尾。
  • 如果<dest>不以尾部斜杠结束,则它将被视为常规文件,<src>的内容将写入<dest>
  • 如果<dest>不存在,则会在其路径中创建所有缺少的目录。

六.构建镜像

在编写完Dockerfile之后,就可以使用docker build命令从Dockerfile和上下文(context)中构建镜像。其中docker build命令的语法为:

docker build [OPTIONS] PATH | URL | -

构建的上下文(context)是指定位置的PATHURL处的文件集合,简单的说就是PATHURL中的所有内容。PATH是本地文件系统上的目录, URL是Git存储库位置。上下文是递归处理的,因此PATH包括任何子目录,URL包括存储库及其子模块。

1.命令选项

docker build命令支持的可选项如下:

--add-host      添加自定义主机名到IP的映射(host:ip)
--build-arg		设置镜像创建时的变量
--cache-from    使用指定镜像作为缓存源
--cgroup-parent 继承自上层的cgroup
--compress		构建上下文时使用gzip压缩
--cpu-period	限制CPU CFS(Completely Fair Scheduler)周期
--cpu-quota		限制CPU CFS(Completely Fair Scheduler)配额
--cpu-shares , -c	CPU的使用权重
--cpuset-cpus	指定使用的cpu id
--cpuset-mems	指定使用的内存 id
--disable-content-trust		跳过镜像验证,默认值为true
--file , -f		指定要使用的Dockerfile的名称(默认为‘PATH/Dockerfile’)
--force-rm		总是删除中间容器
--iidfile		将镜像id写进一个文件
--isolation		使用容器隔离技术
--label		    设置镜像元数据
--memory , -m	最大内存
--memory-swap	设置Swap的最大值等于内存加swap,'-1'表示不限制swap
--network		在构建期间设置RUN指令的网络模式
--no-cache		构建镜像过程中不使用缓存
--output , -o	输出到的目的地(format: type=local,dest=path)
--platform		如果server支持多平台可以设置平台
--progress      设置进度输出类型(auto,plain,tty),默认值为auto
--pull		    总是尝试拉取一个新版本镜像
--quiet , -q	压缩构建输出并且成功只打印镜像id
--rm	    	构建镜像成功后删除中间容器,默认值为true
--secret        私密文件公开构建(仅当启用了BuildKit时):id=mysecret,src=/local/secret
--security-opt	安全设置
--shm-size		设置/dev/shm的大小
--squash        将新创建的多层挤压放入到一层中
--ssh           SSH代理套接字或密钥公开构建(仅当启用了BuildKit时)(格式:default|[=|[,]])
--stream        以流形式持续获取创建的上下文
--tag , -t		镜像的名字及标签,通常为'name:tag'格式
--target        设置创建的目标阶段
--ulimit		Ulimit配置

2.docker build命令构建镜像过程

Docker客户端

当Docker客户端接收到用户命令,首先解析命令行参数。根据第一个参数的不同将分为以下4种情况分别处理:
情况1,第一个参数为“-”,例如:

#从STDIN中读入Dockerfile,没有context
docker build - < Dockerfile
或
#从STDIN中读入压缩的context
docker build - <context.tar.gz

此时根据命令行输入参数对Dockerfile和context进行设置。
情况2,第一个参数为Git远程仓库的URL,例如:

docker build github.com/creack/docker-firefox

则调用git clone--depth 1--recursive命令克隆该Git远程仓库,该操作会在本地的一个临时目录中进行,命令成功之后该目录将作为context传给Docker守护进程(daemon),该目录中的Dockerfile之后会被用来进行镜像构建。
情况3,第一个参数为URL,但不是Git远程仓库的URL,然后从该URL下载context,并将其封装为一个名为io.Reader的io流,后面的处理与情况1相同,只是将STDIN换为了io.Reader。
情况4,context为本地文件或目录:

#使用当前目录作为context
docker build -t vieux/apache:2.0 .
或
#使用/home/me/myapp/dockerfiles/debug作为Dockerfile /home/me/myapp作为context
docker build -f /home/me/myapp/dockerfiles/debug /home/me/myapp

如果上下文(context)中有.dockerignore文件,则将上下文中文件名满足其定义的规则的文件都从上传列表去除,不打包上传给Docker守护进程(daemon),如果用户定义了tag,则对其指定的repository和tag进行验证。完成了相关信息的设置后Docker客户端会向Docker服务端发送POST/build的HTTP请求,包含了所需的上下文。
由于构建过程的第一件事是将整个上下文(context)递归地发送到Docker守护进程(daemon),如果上下文过大,会导致发送大量数据给服务端,延缓创建过程,因此除非是生成镜像所必需的文件,不然不要放到上下文路径下,最好将空目录作为上下文,并将Dockerfile保存在该目录中,仅添加构建Dockerfile所需的文件。默认情况下,如果不额外指定Dockerfile,会将上下文目录下的名为Dockerfile的文件作为Dockerfile,如果使用非上下文路径下的Dockerfile,可以通过-f来指定其路径,不过Dockerfile文件一般习惯使用默认的文件名Dockerfile 并将其置于上下文目录。

警告:不要将根目录/用作PATH,因为它会导致构建将硬盘驱动器的全部内容传输到Docker守护进程(daemon)。

Docker服务端

Docker服务端接收到Docker客户端发来的HTTP请求之后,会进行以下步骤构建镜像,构建由Docker守护进程(daemon)运行。

  1. 创建一个临时目录并将上下文(context)指定的文件系统解压到该目录下。
  2. 读取并解析Dockerfile文件,执行Dockerfile的初步验证,如果语法不正确会返回错误。
  3. 逐个运行Dockerfile中的指令,每条指令都是独立运行的,并且会导致创建新镜像。除了FROM指令,其他每一条指令都会在上一条指令所生成镜像的基础上执行,执行完成提交生成一个新的镜像层,然后将新镜像层覆盖到原镜像之上形成一个新镜像。
  4. Dockerfile所生成的最终镜像就是在基础镜像上面叠加一层层的镜像层构建的,如果指定了tag,就给镜像打上tag,最后一次提交生成的镜像ID会作为最终的镜像ID返回。

为了加速镜像构建,Docker守护进程(daemon)会缓存构建过程中的中间镜像。当从一个已在缓存中的基础镜像开始构建新镜像时,会将Dockerfile中的下一条指令和基础镜像的所有子镜像比较,如果有一个子镜像是由相同的指令生成的,则命中缓存,直接使用该镜像,而不用再生成一个新的镜像。在寻找缓存的过程中,COPYADD指令与其他指令稍有不同,其他指令只对比生成镜像的指令字符串是否相同,ADDCOPY指令除了对比指令字符串外还要对比容器中的文件内容与ADDCOPY所添加的文件内容是否相同。此外,在镜像构建过程中缓存一旦失效,则后续的指令都将生成新的镜像,而不再使用缓存。所以为了有效利用缓存,需要保证指令的连续性,尽量将所有Dockerfile文件中相同的部分都放在前面,而将不同的部分放在后面,达到最大化复用。

3.使用.dockerignore文件

在docker CLI将上下文(context)发送到Docker守护进程(daemon)之前,它会在上下文的根目录中查找名为.dockerignore的文件。如果此文件存在,CLI将修改上下文以排除与其中的模式匹配的文件和目录。这有助于避免不必要地将大型或敏感的文件和目录发送到守护进程,并可能使用ADDCOPY将它们添加到镜像。
.dockerignore文件被CLI解释为用换行符分隔的模式列表,类似Unix shell的文件globs。为了匹配,上下文(context)的根目录被认为是工作目录和根目录。例如模式/foo/barfoo/bar都会在PATHfoo子目录中或位于URL的git远程仓库的根目录中排除名为bar的文件或目录,两者都不会排除任何其他内容。如果.dockerignore文件中的一行的第一列以开头,则此行被视为注释,并在CLI解释之前被忽略。
.dockerignore文件中的模式匹配基于Go的filepath.Match规则完成:

  • #:视为注释,将被忽略。
  • *:表示任意多个字符,例如*/*/temp*将从根目录下两级的任何子目录中排除以temp开头的文件和目录。
  • **:表示任意数量的目录(包括零),例如**/*.go将排除包括构建上下文(context)的根目录在内的所有目录中以.go结尾的所有文件。
  • ?:表示单个字符,例如temp?将排除根目录中名称是temp的单字符扩展的文件和目录。
  • !:表示不匹配(不排除指定的文件或目录),例如!README.md将不会排除README.md

!所处位置会影响行为是一个例外规则,.dockerignore的最后一行指定的文件决定了它是否应该包含或者排除,例如:

*.md
!README*.md
README-secret.md

除了README-secret.md文件以外的以README开头的Markdown文件都不会被排除,其它的Markdown文件都会被排除。

*.md
README-secret.md
!README*.md

包含所有README文件(除了所有README开头的文件外其他Markdown文件都会被排除),中间行没有效果,因为最后一行!README*.mdREADME-secret.md匹配。

甚至可以使用.dockerignore文件来排除Dockerfile.dockerignore文件。这些文件仍然会被发送到Docker守护进程(daemon),但ADDCOPY指令不会将它们复制到镜像中。

如果希望指定要包含在上下文(context)中的文件而不是要排除的文件。可以将*指定为第一个模式,然后指定一个或多个模式!模式。

七.Dockerfile构建镜像示例

下面通过编写一个简单的Dockerfile来整体感受一下构建镜像的过程。这里基于ubuntu:20.10构建一个jdk1.8环境的镜像,首先拉取ubuntu:20.10镜像,再创建一个目录/usr/local/jdk1.8_ubuntu/作为上下文目录,然后上传jdk-8u212-linux-x64.tar.gz/usr/local/jdk1.8_ubuntu/目录。然后编写Dockerfile文件,内容如下:

# 指定基础镜像
FROM ubuntu:20.10
# 设置元数据信息
LABEL maintainer="RtxtitanV" version="1.0.0" description="JDK1.8 IMAGE"
# 指定工作目录
WORKDIR /usr/local/work
# 将jdk压缩包添加并解压至工作目录下的java目录下
ADD jdk-8u212-linux-x64.tar.gz java/
# 设置jdk环境变量
ENV JAVA_HOME /usr/local/work/java/jdk1.8.0_212
ENV PATH $JAVA_HOME/bin:$PATH
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$CLASSPATH

然后将Dockerfile文件放入/usr/local/jdk1.8_ubuntu/目录,命令cd /usr/local/jdk1.8_ubuntu/进入该目录下,执行以下命令构建镜像:

docker build -t jdk1.8/ubuntu:v1.0.0 .

执行过程如下:

Sending build context to Docker daemon    195MB
Step 1/7 : FROM ubuntu:20.10---> bafda420a37f
Step 2/7 : LABEL maintainer="RtxtitanV" version="1.0.0" description="JDK1.8 IMAGE"---> Running in c7039610faa4
Removing intermediate container c7039610faa4---> 372cfee4b3d6
Step 3/7 : WORKDIR /usr/local/work---> Running in 3e566923dab8
Removing intermediate container 3e566923dab8---> 01eab14c3aa2
Step 4/7 : ADD jdk-8u212-linux-x64.tar.gz java/---> 4c94774db8d4
Step 5/7 : ENV JAVA_HOME /usr/local/work/java/jdk1.8.0_212---> Running in a657e430c6dc
Removing intermediate container a657e430c6dc---> 38efa7747c8f
Step 6/7 : ENV PATH $JAVA_HOME/bin:$PATH---> Running in a22409dad523
Removing intermediate container a22409dad523---> c490f7279050
Step 7/7 : ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$CLASSPATH---> Running in 60b76ca90bf1
Removing intermediate container 60b76ca90bf1---> b617770c39ee
Successfully built b617770c39ee
Successfully tagged jdk1.8/ubuntu:v1.0.0

构建成功,查看新构建的镜像:

[root@iZwz94v2sdd3v6zcczsu67Z jdk1.8_ubuntu]# docker images jdk1.8/ubuntu:v1.0.0
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
jdk1.8/ubuntu       v1.0.0              b617770c39ee        2 minutes ago       479MB

使用新构建的jdk1.8/ubuntu:v1.0.0镜像运行一个容器并验证JDK环境,结果如下,输出了JDK版本信息说明JDK环境没问题。

[root@iZwz94v2sdd3v6zcczsu67Z jdk1.8_ubuntu]# docker run -it --name myjdk1.8 jdk1.8/ubuntu:v1.0.0 bash
root@285adebd9438:/usr/local/work# java -version
java version "1.8.0_212"
Java(TM) SE Runtime Environment (build 1.8.0_212-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.212-b10, mixed mode)
root@285adebd9438:/usr/local/work#
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 线性索引查找

    1. 稠密索引: 稠密索引是指将数据suoyin集中的每个记录对应一个索引项。 特点: 稠密索引适合数据量小,关键字码有序表的查找。 2. 分块索引: 特点:把数据分成若干块,块间有序,块内无序; 块间有序:可以利用折半查找,插值查找等方法; 块内无序:只能顺序查找。复杂度分析:…...

    2024/4/15 7:28:55
  2. Window串口编程

    利用Windows应用程序编程接口为程序提供串口通信功能1.串行编程的数据结构:DCB(Device Control Block)、CIMMTIMEOUTSDCB:设备控制块通过该数据结构,完成对串口端的初始化工作 该数据结构包含了 传输波特率、数据位数、奇偶检验类型和停止位数等参数在查询或者配置串行端口…...

    2024/4/19 15:57:51
  3. Python_求n阶乘(n很大)_路漫漫远俢兮

    脚本作用:计算N的阶乘,但是N很大 #数据计算 N=40000 res=[None]*N#存储结果 def countFactorial():i,j,n=None,None,Noneprint("请输入要计算的阶乘数字:")n=input()#输入数据while n!="-1":n=int(n)if(n==0 or n==1):#0 1 的阶乘都是1print(1)print(&qu…...

    2024/4/16 22:09:52
  4. SystemVerilog绿皮书疑难点解析

    8.7 回调(callback) 当你的testbench写好后,如果想在一个task里面添点东西怎么办? 前面添点?后面添点? 你可以将该task定义为一个虚方法,然后在可能的扩展类中覆盖其行为。这样做的缺点是如果你想增加新的行为,可能需要在扩展类的新方法中重复原方法的所有代码。而且一旦…...

    2024/4/17 22:46:43
  5. C运算符!与||的优先级问题&&《The C Programming Language》推荐

    今天写Dijkstra算法时发现有段代码有问题:for(int i=0;i<n;i++){int t=-1;for(int j=1;j<=n;j++){if(!st[j]&&(!t||dist[j]<dist[t])) //!!t=j;}st[t]=true;for(int j=1;j<=n;j++){dist[j]=min(dist[j],dist[t]+g[t][j]);} }在第四行想着写!t来判断t仍为…...

    2024/4/24 6:36:33
  6. Hash表理解

    Hash表: 1、hash表就是通过hash函数将需要保存在hash表中的key值翻译成hash bucket(也就是hash数组,是一个按照序列的数组)。然后查询时候也是通过hash函数计算出bucket的index值,也就是计算出可以在hash桶的第几个位置,这样就能通过访问数组的方式直接访问到需要值,buck…...

    2024/4/24 6:36:30
  7. 如何产生一个高频振荡电路?

    信号源:信号8GHz-12GHz之间,可调可调:就不能用简单的晶振电路实现信号源:稳定干净:杂波/干扰较小产生频率震荡信号:常用压控振荡电路。用可变电压,产生可控的变化的频率如果两个正弦波,如果频率相同,则相位差恒定。如果频率不相等,则相位差会一直变化。鉴相检测电路,…...

    2024/5/10 6:39:34
  8. Android编程风格以及命名规范

    编程风格代码中尽量不要出现中文。注释和除外。代码中通过strings.xml引用来显示中文 控件声明放在activity级别,这样在activity其他地方可以使用 不要重用父类的handler,对应一个类的handler也不应该让其子类用到,否则会导致message.what冲突 在一个View.OnClickListener中…...

    2024/4/24 6:36:29
  9. docker安装redis,并开启外网访问

    1. redis.confbind 0.0.0.0 # 绑定到0.0.0.0,任何ip都可以访问 daemonize NO protected-mode no # 关闭protected-mode模式,此时外部网络可以直接访问 requirepass 1234562. 运行docker run -p 6379:6379 --name redis-server -v /opt/redis/redis.conf:/etc/redis/redis.c…...

    2024/4/24 6:36:26
  10. Netty学习笔记二十二、Netty快速入门实例-Http服务

    一、讲解1、Netty服务在6669端口监听,浏览器发出请求"http://localhost://6669"2、服务器可以回复消息,并对特定的资源进行过滤3、目的:Netty可以做http服务开发,并且理解Handler实例和客户端及其请求的关系。二、代码package com.hao.netty.http;import io.nett…...

    2024/4/24 6:36:28
  11. 服务器是由哪些硬件构成的?带你一探究竟!

    目录电源CPU处理器内存(RAM)硬盘(磁盘)Raid卡(阵列卡)远程管理卡主板服务器其实就是一台配置更高的计算机,它的内部结构也和普通的计算机大同小异。可以看到,服务器是由电源、CPU、内存、硬盘、风扇、光驱等几部分构成。今天,将挑选一些重要的硬件,给大家做详细介绍。…...

    2024/5/10 4:42:22
  12. 面试题总结

    以下为自己亲历面试题,记下来以便自己复习;1、servlet生命周期启动→初始化(init())→请求处理(doGet()、doPost())→服务终止(destory())2、spring特性ioc:将初始化对象的创建交由框架处理;aop实现方法:静态代理、动态代理、cglib代理、aspectj3、集合collection、…...

    2024/4/24 6:36:23
  13. MD5加密算法入门及改进

    MD5消息摘要算法,属Hash算法一类。MD5算法对输入任意长度的信息变换产生一个128位的消息摘要。 原理 1、数据填充 对信息进行数据填充,使信息的长度对512取模得448,设信息长度为X,即满足X mod 512=448。根据此公式得出需要填充的数据长度。填充方法是在信息后面填充第一位为…...

    2024/5/10 6:36:02
  14. 阿里实习面经

    拿到 阿里实习offer,经历了5次面试,其中4轮技术面,1轮HR面试。在这里分享一下自己的面试经验和学习总结。希望能够帮助更多的小伙伴。 我本科毕业于中南大学信管专业,真正开始学习Java是在大三下学期,研究生就读北航的移动云计算专业。刚开始也是小白,也是一步步成成起来…...

    2024/4/24 6:36:25
  15. JVM——类加载器总结

    JVM类加载器 类加载器是什么 类加载阶段中的 “通过一个类的全限定名来获取描述此类的二进制字节流” 这个动作在JVM外部实现,有利于让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块就称为“类加载器”。 类加载器的作用 1.实现类的加载过程中加载这个动作…...

    2024/4/24 6:36:20
  16. socket.timeout: The read operation timed out

    利用pip安装numpy时遇到问题:1.socket.timeout: The read operation timed out2.pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host=files.pythonhosted.org, port=443): Read timed out详情如下图所示:原因:主要是由于网速不稳定,下载过慢,超出…...

    2024/4/24 6:36:19
  17. 光纤宽带接入工程设计降本增效方案集(3)

    本方案集从光纤宽带接入工程的设计方案制定、施工方法及工艺要求、器材选型3个方面列举了在工程设计阶段可实施的降本增效方案共15例,供光纤宽带接入工程设计参考。本文为第3篇:器材选型案例10:农村地区使用轻型自承式光缆(1)现状及问题由于农村地区CMCC缺少既有杆路资源,…...

    2024/4/16 22:09:52
  18. WPF学习笔记——15)文本控件

    试试...

    2024/4/16 22:10:10
  19. tf.keras.layers.Conv2DTranspose中反卷积输入和输出关系

    函数申明:https://tensorflow.google.cn/api_docs/python/tf/keras/layers/Conv2DTransposetf.keras.layers.Conv2DTranspose(filters, kernel_size, strides=(1, 1), padding=valid, output_padding=None,data_format=None, dilation_rate=(1, 1), activation=None, use_bias…...

    2024/4/16 22:09:40
  20. Docker中用Dockerfile添加容器数据卷

    新建mydocker文件夹并进入。 可在DockerFile中使用VOLUME指令来给镜像添加一个或多个数据卷。VOLUME["/dataVolumeContainer","/dataVolumeContainer2","/dataVolumeContainer3"]出于可移植和分享的考虑,用-v 主机目录:容器目录这种方法不能够直…...

    2024/4/16 22:10:16

最新文章

  1. SpringBoot的启动器——Spring-boot-starter介绍和常见启动器

    1、Starter是什么 Spring Boot通过将我们常用的功能场景抽取出来&#xff0c;做成的一系列的启动器&#xff0c;我们只需要在项目中引入这些starter&#xff0c;相关的所有依赖就会全部被导入进来&#xff0c;并且我们可以抛弃繁杂的配置&#xff0c;例如&#xff1a; ​ spri…...

    2024/5/10 10:32:38
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/9 21:23:04
  3. DevOps三步法之反馈:流动是油门,反馈是刹车

    打个比方&#xff0c;流动是油门&#xff0c;反馈是刹车。流动是关于行使&#xff0c;反馈是关于安全。车辆要想持续平稳运行&#xff0c;需要油门与刹车良好配合&#xff0c;否则就有可能车毁人亡。核电站需要使核反应处于临界状态&#xff0c;超出临界状态就是核爆炸这也需要…...

    2024/5/10 0:20:18
  4. Kafka入门到实战-第五弹

    Kafka入门到实战 Kafka常见操作官网地址Kafka概述Kafka的基础操作更新计划 Kafka常见操作 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://kafka.apache.org/Kafka概述 Apache Kafka 是一个开源的分布式事件流平台&…...

    2024/5/7 19:08:30
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/8 6:01:22
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/9 15:10:32
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/9 4:20:59
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/7 11:36:39
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/8 20:48:49
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/7 9:26:26
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/8 19:33:07
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/8 20:38:49
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/10 10:22:18
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/9 17:11:10
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57