使用Dockerfile创建image前, 建议遵循的一些规则.
1. container是阅后即焚式的, 即运行一次后, 如果停掉了, 那么重新运行一个(全新的). 
这点和虚拟机有点不一样, 虚拟机有自己的东西, 可以存在虚拟机内部, 如果虚拟机停掉, 再起来, 在虚拟机运行过程中的变更是会被保留的.
但是container不一样, container产生的变更都会"消失", 除非挂载外部的volume并将变更写入外部volume. 
所以设计时应该考虑到container的特性, image只是一个只读的环境而已, container每次启动就是一个全新的环境. 
为了打破这个问题, 例如要将container的数据持久化, 那么必须挂载外部volume来保存, 在container停止或rm后, 还可以启动其他的container来挂载这个volume.
例如数据库的数据文件, 建议外挂volume.
image我们可以只作为一个运行环境来设计, 例如数据库的image就只有数据库软件; WEB服务的image就只有web服务对应的软件; 而数据文件以及WEB站点文件夹都应该外挂的方式来访问. 这样的话, 当container rm后, 数据还在. 再启动container即可.
2. 使用,dockerignore文件排除建立image不需要的文件和文件夹.
或者使用空文件夹来放Dockerfile.
3. 在image中避免安装不必要的包, 例如database image不需要text edit包. 尽量使image小一点.
4. 每个container只允许一个进程, 如果一个服务有多个进程并且需要相互访问的话, 建议起多个container, 并使用container link来将各个进程连接起来. 方便container的重用.
参考
http://blog.163.com/digoal@126/blog/static/163877040201492710339762/
5. 简化Dockerfile层次, 提高可读性.
6. 当指令比较长时, 建议分行
例如
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion

7. 使用镜像缓存注意, 在指令执行前, 判断是否有镜像缓存可以直接使用
例如 : 
ADD a /
将检查a文件的checksum , 对比以前是否调用过同样的指令, 并且checksum一致.
以上指令将产生一个镜像, 但是在执行前, 可以检查docker server中是否已经存在该image, 那么就直接使用. 而不需要重新生成一个新的中间过程image.
--no-cache=true 表示不使用cache,
8. 指令使用建议 
FROM

建议使用最小化的image.

RUN

有依赖的指令, 最好使用&&写在一条指令中, 例如
RUN apt-get update && apt-get install -y package-bar package-foo package-baz比较长的指令, 最好分行, 并排序
RUN apt-get update && apt-get install -y \aufs-tools \automake \btrfs-tools \build-essential \curl \dpkg-sig \git \iptables \libapparmor-dev \libcap-dev \libsqlite3-dev \lxc=1.0* \mercurial \parallel \reprepro \ruby1.9.1 \ruby1.9.1-dev \s3cmd=1.1.0*

ENV

可用于设置路径, 软件需要的特殊环境变量, 或者便于管理的环境变量等.
使用docker inspect可查.
For example, ENV PATH /usr/local/nginx/bin:$PATH will ensure that CMD [“nginx”] just works.
The ENV instruction is also useful for providing required environment variables specific to services you wish to containerize, such as Postgres’s PGDATA.
Lastly, ENV can also be used to set commonly used version numbers so that version bumps are easier to maintain, as seen in the following example:ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

ADD & COPY

一般建议使用COPY, 如果要下载URL到image, 建议使用wget或curl ,然后解压.
For example, you should avoid doing things like:
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 allAnd instead, do something like:
RUN mdkir -p /usr/src/things \&& curl -SL http://example.com/big.tar.gz \| tar -xJC /usr/src/things \&& make -C /usr/src/things all不需要帮忙自动解压的地方, 建议使用COPY.

ENTRYPOINT
一般建议在末尾加上exec "$@" 那么将传递给ENTRYPOINT脚本.
例如 postgresql的Dockerfile对应的ENTRYPOINT脚本 : 
https://github.com/docker-library/postgres
#!/bin/bash
set -eif [ "$1" = 'postgres' ]; thenchown -R postgres "$PGDATA"if [ -z "$(ls -A "$PGDATA")" ]; thengosu postgres initdbfiexec gosu postgres "$@"
fiexec "$@"

