Building good docker images
The docker registry is bursting at the seams. At the time of this writing, a search for "node" gets just under 1000 hits. How does one choose?
What constitutes a good docker image?
This is a subjective matter, but I have some criteria for a docker image that I consider good:
working. Some examples:
- an Android SDK image should be able to compile a project without first applying updates to the container.
- a MySQL container should expose a way to bootstrap the server with a database and user.
minimal. The beauty of containers is the ability to sandbox an application (if not for security, then to avoid clutter on the host file system). Whereas I could install node.js on my host system or pollute it with a Java Development Kit, I would rather pay a slight premium in disk space or performance to keep them cordoned off from the rest of my files. With that said, it is obviously preferable that these penalties be as small as possible. The docker image should serve its purpose, having exactly what's necessary for it to function but nothing else. Following this principle, the image is more extensible and has fewer things that can break.
whitebox. In the case of docker images, this means having a published
Dockerfile. That way I can evaluate what went into creating the image and tinker with it if I want to.
Unfortunately the docker registry does not make it easy to discover "good" images or even to judge any particular image. It's often a matter of docker pull <...> and then wondering why the 10 megabyte node binary needs 10 file system layers and, ultimately, a 700 megabyte virtual environment.
Building good docker images
Because there is no consensus on "good" docker images, and because the barrier to entry for adding images to the docker registry is very low, the situation is straight out of xkcd #927: everybody just does his or her own thing. The introduction of "official" language-specific docker development environments is a good start. I was happy to see that some of my pet practices (listed below) showed up in those images. However, the "thousand node images" situation probably won't improve much until the docker registry works on its discovery and evaluation mechanisms.
With that said, here are the Dockerfile practices which I've settled on as best. I am no expert (I don't think anybody is at this early point in docker's lifetime), so discussion and feedback are welcome.
Base images off of
debianAt the time of this writing,
ubuntu:14.04is 195 MB whiledebian:wheezyis 85 MB, but the extra hundred megabytes of Ubuntu doesn't buy you anything of value (that I'm aware of). In some extreme cases, it may even be possible to base your image off of 2 MBbusybox. This is probably only practical with a statically linked binary. An example of abusybox-based docker image isprogrium/logspout(link) which clocks in at a respectable 14 MB.Don't install build tools without good reason
Build tools take up a lot of space, and building from source is often slow. If you're just installing somebody else's software, it's usually not necessary to build from source and it should be avoided. For instance, it is not necessary to install python, gcc, etc. to get the latest version of node.js up and running on a Debian host. There is a binary tarball available on the node.js downloads page. Similarly, redis can be installed through the package manager.
There are at least a few good reasons to have build tools:
- you need a specific version (e.g. redis is pretty old in the Debian repositories).
- you need to compile with specific options.
- you will need to
npm install(or equivalent) some modules which compile to binary.
In the second case, think really hard about whether you should be doing that. In the third case, I suggest installing the build tools in another "npm installer" image, based on the minimal node.js image.
Don't leave temporary files lying around
The following
Dockerfileresults in an image size of 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
On the other hand, this seemingly-equivalent
Dockerfileresults in an image size of 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
Thus it seems that if you leave a file on disk between steps in your
Dockerfile, the space will not be reclaimed when you delete the file. It is also often possible to avoid a temporary file entirely, just piping output between commands. For instance,wget -O - http://nodejs.org/dist/v0.10.32/node-v0.10.32-linux-x64.tar.gz | tar zxf -
will extract the tarball without putting it on the file system.
Clean up after the package manager
If you run
apt-get updatein setting up your container, it populates/var/lib/apt/lists/with data that's not needed once the image is finalized. You can safely clear out that directory to save a few megabytes.This
Dockerfilegenerates a 99 MB image:FROM debian:wheezy
RUN apt-get update && apt-get install -y wget
while this one generates a 90 MB image:
FROM debian:wheezy
RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*
Pin package versions
While a docker image is immutable (and that's great), a
Dockerfileis not guaranteed to produce the same output when run at different times. The problem, of course, is external state, and we have little control over it. It's best to minimize the impact of external state on yourDockerfileto the extent that it's possible. One simple way to do that is to pin package versions when updating through a package manager. Here's an example of how to do that:# 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
We can hope, but there is no guarantee, that the package repositories will still serve this version a year from now. However, it's undeniably valuable to explicitly show what version of the software your image depends on.
Combine commands
If you have a sequence of related commands, it is best to chain them into one
RUNcommand. This makes for a more meaningful build cache (logically grouped steps are lumped into one cache step) and keeps the number of file system layers down (I consider this generally desirable but I don't know that it's objectively better).Backslashes
\help you out here for readability:RUN apt-get update && \
apt-get install -y \
wget=1.13.4-3+deb7u1 \
ca-certificates=20130119 \
...
Use environment variables to avoid repeating yourself
This is a trick I picked up from reading the
Dockerfile(link) of the "official" node.js docker image. As an aside, thisDockerfileis great. My only criticism is that it sits on top of a hugebuildpack-deps(link) image, with all sorts of things I don't want or need.You can define environment variables with
ENVand then reference them in subsequentRUNcommands. Below, I've paraphrased an excerpt from the linkedDockerfile: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"
This article is being discussed further in this Hacker News post.
转自http://jonathan.bergknoff.com/journal/building-good-docker-images
Building good docker images的更多相关文章
- Error when Building GPU docker image for caffe: Unsupported gpu architecture 'compute_60'
issue: Error when Building GPU docker image for caffe: Unsupported gpu architecture 'compute_60' rea ...
- 在Linux和Windows的Docker容器中运行ASP.NET Core
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott H ...
- Docker Resources
Menu Main Resources Books Websites Documents Archives Community Blogs Personal Blogs Videos Related ...
- Docker容器中运行ASP.NET Core
在Linux和Windows的Docker容器中运行ASP.NET Core 译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott Hanselman就捷足先登了. ...
- 为Go程序创建最小的Docker Image
本文将会介绍如何使用docker打包一个golang编写的应用程序,最终的产物就是一个makefile文件,可别小瞧这短短几行代码,涉及的知识点可不少,接下来我们就仔细剖析一下吧. FROM gola ...
- kubernetes 实战6_命令_Share Process Namespace between Containers in a Pod&Translate a Docker Compose File to Kubernetes Resources
Share Process Namespace between Containers in a Pod how to configure process namespace sharing for a ...
- Docker容器学习与分享10
Docker容器向外提供服务 用分享04中的Nginx服务来试一下. 不过这次我直接用Nginx镜像创建容器,先下载Nginx镜像. [root@promote ~]# docker search n ...
- Docker的基本使用(部署python项目)
今天开始利用docker来部署项目,当然,首先,需要安装好Docker,这个在我的上篇中写了 一.准备项目 我写的是一个爬取某ppt网站的代码,就一个ppt1.py是爬虫,然后,ppts是存放下载的p ...
- AspNetCore容器化(Docker)部署(一) —— 入门
一.docker注册安装 Windows Docker Desktop https://www.docker.com/products/docker-desktop Linux Docker CE h ...
随机推荐
- 单例模式(Java)
//单例模式 public class Singleton { private static Singleton s; private Singleton(){ } public static Sin ...
- WordPress博客平台的搭建--基于Ubuntu14服务器
环境:阿里云服务器,系统Ubuntu14.04, 阿里云域名 大致流程:LNMP+WordPress 主要参考博客:VPS+LNMP+WordPress搭建个人网站/博客 遇到的问题: 1.在登陆域名 ...
- linux命令:tar
1.命令介绍: tar用来打包,压缩和解压文件. 2.命令格式: tar [选项] 文件 3.命令参数: 必要参数有如下: -A 新增压缩文件到已存在的压缩 -B 设置区块大小 -c 建立新的压缩文件 ...
- Inversion_树状数组***
Problem Description You have a sequence {a1,a2,...,an} and you can delete a contiguous subsequence o ...
- jQuery中bind方法和live方法区别解析
Javascript中的事件有它的独特性,有默认的执行事件,例如冒泡就是其中的一个.在很多比较复杂的应用程序中,停止事件的冒泡或捕获在程序开发当中是十分有用的,而在IE中有它的独特方式来阻止事件的冒泡 ...
- 遥感影像滤波处理软件 — timesat3.2
最近因为要做遥感影像的滤波处理,经过女神推荐,决定用Timesat,可是该软件3.1版本只适合xp系统以及2011的matlab,后来在官网上找到了最新的3.2版本.支持64位操作系统以及2014的m ...
- [c++] stack的使用
cout << ; i<; i++) first.push(i); cout << ...
- easyui datagrid 合并单元格
整理以前做的东西,这个合并单元格的问题再新浪博客也写过了..... 下面这段代码是列表数据 //载入排放系数管理报表数据 function LoadEmissionReportData() { //获 ...
- delegate和protocol
协议和代理对于一个新手来说确实不讨好理解,也有很多的iOS开发的老手对此是懂非懂的.网上的很多博文只是讲了怎么使用,并没有说的很明白.下面我谈一下我的理解. 1.你要先搞明白,协议和代理为什么会出现, ...
- linux部署不同版本mysql
测试环境部署过程中经常会遇到同一个服务器上部署两个不同版本的mysql数据库,在部署过程中也会有各种各样的问题,现将部署多版本mysql的方法总结如下: 1.下载mysql版本 http://down ...