一句话理解Docker上下文
发出docker build
命令时,当前工作目录被称为build context
。默认情况下,Dockerfile 假定位于当前目录,但也可以使用-f参数
指定其他位置。但不管 Dockerfile 实际位于何处,当前目录下所有内容都将作为构建上下文发送到 Docker 守护进程。
详细解释
docker build [OPTIONS] PATH
我们注意到命令的末尾有一个 PATH,它代表的是Dockerfile路径吗?不,它代表的是构建镜像的上下文路径。我们知道 Docker 是一个 C/S 架构程序,我们在客户端输入 docker build 命令,该命令会将 PATH 目录下的所有文件打包并传输给 docker daemon。
比如我们构建一个 nginx 镜像:docker build -t nginx:v1 .
命令末尾的.
表示将当前目录作为上下文,目录下的所有内容都会打包发送给 docker daemon,接着 docker daemon 会将其构建成镜像。
docker build 命令默认 dockerfile 的位置在当前目录,如果想指定 dockerfile 的位置则需要使用-f
参数,示例:docker build -f /path/to/a/Dockerfile -t nginx:v1 .
应用
dockerfile 的 COPY 命令
随便写一个例子:COPY ./package.json /app/
,这并不是要复制执行 docker build 命令所在的目录下的 package.json,也不是复制 Dockerfile 所在目录下的 package.json,而是复制上下文目录下的 package.json。
因此,COPY 这类指令中的源文件的路径都是相对路径。这也是COPY ../package.json /app
或者COPY /opt/xxxx /app
报错的原因,因为这些路径已经超出了上下文的范围,Docker 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去。
dockerfile 的正确使用方式
理解构建上下文对于镜像构建是很重要的,可以避免犯一些不应该犯的错误。比如有些初学者在发现COPY /opt/xxxx /app
报错后,干脆将 Dockerfile 放到了硬盘根目录去构建,结果发现 docker build 执行后,在发送一个几十 GB 的东西,极为缓慢而且很容易构建失败。那是因为这种做法是在让 docker build 打包整个硬盘,这显然是错误的构建镜像姿势。
一般来说,应该将 Dockerfile 置于空目录或者项目根目录下。如果该目录下没有所需文件,则应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用.gitignore
一样的语法写一个.dockerignore
。