您的位置:首页 > 运维架构 > Docker

如何制作高质量的docker镜像

2015-08-06 14:09 645 查看
今天我们讨论下,Docker 的用户们关心的问题,如何制作高质量的镜像。首先我们对高质量镜像标准进行定义。

镜像兼容性好
镜像执行效率高
镜像体积小
镜像可以被继承

尽量使用Dockerfile制作镜像

有两种方法可以制作docker镜像

对一个正在运行的contianer,使用docker commit 创建镜像。
基于dockkerfile,使用
docker build
创建镜像
Docker commit提供了一种灵活的制作镜像的方式,但是它的主要作用时对当前docker 容器内容备份。如果你准备做基础镜像,我们是不推荐这种方式。

Docker commit 会记录docker run时提供的部分参数。
没有Dockerfile作为描述文件,不易于镜像管理维护。
不容易控制docker镜像的层次

使用Dockerfile做镜像的好习惯

提供完整的
MAINTAINER
信息

MAINTAINER
指令用与设置 image的作者信息,如果用户出现问题,可以很容易的联系到原始作者。

除非设计目的时把容器当作系统应用程序使用,否则不要使用ENTRYPOINT

有很多关于CMD和[code]ENTRYPOINT 指令如何工作的讨论,下面我们简单复习CMD和ENTRYPOINT的在docker run 时如何工作。


CMD指令的官方解释是:The main purpose of a CMD is to provide defaults for an executing container
ENTRYPOINT指令的官方解释是: An ENTRYPOINT allows you to configure a container that will run as an executable.

CMD,ENTRYPOINT 及Docker run 时指定的命令,参数关系如下:[/code]

Dockerfile 只设定了[code]CMD
。 如果docker run 没有指定命令和参数,那么CMD设定的命令作为第一个程序被执行。如果docker run设定了命令和参数,CMD指令将不会被调用, docker run 指定的命令将会作为第一个程序被执行。[/code]

Dockerfile 设定了 [code]ENTRYPOINT
, 那么ENTRYPOINT指定的命令作为第一个程序被执行。如果docker run 设定了命令和参数,该命令和参数将最为ENTRYPOINT指定命令的参数;如果docker run 没有设定参数,CMD的指令将作为ENTRYPOINT指定命令的参数[/code]

所以要小心使用 [code]ENTRYPOINT
,除非你的容器时当作命令来设计的,否则不要使用ENTRYPOINT[/code]

使用ARRAY 而不是STRING 来运行程序

你可能已经注意到 CMD和
ENTRYPOINT中
ARRAY 和STRING的区别, ARRAY中的命令会被直接执行,即我们所说的exec; 而STRING会被/bin/sh调用执行。

很多镜像使用wrapper scripts 启动应用程序。 如果你有这样的脚本,应该使用exec来执行它。 否则,docker 发出的信号不会被你的程序截获。举个例子:

我使用start.sh 来启动自己的应用。如果 写成 CMD /start.sh 或者 CMD ["/bin/bash/" "/start.sh"], CTRL+C 命令并不能中止我们的程序,正确的写法是 CMD /start.sh

使用shell exec来执行你的wrapper scripts。

很多镜像使用wrapper scripts, 这样可以在启动应用程序之前做一些配置操作。如果你有这样的脚本,请不要忘记 使用 exec 来调用你的应用。 有的时候,docker 发出的信号可能会被wrapper scripts截获。使用exec可以使你的应用进程pid=0.

在Dockerfile中,EXPOSE 重要的端口

EXPOSE
指令会使得端口对主机及containers可见。 在Dockerfile中使用
EXPOSE
端口,可以被docker ps/inspect 命令显示,对用户了解如何镜像很用帮助。

应该避免 Volumes的使用

VOLUME
指令和
docker run 的 -v
选项会使用外部的文件系统来代替容器内的文件系统。Volumes 具有容器共享,持久保存数据的优点。但是volume和外部系统关联密切,除非特殊需要,应避免在Dockerfile中设置VOLUME指令。合理的做法是,在容器内部预留目录,用户使用docker run -v 参数挂载。

尽量不要使用 root用户

Dcoker 的系统资源隔离并不彻底,Docker实现了对 进程,网络,挂载,机器名,和共享内存的隔离,但是还存在未被隔离的资源,如:/dev/mem, /dev/sd* file system devices,Kernel Modules。 所以如非特殊需求,请使用non-root运行容器。

要注意Dockerfile的层级关系

Dockerfile中的每条指令都会为镜像增加新的一层。
制作基础镜像,合理的设置指令的先后顺序,能够后续image 生成的时间。在遵循Dockerfile规则的前提下,应该把变化较少的指令放在前面,变化较多的放在后面。

要清除指令产生的临时文件

Docker build过程中,临时文件也会被添加到新的一层中,所以应及时清理临时文件,这样才能保证做出来的镜像个头比较小。 如: 下面命令,中每次安装后清楚缓存就是正确的做法,

yum install mysql;yum clean all

要减少对系统的依赖

一个好的image应该在任何系统上都可以执行,如Linux,Solaris,Windows。这就要求我们的基础镜像,应该尽量及于可控的系统,如centos或者ubuntu. 在基础镜像中完成对系统的配置,如yum 安装,apt安装等。

轻量级更新模式

大量的包安装应该发声在基础镜像阶段,后续软件变更,要抛弃包安装模式,采取轻量的更新方式。最后只更改程序变化的部分。

积累重构

随着时间的推移,可能镜像的层级越来越多,当镜像个头比较大时,可以通过从基础镜像重构来降低容量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: