专栏名称: 分布式实验室
最专业的Docker文章,最权威的Docker新闻。关注容器生态圈的发展。
目录
相关文章推荐
51好读  ›  专栏  ›  分布式实验室

Docker与Golang的巧妙结合

分布式实验室  · 公众号  · 后端  · 2016-10-19 07:47

正文

请到「今天看啥」查看全文


docker run --rm golang sh -c \
"go get github.com/golang/example/hello/... && exec hello"

等等,那些花哨的东西是什么?

  • --rm 告诉Docker CLI一旦容器退出,就自动发起一个 docker rm 命令。那样,不会留下任何东西。

  • 使用shell逻辑运算符 && 把创建步骤( go get )和执行步骤( exec hello )联接在一起。如果不喜欢shell, && 意思是“与”。它允许第一部分 go get... ,并且如果(而且仅仅是如果!)那部分运行成功,它将执行第二部分( exec hello )。如果你想知道为什么这样:它像一个懒惰的 and 计算器,只有当左边的值是 true 才计算右边的。

  • 传递命令到 sh –c ,因为如果是简单的做 docker run golang "go get ... && hello" ,Docker将试着执行名为 go SPACE get SPACE etc 的程序。并且那不会起作用。因此,我们启动一个shell,并让shell执行命令序列。

  • 使用 exec hello 而不是 hello :这将使用hello程序替代当前的进程(我们刚才启动的shell)。这确保 hello 在容器里是PID 1。而不是shell的是PID 1而 hello 作为一个子进程。这对这个微小的例子毫无用处,但是当运行更有用的程序,这将允许它们正确地接收外部信号,因为外部信号是发送给容器里的PID 1。你可能会想,什么信号啊?好的例子是 docker stop ,发送 SIGTERM 给容器的PID 1。

使用不同版本的Go

当使用 golang 镜像,Docker扩展为 golang:latest, 将(像你所猜的)映射到Docker Hub上的最新可用版本。

如果想用一个特定的Go版本,很容易:在镜像名字后面用那个版本做标签指定它。

例如,想用Go 1.5,修改上面的例子,用 golang:1.5 替换 golang

docker run --rm golang:1.5 sh -c \
"go get github.com/golang/example/hello/... && exec hello"

你能在Docker Hub的Golang镜像页面上看到所有可用的版本(和变量)。

在系统上安装

好了,如果想在系统上运行编译好的程序,而不是一个容器呢?我们将复制这个编译了的二进制文件到容器外面。注意,仅当容器架构和主机架构匹配的时候,才会起作用;换言之,如果在Linux上运行Docker。(我排除的可能是运行Windows容器的人!)

最容易在容器外获得二进制文件的方法是映射 $GOPATH/bin 目录到一个本地目录,在 golang 容器里, $GOPATH /go. 所以我们可以如下操作:

docker run -v /tmp/bin:/go/bin \
golang go get github.com/golang/example/hello/...
/tmp/bin/hello

如果在Linux上,将看到 Hello, Go examples! 消息。但如果是,例如在Mac上,可能会看到:

-bash:
/tmp/test/hello: cannot execute binary file

我们又能做什么呢?

交叉编译

Go 1.5具备优秀的开箱即用交叉编译能力,所以如果你的容器操作系统和/或架构和你的系统不匹配,根本不是问题!

开启交叉编译,需要设置 GOOS 和/或 GOARCH

例如,假设在64位的Mac上:

docker run -e GOOS=darwin -e GOARCH=amd64 -v /tmp/crosstest:/go/bin \
golang go get github.com/golang/example/hello/...

交叉编译的输出不是直接在 $GOPATH/bin ,而是在 $GOPATH/bin/$GOOS_$GOARCH. 。换言之,想运行程序,得执行 /tmp/crosstest/darwin_amd64/hello.







请到「今天看啥」查看全文