Dockerfile 最佳实践
1. 只添加需要的文件
1.1 使用 .dockerignore
temp?
!README.md
Dockerfile
1.2 用到什么就添加什么
FROM alpine
ADD app /bin/
RUN apk -Uuv add --no-cache ca-certificates tini tzdata && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
mkdir /kuu
WORKDIR /kuu
COPY kuu.json .
ADD docs ./docs
ADD assets ./assets
ENTRYPOINT ["/sbin/tini","--", "app"]
目的
- 忽略多余的文件和目录,精简镜像体积。
- 不必要的文件变动,不影响docker构建过程使用缓存。
2. 一个容器运行单一进程
原子性,环境独立。
gogs
gogs-db
3. 打上易读的镜像仓库名和标签
贴标签,方便快速知道它的用途。
gogs
gogs-db
4. 精简基础镜像
精简,体积小。 可靠,推荐试用官方镜像。alpine版本最好
Alpine Linux是一个独立的,非商业的通用Linux发行版,专为那些喜欢安全性,简单性和资源效率的高级用户而设计。(官网介绍)
FROM alpine
4.1 再精简一下
-
比如使用 --no-install-recommends 参数告诉 apt-get 不要安装推荐的软件包
-
安装完软件包,清 /var/lib/apt/list/ 缓存 (ubuntu)
RUN apt-get update && apt-get install -y \
aufs-tools \
automake \
build-essential \
curl \
dpkg-sig \
libcap-dev \
libsqlite3-dev \
mercurial \
reprepro \
ruby1.9.1 \
ruby1.9.1-dev \
&& rm -rf /var/lib/apt/lists/*
- alpine 中使用 --no-cache
FROM alpine
ADD app /bin/
RUN apk -Uuv add --no-cache ca-certificates tini tzdata
-
删除中间文件:比如下载的压缩包
-
删除临时文件:如果命令产生了临时文件,也要及时删除
5. 缓存问题
5.1 层级顺序
经常变化的内容和基本不会变化的内容要分开,把不怎么变化的内容放在上层,可以更好使用缓存
FROM alpine
ADD app /bin/
RUN apk -Uuv add --no-cache ca-certificates tini tzdata
Run ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
Run mkdir /kuu
5.2 减少层级
一行RUN 就会生成一个镜像的缓存层, 使用换号符号 “\”。
FROM alpine
ADD app /bin/
RUN apk -Uuv add --no-cache ca-certificates tini tzdata && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
mkdir /kuu
5.3 解决5.2产生的可读性问题
尽量按字母排序
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
6. 挂载 VOLUME
包括数据库文件、代码库、配置文件……都应该使用 VOLUME 挂载
7. EXPOSE
- Dockerfile 内不做映射外部端口, 保证镜像灵活性。
EXPOSE 80
- 应该为应用程序使用通用的传统端口。 例如,包含Nginx服务器的映像将使用EXPOSE 80,而包含MongoDB的映像将使用EXPOSE 27017等。
8. 尽量使用明确版本
当镜像没有指定标签时,将默认使用latest 标签。当版本有大迭代升级,可能会导致镜像不可用。
FROM node:alpine
FROM node:carbon-alpine 或 FROM node:8-alpine
9. 利用好CMD与ENTRYPOINT
-
CMD
The main purpose of a CMD is to provide defaults for an executing container.
CMD的作用在于执行容器时提供默认的命令操作
-
ENTRYPOINT
An ENTRYPOINT allows you to configure a container that will run as an executable.
它可以让你的容器功能表现得像一个可执行程序一样
9.1 CMD
CMD echo "Hello world"
执行docker run -it [image]
但当后面加上 docker run -it [image] /bin/bash,CMD 会被忽略掉,命令 bash 将被执行:
root@10a32dc7d3d3:/#
9.2 ENTRYPOINT
ENTRYPOINT ["/bin/echo", "Hello"]
docker run -it [image] 启动, 输出 :Hello
docker run -it [image] World, 输出:Hello World
参数化使用,可执行的程序
10. 添加HEALTHCHECK
运行容器时,可以指定 --restart always 选项。这样的话,容器崩溃时,Docker守护进程(docker daemon)会重启容器。对于需要长时间运行的容器,这个选项非常有用。
但是,如果容器的确在运行,但是不可(陷入死循环,配置错误)用怎么办?使用HEALTHCHECK指令可以让Docker周期性的检查容器的健康状况。我们只需要指定一个命令,如果一切正常的话返回0,否则返回1。
11. 多阶段构建 (可以了解一下)
当编译阶段需要依赖特定系统环境,而运行时依赖少量库或包, 最终上传小镜像即可。(例如: c语言编辑环境)
from debian as build-essential
arg APT_MIRROR
run apt-get update
run apt-get install -y make gcc
workdir /src
from build-essential as foo
copy src1 .
run make
from build-essential as bar
copy src2 .
run make
from alpine
copy --from=foo bin1 .
copy --from=bar bin2 .
cmd ...
参考资料
https://mp.weixin.qq.com/s/wNCfYERWU3GOBHI2juTpmg
https://www.jianshu.com/p/9f15b81759bd
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
https://docs.docker.com/engine/reference/builder/#entrypoint
网友评论