前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Docker学习笔记---Dockerfile

Docker学习笔记---Dockerfile

作者头像
earthchen
发布2020-09-24 15:21:18
6590
发布2020-09-24 15:21:18
举报
文章被收录于专栏:earthchen的专栏earthchen的专栏

Docker可以通过从Dockerfile包含所有命令的文本文件中读取指令,自动构建镜像。

每个需要使用Docker的项目都应该有一个Dockerfile,这个文件描述了我们需要的镜像环境。

Dockerfile指令

FROM

有效的Dockerfile必须从FROM开始,镜像可以是任何有效的镜像。 官方建议,如果只需要一个linux基础镜像,建议使用Debian镜像,控制的很小。

代码语言:javascript
复制
FROM <image> [AS <name>]

或
FROM <image>[:<tag>] [AS <name>]

或
FROM <image>[@<digest>] [AS <name>]

LABEL

代码语言:javascript
复制
LABEL <key>=<value> <key>=<value> <key>=<value> ...

该LABEL指令将元数据添加到图像。A LABEL是一个键值对。要在LABEL值中包含空格,请使用引号和反斜杠,就像在命令行解析中一样。几个用法示例

代码语言:javascript
复制
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."

图像可以有多个标签。要指定多个标签,Docker建议LABEL在可能的情况下将标签组合到单个指令中。每个LABEL指令产生一个新的层

代码语言:javascript
复制
LABEL multi.label1="value1" multi.label2="value2" other="value3"

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

要查看图像的标签,请使用docker inspect命令。

代码语言:javascript
复制
$ docker inspect Ubuntu

RUN

如果你需要RUN多个命令,建议使用多行写出来,使用( \ )分隔多行

RUN有两种形式

  • RUN shell形式,命令在shell中运行,默认为/bin/sh
  • RUN [“executable”, “param1”, “param2”]RUN指令在当前镜像的顶部的新层中执行任何命令,病提交结果,结果提交的图像当被用户下一步Dockerfile

可以使用命令更改shell中的默认的SHELL.

在shell窗体中,可以使用 \ 讲一条指令继续下一行 例如:

代码语言:javascript
复制
RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'
``` 

相当于:
```docker
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
``` 

>注:如果你想使用其他shell比如**bash**,请使用在所需的shell传递参数,**RUN ["/bin/bash", "-c", "echo hello"]**


### apt-get
如果你的基础镜像使用的是**Debian**,那你一定会经常使用**apt-get**命令安装软件

一般来说,我们最好不要使用**apt-get upgrade**或者**apt-get dist-upgrade**,使用上述命令会造成许多非必须包被安装,这是不必要的。如果知道要更新当前基础镜像中中的某一个软件,比如**nginx**,请使用**apt-get install -y nginx**来进行安装更新

通常我们会如下使用他:
```docker
RUN apt-get update && apt-get install -y \
        package-bar \
        package-baz \
        package-foo

先执行apt-get update是为了确保不被缓存所干扰,保证安装的软件是比较新的版本。

以下是一个使用RUNapt-get的一个例子:

