6 Star 72 Fork 28

JustryDeng / notebook

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
[03]Docker上下文环境、Dockerfile与build命令.md 10.76 KB
一键复制 编辑 原始数据 按行查看 历史

Docker上下文环境、Dockerfile与build命令

Docker上下文环境(Context)

介绍

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

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

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

如果在 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 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去

现在就可以理解刚才的命令 docker build -t nginx:v3 . 中的这个 . (即./),实际上是在指定上下文的目录, docker build 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像

如果观察 docker build 输出,我们其实已经看到了这个发送上下文的过程:

$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
...

理解构建上下文对于镜像构建是很重要的,避免犯一些不应该的错误。比如有些初学者在发现 COPY /opt/xxxx /app 不工作后,于是干脆将 Dockerfile 放到了硬盘根目录去构建,结果发现 docker build 执行后,在发送一个几十 GB 的东西,极为缓慢而且很容易构建失败。那是因为这种做法是在让 docker build 打包整个硬盘,这显然是使用错误

一般来说,应该会将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个 .dockerignore ,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的

那么为什么会有人误以为 . 是指定 Dockerfile 所在目录呢?这是因为在默认情况下,如果不额外指定 Dockerfile 的话,会将上下文目录下的名为 Dockerfile 的文件作为 Dockerfile。这只是默认行为,实际上Dockerfile 的文件名并不要求必须为 Dockerfile ,而且并不要求必须位于上下文目录中,比如可以用 -f ../Dockerfile.php 参数指定某个文件作为 Dockerfile。当然,一般大家习惯性的会使用默认的文件名 Dockerfile ,以及会将其置于镜像构建上下文目录中

总结

上下文就是:Docker服务端(即:Docker引擎)里面的一个临时文件夹,build时会将宿主机上(通过相对或绝对位置)指定的文件夹拷贝一份上传到Docker服务端里,作为上下文环境(临时文件夹);后面再执行Dockerfile中的ADD/COPY等指令时,实际上就相当于从Docker服务端里面的该临时文件夹(即:上下文环境)里ADD/COPY到该镜像指定的目录下了

docker build -t {镜像名} .指令中的.(即./),就是将宿主机的当前文件夹作为上下文

给出一张上下文环境测试方法:

图片1

Dockerfile

Makefile简介

一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令

所要完成的Makefile 文件描述了整个工程的编译、连接等规则。其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建哪些库文件以及如何创建这些库文件、如何最后产生我们想要的可执行文件。尽管看起来可能是很复杂的事情,但是为工程编写Makefile 的好处是能够使用一行命令来完成“自动化编译”,一旦提供一个(通常对于一个工程来说会是多个)正确的 Makefile。编译整个工程你所要做的唯一的一件事就是在shell 提示符下输入make命令。整个工程完全自动编译,极大提高了效率

Dockerfile指令

Docker提供了和Makefile完全一样的机制来管理镜像,这就是Dockerfile

指令 说明
FROM 指定要创建的镜像的基础镜像
MAINTAINER 指定镜像维护者(创建者)信息
RUN (当镜像创建容器后,该容器需要)运行的shell命令
注:如果有多条命令,可以用&&连接
CMD docker start启动(镜像创建的)容器后, 要默认运行的命令
LABEL 指定生成镜像的元数据标签信息
EXPOSE 常用于映射(暴露)端口(此表格后,会详细介绍)
ENV 指定环境变量
ADD 复制上下文中的src路径下的内容到容器中的dest路径下
注:src可以为URL
注:如果src路径为tar文件,会自动解压到dest路径下
COPY 复制上下文中的src路径下的内容到容器中的dest路径下
注:一般情况下推荐使用COPY而不是ADD
ENTRYPOINT 指定镜像的默认入口
VOLUME 指定数据挂载点
USER 指定运行容器时的用户名或UID
WORKDIR 配置工作目录
ARG 指定镜像内使用的参数(例如版本号信息等)
ONBUILD ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN , COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行
STOPSIGNAL 容器退出的信号
HEALTHCHECK 健康检查
SHELL 指定使用SHELL时的默认SHELL类型
……

EXPOSE

指定容器需要映射到宿主机器的端口

设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后在运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上的端口号没有被使用。EXPOSE指令可以一次设置多个端口号,相应的运行容器的时候,可以配套的多次使用-p选项

  • 映射一个端口

    EXPOSE port1
  • 相应的运行容器使用的命令

    docker run -p port1 image
  • 映射多个端口

    EXPOSE port1 port2 port3
  • 相应的运行容器使用的命令

    docker run -p port1 -p port2 -p port3 image
  • 还可以指定需要映射到宿主机器上的某个端口号

    docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image

端口映射是docker比较重要的一个功能,原因在于我们每次运行容器的时候容器的IP地址不能指定而是在桥接网卡的地址范围内随机生成的。宿主机器的IP地址是固定的,我们可以将容器的端口的映射到宿主机器上的一个端口,免去每次访问容器中的某个服务时都要查看容器的IP的地址。对于一个运行的容器,可以使用docker port加上容器中需要映射的端口和容器的ID来查看该端口号在宿主机器上的映射端口

BUILD指令

指令

# 若不指定-f,则默认取上下文目录里名为"Dockerfile"的文件作为Dockerfile
docker build -t {镜像名} {上下文目录} -f {Dockerfile文件名}

注:Dockerfile文件可以不在上下文目录下,可以在宿主机上的任意位置,只需要在docker build的时候-f指定一下即可

示例

docker build -t ds/myimages . -f myDockerfile.txt 
  • ds/myimages:镜像名
  • myDockerfile.txt :Dockerfile文件
  • .:上下文目录,等价于./
1
https://gitee.com/JustryDeng/notebook.git
git@gitee.com:JustryDeng/notebook.git
JustryDeng
notebook
notebook
master

搜索帮助