阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

创建尽可能小的 Docker 容器

441次阅读
没有评论

共计 5669 个字符,预计需要花费 15 分钟才能阅读完成。

当我们在使用 Docker 的时候,你会很快注意到你正在下载很多 MB 作为你的预先配置的容器。一个简单的 Ubuntu 容器很容易超过 200 MB,并且随着在上面安装软件,尺寸在逐渐增大。在某些情况下,你不需要任何事情都使用 Ubuntu。例如,如果你只是简单的想运行一个 web 服务,使用 GO 编写的,没有必要围绕它使用任何工具。

创建尽可能小的 Docker 容器

我一直在寻找尽可能小的容器入手,并且发现了一个:

  1. docker pull scratch

scratch 镜像是完美的,真正的完美!它简洁,小巧以及快速。它不包含任何 bug,安全泄漏,慢的代码或是技术债务。这是因为它是一个空的镜像。除了一点由 Docker 加入的元数据。事实上,你可以使用如下命令按照 Docker 文档描述的那样创建一个自己的 scratch 镜像。

  1. tar cv --files-from/dev/null| docker import- scratch

所以这可能就是最小的 Docker 镜像。

或者我们可以说说关于这个的更多东西?比如,你怎样使用 scratch 镜像。这给自己带来了一些挑战。

 

为 scratch 镜像创建内容

我们可以在一个空镜像中运行什么?一个没有依赖的可执行程序。你是否有没有依赖的可执行程序?

我过去常常使用 Python,Java 和 Javascript 编写代码。每一个这样的语言 / 平台都需要一个运行时的安装。最近,我开始涉及 Go(或是 golang 如果你喜欢)平台。看起来 Go 是静态连接的。因此我尝试编译一个简单的 web 服务输出 Hello World 并且运行在 scratch 容器中。下面是这个 Hello World web 服务的代码:

  1. package main
  2. import(
  3. "fmt"
  4. "net/http"
  5. )
  6. func helloHandler(w http.ResponseWriter, r *http.Request){
  7. fmt.Fprintln(w,"Hello World from Go in minimal Docker container")
  8. }
  9. func main(){
  10. http.HandleFunc("/", helloHandler)
  11. fmt.Println("Started, serving at 8080")
  12. err := http.ListenAndServe(":8080",nil)
  13. if err !=nil{
  14. panic("ListenAndServe:"+ err.Error())
  15. }
  16. }

明显地,我不能在 scratch 容器中编译我的 web 服务,因为容器中没有 Go 编译器。正如我在 Mac 上工作,我也无法编译 Linux 的二进制文件一样(实际上,是可以在不同的平台上交叉编译 Go 的源码的,但这会在另外一篇博客中介绍)。

因此,我首先需要一个有 Go 编译器的 Docker 容器。让我们开始:

  1. docker run -ti google/golang /bin/bash

在这个容器里面,我可以构建一个 Web 服务,通过我已经提交到一个 GitHub 仓库的代码。

  1. go get github.com/adriaandejonge/helloworld

go get 命令是 go build 命令的变种,运行获取和构建远程的依赖。你可以运行可执行的结果:

  1. $GOPATH/bin/helloworld

它工作了,但是这不是我们想要的。我们需要 hello world 容器运行在 scratch 容器里面。因此,实际上,我们需要一个 Dockerfile :

  1. FROM scratch
  2. ADD bin/helloworld /helloworld
  3. CMD ["/helloworld"]

然后启动它,不幸的是,我们开始 google/golang 容器的这个方法,没有办法构建这个 Dockerfile。因此,首先,我们需要一种方法从这个容器内部访问到 Docker。

 

从 Docker 内部调用 Docker

当你使用 Dokcer 时,你迟早会遇到需要从 Docker 内部访问 Docker。可以有多种方法实现它。你可以使用递归和在 Docker 中运行 Docker。尽管如此,这样看起来会很复杂并且导致容器很大。你还可以使用一些额外的命令选项在实例外访问 Docker 服务器:

  1. docker run -v /var/run/docker.sock:/var/run/docker.sock -v $(which docker):$(which docker)-ti google/golang /bin/bash

在你继续前,你重新运行 Go 编译器,由于在重启动过程中 Docker 忘记了我们以前编译过。

  1. go get github.com/adriaandejonge/helloworld

