原文地址: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 mainimport (    "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 scratchADD main /CMD ["/main"]

运行
输入如下

# docker build -t example-scratch .Sending build context to Docker daemon 8.054 MBStep 0 : FROM scratch ---> Step 1 : ADD main / ---> 4ad02fa47a7dRemoving intermediate container d64080c4b42fStep 2 : CMD /main ---> Running in 5d9a08c3a20e ---> 5c29c8249678Removing intermediate container 5d9a08c3a20eSuccessfully built 5c29c8249678

这样镜像就创立胜利了,查看一下:

[root@localhost work]# docker imagesREPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZEexample-scratch     latest              5c29c8249678        3 minutes ago       8.052 MB

只有8M左右,十分的小。

然而运行这个镜像,容器无奈创立:

# docker run -it -p 4242:4242 example-scratchno such file or directoryError 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 imagesREPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZEexample-scratch     latest              2ea4bbfd67dc        10 minutes ago      8.01 MB# docker tag 2ea4bbfd67dc smallnest/example-scratch# docker imagesREPOSITORY                  TAG                 IMAGE ID            CREATED             VIRTUAL SIZEsmallnest/example-scratch   latest              2ea4bbfd67dc        10 minutes ago      8.01 MBexample-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多平台公布