docker 容器部署_在Docker容器中部署Go应用程序

docker 容器部署

介绍 (Intro)

If you’ve never heard about Docker, but that’s unlikely, the first thing you should know is that Docker allows you to run applications in isolation and with a great separation of concerns, yet allows them to communicate and interact with the external world.

如果您从未听说过Docker,但是那不太可能,那么您应该知道的第一件事是,Docker允许您独立运行应用程序,且关注点分离很大,但允许它们与外部世界进行通信和交互。

And you should know that everyone uses it, and every major cloud provider has a solution dedicated to running containers, so you should learn it!

而且您应该知道每个人都使用它,并且每个主要的云提供商都提供专用于运行容器的解决方案,因此您应该学习它!

安装 (Install)

Installation changes depending on your system, so check https://www.docker.com/get-docker.

安装会根据您的系统而变化,因此请检查https://www.docker.com/get-docker

I assume you already installed Docker and have the docker command available in your shell.

我假设您已经安装了Docker并在您的Shell中使用了docker命令。

Go官方图片 (The Go official images)

Docker maintains a list of official images for many different languages, and Go is no exception, being it part of the original official images launch back in 2014.

Docker维护着许多不同语言的官方映像列表,Go也不例外,它是2014年发布的原始官方映像的一部分。

The official image repository can be found at https://hub.docker.com/_/golang/. There are many tags that identify both the Go version, and the operating system you want to fetch.

官方映像存储库可在https://hub.docker.com/_/golang/中找到。 有很多标记既可以标识Go版本,也可以标识要获取的操作系统。

一个示例应用 (An example app)

As an example, I’m going to deploy a little Go app in a Docker container. It listens on port 8000, gets a webpage as a q query parameter, fetches it and prints the links it finds:

例如,我将在Docker容器中部署一个小Go应用程序。 它侦听端口8000,获取网页作为q查询参数,将其获取并打印找到的链接:

findlinks.go

findlinks.go

package main

import (
	"fmt"
	"log"
	"net/http"

	"golang.org/x/net/html"
)

