文档章节

微容器:更小的,更轻便的Docker容器

阿里百川
 阿里百川
发布于 2016/03/14 17:59
字数 2042
阅读 264
收藏 11

【编者的话】本文介绍了微容器的概念和好处,并用一些例子介绍了如何构建微镜像,从scratch到Alpine Linux,并推荐了一些已有的基础微镜像,方便为几乎所有主流语言的应用构建微镜像。本文也指出了构建微镜像的基本原理:将构建时依赖和运行时依赖分开,构建时所用的镜像包含所有构建所用的工具,它可以比较大,但运行时的基础镜像应该仅包含运行时依赖。使用微容器,no going back!



Docker 使你能把你的应用和应用的依赖打包到一个良好的自包含镜像中。然后你可以用该那个镜像来在容器中运行你的应用。问题是,你通常也打包了一些你可能不需要比你需要的更多的东西,最终座椅最重你得到了一个巨大的镜像和巨大的容器。大多数开始使用Docker的人会使用Docker的官方仓库作为他们的语言的选择,但是不幸的是,如果你使用官方镜像,你会得到一个巨大的镜像,而本来你可以得到一个小镜像的。你并不需要和这些官方镜像中一起的许多复杂的东西。例如,如果你使用官方的Node镜像构建一个你的应用的Node的镜像,它至少有643MB大,因为这是官方Node镜像的大小

我构建了一个简单的Hello World Node 应用,在官方Node镜像上构建,它的大小是644MB。


这太大了!我的应用加上依赖也不超过1MB,Node.js的运行时大概20MB,那是什么占据了剩下的620MB?我们应该能做得更好。


什么是微容器?


一个微容器仅包含OS库和运行应用所需要的语言依赖以及应用本身。其他都不需要。

与其包含所有,不如仅包含最基本的,在需要的时候添加依赖。

以上面的Node应用为例,使用一个小的基础镜像,然后安装核心的部分,即Node.js和它的依赖,它只有29MB,小了22倍(见下图)!




如果你想,现在试试运行这两个镜像,docker run –rm -p 8080:8080 treeder/tiny-node:fat 然后 docker run –rm -p 8080:8080 treeder/tiny-node:latest。完全一样的应用,而大小大不相同。


为什么微容器很棒?


有许多使用微容器的好处:

  • 大小 —— 微容器很小。像上面展示的,没有改变任何代码,镜像大小减少了22倍。

  • 快速/简单的发布 —— 因为镜像非常小,可以更快地从 Docker registry(例如 Docker Hub)下载镜像,因而可以更快地发布到不同的机器。

  • 提高安全性 —— 更少的代码和程序在容器中意味着更小的攻击面。基础OS就更安全(详见下文)。


这些好处和Unikernels的好处类似,没有任何缺点。


如何构建微容器


所有Docker镜像的基础镜像是scratch镜像。它本质上什么都没有。听起来它好像没什么无用,但是你可以用它创建你的应用的最小可能镜像,如果你把你的应用编译为一个没有依赖的静态二进制文件,像Go或C那样。例如,我的treeder/static-go 镜像 包含了一个Go的Web应用,则整个镜像(包括我的应用)是5MB。


这是关于如何得到尽可能小的镜像:scratch镜像+你的应用的二进制文件。

然而并不是所有人都是用Go,所以你可能有更多的依赖,并且你需要比scratch镜像要多一些的东西。关于Alpine Linux,我不会枯燥地告诉你关于它的细节,但是他们的广告语说出了全部:“Alpine Linux是一个面向安全的,轻量的Linux发行版,基于musl libc和busybox。” 你可以在这里得到详细说明,但是我们这篇文章最关心的是“轻量”的部分。基础的Alpine镜像只有5MB。


现在我们有一个非常好的OS作为一个基础镜像,它有一个很好的包管理系统来添加我们的依赖。对于我们的简单的Node应用而言,我们只需要Node自己,所以我们可以只添加Node包。我们的Dockerfile看起来像这样:

FROM alpine
RUN apk update && apk upgrade
RUN apk add nodejs


简单而整洁。现在我们只在镜像中有Node和Node的依赖。
现在为了添加我们的代码到镜像中,只需要在我们的Dockerfile中添加几行:

FROM alpine
RUN apk update && apk upgrade
RUN apk add nodejs
WORKDIR /app
ADD . /app
ENTRYPOINT [ "node", "server.js" ]