另一个例子 :

(for example, docker run -it mysql mysqld --some --flags will transparently run mysqld --some --flags after ENTRYPOINT runs initdb).

mysql的ENTRYPOINT脚本 :

#!/bin/bash
set -eif [ -z "$(ls -A /var/lib/mysql)" -a "${1%_safe}" = 'mysqld' ]; thenif [ -z "$MYSQL_ROOT_PASSWORD" ]; thenecho >&2 'error: database is uninitialized and MYSQL_ROOT_PASSWORD not set'echo >&2 '  Did you forget to add -e MYSQL_ROOT_PASSWORD=... ?'exit 1fimysql_install_db --user=mysql --datadir=/var/lib/mysql# These statements _must_ be on individual lines, and _must_ end with# semicolons (no line breaks or comments are permitted).# TODO proper SQL escaping on ALL the things D:TEMP_FILE='/tmp/mysql-first-time.sql'cat > "$TEMP_FILE" <<-EOSQLDELETE FROM mysql.user ;CREATE USER 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION ;DROP DATABASE IF EXISTS test ;EOSQLif [ "$MYSQL_DATABASE" ]; thenecho "CREATE DATABASE IF NOT EXISTS $MYSQL_DATABASE ;" >> "$TEMP_FILE"fiif [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; thenecho "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" >> "$TEMP_FILE"if [ "$MYSQL_DATABASE" ]; thenecho "GRANT ALL ON $MYSQL_DATABASE.* TO '$MYSQL_USER'@'%' ;" >> "$TEMP_FILE"fifiecho 'FLUSH PRIVILEGES ;' >> "$TEMP_FILE"set -- "$@" --init-file="$TEMP_FILE"
fichown -R mysql:mysql /var/lib/mysql
exec "$@"

使用例子 :

COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]

VOLUME
The VOLUME instruction should be used to expose any database storage area, configuration storage, or files/folders created by your docker container. You are strongly encouraged to use VOLUME for any mutable and/or user-serviceable parts of your image.
USER
如果服务不需要使用root权限, 那么建议使用非root用户执行,
避免使用sudo(可能引起问题).
不要频繁的变更USER, 会带来更多的层级. 
WORKDIR
改变工作目录可以使用WORKDIR, 或者在同一条指令中执行, 例如 : 
RUN cd … && do-something
但是为了提高可读性, 建议使用WORKDIR指令.
ONBUILD
ONBUILD一般用于后续会有其他image要基于该image来创建, 并需要依赖一些环境的情况(那么这些依赖的环境可以写在ONBUILD中安装执行)
ONBUILD is only useful for images that are going to be built FROM a given image. For example, you would use ONBUILD for a language stack image that builds arbitrary user software written in that language within the Dockerfile, as you can see in Ruby’s ONBUILD variants.
Images built from ONBUILD should get a separate tag, for example: ruby:1.9-onbuild or ruby:2.0-onbuild.
Be careful when putting ADD or COPY in ONBUILD. The “onbuild” image will fail catastrophically if the new build's context is missing the resource being added. Adding a separate tag, as recommended above, will help mitigate this by allowing the Dockerfile author to make a choice.

不建议在ONBUILD中使用ADD COPY.

[参考]

1. https://docs.docker.com/articles/dockerfile_best-practices/
2. https://github.com/docker-library/postgres