当我们启动这个容器,-v 参数在 Docker 容器中创建一个卷并且允许你从 Docker 的机器提供一个文件作为输入。/var/run/docker.sock 是 UNIX socket,通过这个允许你访问 Docker 服务。(which docker) 部分是一个非常聪明的方法,它提供了一个在 容器中的 Docker 可执行文件的路径,而不是硬编码。尽管如此,当你在 Mac 上通过 boot2docker 使用这个命令的时候需要小心。如果 Docker 的可执行文件与 boot2docker 虚拟机的在不同的位置,将导致不匹配。因此,你或许想使用 /usr/local/bin/docker 硬编码的方式替换 $(which docker),如果你运行在不同的系统,/var/run/docker.sock 有在不同位置的机会,你需要做相应的调整。

现在你可以在 google/golang 容器的 $GOPATH 目录使用 Dockerfile,在这个示例中指向 /gopath。实际上,我已经在 github 上检查过了这个 Dockerfile,因此,你可以从 Go build 目录复制它到所需的位置,像这样:

  1. cp $GOPATH/src/github.com/adriaandejonge/helloworld/Dockerfile $GOPATH

你需要复制这个作为二进制的编译���件,现在位于 $GOPATH/bin,并且它不可能从父目录包含文件当构建一个 Dockerfile 的时候。因此复制后,下一步是:

  1. docker build -t adejonge/helloworld $GOPATH

所有的都完成以后,Docker 给出如下响应:

  1. Successfully built 6ff3fd5a381d

允许你运行这个容器:

  1. docker run -ti --name hellobroken adejonge/helloworld

但是不幸的是,Docker 这次响应如下:

  1. 2014/07/0217:06:48no such file or directory

那么到底是怎么回事?我们在 scratch 容器中有可执行的静态链接。难道我们犯了一个错误?

事实证明,Go 不是静态链接库。或者至少不是所有的库。在 Linux 下,我们可以使用 ldd 命令来看到动态链接库:

  1. ldd $GOPATH/bin/helloworld

得到如下响应:

  1. linux-vdso.so.1=>(0x00007fff039fe000)
  2. libpthread.so.0=>/lib/x86_64-linux-gnu/libpthread.so.0(0x00007f61df30f000)
  3. libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007f61def84000)
  4. /lib64/ld-linux-x86-64.so.2(0x00007f61df530000)

因此,在我们运行我们的 web 服务之前,我需要告诉 go 编译器实际的静态链接。

 

创建在 Go 中的可执行静态链接

为了创建可执行的静态链接,我们需要告诉 Go 使用 cgo 编译器而不是 go 编译器。命令如下:

  1. CGO_ENABLED=0 go get-a -ldflags '-s' github.com/adriaandejonge/helloworld

CGO_ENABLED 环境变量告诉 Go 使用 cgo 编译器而不是 go 编译器。-a 参数告诉 GO 重薪构建所有的依赖。否则的话你将以动态链接依赖结束。最后的 -ldflags '-s' 参数是一个非常好的扩展。它大概降低了可执行文件 50% 的文件大小。你也可以不通过 cgo 使用这个。尺寸缩小是去除了调试信息的结果。

为了确定,运行 ldd 命令:

  1. ldd $GOPATH/bin/helloworld

返回是:

  1. not a dynamic executable

你也可以重新运行步骤,围绕着从 scratch 创建 Docker 容器的可执行文件。

  1. docker build -t adejonge/helloworld $GOPATH

如果一切顺利,Docker 将响应如下:

  1. Successfully built 6ff3fd5a381d

允许你运行这个容器:

  1. docker run -ti --name helloworld adejonge/helloworld

响应如下:

  1. Started, serving at 8080

到目前为止,有许多手动的步骤和很多错误的地方。让我们退出 google/golang 容器并且从周边服务器继续:

  1. <PressCtrl-C>
  2. exit

你可以检查 Docker 容器和镜像存在不存在:

  1. docker ps -a
  2. docker images -a

你可以使用如下命令清理:

  1. docker rm -f helloworld
  2. docker rmi -f adejonge/helloworld

 

创建一个 Docker 容器来创建一个 Docker 容器

目前为止,我们花了那么多步骤,我们还可以记录在 Dockerfile 中并且 Docker 会为我们做这些工作:

  1. FROM google/golang
  2. RUN CGO_ENABLED=0 go get-a -ldflags '-s' github.com/adriaandejonge/helloworld
  3. RUN cp /gopath/src/github.com/adriaandejonge/helloworld/Dockerfile/gopath
  4. CMD docker build -t adejonge/helloworld gopath

我在 一个单独的称为 adriaandejonge/hellobuild 的 GitHub 仓库检查了 Dockerfile。它可以使用下面的命令构建:

  1. docker build -t adejonge/hellobuild github.com/adriaandejonge/hellobuild