代码语言:javascript
复制
RUN apt-get update && apt-get install -y \
    aufs-tools \
    automake \
    build-essential \
    curl \
    dpkg-sig \
    libcap-dev \
    libsqlite3-dev \
    mercurial \
    reprepro \
    ruby1.9.1 \
    ruby1.9.1-dev \
    s3cmd=1.1.* \
 && rm -rf /var/lib/apt/lists/*

最后删除/var/lib/apt/lists/是为了清理缓存从而减少镜像大小,Debian和Ubuntu都会在最后自动调用*apt-get clean来清理,不需要显示调用

CMD

该指令有三种形式:

  • CMD [“executable”,”param1”,”param2”],这是首先方式
  • CMD [“param1”,”param2”],作为ENTRYPOINT的默认参数
  • CMD command param1 param2 外壳形式

当以shell或者exec格式使用是,该CMD指令设置运行镜像时要执行的命令 如果你使用shell的形式CMD,那么将执行 /bin/sh -c:

代码语言:javascript
复制
FROM ubuntu
CMD echo "This is a test." | wc -

如果您想在 没有shell 的情况下运行,那么您必须将该命令表达为JSON数组,并提供可执行文件的完整路径。 此数组形式是首选格式CMD。任何其他参数必须单独表示为数组中的字符串:

代码语言:javascript
复制
FROM ubuntu
CMD ["/usr/bin/wc","--help"]

CMD指令应用与运行镜像中所包含的软件,及其参数。CMD应该以CMD [“executable”, “param1”, “param2”…]表示。

在很多时候,CMD给出的是一个交互式shell,比如bash,Python等,比如CMD [“perl”, “-de0”]CMD [“python”],或 CMD [“php”, “-a”]

EXPOSE

该指令指示容器讲监听链接的端口,类似于,将容器中的某一个端口暴露出去,从而在外部访问绑定该端口。在容器内部,应该使用应用的传统通用端口。

代码语言:javascript
复制
EXPOSE <port> [<port>...]

该EXPOSE指令通知Docker容器在运行时监听指定的网络端口。EXPOSE不使主机的端口可以访问。为此,您必须使用该-p标志来发布一系列端口,或者使用该-P标志来发布所有暴露的端口。您可以公开一个端口号,并在外部发布另一个端口号

ENV

代码语言:javascript
复制
ENV <key> <value>
ENV <key>=<value> ...

注:

  • 该ENV指令将环境变量设置为该值 。该值将处于所有“后代” Dockerfile命令的环境中
  • 该ENV指令有两种形式。第一个表单ENV 将会将一个变量设置为一个值。第一个空格后的整个字符串将被视为- 包括空格和引号等字符。
  • 第二种形式ENV = …允许一次设置多个变量。请注意,第二种形式在语法中使用等号(=),而第一种形式则不使用等号。像命令行解析一样,引号和反斜杠可用于在值中包含空格。

例如:

代码语言:javascript
复制
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy


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

上述两种方法所产生的结果是一样的,推荐使用第一种方式。

使用ENV来更新容器中的环境变量PATH,例如:ENV PATH /usr/local/nginx/bin:$PATH将确保CMD [“nginx”]工作正常。

ENV指令用于提供特定服务所需要的环境变量

ENV指令还可以用来设置常用的版本号,使其更方便维护,例子如下:

代码语言:javascript
复制
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

ADD or COPY

上述两个指令的功能上是类似的,都是复制文件到容器中。

COPY只支持讲本地文件复制到容器中 ADD不但支持讲本地文件复制到容器中,还支持本地提取文件和远程url下载

所以ADD最适合的恰当的使用就是讲压缩文件提取到容器中。如ADD rootfs.tar.xz /

COPY可以多次使用,例如下列例子可以使RUN缓存无效的数量减少:

代码语言:javascript
复制
COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt
COPY . /tmp/

ADD不鼓励使用远程url并提取包。应该使用wget或者curl替代。可以在解压完成之后删除不需要的压缩包。 以下做法是正确的范例:

代码语言:javascript
复制
RUN mkdir -p /usr/src/things \
    && curl -SL http://example.com/big.tar.xz \
    | tar -xJC /usr/src/things \
    && make -C /usr/src/things all

对于不需要提取文件的操作,我们应该均使用COPY来进行文件复制操作。

ADD

该指令有两种方式

  • ADD …
  • [““,… ““]

ADD指令将复制新文件,目录或远程文件URL ,并将其添加到路径中图像的文件系统。

可以指定多个资源,但如果它们是文件或目录,则它们必须相对于正在构建的源目录(构建的上下文)。

每个可能包含通配符,并使用Go的filepath.Match规则进行匹配 。例如

代码语言:javascript
复制
ADD hom* /mydir/        # adds all files starting with "hom"
ADD hom?.txt /mydir/    # ? is replaced with any single character, e.g., "home.txt"

是一个绝对路径,或相对于一个路径WORKDIR,到其中的源将在目标容器内进行复制

代码语言:javascript
复制
ADD test relativeDir/          # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/         # adds "test" to /absoluteDir/

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

代码语言:javascript
复制
ADD arr[[]0].txt /mydir/    # copy a file named "arr[0].txt" to /mydir/

COPY

同样COPY也有两种形式:

  • COPY …
  • COPY [““,… ““] (此窗体是包含空格的路径所必需的)

COPY指令将复制新文件或目录<src ,并将其添加到该路径上容器的文件系统。

其他内容参见ADD部分

ENTRYPOINT

该指令也有两种形式:

  • ENTRYPOINT [“executable”, “param1”, “param2”] (首选)
  • ENTRYPOINT command param1 param2 (外壳形式)

ENTRYPOINT允许你配置作为可执行文件运行的容器

例如,以下将使用默认内容启动nginx,在端口80上侦听:

代码语言:javascript
复制
docker run -i -t --rm -p 80:80 nginx

执行from ENTRYPOINT例子

您可以使用exec形式ENTRYPOINT设置相当稳定的默认命令和参数,然后使用任何一种形式CMD来设置更有可能更改的其他默认值。

代码语言:javascript
复制
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

运行容器时,您可以看到这top是唯一的过程:

代码语言:javascript
复制
$ docker run -it --rm --name test  top -H

top - 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
    1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 top

执行外壳形式的 ENTRYPOINT例子

您可以指定一个纯粹的字符串,ENTRYPOINT并在其中执行/bin/sh -c。此表单将使用shell处理来替换shell环境变量,并将忽略任何CMD或docker run命令行参数。为了确保能够正确地docker stop发出任何长时间运行的ENTRYPOINT可执行文件,您需要记住启动它exec:

代码语言:javascript
复制
FROM ubuntu
ENTRYPOINT exec top -b

运行此镜像时,您将看到单个PID 1过程:

代码语言:javascript
复制
$ docker run -it --rm --name test top

Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
Load average: 0.08 0.03 0.05 2/98 6
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     R     3164   0%   0% top -b

该指令最恰当的用户是社会镜像的主要命令,允许该镜像像该命令一样运行,然后使用CMD作为默认标志

代码语言:javascript
复制
ENTRYPOINT ["s3cmd"]
CMD ["--help"]

我们可以输入以下命令来显示命令的帮助

代码语言:javascript
复制
$ docker run s3cmd

使用正确的参数执行该命令:

代码语言:javascript
复制
$ docker run s3cmd ls s3://mybucket

VOLUME

该指令用于公开暴露容器所创建的任何数据存储区域,配置存储文件或者文件夹。使用VOLUME指令配置任何可变的或是用户可维护的部分。

代码语言:javascript
复制
VOLUME ["/data"]

该VOLUME指令将创建具有指定名称的安装点,并将其标记为从本机主机或其他容器保存外部安装的卷。该值可以是JSON数组,VOLUME [“/var/log/“]或具有多个参数的纯字符串,例如VOLUME /var/log或VOLUME /var/log /var/db

USER

该指令用于配置运行服务的用户,一般用户将普通用户更改我root用户,解决权限不足的问题

代码语言:javascript
复制
USER <user>[:<group>] or
USER <UID>[:<GID>]

该USER指令设置用户名(或UID)和可选的用户组(或GID)在运行图像时使用RUN

注:当用户没有主组时,将使用该root组运行映像

WORKDIR

代码语言:javascript
复制
WORKDIR /path/to/workdir

该指令用于配置工作目录,其参数应该使用绝对目录。该命令其实也就是RUN cd … && do-something的变体。使其更清楚

该WORKDIR指令可以在一次使用多次Dockerfile。如果提供了相对路径,它将相对于上一条WORKDIR指令的路径 。例如:

代码语言:javascript
复制
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

最终pwd命令的输出Dockerfile就是这样 /a/b/c

ARG

代码语言:javascript
复制
ARG <name>[=<default value>]

该ARG指令定义了用户可以docker build使用该–build-arg = 标志使用命令在构建时传递给构建器的变量。如果用户指定了在Dockerfile中未定义的构建参数,则构建会输出警告[Warning] One or more build-args [foo] were not consumed.

Docker文件可以包括一个或多个ARG指令。例如,以下是一个有效的Docker文件

代码语言:javascript
复制
FROM busybox
ARG user1
ARG buildno
...

ARG默认值

ARG指令可以可选地包括一个默认值

代码语言:javascript
复制
FROM busybox
ARG user1=someuser
ARG buildno=1
...

如果ARG指令具有默认值,并且如果在构建时没有传递任何值,则构建器将使用默认值。

## ONBUILD 该指令在当前Dockerfile构建完成后执行。ONBUILD在导出FROM当前图像的任何子图像中执行。将该ONBUILD命令视为父母Dockerfile给予孩子的指示Dockerfile。

注:

  • ddocker Version: 17.05.0-ce
  • docker-machine version 0.12.2, build 9371605
  • 上述环境在ubuntu16.04 lts中搭建测试成功
  • 上述文字皆为个人看法,如有错误或建议请及时联系我
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-08-23,,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Dockerfile指令
    • FROM
      • LABEL
        • RUN
          • CMD
            • EXPOSE
              • ENV
                • ADD or COPY
                  • ADD
                  • COPY
                • ENTRYPOINT
                  • 执行from ENTRYPOINT例子
                  • 执行外壳形式的 ENTRYPOINT例子
                • VOLUME
                  • USER
                    • WORKDIR
                      • ARG
                        • ARG默认值
                    相关产品与服务
                    命令行工具
                    腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档