Dockerfile best practices相关推荐

  1. (转) Dockerfile 中的 COPY 与 ADD 命令

    原文:https://www.cnblogs.com/sparkdev/p/9573248.html Dockerfile 中提供了两个非常相似的命令 COPY 和 ADD,本文尝试解释这两个命令的基 ...

  2. (转) Dockerfile 中的 COPY 与 ADD 命令 1

    原文:https://www.cnblogs.com/sparkdev/p/9573248.html Dockerfile 中提供了两个非常相似的命令 COPY 和 ADD,本文尝试解释这两个命令的基 ...

  3. Dockerfile最佳实践(二)

    本文讲的是Dockerfile最佳实践(二),[编者的话]本文是 Docker 入门教程第三章-DockerFile 进阶篇的第二部分.作者主要介绍了 Docker 的变化.常用指令以及基础镜像的最佳 ...

  4. Dockerfile 参考文档中文版

    一.概述 原文:https://docs.docker.com/engine/reference/builder/#dockerignore-file Docker 可以通过从 Dockerfile ...

  5. Docker学习总结(6)——通过 Docker 化一个博客网站来开启我们的 Docker 之旅

    2019独角兽企业重金招聘Python工程师标准>>> 通过 Docker 化一个博客网站来开启我们的 Docker 之旅 这篇文章包含 Docker 的基本概念,以及如何通过创建一 ...

  6. 怎样去构建一个优质的Docker容器镜像

    抛砖引玉 先说结论 以不变应万变 善用 cache, 使用一个相对固定的 build 环境 构建 自己的基础镜像 洁身自好 保持 context 干净: .dockerignore 镜像环境清理 你需 ...

  7. 如何使用Docker Compose安装Drupal

    The author selected United Nations Foundation to receive a donation as part of the Write for DOnatio ...

  8. Dockerfile 最佳实践

    之前 一篇文章介绍 docker 的镜像基本原理和概念 ,主要介绍在编写 docker 镜像的时候一些需要注意的事项和推荐的做法. 虽然 Dockerfile 简化了镜像构建的过程,并且把这个过程可以 ...

  9. Docker Review - dockerfile 入门篇

    文章目录 Docker 镜像.容器 .Docker file 概述 Docker File文件格式 Docker File 解读 1.FROM 指定基础镜像 2.RUN 执行命令 3.COPY 复制文 ...

  10. dockerfile arg_Dockerfile最佳实践

    帆仔 16年入职网易,先后负责过多个重要手游项目:关注自动化.容器.云等方向: 在容器领域,docker 公司提出的容器镜像已经成为目前容器打包交付的事实标准.构建镜像需要编写 Dockerfile, ...

最新文章

  1. 搞透Kafka的存储架构,看这篇就够了
  2. C语言经典算法 21-30
  3. 网络爬虫入门系列(3) httpClient
  4. zabbix v3.0安装部署【转】
  5. IO流 练习 -- 文件夹的删除
  6. ERC20代币合约详解,附实现代码
  7. php 开源留言板,PHP开源多功能留言板(SyGuestBook)
  8. 二、量子通信与量子加密
  9. discuz X2中template文件夹中模板文件目录
  10. 2018-06-27 关于小米电力猫小猫一直黄灯闪烁不匹配的问题
  11. C#实现微信公众号群发消息(解决一天只能发一次的限制)
  12. Asp连接数据库时的问题Microsoft OLE DB Provider for ODBC Drivers error ‘80004005‘
  13. 代码分享:面波数据快速成图
  14. 电信4g网络问题及恢复方案
  15. MIPS DMIPS MFLOPS名词解释
  16. maven 项目 springMVC实现文件图片的上传下载功能详解(源码已提供,小白必看)
  17. sqrt 和pow 的返回值类型错误({从小白开始c语言常见错误归纳第2弹)
  18. LaTex命令和环境的定义与重定义
  19. 家教信息管理系统的设计与实现
  20. python正则库_python 正则表达式第三方库 re的基本使用

热门文章

  1. echarts大屏模板_大屏数据展示模板智慧城市
  2. 让计算机工作起来教学反思,计算机教学反思
  3. 二叉排序树的中序遍历规律_王道数据结构|第四章 树与二叉树 04 二叉树的遍历...
  4. 巴伦变压器电路图_基于变压器原理的巴伦电路系统分析
  5. kali字典_Web渗透测试——暴力破解字典制作工具的使用2
  6. NMS(非极大值抑制)算法 -- 理论、代码
  7. vscode 左侧图标_分钟将vscode撸成小霸王
  8. (转) windows 下ORA-12514:TNS 监听问题
  9. mysql 主从同步机制
  10. ES6新特性:Javascript中Generator(生成器)