Docker可以通过Dockerfile构建镜像。当执行docker build
命令时,当前的工作目录称为build context
。
默认,Dockerfile会位于当前目录,但是也可以通过-f选项指定不同的位置。
简单的构建Dockerfile过程如下
mkdir myproject && cd myproject
echo "hello" > hello
echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > Dockerfile
docker build -t helloapp:v1 .
其中,构建文件是Dockerfile,构建环境是当前目录.
如果此时将Dockerfile与hello文件移动到不同的路径,则操作改为
mkdir -p dockerfiles context
mv Dockerfile dockerfiles && mv hello context
docker build --no-cache -t helloapp:v2 -f dockerfiles/Dockerfile context
其中,构建文件是dockerfiles/Dockerfile,构建环境是context目录。
如果需要指定多个标签,可以
$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
如果要查看build context的大小,可以在构建Dockerfile时,注意输出日志
Sending build context to Docker daemon 187.8MB
.dockerignore
排除与构建无关的文件,可以使用.dockerignore
文件,它与.gitignore
类似。
multi-stage构建
如果使用Docker 17.05+,可以选择使用multi-stage build,从而显著减少镜像的体积。
一个go应用的Dockerfile如下所示
FROM golang:1.9.2-alpine3.6 AS build
# Install tools required to build the project
# We need to run `docker build --no-cache .` to update those dependencies
RUN apk add --no-cache git
RUN go get github.com/golang/dep/cmd/dep
# Gopkg.toml and Gopkg.lock lists project dependencies
# These layers are only re-built when Gopkg files are updated
COPY Gopkg.lock Gopkg.toml /go/src/project/
WORKDIR /go/src/project/
# Install library dependencies
RUN dep ensure -vendor-only
# Copy all project and build it
# This layer is rebuilt when ever a file has changed in the project directory
COPY . /go/src/project/
RUN go build -o /bin/project
# This results in a single layer image
FROM scratch
COPY --from=build /bin/project /bin/project
ENTRYPOINT ["/bin/project"]
CMD ["--help"]
最小化layer数量
在Docker 17.05之前,甚至是Docker 1.10之前,镜像的layer数目需要最小化。
在Docker 1.10+,只有RUN
、COPY
、ADD
会创建layer;其他命令只会创建临时的中间层镜像,不会直接增加构建体积。
在Docker 17.05+,支持multi-stage builds,允许将所需要的artifacts拷贝到最后的镜像;而在中间层构建过程中可以包含工具和debug信息,但它不会增加最后镜像的体积。
多行参数
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
构建缓存
在使用Dockerfile构建镜像时,在每次命令执行时都会检查缓存中是否有存在的镜像,如果不想使用缓存构建,可以在执行docker build
命令时,添加选项--no-cache=true
Docker镜像构建时的缓存规则:
如果cache存在parent image,则下一条命令执行时会比较所有派生自parent image的child images,是否执行了相同的命令;如果没有,则cache失效。
在大多数情况下,仅仅是用指令比较child images就可以了。但是存在某些指令需要额外的检验。
ADD和COPY指令会验证文件内容并计算checksum。如果比较中的checksum与已存在镜像的checksum不同,则cache失效。