CODE4FUN
Dockerfile最佳实践

Dockerfile提供了一个简单的语法来构建Image. 以下是几点技巧帮助你更好的使用Dockerfile.

使用缓存

Dockerfile中的每一个操作都会提交一个更改到一个新的Image中, 并且这个Image会做为下一个操作的Base Image. 如果一个使用相同操作的Image存在, 那么这些操作不会执行, 而是直接使用这个Image.

例如所有的Dockerfile都可以使用以下的共通代码.

FROM ubuntu
MAINTAINER Michael Crosby <michael@crosbymichael.com>

RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get upgrade -y

保持通用操作在Dockerfile顶部, 以使用缓存

使用标签

除非仅仅是出于实验目的, 不然你应该使用docker build -t命令来创建Image.

总是使用参数-t

暴露端口

docker的两个重要特性是可重复利用和可移植. Image应该在任何主机上能运行多次. 所以你不应该在Dockerfile中指定公开端口. 如果Image的使用者需要指定公开端口, 他/她们会使用-p参数的.

不要在Dockerfile中指定公开端口

CMD和ENTRYPOINT语法

CMD和ENTRYPOINT都有两种语法.

CMD /bin/echo
# or
CMD ["/bin/echo"]

第一种语法在执行的时候, docker会将命令包装成/bin/sh -c的形式. 这在有些情况下会产生一些难以发现的错误.

CMD和ENTRYPOINT总是使用数组形式的语法

CMD和ENTRYPOINT更好的配合

ENTRYPOINT可以让你docker化的程序像一个可执行程序一样运行. 你可以传递参数到ENTRYPOINT指定的命令中, 而不用担心在运行docker run的时候会被覆盖. 有时ENTRYPOINT和CMD同时使用会有更好的效果. 例如Rethinkdb的Dockerfile.

# Dockerfile for Rethinkdb
# http://www.rethinkdb.com/

FROM ubuntu

MAINTAINER Michael Crosby <michael@crosbymichael.com>

RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get upgrade -y

RUN apt-get install -y python-software-properties
RUN add-apt-repository ppa:rethinkdb/ppa
RUN apt-get update
RUN apt-get install -y rethinkdb

# Rethinkdb process
EXPOSE 28015
# Rethinkdb admin console
EXPOSE 8080

# Create the /rethinkdb_data dir structure
RUN /usr/bin/rethinkdb create

ENTRYPOINT ["/usr/bin/rethinkdb"]

CMD ["--help"]

所有运行docker run时传递的参数都会被传递到ENTRYPOINT指定的命令/usr/bin/rethinkdb中, 当没有指定参数时使用CMD指定的--help参数.

运行docker run crosbymichael/rethinkdb, 会输出:

Running 'rethinkdb' will create a new data directory or use an existing one,
  and serve as a RethinkDB cluster node.
File path options:
  -d [ --directory ] path           specify directory to store data and metadata
  --io-threads n                    how many simultaneous I/O operations can happen
                                    at the same time

Machine name options:
  -n [ --machine-name ] arg         the name for this machine (as will appear in
                                    the metadata).  If not specified, it will be
                                    randomly chosen from a short list of names.

Network options:
  --bind {all | addr}               add the address of a local interface to listen
                                    on when accepting connections; loopback
                                    addresses are enabled by default
  --cluster-port port               port for receiving connections from other nodes
  --driver-port port                port for rethinkdb protocol client drivers
  -o [ --port-offset ] offset       all ports used locally will have this value
                                    added
  -j [ --join ] host:port           host and port of a rethinkdb node to connect to
  .................

而运行docker run crosbymichael/rethinkdb --bind all, 会输出:

info: Running rethinkdb 1.7.1-0ubuntu1~precise (GCC 4.6.3)...
info: Running on Linux 3.2.0-45-virtual x86_64
info: Loading data from directory /rethinkdb_data
warn: Could not turn off filesystem caching for database file: "/rethinkdb_data/metadata" (Is the file located on a filesystem that doesn't support direct I/O (e.g. some encrypted or journaled file systems)?) This can cause performance problems.
warn: Could not turn off filesystem caching for database file: "/rethinkdb_data/auth_metadata" (Is the file located on a filesystem that doesn't support direct I/O (e.g. some encrypted or journaled file systems)?) This can cause performance problems.
info: Listening for intracluster connections on port 29015
info: Listening for client driver connections on port 28015
info: Listening for administrative HTTP connections on port 8080
info: Listening on addresses: 127.0.0.1, 172.16.42.13
info: Server ready
info: Someone asked for the nonwhitelisted file /js/handlebars.runtime-1.0.0.beta.6.js, if this should be accessible add it to the whitelist.

更好的配合使用CMD和ENTRYPOINT


原文: Dockerfile Best Practices

参考:

How to Use Entrypoint in Docker Builder

Dockerfile tutorial Level1

Dockerfile tutorial Level2