怎样构建一个好的 Docker 镜像
2015-01-05 21:58
281 查看
本文的原文地址是 What constitutes a good docker image?
注:本文不会全部翻译,只会挑选个人认为有价值的部分进行摘取性翻译,如想详细阅读,请看原文
至少有几个很好的理由使用构建工具:
你需要一个指定的版本(比如,在 Debian 仓库,redis 版本太老)
你需要使用指定的选项编译
你需要
在第二种情况下,好好的想清楚,你是否真应该这样做。在第三种情况下,我建议在另外一个 "npm installer" 镜像安装构建工具,基于最小的 node.js 镜像。
在另一方面,这看似相当的
因此看起来如果你在
将提取压缩文件,并没有把它放在文件系统上。
这个
然而这个生成一个 90 MB 的镜像:
我们所能希望的是,但是这是没有保障的,包仓库从现在开始的一年仍然会是这个版本。尽管如此,明确的显示你镜像中依赖的软件版本是不可否认的价值。
反斜线符号
你可以使用
上面这个版本信息,你只需要使用环境变量
注:本文不会全部翻译,只会挑选个人认为有价值的部分进行摘取性翻译,如想详细阅读,请看原文
构建一个好的 Docker 镜像
debian 的基础镜像
在撰写本文时,ubuntu:14.04为 195 MB,然而
debian:wheezy是 85 MB,但是 Ubuntu 额外的几百兆字节不会给你带来任何价值(我所知道的)。在一些极端情况下,甚至可能你的基础镜像是 2 MB
busybox。这可能仅仅实际上是二进制包的静态连接。
没有充足的原因,不要安装构建工具
构建工具占用太多空间,并且从源码构建通常很慢。如果你只是安装别人的软件,通常不需要从源码构建,并且它应该被避免。比如,没有必要安装 python,gcc 等等。为了获取最新版本的 node.js 并运行在一台 Debian 主机上。在 node.js downloads page 这里有一个可用的二进制的压缩包。类似的,redis 可以通过包管理器安装。至少有几个很好的理由使用构建工具:
你需要一个指定的版本(比如,在 Debian 仓库,redis 版本太老)
你需要使用指定的选项编译
你需要
npm install安装一些模块来编译进二进制包
在第二种情况下,好好的想清楚,你是否真应该这样做。在第三种情况下,我建议在另外一个 "npm installer" 镜像安装构建工具,基于最小的 node.js 镜像。
不要遗留临时文件
下面的Dockerfile结果镜像大小是 109 MB:
FROM debian:wheezy RUN apt-get update && apt-get install -y wget RUN wget http://cachefly.cachefly.net/10mb.test RUN rm 10mb.test
在另一方面,这看似相当的
Dockerfile结果镜像大小是 99 MB:
FROM debian:wheezy RUN apt-get update && apt-get install -y wget RUN wget http://cachefly.cachefly.net/10mb.test && rm 10mb.test
因此看起来如果你在
Dockerfile的两个步骤之间在磁盘空间留下了一个文件,当你删除这个文件的时候,空间不会被回收。也可以完全避免临时文件,仅仅在命令行之间管道输出。比如:
wget -O - http://nodejs.org/dist/v0.10.32/node-v0.10.32-linux-x64.tar.gz | tar zxf -
将提取压缩文件,并没有把它放在文件系统上。
包管理后进行清理
如果你运行apt-get update设置你的容器,它在
/var/lib/apt/lists/目录构成了数据,但是一旦镜像完成,这些数据是不需要的。你可以安全的清理那个目录来节约一些兆字节。
这个
Dockerfile生成一个 99 MB 镜像:
FROM debian:wheezy RUN apt-get update && apt-get install -y wget
然而这个生成一个 90 MB 的镜像:
FROM debian:wheezy RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*
指定包的版本
当一个 Docker 镜像是不可变的,一个Dockerfile是不保证在运行在不同的时间生成相同的输出。这个问题,当然,是外部状态,并且我们难以控制它。最好在某种程度上最小化你的
Dockerfile外部状态的影响,这是有可能的。做这个的一个简单方式是指定包的版本,当通过包管理器更新的时候。这里有一个怎样做的示例:
# apt-get update # apt-cache showpkg redis-server Package: redis-server Versions: 2:2.4.14-1 ... # apt-get install redis-server=2:2.4.14-1
我们所能希望的是,但是这是没有保障的,包仓库从现在开始的一年仍然会是这个版本。尽管如此,明确的显示你镜像中依赖的软件版本是不可否认的价值。
组合命令
如果你有一系列的相关命令,最好的方式是在一个命令中串联它们。这是一个更有意义的构建缓存(逻辑分组步骤集中到一个缓存步骤)并使得文件系统层级数量降下来了(我认为通常这是可取的,但是不知道在客观上是否是更好的)。反斜线符号
\在这里帮助你提升可读性:
RUN apt-get update && \ apt-get install -y \ wget=1.13.4-3+deb7u1 \ ca-certificates=20130119 \ ...
使用环境变量避免重复
这是我阅读官方的 node.js Docker 镜像的 Dockerfile 学来的一个技巧。此外,这个Dockerfile是非常棒的。我唯一的指责就是它是基于一个巨大的 buildpack-deps 镜像,带着各种各样我不需要或不想要的东西。
你可以使用
ENV定义环境变量,然后在一系列的命令中引用它们。下面,我从链接的
Dockerfile中转述了摘要:
ENV NODE_VERSION 0.10.32 RUN curl -SLO "http://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" \ && tar -xzf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local --strip-components=1 \ && rm "node-v$NODE_VERSION-linux-x64.tar.gz"
上面这个版本信息,你只需要使用环境变量
NODE_VERSION定义一次即可,而不用每次都写。
相关文章推荐
- Docker学习一(安装docker并构建一个可ssh登录的镜像)
- 手写一个dockerfile构建beego_blog镜像
- 构建一个jdk8的docker镜像
- Nodejs课堂笔记-第三课 构建一个nodejs的Docker镜像
- 从零开始构建一个centos+jdk7+tomcat7的docker镜像文件
- 利用Dockerfile构建一个基于CentOS 7镜像
- daocloud中构建一个hallo docker网页服务器的docker镜像并部署
- 从零开始构建一个centos+jdk7+tomcat7的镜像文件 centos7系统下docker运行环境的搭建 准备centos基础镜像 docker pull centos 或者直接下载我准备
- Spring Boot教程(十一) springboot程序构建一个docker镜像
- 从零开始构建一个centos+jdk7+tomcat7的docker镜像文件
- 利用Dockerfile构建一个基于CentOS 7镜像参考
- 利用Dockerfile构建一个基于centos 7,包括java 8, tomcat 7,php ,mysql+mycat的镜像
- Spring Boot教程(三十三) springboot程序构建一个docker镜像
- 利用Dockerfile构建一个基于centos 7,包括java 8, tomcat 7,php ,mysql+mycat的镜像
- 「二」创建一个带 ssh 服务的基础镜像(修订版)--使用 Dockerfile 创建
- Docker学习笔记(3)-- 如何使用Dockerfile构建镜像
- 构建最小的docker registry镜像
- docker学习笔记2—创建一个nginx的镜像,并使用浏览器访问
- Docker 学习笔记1—创建一个docker nginx镜像并通过浏览器访问
- Dockerfile实战:构建基础的ubuntu14.04镜像