2. dockerfile编写最佳实践¶
2.1. 一般准则和建议¶
创建尽可能精简的容器
了解构建上下文
通过stdin管道Dockerfile
包含dockerignore文件
使用多阶段构建
不要安装不必要的包
解构应用程序,分离容器功能,每个容器限制为单个进程,保存容器的清洁和模块化,容器直接可以通过网络通信。
最小化层级
一个命令可以使用转义为多行,美化dockerfile文件。让别人看起来舒服点。
利用构建缓存
2.2. 通过stdin管道Dockerfile的样例¶
docker build -t foo -<<EOF
FROM busybox
RUN echo "hello world"
EOF
docker build -t foo . -f-<<EOF
FROM busybox
RUN echo "hello world"
COPY . /my-copied-files
EOF
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
2.3. docker指令¶
2.3.1. FROM¶
尽量选择alpine镜像作为源镜像,这样构建的镜像才最小
2.3.2. LABEL¶
LABEL用来说明我们的镜像信息的,尽可能的详细点。
比较详细的dockerfile label
# Set one or more individual labels
LABEL com.example.version="0.0.1-beta"
LABEL vendor1="ACME Incorporated"
LABEL vendor2=ZENITH\ Incorporated
LABEL com.example.release-date="2015-02-12"
LABEL com.example.version.is-production=""
但是上面的label会构建多层的。需要改进为如下风格的。
LABEL vendor=ACME\ Incorporated \
com.example.is-beta= \
com.example.is-production="" \
com.example.version="0.0.1-beta" \
com.example.release-date="2015-02-12"
2.3.3. RUN¶
使用来分割命令为多行,来增加可读性和可维护性。
2.3.4. USING PIPES¶
docker使用/bin/sh -c来解释run命令,该解释器仅仅评估管道中最后一个的操作码来确定成功,
# 即使wget失败,后续的wc -l成功,整句的就是成功的。
RUN wget -O - https://some.site | wc -l > /number
2.3.5. CMD¶
CMD 尽可能采用数组形式的,且只提供参数,具体的命令使用ENDPOINT指定。
2.3.6. EXPOSE¶
2.3.7. ENV¶
为了确保你的应用程序以比较简单的方式去运行,可以使用env去添加环境变量。
ENV PATH /usr/local/nginx/bin:$PATH
CMD ["nginx"]
每个ENV会添加一层,可以一次添加多个行间变量。可以使用run来替代ENV
FROM alpine
RUN export ADMIN_USER="mark" \
&& echo $ADMIN_USER > ./mark \
&& unset ADMIN_USER
CMD sh
2.3.8. ADD or COPY¶
ADD和COPY都可以完成文件的copy工作。 但是ADD可以下载网络资源,并可以自动完成解压到特定目录去。 强烈建议不要使用ADD从远程URL中获取包。 你应该使用curl或wget代替,样例如下。
错误做法:
ADD http://example.com/big.tar.xz /usr/src/things/ RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things RUN make -C /usr/src/things all
替代做法:
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
备注
如果不需要add的自动解压功能,你应该始终使用COPY。
2.3.9. ENTRYPOINT¶
ENTRYPOINT用于定义程序的主命令,CMD用来定义给ENTRYPOINT的参数,且2中都采用数组形式。
exec用于执行一个新命令去替换现有进程,可以保证我们的进程启动在pid为1 。
2.3.10. VOLUME¶
使用卷去存储数据库数据,或者配置文件等。
2.3.11. USER¶
可以指定一个非root的用户作为容器的运行身份。
2.3.12. WORKDIR¶
写WORKDIR请采用绝对路径,采用相对路径会增加维护和故障排查问题。
2.3.13. ONBUILD¶
ONBUILD命令是执行在当前dockefile构建完毕的镜像被别人作为基础镜像后的执行脚本。