Docker学习笔记---Dockerfile

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

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

Dockerfile指令

FROM

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

FROM <image> [AS <name>]

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

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

LABEL

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

该LABEL指令将元数据添加到图像。A 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."

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

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

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

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

$ docker inspect Ubuntu

RUN

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

RUN有两种形式

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

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

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

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

相当于:

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来进行安装更新

通常我们会如下使用他:

RUN apt-get update && apt-get install -y \
        package-bar \
        package-baz \
        package-foo

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

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

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,那么<command>将执行 /bin/sh -c:

FROM ubuntu
CMD echo "This is a test." | wc -

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

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

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

EXPOSE <port> [<port>...]

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

ENV

ENV <key> <value>
ENV <key>=<value> ...

注:

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

例如:

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指令还可以用来设置常用的版本号,使其更方便维护,例子如下:

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缓存无效的数量减少:

COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt
COPY . /tmp/

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

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 <src>...<dest>
  • ["<src>",... "<dest>"]

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

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

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

ADD hom* /mydir/        # adds all files starting with "hom"
ADD hom?.txt /mydir/    # ? is replaced with any single character, e.g., "home.txt"

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

ADD test relativeDir/          # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/         # adds "test" to /absoluteDir/

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

ADD arr[[]0].txt /mydir/    # copy a file named "arr[0].txt" to /mydir/

COPY

同样COPY也有两种形式:

  • COPY <src>... <dest>
  • COPY ["<src>",... "<dest>"] (此窗体是包含空格的路径所必需的)

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

其他内容参见ADD部分

ENTRYPOINT

该指令也有两种形式:

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

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

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

docker run -i -t --rm -p 80:80 nginx

执行from ENTRYPOINT例子

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

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

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

$ 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:

FROM ubuntu
ENTRYPOINT exec top -b

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

$ 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作为默认标志

ENTRYPOINT ["s3cmd"]
CMD ["--help"]

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

$ docker run s3cmd

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

$ docker run s3cmd ls s3://mybucket

VOLUME

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

VOLUME ["/data"]

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

USER

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

USER <user>[:<group>] or
USER <UID>[:<GID>]

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

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

WORKDIR

WORKDIR /path/to/workdir

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

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

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

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

ARG

ARG <name>[=<default value>]

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

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

FROM busybox
ARG user1
ARG buildno
...

ARG默认值

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

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中搭建测试成功
  • 上述文字皆为个人看法,如有错误或建议请及时联系我
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 转载自 http://blog.opskumu.com/docker.html 一、Docker 简介 Docke...
    极客圈阅读 10,481评论 0 120
  • 1 基本结构 Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。 一般的,Dockerfi...
    一路向北__阅读 98评论 0 0
  • docker基本概念 1. Image Definition 镜像 Image 就是一堆只读层 read-only...
    慢清尘阅读 8,728评论 1 21
  • —— 2017年6月21日,我们在一起1274天。 今晚早点睡,明早起来看我写的文章。 第一次忍着没...
    心浮少年阅读 287评论 0 0
  • 以前很虔诚的 许个愿望 就时时想念 念念不忘 就必有回响 现在呢 既然如此 我就心里默默复习一下 我许了三个 很贪...
    LUPOU阅读 258评论 0 1