小言_互联网的博客

Dockerfile : 常用指令

347人阅读  评论(0)

镜像的定制

镜像是多层存储,每一层是在前一层的基础上进行的修改;而容器同样也是多层存储,是在以镜像为基础层,在其基础上加一层作为容器运行时的存储层。

镜像的定制实际上就是定制每一层所添加的配置、文件。

如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么曾经遇到的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。

Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

有了 Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻烦。

Dockerfile文件格式

##  Dockerfile文件格式

# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..

# 1、第一行必须指定 基础镜像信息
FROM ubuntu

# 2、维护者信息
MAINTAINER docker_user docker_user@email.com

# 3、镜像操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

# 4、容器启动执行指令
CMD /usr/sbin/nginx

Dockerfile 分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动执行指令

  • 一开始必须要指明所基于的镜像名称,接下来一般会说明维护者信息;后
  • 面则是镜像操作指令,例如 RUN 指令。每执行一条RUN 指令,镜像添加新的一层,并提交;
  • 最后是 CMD 指令,来指明运行容器时的操作命令。
     

构建镜像

使用 docker build 命令进行镜像构建。其格式为:

docker build [选项] <上下文路径/URL/->

docker build 命令会根据 Dockerfile 文件及上下文构建新 Docker 镜像。

镜像构建上下文(Context)

如果注意,会看到 docker build 命令最后有一个 .. 表示当前目录,而 Dockerfile 就在当前目录,因此不少初学者以为这个路径是在指定 Dockerfile 所在路径,这么理解其实是不准确的。如果对应上面的命令格式,你可能会发现,这是在指定 上下文路径。那么什么是上下文呢?

首先我们要理解 docker build 的工作原理。

Docker 在运行时分为 Docker 引擎(也就是服务端守护进程)和客户端工具。Docker 的引擎提供了一组 REST API,被称为 Docker Remote API,而如 docker 命令这样的客户端工具,则是通过这组 API 与 Docker 引擎交互,从而完成各种功能。因此,虽然表面上我们好像是在本机执行各种 docker 功能,但实际上,一切都是使用的远程调用形式在服务端(Docker 引擎)完成。也因为这种 C/S 设计,让我们操作远程服务器的 Docker 引擎变得轻而易举。

当我们进行镜像构建的时候,并非所有定制都会通过 RUN 指令完成,经常会需要将一些本地文件复制进镜像,比如通过 COPY 指令、ADD 指令等。而 docker build 命令构建镜像,其实并非在本地构建,而是在服务端,也就是 Docker 引擎中构建的。那么在这种客户端/服务端的架构中,如何才能让服务端获得本地文件呢?

这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。

构建上下文是指 Dockerfile 所在的本地路径或一个URL(Git仓库地址)。构建上下文环境会被递归处理,所以构建所指定的路径还包括了子目录,而URL还包括了其中指定的子模块。

如果在 Dockerfile 中这么写:

COPY ./package.json /app/

这并不是要复制执行 docker build 命令所在的目录下的 package.json,也不是复制 Dockerfile 所在目录下的 package.json,而是复制 上下文(context) 目录下的 package.json

因此,COPY 这类指令中的源文件的路径都是相对路径。这也是初学者经常会问的为什么 COPY ../package.json /app 或者 COPY /opt/xxxx /app 无法工作的原因,因为这些路径已经超出了上下文的范围,Docker 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去。

Dockerfile 指令详解

1、FROM指令

使用说明:

    使用格式:FROM <image>或FROM <image>:tag

    作用描述:dockerfile的第一条非注释指令,为后面提供基础镜像。

②使用建议:

(1)建议尽可能使用官方提供的image版本作为baseimage。

(2)建议使用Debian image,因为这些image易于控制同时尺寸都很小,大多数在100MB以下,非常适合进行分发。

2、RUN指令

①使用说明:

    使用格式:RUN <command> 或 RUN [“executable”,”param1”,”param2”]

    作用描述:run指令会在前一条命令创建出的镜像基础上启动一个容器,并在容器中运行命令,命令结束后会提交一个新镜像。上述两种用法,前者将在shell终端中运行命令,即 /bin/sh -c ;后者则使用 exec 执行。指定使用其它终端可以通过第二种方式实现,例如 RUN ["/bin/bash", "-c", "echo hello"]

②使用建议:

(1)为了保持Dockerfile可读性,易于理解,方便维护。建议将多条RUN 命令使用"/"连接起来。