func main() {
	http.HandleFunc("/", handler)
	log.Fatal(http.ListenAndServe("0.0.0.0:8000", nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
	url := r.URL.Query().Get("q")
	fmt.Fprintf(w, "Page = %q\n", url)
	if len(url) == 0 {
		return
	}
	page, err := parse("https://" + url)
	if err != nil {
		fmt.Printf("Error getting page %s %s\n", url, err)
		return
	}
	links := pageLinks(nil, page)
	for _, link := range links {
		fmt.Fprintf(w, "Link = %q\n", link)
	}
}

func parse(url string) (*html.Node, error) {
	fmt.Println(url)
	r, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("Cannot get page")
	}
	b, err := html.Parse(r.Body)
	if err != nil {
		return nil, fmt.Errorf("Cannot parse page")
	}
	return b, err
}

func pageLinks(links []string, n *html.Node) []string {
	if n.Type == html.ElementNode && n.Data == "a" {
		for _, a := range n.Attr {
			if a.Key == "href" {
				links = append(links, a.Val)
			}
		}
	}
	for c := n.FirstChild; c != nil; c = c.NextSibling {
		links = pageLinks(links, c)
	}
	return links
}

Example usage:

用法示例:

将应用程序移至Docker (Moving the app to Docker)

I put the app on https://github.com/flaviocopes/findlinks.

我将应用程序放在https://github.com/flaviocopes/findlinks上

Using go get I can easily download and install it, using go get github.com/flaviocopes/findlinks.

使用go get可以使用go get github.com/flaviocopes/findlinks轻松下载并安装它。

Running

跑步

docker run golang go get -v github.com/flaviocopes/findlinks

will first download the golang Docker image, if you don’t have it already, then it will fetch the repository and will scan for additional dependencies not included in the standard library. In this case, golang.org/x/net/html.

将首先下载golang Docker映像,如果您还没有的话,它将获取存储库并扫描标准库中未包含的其他依赖项。 在这种情况下,请访问golang.org/x/net/html

$ docker run golang go get -v github.com/flaviocopes/findlinks
github.com/flaviocopes/findlinks (download)
Fetching https://golang.org/x/net/html?go-get=1
Parsing meta tags from https://golang.org/x/net/html?go-get=1 (status code 200)
get "golang.org/x/net/html": found meta tag main.metaImport{Prefix:"golang.org/x/net", VCS:"git", RepoRoot:"https://go.googlesource.com/net"} at https://golang.org/x/net/html?go-get=1
get "golang.org/x/net/html": verifying non-authoritative meta tag
Fetching https://golang.org/x/net?go-get=1
Parsing meta tags from https://golang.org/x/net?go-get=1 (status code 200)
golang.org/x/net (download)
golang.org/x/net/html/atom
golang.org/x/net/html
github.com/flaviocopes/findlinks

This command creates a container, and runs it. We can inspect it using docker ps -l (the -l option tells Docker to list the latest container ran):

此命令创建一个容器并运行它。 我们可以使用docker ps -l检查它( -l选项告诉Docker列出最新运行的容器):

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
343d96441f16        golang              "go get -v github...."   3 minutes ago       Exited (0) 2 minutes ago                       mystifying_swanson

The container exited when the go get command completed.

go get命令完成后,容器退出。

Docker just built an on demand image and ran it; to run it again, we would need to repeat the process, but images help us: let’s now create an image from this container, so we can run it later:

Docker只是构建了一个按需映像并运行了它。 要再次运行它,我们将需要重复该过程,但是图像可以帮助我们:让我们现在从此容器中创建一个图像,以便以后可以运行它:

docker commit $(docker ps -lq) findlinks

The above command gets the last container ID using docker ps -lq, and commits the image. The image has now been installed, as you can check using docker images findlinks:

上面的命令使用docker ps -lq获取最后一个容器ID,并提交映像。 该映像现已安装,您可以使用docker images findlinks进行检查:

$ docker images findlinks
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
findlinks           latest              4e7ebb87d02e        11 seconds ago      720MB

We can run the findlinks command on our findlinks image with

我们可以使用findlinks命令在我们的findlinks图像上运行findlinks命令:

docker run -p 8000:8000 findlinks findlinks

That’s it! Our app will now respond on http://192.168.99.100:8000/, where 192.168.99.100 is the IP address of the Docker container.

而已! 我们的应用程序现在将在http://192.168.99.100:8000/响应,其中192.168.99.100是Docker容器的IP地址。

You can test calling http://192.168.99.100:8000/?q=flaviocopes.com, which will print the same output we had when we run the app locally:

您可以测试调用http://192.168.99.100:8000/?q=flaviocopes.com ,它将打印出与我们在本地运行该应用程序时相同的输出:

Page = "flaviocopes.com"
Link = "https://flaviocopes.com/index.xml"
Link = "https://twitter.com/flaviocopes"
Link = "https://github.com/flaviocopes"
Link = "https://stackoverflow.com/users/205039/flaviocopes"
Link = "https://linkedin.com/in/flaviocopes/"
Link = "mailto:copesc@gmail.com"
Link = "/"
Link = "/page/contact/"
Link = "/page/about/"
Link = "https://flaviocopes.com/golang-tutorial-rest-api/"
Link = "https://flaviocopes.com/golang-environment-variables/"
Link = "https://flaviocopes.com/golang-sql-database/"
Link = "https://flaviocopes.com/golang-is-go-object-oriented/"
Link = "https://flaviocopes.com/golang-comparing-values/"
Link = "https://flaviocopes.com/golang-data-structures/"
Link = "https://flaviocopes.com/golang-data-structure-binary-search-tree/"
Link = "https://flaviocopes.com/golang-data-structure-graph/"
Link = "https://flaviocopes.com/golang-data-structure-linked-list/"
Link = "https://flaviocopes.com/golang-data-structure-queue/"
Link = "https://flaviocopes.com/golang-data-structure-stack/"
Link = "https://flaviocopes.com/golang-event-listeners/"

修剪Docker映像 (Trim the Docker image)

This strategy is now deprecated in favor of multi-stage builds

现在不建议使用此策略,而建议使用多阶段构建

The problem with the above result is, the image is huge: 720MB for this simple program is not really acceptable, keep in mind this is a very simple scenario. We might want to deploy thousands of instances of the application, and this size is not going to work.

上述结果的问题是, 图像很大 :这个简单程序的720MB容量实际上是不可接受的,请记住,这是一个非常简单的方案。 我们可能要部署数千个应用程序实例,而这个大小将无法正常工作。

Why is the image this big? Because what happens is that the Go app is compiled inside the container. So the image needs to have a Go compiler installed. And everything needed by the compiler of course, GCC, and a whole Linux distribution (Debian Jessie). It downloads Go and installs it, compiles the app and runs it.

为什么图像这么大? 因为发生的事情是Go应用程序是在容器内编译的。 因此,该映像需要安装Go编译器。 当然还有编译器,GCC和整个Linux发行版(Debian Jessie)所需的一切。 它下载Go并安装,编译该应用程序并运行它。

It’s all so fast we don’t even realize. But we can do better. How? I apply what I learned on Building Minimal Docker Containers for Go Applications by Nick Gauthier

它是如此之快,我们甚至都没有意识到。 但是我们可以做得更好。 怎么样? 我运用了我在Nick Gauthier上 为Go应用程序构建最小的Docker容器中学到的知识

We tell Docker to run the golang:1.8.3 image and statically compile our application, disabling CGO, which means the image doesn’t even need the C libraries it normally needs to access when dynamically linked, using:

我们告诉Docker运行golang:1.8.3映像并静态编译我们的应用程序,从而禁用CGO,这意味着该映像甚至不需要动态链接时通常需要访问的C库,可以使用:

docker run --rm -it -v "$GOPATH":/gopath -v "$(pwd)":/app -e "GOPATH=/gopath" -w /app golang:1.8.3 sh -c 'CGO_ENABLED=0 go build -a --installsuffix cgo --ldflags="-s" -o findlinks'

We now have a findlinks binary in the folder:

现在,我们在文件夹中有一个findlinks二进制文件:

$ ll
.rw-r--r--   77 flavio 17 Aug 18:57 Dockerfile
.rwxr-xr-x 4.2M flavio 17 Aug 19:13 findlinks
.rw-r--r-- 1.1k flavio 12 Aug 18:10 findlinks.go

$ file findlinks
findlinks: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

Notice that this of course is not the same file that I get if I go build on OSX, it’s a linux-ready binary:

请注意,这当然不是我在OSX上go build时得到的文件,它是Linux就绪的二进制文件:

$ file findlinks
findlinks: Mach-O 64-bit executable x86_64

We then create a Dockerfile, telling Docker to use iron/base, a very light image:

然后,我们创建一个Dockerfile,告诉Docker使用iron / base ,这是一个非常轻便的映像:

FROM iron/base
WORKDIR /app
COPY findlinks /app/
ENTRYPOINT ["./findlinks"]

We can now build the image, tagging it flaviocopes/golang-docker-example-findlinks:

现在,我们可以构建图像,将其标记为flaviocopes/golang-docker-example-findlinks

docker build -t flaviocopes/golang-docker-example-findlinks .

and run it:

并运行它:

docker run --rm -it -p 8000:8000 flaviocopes/golang-docker-example-findlinks

The output is the same as before, but this time the image is not 720MB, but just 11.1MB

输出与以前相同,但是这次图像不是720MB,而是11.1MB

REPOSITORY                                    TAG                 IMAGE ID            CREATED             SIZE
flaviocopes/golang-docker-example-findlinks   latest              f32d2fd74638        14 minutes ago      11.1MB
findlinks                                     latest              c60f6792b9f3        20 minutes ago      720MB

多阶段构建 (Multi-stage builds)

This section was added thanks to Reddit comments pointing me to multi-stage builds, a recent addition to Docker 17.05

添加此部分是由于Reddit的评论将我指向多阶段构建,这是Docker 17.05的最新功能

Multi-stage builds allow us to have a lightweight image very easily, without the need to compile the binary and then run it separately. This is the Dockerfile to put in the app:

多阶段构建使我们可以非常轻松地获得轻量级映像,而无需编译二进制文件然后单独运行它。 这是要放入应用程序的Dockerfile:

FROM golang:1.8.3 as builder
WORKDIR /go/src/github.com/flaviocopes/findlinks
RUN go get -d -v golang.org/x/net/html
COPY findlinks.go  .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o findlinks .

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/flaviocopes/findlinks/findlinks .
CMD ["./findlinks"]

Run

$ docker build -t flaviocopes/golang-docker-example-findlinks .

which builds a lightweight (10.8MB) image:

生成一个轻量级(10.8MB)的图像:

$ docker images
REPOSITORY                                    TAG                 IMAGE ID            CREATED             SIZE
flaviocopes/golang-docker-example-findlinks   latest              aa2081ca7016        12 seconds ago      10.8MB

Run the image with

使用运行图像

$ docker run --rm -it -p 8000:8000 flaviocopes/golang-docker-example-findlinks

翻译自: https://flaviocopes.com/golang-docker/

docker 容器部署

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值