提供 -t 参数命名 adejonge/hellobuild 镜像并且它的最新的隐式的标签。这些名字让你以后更容易去除镜像。下一步,你可以使用就像我们在这篇文章前面看到的那样提供一个参数从这个镜像中创建一个容器:

  1. docker run -v /var/run/docker.sock:/var/run/docker.sock -v $(which docker):$(which docker)-ti --name hellobuild adejonge/hellobuild

提供 --name hellobuild 参数使得在运行后更容易移除容器。事实上,你可以这样做,因为运行这个命令后,你已经创建了一个 adejonge/helloworld 镜像:

  1. docker rm -f hellobuild
  2. docker rmi -f adejonge/hellobuild

现在你可以创建一个基于 adejonge/helloworld 镜像的名为 helloworld 的新容器,就像你以前做的那样:

  1. docker run -ti --name helloworld adejonge/helloworld

因为所有的这些步骤都是从相同的命令中运行,不需要在 Docker 中打开一个 bash shell。你可以把这些步骤添加进一个 bash 脚本,自动运行它,为了使你方便,我已经把这些脚本加入了 hellobuild GitHub 仓库。

另外,如果你想尝试一个尽可能小的容器,但是又不想遵循博客中的步骤,你可以使用我检入进 Docker Hub repository 的预先构建好的镜像。

  1. docker pull adejonge/helloworld

使用 docker images -a,你可以看到大小是 3.6MB。当然,如果你成功创建一个比我使用 Go 编写的 web 服务还小的可执行文件,你可以使得它更小。使用 C 语言或者是汇编,你可以这样做到。尽管如此,你不可能使得它比 scratch 镜像还小

扩展阅读

  • OPTIMIZING DOCKER IMAGES

如何在 Ubuntu 14.10 上安装 WordPress?http://www.linuxidc.com/Linux/2015-02/112648.htm

Docker 安装应用 (CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm 

在 Docker 中使用 MySQL http://www.linuxidc.com/Linux/2014-01/95354.htm

在 Ubuntu Trusty 14.04 (LTS) (64-bit) 安装 Docker http://www.linuxidc.com/Linux/2014-10/108184.htm 

Docker 安装应用 (CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm 

Ubuntu 14.04 安装 Docker  http://www.linuxidc.com/linux/2014-08/105656.htm 

阿里云 CentOS 6.5 模板上安装 Docker http://www.linuxidc.com/Linux/2014-11/109107.htm 

Docker 的详细介绍 :请点这里
Docker 的下载地址 :请点这里

本文永久更新链接地址 :http://www.linuxidc.com/Linux/2015-06/118586.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-20发表,共计5669字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
7995932
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
星哥带你玩飞牛NAS-4:飞牛NAS安装istore旁路由,家庭网络升级的最佳实践

星哥带你玩飞牛NAS-4:飞牛NAS安装istore旁路由,家庭网络升级的最佳实践

星哥带你玩飞牛 NAS-4:飞牛 NAS 安装 istore 旁路由,家庭网络升级的最佳实践 开始 大家好我是...
星哥带你玩飞牛NAS硬件02:某鱼6张左右就可拿下5盘位的飞牛圣体NAS

星哥带你玩飞牛NAS硬件02:某鱼6张左右就可拿下5盘位的飞牛圣体NAS

星哥带你玩飞牛 NAS 硬件 02:某鱼 6 张左右就可拿下 5 盘位的飞牛圣体 NAS 前言 大家好,我是星...
从“纸堆”到“电子化”文档:用这个开源系统打造你的智能文档管理系统

从“纸堆”到“电子化”文档:用这个开源系统打造你的智能文档管理系统

从“纸堆”到“电子化”文档:用这个开源系统打造你的智能文档管理系统 大家好,我是星哥。公司的项目文档存了一堆 ...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...
支付宝、淘宝、闲鱼又双叕崩了,Cloudflare也瘫了连监控都挂,根因藏在哪?

支付宝、淘宝、闲鱼又双叕崩了,Cloudflare也瘫了连监控都挂,根因藏在哪?

支付宝、淘宝、闲鱼又双叕崩了,Cloudflare 也瘫了连监控都挂,根因藏在哪? 最近两天的互联网堪称“故障...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞...
星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛 NAS-11:咪咕视频订阅部署全攻略 前言 在家庭影音系统里,NAS 不仅是存储中心,更是内容...
每天一个好玩的网站-手机博物馆-CHAZ 3D Experience

每天一个好玩的网站-手机博物馆-CHAZ 3D Experience

每天一个好玩的网站 - 手机博物馆 -CHAZ 3D Experience 一句话介绍:一个用 3D 方式重温...
恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击

恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击

恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击 PHP-FPM(FastCGl Process M...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...