(2)apt-get应该是大多数Dockerfile都会定义的RUN 命令。当使用apt-get,有如下建议可参考:不用将RUN apt-get update单独作为一条命令。如果关联包发生变化后,在执行apt-get install 命令时,docker 查找cache时有可能会有问题。

(3)回避使用 RUN apt-get upgrade 或者 disk-upgrade 命令。因为很多外部的软件包在未经认证情况执行upgrade会失败。如果有一些软件包过期了,那么你应该联系软件包的维护者来确定是否需要升级。比如你确定一个第三方的软件包 foo 可以进行升级。那么执行apt-get install -y foo就可以自动完成升级。

(4)如果可能的话,将你准备安装的软件包安装字母顺序排列。这样可以回避重复安装软件包的情况,同时也有助于进行软件更新。通过添加"\"进行分割,将增强代码的可读性。

3、ADD和COPY指令

①使用说明:

    使用格式:两个命令的使用方式类似 ADD <src> <dest>、COPY <src> <dest>

作用描述:

    ADD:该命令将复制指定的 <src> 到容器中的 <dest> 。 其中 <src> 可以是Dockerfile所在目录的一个相对路径;也可以是一个URL;还可以是一个tar文件(自动解压为目录)

    COPY:复制本地主机的<src>(为Dockerfile所在目录的相对路径)到容器中的<dest>。

②使用建议:

(1)当使用本地目录为源目录时,推荐使用 COPY

4、CMD与ENTRYPOINT指令

①使用说明:

使用格式:

其中CMD有以下三种使用方式

CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式;

CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用;

CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数;

ENTRYPOINT 使用格式:

ENTRYPOINT ["executable", "param1", "param2"]

ENTRYPOINT command param1 param2 (shell中执行)

作用描述:

CMD:指定启动容器时执行的命令,每个Dockerfile只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。

ENTRYPOINT :配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。每个Dockerfile中只能有一个 ENTRYPOINT ,当指定多个时,只有最后一个起效

②使用建议:

(1)CMD命令用来执行image中的所有应用。CMD一般采用CMD [“executable”, “param1”, “param2”…]的格式来运行。所以,如果你的image是用来提供服务的,例如Apache,Rails。你就应该执行类似这样的命令CMD ["apache2","-DFOREGROUND"]。

(2)在其他的case中,CMD用来执行特定的shell,比如:bash,python,perl等等。比如: CMD ["perl", "-de0"] ,  CMD ["python"] , or  CMD [“php”, “-a”]。

(3)当你执行docker run -it python时就可以进入特定的shell中。

(4)CMD经常是配合 ENTRYPOINT 来使用的。除非确定你的用户非常了解ENTRYPOINT 的特性。否则还是建议你事先设定好ENTRYPOINT

5、EXPOSE指令

①使用说明:

    使用格式:EXPOSE <port> [<port>...]

    作用描述:指定容器暴露的端口

②使用建议:

(1)EXPOSE命令定义了container用来监听连接者的端口。因此,你应该为你的image定义一个比较通用的端口。比如一个用来提供Apache web服务的image,你应该expose 80.而提供MongoDB的image,应该提供27017端口。

(2)对于一些外部访问,你的用户可以使用docker run -p的形式来进行端口绑定。

6、ENV指令

①使用说明:

使用格式:ENV <key> <value>或ENV <key>=<value>

作用描述:为创建出来的容器创建环境变量

②使用建议:

(1)为了保证application可以顺利执行,你可以通过ENV来更新PATH环境变量。比如:通过ENV PATH /usr/local/nginx/bin:$PATH 可以确保CMD ["nginx"]顺利执行。

(2)ENV也可以用来提供特定的环境变量,比如你可以自定义postgres所需要的PGDATA变量。

(3)最后ENV可以用来定义一些版本信息。

7、WORKDIR指令

①使用说明:

使用格式:WORKDIR /path/to/workdir 。

作用描述:为后续的 RUN 、 CMD 、 ENTRYPOINT 指令配置工作目录。可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。

②使用建议:

(1)为了保持执行过程清晰,你应该经常使用绝对路径来设定WORKDIR。

(2)你应该使用WORKDIR来替代 RUN cd .. && do-something

8、VOLUME指令

①使用说明:

使用格式:VOLUME ["/data"] 。

作用描述:创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

②使用建议:

(1)VOLUME应该被用来导出数据库存储区域,配置文件存储区域或者container内部app创建的目录或者文件。

参考:

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/


转载:https://blog.csdn.net/fly910905/article/details/102513630
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场