返回 登录
0

Docker:更小更轻量的微容器

想了解更多的docker知识,欢迎加入技术交流群:547147889

说到Docker,可能大家都不陌生了,我们可以用Docker技术将应用以及所有的依赖项打包到一个镜像中,然后把这个镜像部署到容器中运行。这里就有一个问题,因为我们在打包的时候往往会把一些杂七杂八非必要的东西也打包进去,所以最后构建出来的镜像就很庞大,直接导致我们的容器也变得很大。对于刚入门的Docker新手来说,大家一开始基本都是用的Docker官方镜像仓库里提供的基础镜像,可惜的是,这些基础镜像通常都包含了很多我们用不着的文件,有的时候我们的镜像明明可以建得很小,但是用这些基础镜像来构建我们自己的镜像的话,最后建下来文件体积都会变得超大。比方说,如果我们用官方的Node镜像来建自己的应用镜像,那么构建下来镜像文件的体积肯定是在643MB以上,因为Docker官方的Node镜像本来就有那么大。
大家不信可以试试看。我用官方的Node镜像建了一个Hello World的Node应用镜像,这个应用够简单了吧,可是这么简单的一个应用,镜像却有644MB。

这个size也太大了,我的应用加上依赖项总共还不到1MB,Node.js的运行时环境大概是20MB,剩下的620MB到底是什么鬼?!这种大小是无法接受的。那么问题来了,有没有什么办法可以让镜像文件小点呢?
关于微容器
答案是肯定的。这里我要向大家隆重推荐微容器,通过微容器我们就可以完美解决上面说的问题了。微容器只包含了运行应用必需的OS库文件和开发语言依赖项,还有就是应用本身,其他的统统不包含。
构建微镜像的时候,大家不用像以前一样从那种大而全的基础镜像开始搭建,只要根据自己的需求,先从最基本的应用开始,逐步添加依赖项就可以了。

微容器的优势
说了这么多,到底微容器有哪些优势呢?
体积更小。微容器的体积都很小,从上面那个例子大家可以看到,我们不用改任何代码,就能把镜像体积缩小到普通镜像的22分之一。
部署更快,更简便。因为镜像体积大大减小了,从Docker Hub之类的Docker镜像仓库下载镜像的速度就会快很多,我们就可以更快地部署镜像到各台主机上。
安全性更高。微容器里包含的代码和程序更少,攻击面也就更窄,所以底层OS的安全性也就相应地提升了。
从优点上看微容器跟Unikernels很像,但是微容器没有Unikernels的那些短板,总体来说要优于Unikernels。
微容器构建教程
所有Docker镜像都是以scratch镜像为基础创建的。scratch 镜像是一个空的镜像文件,虽然看起来好像没什么用处,但特别适合用来创建超级小的镜像。如果我们在编译的时候可以像Go或者C语言编译那样,把应用编译成没有依赖项的静态二进制文件,那最后创建出来的镜像体积就很完美了。比方说,我创建了一个treeder/static-go镜像,其中包含了一个Go 的web应用,整个镜像包括应用在内总共才5MB。

由此可见,通过scratch镜像+应用的二进制文件的方式,我们就可以构建出极小化的镜像。
不过Go语言毕竟还是比较小众的,也不是所有人都会用,所以大家在创建镜像的时候可能还是或多或少的要打包一些依赖项,这个时候scratch镜像就不能满足需求了,推荐大家有这方面问题的都使用Alpine Linux。Alpine Linux是一个面向安全应用的轻量级Linux发行版,是在musl libc和busybox的基础上构建的。多的话我也不说了,大家可以自己去找相关的文章来看,这里我想说的是,轻量才是王道,Alpine基础镜像的大小只有5MB:

Alpine是一个很不错的操作系统,在此基础上我们再将各种依赖项打包到系统中,就可以构建一个完备的轻量级镜像了。就以上面的Node应用为例,因为我们只需要用到Node,所以只要添加Node包就可以了。我们可以用下面的Dockerfile来构建镜像:
FROM alpine
RUN apk update && apk upgrade
RUN apk add nodejs
这样创建出来的镜像只包含Node以及一些必要的依赖项。怎么样,够简洁吧?
下面我们要往镜像中添加代码,操作也很简单,多写几行Dockerfile指令就行了:
FROM alpine
RUN apk update && apk upgrade
RUN apk add nodejs
WORKDIR /app
ADD . /app
ENTRYPOINT [ “node”, “server.js” ]
大概的原理就是这样,大家可以自己去网上找更详细的代码示例。这样做的好处是,我们最终得到的镜像里只包含一个非常轻量的操作系统、必要的依赖项以及应用的代码,没有任何多余的东西。
不只是Node,其他开发语言的镜像也可以依此类推。
更多基础镜像
除了上面说的微镜像以外,还有更给力的。现在在github上有很多轻量的基础镜像,基本上所有主流开发语言的基础镜像都有,大家可以戳下面这个链接,自己去github上下载合适的镜像。
https://github.com/iron-io/dockers
这些镜像都是经过优化的,文件体积很小,而且Github还会定期更新,大家可以直接用这些镜像,效率要比我们自己创建镜像好一些。还是以上面的Node应用为例,如果用Iron.io上面的基础镜像,Dockerfile指令还可以更简单一些:
FROM iron/node
WORKDIR /app
ADD . /app
ENTRYPOINT [ “node”, “server.js” ]
另外说一下,Github上面的基础镜像都有两个版本,一个用于应用编译,一个用于运行应用,用来做编译的镜像包含了很多编译工具,体积要大很多,这个大家要注意一下。
比方说,如果要编译Node依赖项,就要用iron/node:dev做基础镜像:
docker run –rm -v “[Math Processing Error]PWD”:/app -w /app iron/node node server.js
上面的方式也适用于其他语言,不过写命令的时候要用各自的build/vendor/run命令。
如果要对某种语言的某个特定版本创建镜像的话,我们只要改一下上面命令里的tag就行了,比如说要创建node 4.1或者node 0.12的镜像,就直接把镜像名改成iron/node:4.1或者iron/node:0.12就行。Docker Hub上针对每一种语言的每个版本都有相应的tag镜像,比如说Node的各种镜像就可以在这个链接下载到:https://hub.docker.com/r/iron/node/tags/. 其他语言的镜像可以去iron-io/dockers仓库下载。
各种语言的镜像构建方法
这个问题要复杂一些,大家可以戳下面这个链接,里面包含了大多数主流开发语言的微镜像构建方法。
https://github.com/iron-io/dockerworker
进去以后大家可以查看各种开发语言对应的README文档,这里面的教程是很全面的,大家可以参照教程来编译依赖项、测试应用代码、构建微型Docker镜像并测试镜像。
在提倡微服务架构的今天,对应用部署的要求越来越高,容器的大小直接影响到服务的部署和运行。而容器从本质上说只是镜像的一个实例,所以归根结底,应用的性能和体验在很大程度上还是取决于镜像的大小。希望大家读完本文之后,都能独立地创建出不含任何多余文件的Docker微镜像,这个问题很重要,因为我们一旦开始在容器里运行镜像,就不可避免地会碰到文件体积问题,这个时候只有微容器才是最好的解决方案,希望大家从一开始就考虑到这个问题,并在今后的实战中坚持贯彻微容器的思想。

