Dockerfile 基本命令

前言:Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
在一个文件夹中,如果有一个名字为 Dockfile 的文件,其内容满足语法要求,在这个文件夹路径下执行命令:docker build --tag name:tag .,就可以按照描述构建一个镜像了。name 是镜像的名称,tag 是镜像的版本或者是标签号,不写的话默认为 lastest。注意后面有一个空格和点。

1. FROM 指定基础镜像

  • FROM 指令用于指定其后构建新镜像所使用的基础镜像。FROM 指令必是 Dockerfile 文件中的首条命令,启动构建流程后,Docker 将会基于该镜像构建新镜像,FROM 后的命令也会基于这个基础镜像。
  • 语法格式如下:
FROM <image>
# 或
FROM <image>:<tag>
# 或
FROM <image>:<digest>
  • 通过 FROM 指定的镜像,可以是任何有效的基础镜像。FROM 有以下限制:
    • FROM 必须 是 Dockerfile 中第一条非注释命令。
    • 在一个 Dockerfile 文件中创建多个镜像时,FROM 可以多次出现。只需在每个新命令 FROM 之前,记录提交上次的镜像 ID。
    • tagdigest 是可选的,如果不使用这两个值时,会使用 latest 版本的基础镜像。

2. RUN 执行命令

  • RUN 指令在镜像的构建过程中执行特定的命令,并生成一个中间镜像。
  • 语法格式如下(有两种格式):

shell 格式:

RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。

exec 格式:

RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
  • RUN 命令将在当前 image 中执行任意合法命令并提交执行结果。命令执行提交后,就会自动执行 Dockerfile 中的下一个指令。
  • 层级 RUN 指令和生成提交是符合 Docker 核心理念的做法。它允许像版本控制那样,在任意一个点,对 image 镜像进行定制化构建。
  • RUN 指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定 --no-cache 参数,如:docker build --no-cache

注意

Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz

以上执行会创建 3 层镜像。可简化为以下格式:

FROM centos
RUN yum -y install wget \
  && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
  && tar -xvf redis.tar.gz

如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。

3. COPY 复制文件

  • 复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
  • 语法格式如下:
COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]

参数说明:

  • [--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。

  • <源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY hom* /mydir/
COPY hom?.txt /mydir/
  • <目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

补充说明

COPYRUN 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。比如:

COPY package.json /usr/src/app/

<源路径> 可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match 规则,如:

COPY hom* /mydir/
COPY hom?.txt /mydir/

<目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。

4. ADD 更高级的复制文件

  • ADD 指令和 COPY 的格式和性质基本一致(同样需求下,官方推荐使用 COPY)。但是在 COPY 基础上增加了一些功能。比如 <源路径> 可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 <目标路径> 去。

  • 在构建镜像时,复制上下文中的文件到镜像内,语法格式如下:

ADD <源路径1>... <目标路径>
ADD ["<源路径1>",... "<目标路径>"]
  • ADD 的优点:在执行 <源文件>tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>
  • ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
  • 注意:如果 docker 发现文件内容被改变,则接下来的指令都不会再使用缓存。关于复制文件时需要处理的/,基本跟正常的 copy 一致。

5. CMD

  • 类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

    • CMDdocker run 时运行,在构建时不进行任何操作。
    • RUN 是在 docker build,并生成一个新的镜像。
  • 作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

  • 注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

  • 语法格式如下(有三种格式):

CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...] 
CMD ["<param1>","<param2>",...]  # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh

6. ENTRYPOINT

  • ENTRYPOINT 用于给容器配置一个可执行程序。也就是说,每次使用镜像创建容器时,通过 ENTRYPOINT 指定的程序都会被设置为默认程序。

  • 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

  • 但是,如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。

  • 优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

  • 注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

  • 语法格式如下:

ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,下面的示例会提到。

  • 示例:

假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx

ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参 

1、不传参运行

$ docker run  nginx:test

容器内会默认运行以下命令,启动主进程。

nginx -c /etc/nginx/nginx.conf

2、传参运行

$ docker run  nginx:test -c /etc/nginx/new.conf

容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

nginx -c /etc/nginx/new.conf

7. ENV 设置环境变量

  • 设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

  • 语法格式如下(有两种格式):

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
  • 这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
ENV VERSION=1.0 DEBUG=on \
    NAME="Happy Feet"

这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 Shell 下的行为是一致的。

8. ARG

  • 构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
  • 构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
  • 语法格式如下:
ARG <参数名>[=<默认值>]

例如,通过 ARG 指定两个变量:

ARG site
ARG build_user=IT笔录

以上我们指定了 sitebuild_user 两个变量,其中 build_user 指定了默认值。在使用 docker build 构建镜像时,可以通过 --build-arg <varname>=<value> 参数来指定或重设置这些变量的值。

docker build --build-arg site=itiblu.com -t itbilu/test .

这样我们构建了 itbilu/test 镜像,其中 site 会被设置为 itbilu.com,由于没有指定 build_user,其值将是默认值 IT 笔录。

9. VOLUME 定义匿名卷

  • 定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

  • 作用:

    • 避免重要的数据,因容器重启而丢失,这是非常致命的。
    • 避免容器不断变大。
  • 语法格式如下:

VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:

  • 卷可以容器间共享和重用
  • 容器并不一定要和其它容器共享卷
  • 修改卷后会立即生效
  • 对卷的修改不会对镜像产生影响
  • 卷会一直存在,直到没有任何容器在使用它

VOLUME 让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。

10. EXPOSE

  • 为构建的镜像设置监听端口,使容器在运行时监听(仅仅只是声明端口)。
  • 作用:
    • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
    • 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
  • 语法格式如下:
EXPOSE <port> [<port>...]
  • EXPOSE 指令并不会让容器监听 host 的端口,如果需要,需要在 docker run 时使用 -p-P 参数来发布容器端口到 host 的某个端口上。

11. WORKDIR 指定工作目录

  • 指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
  • docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
  • 语法格式如下:
WORKDIR <工作目录路径>
  • 通过 WORKDIR 设置工作目录后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。

例如,使用 WORKDIR 设置工作目录:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

在以上示例中,pwd 最终将会在 /a/b/c 目录中执行。在使用 docker run 运行容器时,可以通过 -w 参数覆盖构建时所设置的工作目录。

12. USER 指定当前用户

  • 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

  • 语法格式如下:

USER <用户名>[:<用户组>]
  • 使用 USER 指定用户时,可以使用用户名、UID 或 GID,或是两者的组合。以下都是合法的指定:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
  • 使用 USER 指定用户后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT 都将使用该用户。镜像构建完成后,通过 docker run 运行容器时,可以通过 -u 参数来覆盖所指定的用户。

13. HEALTHCHECK

  • 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
  • 语法格式如下:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。

14. ONBUILD

  • ONBUILD 用于设置镜像触发器。
  • 语法格式如下:
ONBUILD <其它指令>
  • 当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发。

如,当镜像被使用时,可能需要做一些处理:

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

15. LABEL

  • LABEL 用于为镜像添加元数据(metadata),元数以键值对的形式指定。
  • 语法格式如下:
LABEL <key>=<value> <key>=<value> <key>=<value> ...

使用 LABEL 指定元数据时,一条 LABEL 指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条 LABEL 指令指定,以免生成过多的中间镜像。

例如,通过 LABEL 指定一些元数据:

LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"

指定后可以通过 docker inspect 查看:

docker inspect itbilu/test
"Labels": {
    "version": "1.0",
    "description": "这是一个Web服务器",
    "by": "IT笔录"
},

16. STOPSIGNAL

  • STOPSIGNAL 用于设置停止容器所要发送的系统调用信号。
  • 语法格式如下:
STOPSIGNAL signal

所使用的信号必须是内核系统调用表中的合法的值,如:SIGKILL。

17. SHELL

  • SHELL 用于设置执行命令(shell式)所使用的的默认 shell 类型。
  • 语法格式如下:
SHELL ["executable", "parameters"]
  • SHELL 在 Windows 环境下比较有用,Windows 下通常会有 cmdpowershell 两种 shell,可能还会有 sh。这时就可以通过 SHELL 来指定所使用的 shell 类型:
FROM microsoft/windowsservercore

# Executed as cmd /S /C echo default
RUN echo default

# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default

# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello

# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S"", "/C"]
RUN echo hello

18. 实践操作(Ubuntu)

1. 创建 DockerFile 文件

  • 首先创建一个空文件夹单独存放 Dockerfile 文件,然后创建一个 Dockerfile 文件。命令如下:
mkdir mydocker
cd mydocker
touch Dockerfile

在这里插入图片描述

2. 进入文件

命令如下:

sudo vim Dockerfile

注意
有的虚拟机可能没有安装 vim,导致会出现下面这样的错误:

sudo: vim: command not found

此时,可以输入下面这条命令进行下载:

sudo apt-get install vim-gtk

进入文件后的界面如下:

在这里插入图片描述

补充:文件编辑好之后如何进行退出

  • 【要退出,但是不保存】:先按 Esc,然后输入:q,按回车键即可退出。无法退出,则在 :q 加入一个叹号 ! ,再按回车键就行了,即 !q!
  • 【要退出,保存】:先按 Esc,输入 :wq,按回车键即可退出。强制保存退出,则输入 :wq!
  • 【以 nano 开头编辑文件的要退出】:按 Ctrl+x,回车键。如要保存的,则先按 Ctrl+o,再按 x 退出。

3. 输入文件内容

#基础镜像
FROM ubuntu

#维护者信息
MAINTAINER carson carson@email.com

#镜像的操作指令
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server

#容器启动时的执行命令
CMD /user/sbin/nginx

在这里插入图片描述

补充:在 Dockerfile 中添加维护者信息是可选的,它用于指定镜像的作者或维护人员。维护者信息可以帮助其他人了解镜像的来源和相关信息。以下是在 Dockerfile 中添加维护者信息的语法和示例:

  • 语法:
MAINTAINER <作者或维护者的姓名和邮箱>
  • 示例:
FROM ubuntu:latest
MAINTAINER John Doe <john.doe@example.com>

# 添加其他指令
...

在示例中,我们使用 FROM 指令指定基础镜像为最新版本的 Ubuntu。然后,使用 MAINTAINER 指令指定了维护者的姓名和邮箱地址。

注意:从 Docker 1.13 版本开始,MAINTAINER 指令已经被标记为过时(deprecated)。推荐使用 LABEL 指令来添加维护者信息和其他元数据。下面是使用 LABEL 指令的示例:

FROM ubuntu:latest
LABEL maintainer="John Doe <john.doe@example.com>"

# 添加其他指令
...

使用 LABEL 指令的好处是可以添加多个标签,包括维护者信息和其他自定义元数据,使镜像更丰富和可理解。
总结起来,可以选择使用 MAINTAINERLABEL 指令来添加维护者信息,具体选择取决于使用的 Docker 版本和个人偏好。

4. 生成镜像

  • 编辑完 Dockerfile 后使用 docker build 指令生成镜像。命令如下:
docker build -t myngix .

在这里插入图片描述

运行该命令后的截图:

在这里插入图片描述

5. 验证镜像是否生成成功

输入以下命令:

# 普通用户涉及权限问题,在该命令之前加上 sudo 即可
docker images

在这里插入图片描述
由上面的截图可知,镜像生成成功!

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值