原文地址:https://colobu.com/2015/10/12…
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"
"log"
"net/http"
"os"
"syscall"
"github.com/aymerick/raymond"
"github.com/fvbock/endless"
"github.com/go-zoo/bone"
)
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 -ldflags '-extldflags"-static"' -o main .
而后从新生成镜像并运行:
# 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/smal… 能够看到刚刚 push 的这个镜像,这样咱们就能够 pull 到其它机器上运行了。
参考文档
- https://blog.golang.org/docker
- https://hub.docker.com/_/golang/
- https://blog.codeship.com/bui…
- https://medium.com/@kelseyhig…
- http://www.iron.io/blog/2015/…
- https://labs.ctl.io/small-doc…
- http://dockerpool.com/static/…
- https://docs.docker.com/insta…
- http://segmentfault.com/a/119…
原文地址:https://colobu.com/2015/10/12…
关注 golang 技术实验室
获取更多好文
本文由 mdnice 多平台公布