Alpine是一个很不错的操作系统,在此基础上我们再将各种依赖项打包到系统中,就可以构建一个完备的轻量级镜像了。就以上面的Node应用为例,因为我们只需要用到Node,所以只要添加Node包就可以了。我们可以用下面的Dockerfile来构建镜像:
FROM alpine
RUN apk update && apk upgrade
RUN apk add nodejs
这样创建出来的镜像只包含Node以及一些必要的依赖项。怎么样,够简洁吧?
下面我们要往镜像中添加代码,操作也很简单,多写几行Dockerfile指令就行了:
FROM alpine
RUN apk update && apk upgrade
RUN apk add nodejs
WORKDIR /app
ADD . /app
ENTRYPOINT [ “node”, “server.js” ]
大概的原理就是这样,大家可以自己去网上找更详细的代码示例。这样做的好处是,我们最终得到的镜像里只包含一个非常轻量的操作系统、必要的依赖项以及应用的代码,没有任何多余的东西。
不只是Node,其他开发语言的镜像也可以依此类推。
更多基础镜像
除了上面说的微镜像以外,还有更给力的。现在在github上有很多轻量的基础镜像,基本上所有主流开发语言的基础镜像都有,大家可以戳下面这个链接,自己去github上下载合适的镜像。
https://github.com/iron-io/dockers
这些镜像都是经过优化的,文件体积很小,而且Github还会定期更新,大家可以直接用这些镜像,效率要比我们自己创建镜像好一些。还是以上面的Node应用为例,如果用Iron.io上面的基础镜像,Dockerfile指令还可以更简单一些:
FROM iron/node
WORKDIR /app
ADD . /app
ENTRYPOINT [ “node”, “server.js” ]
另外说一下,Github上面的基础镜像都有两个版本,一个用于应用编译,一个用于运行应用,用来做编译的镜像包含了很多编译工具,体积要大很多,这个大家要注意一下。
比方说,如果要编译Node依赖项,就要用iron/node:dev做基础镜像:
docker run –rm -v “[Math Processing Error]PWD”:/app -w /app iron/node node server.js
上面的方式也适用于其他语言,不过写命令的时候要用各自的build/vendor/run命令。
如果要对某种语言的某个特定版本创建镜像的话,我们只要改一下上面命令里的tag就行了,比如说要创建node 4.1或者node 0.12的镜像,就直接把镜像名改成iron/node:4.1或者iron/node:0.12就行。Docker Hub上针对每一种语言的每个版本都有相应的tag镜像,比如说Node的各种镜像就可以在这个链接下载到:https://hub.docker.com/r/iron/node/tags/. 其他语言的镜像可以去iron-io/dockers仓库下载。
各种语言的镜像构建方法
这个问题要复杂一些,大家可以戳下面这个链接,里面包含了大多数主流开发语言的微镜像构建方法。
https://github.com/iron-io/dockerworker
进去以后大家可以查看各种开发语言对应的README文档,这里面的教程是很全面的,大家可以参照教程来编译依赖项、测试应用代码、构建微型Docker镜像并测试镜像。
在提倡微服务架构的今天,对应用部署的要求越来越高,容器的大小直接影响到服务的部署和运行。而容器从本质上说只是镜像的一个实例,所以归根结底,应用的性能和体验在很大程度上还是取决于镜像的大小。希望大家读完本文之后,都能独立地创建出不含任何多余文件的Docker微镜像,这个问题很重要,因为我们一旦开始在容器里运行镜像,就不可避免地会碰到文件体积问题,这个时候只有微容器才是最好的解决方案,希望大家从一开始就考虑到这个问题,并在今后的实战中坚持贯彻微容器的思想。
想了解更多的docker知识,欢迎加入技术交流群:547147889

评论