你可以获得示例代码并且在这里(https://github.com/treeder/tiny-node-docker)查看完整的构建指导。

同样的规则适用于所有其他的语言。


适用于所有语言的基础镜像


幸运的是,我们已经构建了一个适用所有主要语言的基础镜像,你可以在这里找到它们:https://github.com/iron-io/dockers

它们有一些优化来使它们尽可能的小,并且我们会定期更新,使用基础镜像使得它们比起你自己来更好。通过使用Iron.io的基础镜像,上面Node应用的Dockerfile变成这样:

FROM iron/node
WORKDIR /app
ADD . /app
ENTRYPOINT [ "node", "server.js" ]


另外,对于每一种其他语言,我们构建了两个版本的这种镜像,一个用于构建,另一个用于运行。用于构建的镜像有所有的构建工具在其中,所以可能比运行时要更大。

例如,为了构建Node的依赖,你要像这样使用iron/node:dev

docker run --rm -v "$PWD":/app -w /app iron/node:dev npm install


然后在你的Dockerfile中使用iron/node然后运行它:

docker run --rm -it -p 8080:8080 -v "$PWD":/app -w /app iron/node node server.js


上述方法同样适用于其他语言,但是你需要使用它们自己的build/vendor/run的指令。

如果你想要一个语言的不同版本,你可以改变tag,例如你可以使用iron/node:4.1或者iron/node:0.12。你可以在Docker Hub上找到每个语言的所有的版本tag。例如Node的tag在这里:https://hub.docker.com/r/iron/node/tags/。你可以在iron-io/dockers的项目里找到所有其他Docker Hub tags的链接。


如何为所有的语言构建和打包


这可能没那么幸运了,但是我们有一些例子可以让大多数主流语言使用上面的基础镜像:https://github.com/iron-io/dockerworker

你可以看看那个项目中的每个语言的README,它会指引你如何构建你的依赖,测试你的代码,构建一个小的Docker镜像和测试镜像。


没有回头


读完本文之后,你应该可以为你的应用创建只包含运行应用所需要的东西的Docker镜像。容器本质是一个镜像的实例,所以一旦你开始用你的镜像来运行容器,你就进入了微容器的世界。没有(理由)回头。

刚使用了你的“小镜像”技术在我的一个golang项目上,很棒!感谢这篇伟大的文章。竟然令人震惊地减小到5mb。 —— Harlow Ward @ Clearbit

原文链接:Microcontainers – Tiny, Portable Docker Containers (翻译:陈光 审校:高婧雅)



关于阿里百川

阿里百川(baichuan.taobao.com)是阿里巴巴集团“云”+“端”的核心战略是阿里巴巴集团无线开放平台,基于世界级的后端服务和成熟的商业组件,通过“技术、商业及大数据”的开放,为移动创业者提供可快速搭建App、商业化APP并提升用户体验的解决方案;同时提供多元化的创业服务-物理空间、孵化运营、创业投资等,为移动创业者提供全面保障。




本文转载自:http://dockone.io/article/1035

共有 人打赏支持
阿里百川
粉丝 50
博文 37
码字总数 61962
作品 0
杭州
技术主管
私信 提问
Docker入门及centOS7下安装

Docker入门及centOS7下安装 简介:利用go语言实现的应用容器引擎 docker引擎基础是linux容器(Linux Containsers, LXC)技术 它可以使开发和运维结合的更容易 Docker 是一个开源的应用容器引擎,...

garwer
2018/04/20
0
0
三个技巧,将Docker镜像体积减小90%

在构建Docker容器时,应该尽量想办法获得体积更小的镜像,因为传输和部署体积较小的镜像速度更快。 但RUN语句总是会创建一个新层,而且在生成镜像之前还需要使用很多中间文件,在这种情况下,...

程序师
2018/09/07
0
0
Docker笔记1——5W简述docker基本概念

Who? docker适合谁?运维,和devops的开发。 Docker 开发方向: 语言:Golang 相关的技术:Swarm、Compose、Machine、mesos、k8s.....--- CI/CD Jeckins整合 WHY? 为什么要用docker?解决了...

HappyBKs
02/16
0
0
docker基础使用与入门实践

一、何为docker docker最早基于LXC实现(LinuX Container)从0.7版本以后开始去除LXC转而使用自行开发的libcontainer,从1.11开始,演进为runC和containerd;docker是go语言开发,基于Linux内...

dyc2005
2018/04/14
0
0
Kubernetes最佳实践S01E01:如何构建尽可能小的容器镜像?

这是是Google Developer Advocate 关于如何充分利用Kubernetes环境的七部分视频和博客系列的第一部分。 今天,他主要讲保持容器镜像尽可能小的理论和实用性。 Docker使构建容器镜像变得轻而易...

店家小二
2018/12/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。

import java.util.Stack; public class Solution { public boolean IsPopOrder(int [] pushA,int [] popA) { if(pushA.length==0||popA.length==0) return false; Stack......

南桥北木
38分钟前
1
0
互联网浪潮下,Java程序员如何追赶技术革新的脚步?

一:时代背景 身处互联网行业的我们一直处在变革的最前端,受到行业发展浪潮的洗礼,不停歇地追赶着技术革新的脚步。特别是近几年来, 互联网架构不断演化,经历了从集中式架构到分布式架构,...

老道士
45分钟前
1
0
flink系列(9)-flink启动流程分析

连续写了几天的flink StreamGraph的代码,今天闲来说一下flink的启动

yiduwangkai
58分钟前
1
0
取变量的地址赋值给另一个变量,C通过,C++编译出错

取变量的地址赋值给另一个变量,C通过。正常运行,C++编译出错。 代码如下: #include <stdio.h>int main(int argc, char *argv[]){int x = 3;int *p = &x;int y = p;/*c ...

SamXIAO
今天
1
0
利用隐写术实施攻击

尽管隐写术是一种低频攻击途径,但网络犯罪分子已经开始利用它结合社交媒体的普遍性和快速传播性来传递恶意有效负载。 低调但有效的隐写技术虽然是旧把戏,但将代码隐藏在看似正常的图像中,...

Linux就该这么学
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部