..

【翻译】dockerfile最佳实践

此文包含官方推荐的docker镜像编译方式。dockerfile是一个包含一些列有序指令的文件,docker编译镜像的时候会自动读取dockerfile文件中的指令。docker镜像中包含一些只读的层,每一层都是对上一层的覆盖。请看如下的dockerfile

FROM ubuntu:15.04
COPY . /app
RUN make /app
CMD python /app/app.py

每个指令都会在原来的镜像的基础上添加一层:

  • FROM 在ubuntu:15.04的基础上创建一层
  • COPY 拷贝当前目录的文件到镜像中
  • RUN 使用make命令执行命令
  • CMD 在容器中执行的特殊程序 当启动镜像时候,会在原来的镜像上添加一个新的可以读写的层,并且生成一个容器,在容器中能对该层镜像读写,删除等。

常规指导建议

创建临时容器

dockerfile能够产生临时的容器,并且Dokerfile能够被反复编译成镜像.

理解编译的上下文

当你在执行docker build命令的时候,当我目录就是编译的上下文件,默认情况下dockerfile应该就在当前目录下,当然也可以在别的目录,通过docker build -f指定Dockefile的文件地址即可。 当执行docker build的时候,上下文(当前目录)所有文件都会被递归的发送给docker daemon进程,在dockerfile中能够使用上下文件中的文件,所以上文的大小也会影响编译时间.

创建一个空目录当前编译的上下文目录,在上下文中创建名字为hello的文件,创建dockerfile,并且在dockerfile中cat这个hello文件,然后指定编译的上下文目录为当前文件 .

mkdir myproject && cd myproject
echo "hello" > hello
echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > dockerfile
docker build -t helloapp:v1 .

将hello文件和dockerfile分离,我们编译第二个版本的镜像,我们使用 -f来指定dockerfile文件,使用特殊的文件作为编译的上下文目录,而不是使用当前目录。

mkdir -p dockerfiles context
mv dockerfile dockerfiles && mv hello context
docker build --no-cache -t helloapp:v2 -f dockerfiles/dockerfile context

不要讲不必要的文件加入到镜像,他会是增加镜像的体积,进行会增加push镜像和pull镜像的时间,同事也会增加容器运行的大小。当我们在编译dockerfile的时候,我们能够看到当前上下文件的大小:

Sending build context to docker daemon  187.8MB

从管道读入dockerfile

docker 17.05添加从管道读取dockerfile的能力,在早期的dockerfile版本,可以直接从标准输入dockerfile,而不需编译的上下文目录。

docker 17.04以及更老的版本

docker build -t foo -<<EOF
FROM busybox
RUN echo "hello world"
EOF

docker 17.05 以及更新的版本(使用本地目录作为编译上下文)

docker build -t foo . -f-<<EOF
FROM busybox
RUN echo "hello world"
COPY . /my-copied-files
EOF

docker 17.05 以及更新的版本(使用远程目录作为编译上下文)

docker build -t foo https://github.com/thajeztah/pgadmin4-docker.git -f-<<EOF
FROM busybox
COPY LICENSE config_local.py /usr/local/lib/python2.7/site-packages/pgadmin4/
EOF

使用.dockerignore忽略文件

在编译的时候,希望提高编译速度,减小编译的上下文目录的大小,可以使用.dockerignore文件来指定需要忽略的文件,他的语法类似于.gitignore文件的语法。

使用多步骤构建

docker 17.05版本以后,不需要竭力去控制编译层数就能大幅度减少镜像的体积大小。docker会利用镜像缓存的方式来减少镜像的大小。当你编译一个多层的镜像的时候,能够通过编排指令的顺序来体用镜像的缓存机制:

  1. 安装依赖工具
  2. 安装和更新程序依赖
  3. 安装应用程序

一个golang程序的dockerfile如下:

FROM golang:1.9.2-alpine3.6 AS build

# Install tools required for project
# Run `docker build --no-cache .` to update dependencies
RUN apk add --no-cache git
RUN go get github.com/golang/dep/cmd/dep

# List project dependencies with Gopkg.toml and Gopkg.lock
# 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 the entire project and build it
# This layer is rebuilt when a file changes 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"]

减少非必要软件包

如非必要,不要安装你不会用到的软件包,这能帮你降低镜像的体积大小。