如何使用Docker部署一个Go Web应用程序

Posted 张伯雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用Docker部署一个Go Web应用程序相关的知识,希望对你有一定的参考价值。

熟悉Docker如何提升你在构建、测试并部署Go Web应用程序的方式,并且理解如何使用Semaphore来持续部署。

简介

大多数情况下Go应用程序被编译成单个二进制文件,web应用程序则会包括模版和配置文件。而当一个项目中有很多文件的时候,由于很多文件没有同步就会导致错误的发生并且产生很多的问题。

在本教程中,你将学习如何使用Docker部署一个Go web应用程序,并且认识到Docker将如何改进你的开发工作流及部署流程。各种规模的团队都会从这里所介绍的设置中受益。

目标

在本文结束后,你将:

。对Docker有基本的了解,

。发现在Docker将如何帮助你开发Go应用程序

。学习如何为一个生产环境中的Go应用程序创建Docker容器

。知道如何使用Semaphore持续地在你的服务器上部署Docker容器

先决条件

为了学习本教程,你讲需要:

。在你的主机或者服务器上安装Docker

。具有一台能够使用SSH密钥对SSH请求进行认证的服务器

理解Docker

Docker帮助你为应用程序创建一个单独的可部署单元。这个单元,也被称为容器,包含该应用程序需要的所有东西。它包括代码(或者二进制文件)、runtime(运行环境)、系统工具盒系统库。将所有必需的资源打包成一个单元将确保无论应用程序部署到哪里都有完全相同的环境。这也有助于维护一个完全相同的开发和生产配置,这在以前是很难追踪的。

一旦开始,容器的创建和部署将自动完成。它消除了一大类问题。这些问题主要是由于文件没有同步或者开发和生产环境之间的差异导致的。Docker帮助解决了这些问题。

相比于虚拟机的优势

容器提供了与虚拟机相似的资源分配和隔离优势。然而,相同之处仅此而已。

一个虚拟机需要它自己的客户操作系统而容器共享主机操作系统的内核。这意味着容器更加轻量而且需要更少的资源。从本质上讲,一个虚拟机是操作系统中的一个操作系统。而另一方面的容器则更像是操作系统中的其它应用程序。基本上,容器需要的资源(内存、磁盘空间等等)比虚拟机少很多,并且具有比虚拟机快很多的启动时间。

Docker在开发阶段的优势

在开发中使用Docker的优势包括:

。一个用于所有团队成员的标准开发环境

。更新的依赖性集中化以及在任何地方都能使用相同的容器

。在开发和生产中完全相同的环境

。修复了可能只会出现在生产环境中的潜在问题

为什么使用Docker运行一个Go Web应用程序?

多数Go应用程序时简单的二进制文件。这就引发一个问题 - 为什么使用Docker运行一个Go应用程序?一些使用Docker运行Go的理由包括:

。Web应用程序通常都有模版和配置文件。Docker有助于保持这些文件与二进制文件的同步

。Docker确保了在开发或生产中完全相同的配置。很多时候当应用程序可以在开发环境中正常工作时,在生产环境去无法正常工作。使用DOcker则把你从对这些问题的担心中解放了出来。

。在一个大型的团队中主机、操作系统及所安装的软件可能存在很大的不同。Docker提供了一种机制来确保一致的开发环境配置。这将提升团队的生产力并且在开发阶段减少冲突和可避免问题的发生。

创建一个简单的Go Web应用程序

在本文中味了演示,我们会用Go创建一个简单的Web应用程序。这个我们称之为MathApp的应用程序将:

。探索不同数学运算的路径

。在视图中使用html模版

。使用一个可配置的文件来定制化该应用程序

。包含所选功能的测试

访问 /sum/3/6 将显示一个包含3与6相加后结果的页面。同样的,访问 /product/3/6 将显示一个3和6乘积的页面。

在本文中我们使用 Beego 框架。请注意你可以为你的应用亨旭使用任何框架(或者什么也不用)。

最终的目录结构

完成之后,MathApp的目录结构应该看起来如下:

MathApp

├── conf

│   └── app.conf

├── main.go

├── main_test.go

└── views

    ├── invalid-route.html

    └── result.html

我们假设 MathApp 目录位于 /app 目录之中。

应用程序的主文件时 main.go ,为主应用程序的根目录中。这个文件包含该应用的所有功能。一些 main.go 中的功能是使用 main_test.go 来测试的。

views文件夹中包含视图文件 invald-route.html 和 result.html 。配置文件 app.conf 位于 conf 文件夹中。 Beego 使用该文件来定制化应用程序。

应用程序文件的内容

应用程序主文件(main.go)包含所有的应用程序逻辑。该文件的内容如下:

*// main.go*



**package** main



**import** (

    "strconv"



    "github.com/astaxie/beego"

)



*// The main function defines a single route, its handler*

*// and starts listening on port 8080 (default port for Beego)*

**func** main() {

    */* This would match routes like the following:*

*/sum/3/5*

*/product/6/23*

*...*

**/*

    beego.Router("/:operation/:num1:int/:num2:int", &mainController{})

    beego.Run()

}



*// This is the controller that this application uses*

**type** mainController **struct** {

    beego.Controller

}



*// Get() handles all requests to the route defined above*

**func** (c *mainController) Get() {

    *//Obtain the values of the route parameters defined in the route above*

    operation := c.Ctx.Input.Param(":operation")

    num1, _ := strconv.Atoi(c.Ctx.Input.Param(":num1"))

    num2, _ := strconv.Atoi(c.Ctx.Input.Param(":num2"))



    *//Set the values for use in the template*

    c.Data["operation"] = operation

    c.Data["num1"] = num1

    c.Data["num2"] = num2

    c.TplName = "result.html"



    *// Perform the calculation depending on the \'operation\' route parameter*

    **switch** operation {

    **case** "sum":

        c.Data["result"] = add(num1, num2)

    **case** "product":

        c.Data["result"] = multiply(num1, num2)

    **default**:

        c.TplName = "invalid-route.html"

    }

}



**func** add(n1, n2 int) int {

    **return** n1 + n2

}



**func** multiply(n1, n2 int) int {

    **return** n1 * n2

}

在你的应用程序中,它可能被分割到多个文件中。然而,针对本教程的目的,我们希望事情简单化。

测试文件的内容

main.go文件有一些需要测试的功能。对于这些功能的测试可以在main_test.go中找到。该文件的内容如下:

// main_test.go



package main



import "testing"



func TestSum(t *testing.T) {

if add(2, 5) != 7 {

    t.Fail()

}

if add(2, 100) != 102 {

    t.Fail()

}

if add(222, 100) != 322 {

    t.Fail()

}

}



func TestProduct(t *testing.T) {

if multiply(2, 5) != 10 {

    t.Fail()

}

if multiply(2, 100) != 200 {

    t.Fail()

}

if multiply(222, 3) != 666 {

    t.Fail()

}

}

如果你想进行持续的部署,那么对你的应用程序进行测试是特别有用的。如果你有了足够的测试,那么你可以持续地部署而不必担心在你的应用程序中出现错误。

视图文件内容

视图文件时HTML模版。应用程序使用它们来显示对请求的应答。result.html的内容如下:

<!-- result.html --><!-- This file is used to display the result of calculations --><!doctype html><html><head><title>MathApp - {{.operation}}</title></head><body>

    The {{.operation}} of {{.num1}} and {{.num2}} is {{.result}}

</body></html>



invalid-route.html的内容如下:



<!-- invalid-route.html --><!-- This file is used when an invalid operation is specified in the route --><!doctype html><html><head><title>MathApp</title><meta name="viewport" content="width=device-width, initial-scale=1"><meta charset="UTF-8"></head><body>

    Invalid operation

</body></html>

配置文件的内容

app.conf是Beego用于配置应用程序的文件。它的内容如下:

; app.conf

appname = MathApp

httpport = 8080

runmode = dev

在这个文件中:

。appname是应用程序将要运行的进程的名字

。httpport是应用程序将要监听的的端口

。runmode声明了应用程序将要运行的模式。有效的指包括dev用于开发而prod用于生产。

在开发中使用Docker

本节将介绍在开发过程中使用Docker的好处,并且向你展示在开发中使用Docker的必须步骤。

配置Docker用于开发

我们将使用dockerfile来配置Docker以便用于开发。针对开发环境,对其的配置应该满足以下的要求:

。我们将使用上一节所提及的应用程序

。这些文件无论从容器的内部还是外部都可以访问

。我们将使用beego自带的bee工具。它用于在开发过程中在线地重新加载应用程序(在Docker容器的内部)

。Docker将为应用程序开放8080端口

。在我们的主机上,应用程序保存在/app/MathApp中

。在Docker容器中,应用程序保存在/go/src/MathApp中

。我们将为开发所创建的Docker image的名字是ma-image

。我们将要运行的Docker容器的名字是ma-instance

步骤一 - 创建Dockerfile

如下的Dockerfile可以满足以上的要求:

**FROM** golang:1.6



*# Install beego and the bee dev tool*

**RUN** go get github.com/astaxie/beego && go get github.com/beego/bee



*# Expose the application on port 8080*

**EXPOSE** 8080



*# Set the entry point of the container to the bee command that runs the*

*# application and watches for changes*

**CMD** ["bee", "run"]

第一行,

FROM golang:1.6

将Go的官方映像文件作为基础映像。该映像文件预安装了 Go 1.6 . 该映像已经把 $GOPATH 的值设置到了 /go 。所有安装在 /go/src 中的包将能够被go命令访问。

第二行,

RUN go get github.com/astaxie/beego && go get github.com/beego/bee

安装 beego 包和 bee 工具。 beego 包将在应用程序中使用。 bee 工具用语在开发中再现地重新加载我们的代码。

第三行,

EXPOSE 8080

在开发主机上利用容器为应用程序开放8080端口。

最后一行,

CMD ["bee", "run"]

使用bee命令启动应用程序的在线重新加载。

步骤二 - 构建image

一旦创建了Docker file,运行如下的命令来创建image:

docker build -t ma-image .

执行以上的命令将创建名为ma-image的image。该image现在可以用于使用该应用程序的任何人。这将确保这个团队能够使用一个统一的开发环境。

为了查看你的系统上的image列表,运行如下的命令:

docker images

这行该命令将输出与以下类似的内容:

REPOSITORY  TAG     IMAGE ID      CREATED         SIZE

ma-image    latest  8d53aa0dd0cb  31 seconds ago  784.7 MB

golang      1.6     22a6ecf1f7cc  5 days ago      743.9 MB

注意image的确切名字和编号可能不同,但是,你应该至少看到列表中有 golang 和 ma-image image。

步骤三 - 运行容器

一旦 ma-image 已经完成,你可以使用以下的命令启动一个容器:

docker run -it --rm --name ma-instance -p 8080:8080 \\

-v /app/MathApp:/go/src/MathApp -w /go/src/MathApp ma-image

让我们分析一下上面的命令来看看它做了什么。

。docker run命令用于从一个image上启动一个容器

。-it 标签以交互的方式启动容器

。--rm 标签在容器关闭后将会将其清除

。--name ma-instance 将容器命名为ma-instance

。-p 8080:8080 标签允许通过8080端口访问该容器

。-v /app/MathApp:/go/src/MathApp更复杂一些。它将主机的/app/MathApp映射到容器中的/go/src/MathApp。这将使得开发文件在容器的内部和外部都可以访问。

。ma-image 部分声明了用于容器的image。

执行以上的命令将启动Docker容器。该容器为你的应用程序开发了8080端口。无论何时你做了变更,它都将自动地重构你的应用程序。你将在console(控制台)上看到以下的输出:

bee   :1.4.1

beego :1.6.1

Go    :go version go1.6 linux/amd64



2016/04/10 13:04:15 [INFO] Uses \'MathApp\' as \'appname\'

2016/04/10 13:04:15 [INFO] Initializing watcher...

2016/04/10 13:04:15 [TRAC] Directory(/go/src/MathApp)

2016/04/10 13:04:15 [INFO] Start building...

2016/04/10 13:04:18 [SUCC] Build was successful

2016/04/10 13:04:18 [INFO] Restarting MathApp ...

2016/04/10 13:04:18 [INFO] ./MathApp is running...

2016/04/10 13:04:18 [asm_amd64.s:1998][I] http server Running on :8080

为了检查相关的设置,可以在浏览器中访问 http://localhost:8080/sum/4/5 。你讲看到与下面类似的东西:

注意:这里假定你是在使用本地主机

步骤四 - 开发应用程序

现在,让我们看看这将如何在开发阶段提供帮助。在完成以下的操作时请确保容器在运行。在## main.go ##文件中,将第34行:

c.Data["operation"] = operation

改成:

c.Data["operation"] =  "real " + operation

在你保存修改的一刻,你讲看到类似以下的输出:

2016/04/10 13:17:51 [EVEN] "/go/src/MathApp/main.go": MODIFY

2016/04/10 13:17:51 [SKIP] "/go/src/MathApp/main.go": MODIFY

2016/04/10 13:17:52 [INFO] Start building...

2016/04/10 13:17:56 [SUCC] Build was successful

2016/04/10 13:17:56 [INFO] Restarting MathApp ...

2016/04/10 13:17:56 [INFO] ./MathApp is running...

2016/04/10 13:17:56 [asm_amd64.s:1998][I] http server Running on :8080

为了检查该变更,在你的浏览器中访问 http://localhost:8080/sum/4/5 。你将看到类似下面的输出:

如你所见,你的应用程序在保存了修改之后自动地编译并提供了服务。

在生产中使用Docker

本节将讲解如何在一个Docker容器中部署Go应用程序。我们将使用Semaphore来完成以下的工作:

。当一个变更被推送到git资料库后自动地进行编译

。自动地运行测试

。如果编译成功并且通过测试就创建一个Docker映像

。将Docker映像文件推送入Docker Hub

。更新服务器以便使用最新的Docker映像

创建一个生产用的Dockerfile

在开发过程中,我们的目录有如下的结构:

MathApp

├── conf

│   └── app.conf

├── main.go

├── main_test.go

└── views

├── invalid-route.html

└── result.html

由于我们想要从项目中构建Docker映像,我们需要创建一个将用于生产环境的Dockerfile。在项目的根目录中创建一个Dockerfile。新的目录结构如下所示:

MathApp

├── conf

│   └── app.conf

├── Dockerfile

├── main.go

├── main_test.go

└── views

├── invalid-route.html

└── result.html

在Dockerfile文件中输入以下的内

以上是关于如何使用Docker部署一个Go Web应用程序的主要内容,如果未能解决你的问题,请参考以下文章

如何使用docker部署vue项目

使用docker部署一个go应用

使用docker部署一个go应用

使用docker部署node项目(一)

如何使用docker部署web应用

docker部署react项目