创建超小的Golang docker 镜像
原文: http://colobu.com/2015/10/12/create-minimal-golang-docker-images/
本文对于创建超小的镜像非常有用
Docker是PaaS供应商dotCloud开源的一个基于LXC 的高级容器引擎,源代码托管在 GitHub 上, 基于Go语言开发并遵从Apache 2.0协议开源。正如DockerPool在免费Docker电子书Docker —— 从入门到实践中这样提到的:
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。
首先,Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。
Docker让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app)。几乎没有性能开销,可以很容易地在机器和数据中心中运行。最重要的是,他们不依赖于任何语言、框架包括系统。
本文不会介绍Docker原理和操作,而是介绍如何使用Docker创建一个Golang应用程序的镜像,这样我们就可以在其它机器上运行这个镜像。
本文参考了很多的文章,这些文章列在了本文的底部。
编写一个Golang服务器
这里我在研究endless库的时候写了一个测试程序,就用它来测试一下docker镜像的创建。
endless可以允许我们在重启网络服务器的时候零时间宕机, 英语是graceful restart,我称之为无缝重启。
服务器监听4242端口,顺便使用raymond模版引擎替换golang自带的模版引擎,采用bone这个高性能的mux库。
代码如下:
package main import (
"flag"
"github.com/aymerick/raymond"
"github.com/fvbock/endless"
"github.com/go-zoo/bone"
"log"
"net/http"
"os"
"syscall"
) var (
//homeTpl, _ = raymond.ParseFile("home.hbs")
homeTpl = raymond.MustParse(`<html>
<head>
<title>test</title>
</head>
</body>
<div class="entry">
<h1></h1>
<div class="body"> </div>
</div>
</body>
</html>
`)
) func homeHandler(rw http.ResponseWriter, req *http.Request) {
ctx := map[string]string{"greet": "hello", "name": "world"}
result := homeTpl.MustExec(ctx)
rw.Write([]byte(result))
}
func varHandler(rw http.ResponseWriter, req *http.Request) {
varr := bone.GetValue(req, "var")
test := bone.GetValue(req, "test") rw.Write([]byte(varr + " " + test))
}
func Handler404(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte("These are not resources you're looking for ..."))
}
func restartHandler(rw http.ResponseWriter, req *http.Request) {
syscall.Kill(syscall.Getppid(), syscall.SIGHUP)
rw.Write([]byte("restarted"))
}
func main() {
flag.Parse()
mux := bone.New()
// Custom 404
mux.NotFoundFunc(Handler404)
// Handle with any http method, Handle takes http.Handler as argument.
mux.Handle("/index", http.HandlerFunc(homeHandler))
mux.Handle("/index/:var/info/:test", http.HandlerFunc(varHandler))
// Get, Post etc... takes http.HandlerFunc as argument.
mux.Post("/home", http.HandlerFunc(homeHandler))
mux.Get("/home/:var", http.HandlerFunc(varHandler))
mux.GetFunc("/test/*", func(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte(req.RequestURI))
})
mux.Get("/restart", http.HandlerFunc(restartHandler))
err := endless.ListenAndServe(":4242", mux)
if err != nil {
log.Fatalln(err)
}
log.Println("Server on 4242 stopped")
os.Exit(0)
}
Golang镜像
Docker官方提供了Golang各版本的镜像: Official Repository - golang.
它包含了Golang的编译和运行时环境。最简单的使用方法就是在你的Dockerfile
文件中加入
FROM golang:1.3-onbuild
这个镜像包含了多个ONBUILD
触发器。你可以编译和运行你的镜像:
$ docker build -t my-golang-app .
$ docker run -it --rm --name my-running-app my-golang-app
上面的Golang容器相当的大,因为它包含了Golang的编译和运行环境。为编译好的Golang应用创建小的镜像
官方网站上列出了镜像的大小:
golang:1.5.1-onbuild $ docker pull library/golang@sha256:f938465579d1cde302a447fef237a5a45d7e96609b97c83b9144446615ad9e72 Total Virtual Size: 709.5 MB (709470237 bytes)
Total v2 Content-Length: 247.0 MB (246986021 bytes)
实际上我们并不需要那么多的软件,因为我们的Golang应用程序是预先编译好的,而不是在Golang容器中现场编译运行,因此我们不需要Golang的编译环境等。如果你查看golang:1.5的Dockerfile, 会发现它基于buildpack-deps:jessie-scm,会安装GCC及一堆的build工具,下载Go的发布文件并安装。基本上这些对于我们来说并不需要。我们需要的是:
一个可以运行我们编译好的Golang应用的镜像。
我们可以从scratch
镜像创建。scratch
镜像是一个空的镜像文件,特别适合创建超级小的镜像。Dockerfile
文件如下:
FROM scratch
ADD main /
CMD ["/main"]
# docker build -t example-scratch .
Sending build context to Docker daemon 8.054 MB
Step 0 : FROM scratch
--->
Step 1 : ADD main /
---> 4ad02fa47a7d Removing intermediate container d64080c4b42f
Step 2 : CMD /main
---> Running in 5d9a08c3a20e
---> 5c29c8249678
Removing intermediate container 5d9a08c3a20e
Successfully built 5c29c8249678
这样镜像就创建成功了,查看一下:运行
输出如下
[root@localhost work]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
example-scratch latest 5c29c8249678 3 minutes ago 8.052 MB
只有8M左右,非常的小。
但是运行这个镜像,容器无法创建:
# docker run -it -p 4242:4242 example-scratch
no such file or directory
Error response from daemon: Cannot start container 79bb9fb62788b4a8c1487695a3219ddf3aa85bde2bc44473838f6f4d1583a204: [8] System error: no such file or directory
原因是我们的main文件生成的时候依赖的一些库如libc还是动态链接的,但是scratch 镜像完全是空的,什么东西也不包含,所以生成main时候要按照下面的方式生成,使生成的main静态链接所有的库:
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
注意:其实主要的是使用 CGO_ENABLED=0 ,关闭cgo
然后重新生成镜像并运行:
# docker build -t example-scratch .
# docker run -it -p 4242:4242 example-scratch
容器运行成功,在浏览器中访问http://宿主IP:4242/index成功返回结果
发布
可以方便的将刚才的镜像发布到docker.io上。
首先将刚才的镜像打tag:
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
example-scratch latest 2ea4bbfd67dc 10 minutes ago 8.01 MB
# docker tag 2ea4bbfd67dc smallnest/example-scratch
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
smallnest/example-scratch latest 2ea4bbfd67dc 10 minutes ago 8.01 MB
example-scratch latest 2ea4bbfd67dc 10 minutes ago 8.01 MB
运行docker login
登录,然后运行下面的命令push到docker.io上。
docker push smallnest/example-scratch
访问 https://hub.docker.com/r/smallnest/example-scratch/ 可以看到刚刚push的这个镜像,这样我们就可以pull到其它机器上运行了。
参考文档
- https://blog.golang.org/docker
- https://hub.docker.com/_/golang/
- https://blog.codeship.com/building-minimal-docker-containers-for-go-applications/
- https://medium.com/@kelseyhightower/optimizing-docker-images-for-static-binaries-b5696e26eb07
- http://www.iron.io/blog/2015/07/an-easier-way-to-create-tiny-golang-docker-images.html
- https://labs.ctl.io/small-docker-images-for-go-apps/
- http://dockerpool.com/static/books/docker_practice/introduction/why.html
- https://docs.docker.com/installation/centos/
- http://segmentfault.com/a/1190000002766882
创建超小的Golang docker 镜像的更多相关文章
- 两种方式创建支持SSH服务的docker镜像
方法一:基于commit命令创建 1.首先,从docker的源中查看我们需要的镜像,本案例中使用Ubuntu作为基础镜像. # federico @ linux in ~ [16:57:38] $ s ...
- Centos7创建支持ssh服务的docker镜像
如何在centos7中使用docker创建一个支持ssh连接的容器 1.拉取centos7.4镜像(由于7.4目前是最稳定的版本,所以推荐使用centos7.4) docker pull centos ...
- 004.Docker镜像管理
一 镜像基本操作 镜像是一个包含程序运行必要依赖环境和代码的只读文件,其本质是磁盘上一系列文件的集合.它采用分层的文件系统,将每一次改变以读写层的形式增加到原来的只读文件上.镜像是容器运行的基石. 1 ...
- Docker容器技术-优化Docker镜像
一.优化Docker镜像 1.降低部署时间 一个大的Docker应用是如何影响在新Docker宿主机上的部署时间. (1)编写Dockerfile创建一个大Docker镜像 [root@bogon ~ ...
- 如何为你的Go应用创建轻量级Docker镜像?
介绍 多什么? 简单来讲,多阶段. 多阶段允许在创建Dockerfile时使用多个from,它非常有用,因为它使我们能够使用所有必需的工具构建应用程序.举个例子,首先我们使用Golang的基础镜像,然 ...
- 多阶段构建Golang程序Docker镜像
Docker简介 Docker是基于Linux容器技术(LXC),使用Go语言实现的开源项目,诞生于2013年,遵循Apache2.0协议.Docker自开源后,受到广泛的关注和讨论. Docker在 ...
- 基于空镜像scratch创建一个新的Docker镜像
我们在使用Dockerfile构建docker镜像时,一种方式是使用官方预先配置好的容器镜像.优点是我们不用从头开始构建,节省了很多工作量,但付出的代价是需要下载很大的镜像包. 比如我机器上docke ...
- 为你的Go应用创建轻量级Docker镜像?
缩小Go二进制文件大小 环境 youmen@youmendeMacBook-Pro % gcc -dumpversion 12.0.5 youmen@youmendeMacBook-Pro % go ...
- Docker镜像的创建、存出、载入
创建镜像的方法有三种:基于已有镜像的容器创建.基于本地模板导入.基于Dockerfile创建,本博文讲解前两种. 基于已有镜像的容器创建 该方法是使用docker commit命令,其命令格式为: ...
随机推荐
- Java并发编程(二):JAVA内存模型与同步规则
一.Java内存模型(JMM) 它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式.一个线程如何和何时能看到其他线程共享变量的值,以及在 ...
- Effective Java-第二章
第1章 如何最有效地使用Java程序设计语言机器基本类库:java.lang,java.util,java.util.concurrent和java.io. Sun JDK1.6_05版本 第2章 创 ...
- atitit.流程标准化--- mysql启动不起来的排查流程attilax总结
atitit.流程标准化--- mysql启动不起来的排查流程attilax总结 1. mysql的启动日志文件 1 2. console方式 1 3. 安装为服务 1 3.1. 使用默认配置文件 1 ...
- flink on yarn部分源码解析 (FLIP-6 new mode)
我们在https://www.cnblogs.com/dongxiao-yang/p/9403427.html文章里分析了flink提交single job到yarn集群上的代码,flink在1.5版 ...
- post请求与get请求
$.post('/manage.aa', function (response) { agentList = response.data; }, 'json'); var categoryId; $. ...
- 0045 Spring中使用DataSourceTransactionManager进行事务管理的xml配置
在一个业务的实现过程中,可能需要多条sql完成对数据库的操作,比如账户登录,需要匹配用户名和密码,然后要增加积分,还要记录登录的ip和时间,这可能需要三个sql语句,这三个语句应当是一个整体,任意一个 ...
- CCNA2.0笔记_IPv6
IPv6地址表示方法: 连续的零字段可表示为:: (每个地址只能用一次) 示例: 2031:0000:130F:0000:0000:09C0:876A:130B –可表示为2031:0:130f::9 ...
- WebRTC编译具体介绍
WebRTC编译具体介绍--记录+转载 原文地址:http://blog.csdn.net/temotemo/article/details/7056581 WebRTC编译 本人环境: 操作系统:X ...
- ActiveMQ 无法启动 提示端口被占用 解决方案
http://bob-zhangyong.blog.163.com/blog/static/17610982012729113326153/ ————————————————————————————— ...
- Papers of Word Embeddings
首先解释一下什么叫做embedding.举个例子:地图就是对于现实地理的embedding,现实的地理地形的信息其实远远超过三维 但是地图通过颜色和等高线等来最大化表现现实的地理信息. embeddi ...