Dockerfile最佳实践
官网地址:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/。
一个容器只运行一个进程
原因
- 提供单独的扩展,仅对出现性能瓶颈的容器进行扩缩容,合理的利用资源。
- 安全:避免当一个程序受到攻击入侵时,另一个程序直接暴露在危险之中。
- 隔离:避免程序之间的资源竞争,合理的规划单个程序的资源限制。
不要在构建中升级版本
比如不建议在Ubuntu系统中使用apt-get upgrade。因为这个命令会把本地已安装的软件与软件列表中对应的软件进行对比,如果发现已安装的软件版本太低,就会提示更新,这样就会导致软件版本的不可控和最终构建镜像的不一致性。
将变化频率一样的RUN指令合一
RUN指令常用于安装软件包,建议把使用到的apt-get install命令合并在一起,其目的是为了更好的将镜像分层,避免带来不必要的成本。如下所示。
FROM nginx:latest
RUN apt-get update && \
apt-get install -y iproute2 && \
rm -rf /var/lib/apt/lists/*
使用特定的标签
建议指定特定的标签,如:14.04。因为默认的标签为:latest,当镜像更新时,标签将指向最新的镜像,这将导致最终构建镜像不一致或者有可能失败。
FROM ubuntu:14.04
删除多余的文件
当我们更新了apt-get源,下载解压并安装了一些软件包,它们都保存在"/var/lib/apt/lists/“目录中。但是,运行应用时Docker镜像中并不需要这些文件。通过删除”/var/lib/apt/lists/"目录实现清理apt cache。
除此之外,在使用Dockerfile过程中应及时清理不必要的文件,如安装包、压缩包等。参考网址:https://blog.csdn.net/qq_38556887/article/details/124431586。
RUN apt-get update && apt-get install -y nginx && rm -rf /var/lib/apt/lists/*
选择合适的基础镜像
尽可能的使用对应部署环境的官方镜像(https://hub.docker.com)。对于一些不需要部署环境的镜像,建议使用 Alpine镜像,因为它非常的小(目前不足6MB)但确是一个完整的Linux发行版,非常适合作为基础镜像。
FROM node:7-alpine
设置WORKDIR和CMD
建议使用绝对路径作为工作目录,因为这读起来更加清晰明确。
同时,这将导致之后RUN/CMD/ENTRYPOINT指令默认在工作目录执行。
WORKDIR /opt/project/npm
CMD ["npm","start"]
使用ENTRYPOINT(可选)
可以将ENTRYPOINT指令作为容器的默认执行命令,用CMD作为参数,让docker用来就像systemctl一样方便。
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
docker run start
在entrypoint脚本中使用exec
在上面的./entrypoint.sh中如果存在exec的命令执行,该命令将是容器中pid为1的进程。
优先使用COPY
COPY相较于ADD,更加透明可控。COPY仅支持基础的文件从本地到容器的移动,而ADD会把压缩包解压。ADD更适合于从压缩包中提取数据到容器。
合理调整COPY和RUN的顺序
将不易变化的部分先COPY,然后执行RUN命令,最后COPY剩余的部分。
设置默认的环境变量、映射端口和数据卷
- ENV指令指定的环境变量在容器中可以使用。
- ARG指令指定的变量仅在构建镜像时生效。
ENV PATH=/usr/local/nginx/bin:$PATH
使用EXPOSE暴露端口
EXPOSE指令可用于指定容器将要监听的端口。
多阶段构建
多阶段构建可以极大的降低镜像的大小,减少层数。例如我们可以使用第一个镜像完成编译构建过程,将产物传输到第二个镜像形成镜像包,实现构建与部署的解耦。
# syntax=docker/dockerfile:1
FROM golang:1.16-alpine 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"]
使用VOLUME管理数据卷
VOLUME指令可以用于暴露任何数据库存储文件、配置文件或容器创建的文件和目录。
使用LABEL设置镜像元数据
合理的使用LABEL对镜像做一些标注,如发行版本、证书信息、联系方式等。
添加HEALTHCHECK
编写.dockerignore文件
功能类似.gitignore。