跳转到主要内容

Docker 是一项真正出色的技术,它允许我们在一个简单的 Dockerfile 中指定我们希望所有应用程序存在的环境。 这有效地允许更轻松的协作,并使我们摆脱了在全球开发团队中非常普遍的“它在我的机器上工作”的问题。

因此,我觉得写一篇关于如何使用 Docker 容器化技术有效地容器化 Go 应用程序的教程是一个好主意。

在本教程结束时,您应该能够很好地掌握以下内容:

  • Docker 的基础知识以及它对我们开发人员的用处
  • 为你的 Go 应用程序编写一个简单的 Dockerfile
  • 最后,我们将看看如何轻松地将这些应用程序部署到 DigitalOcean

为什么选择数字海洋? 我们会偷偷地希望他们开始赞助我即将发布的一些视频教程,这样我就可以开始全职专注于编写内容了! :D

视频教程

https://youtu.be/lIbdPrUpGz4

为什么选择 Docker?


在过去的几年里,我在许多不同的环境中多次被问到这个问题,并且我已经向各种经验水平的开发人员讨论了这项特殊的技术。

当您处理需要复杂环境设置才能运行的关键应用程序时,Docker 的主要优势变得显而易见。本质上,您的应用程序需要运行的所有内容都应该在应用程序根目录的 Dockerfile 中定义。

这包括环境变量、特定的 Go 版本或构建步骤,或关于需要挂载的目录的说明等内容。

通过花时间在 Dockerfile 中预先声明这些,您基本上可以使您的应用程序在任何可以运行 docker 的机器上移植。如果您有新的开发人员加入团队,您只需将他们指向其中已定义 Dockerfile 的存储库,给他们启动命令以在本地运行它,然后他们就可以设置并准备开始在您的系统上工作。

我们的 Go 代码


本教程将有效地充当这种可移植性的完美示例,在本文的最后,如果我的工作做得对,您应该能够使用简单的 docker 命令在本地运行此应用程序。

注意 - 对于这个特定的教程,我将从我的另一个教程中窃取源代码,内容是在 Go 中构建一个简单的 Web 服务器。

my-project/main.go

package main

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

func main() {

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
    })

    http.HandleFunc("/hi", func(w http.ResponseWriter, r *http.Request){
        fmt.Fprintf(w, "Hi")
    })

    log.Fatal(http.ListenAndServe(":8081", nil))

}

太棒了,如果我们想运行它,那么我们可以通过运行 go run main.go 来实现,这将启动 http://localhost:8081 上的服务器。

编写 Dockerfile


现在我们有了服务器,让我们开始编写 Dockerfile 并构建我们新诞生的 Go 应用程序所在的容器。

my-project/Dockerfile

## We specify the base image we need for our
## go application
FROM golang:1.12.0-alpine3.9
## We create an /app directory within our
## image that will hold our application source
## files
RUN mkdir /app
## We copy everything in the root directory
## into our /app directory
ADD . /app
## We specify that we now wish to execute 
## any further commands inside our /app
## directory
WORKDIR /app
## we run go build to compile the binary
## executable of our Go program
RUN go build -o main .
## Our start command which kicks off
## our newly created binary executable
CMD ["/app/main"]


现在我们已经定义了我们的 Go 应用程序在 Dockerfile 中运行所需的一切,我们现在可以使用这个文件构建一个镜像。为此,我们需要运行以下命令:

$ docker build -t my-go-app .
Sending build context to Docker daemon   5.12kB
Step 1/6 : FROM golang:1.12.0-alpine3.9
 ---> d4953956cf1e
Step 2/6 : RUN mkdir /app
 ---> Using cache
 ---> be346f9ff24f
Step 3/6 : ADD . /app
 ---> eb420da7413c
Step 4/6 : WORKDIR /app
 ---> Running in d623a88e4a00
Removing intermediate container d623a88e4a00
 ---> ffc439c5bec5
Step 5/6 : RUN go build -o main .
 ---> Running in 15805f4f7685
Removing intermediate container 15805f4f7685
 ---> 31828faf8ae4
Step 6/6 : CMD ["/app/main"]
 ---> Running in 9d54463b7e84
Removing intermediate container 9d54463b7e84
 ---> 3f9244a1a240
Successfully built 3f9244a1a240
Successfully tagged my-go-app:latest


你会看到这个构建命令的输出已经通过了我们在 Dockerfile 中定义的所有 6 行作为单独的步骤。现在你第一次运行它可能需要相当长的时间,因为它需要拉下任何依赖项,但是在这个初始加载之后,构建你的图像应该是相当快的,因为 Docker 巧妙地缓存了每个步骤的结果以确保快速后续构建的构建时间。

我们现在可以通过输入 docker images 来验证我们的图像是否存在于我们的机器上:

$ docker images
REPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE
my-go-app                                  latest              3f9244a1a240        2 minutes ago       355MB


太棒了,我们现在有了一个 docker 镜像,我们随后可以在我们的机器上运行它!

为了运行这个新创建的镜像,我们可以使用 docker run 命令并传入我们想要映射到的端口和我们希望运行的镜像。

$ docker run -p 8080:8081 -it my-go-app

 

  • -p 8080:8081 - 这会暴露我们的应用程序,该应用程序在本地机器上的 http://localhost:8080 上的容器内的端口 8081 上运行。
  • -it - 此标志指定我们希望以交互模式运行此映像,并为此容器进程提供一个 tty。
  • my-go-app - 这是我们要在容器中运行的映像的名称。

太棒了,如果我们在浏览器中打开 http://localhost:8080,我们应该会看到我们的应用程序正在成功响应 Hello,“/”。

在后台运行我们的容器


你会注意到,如果我们在终端中按 ctrl-c 这个,它会杀死容器。如果我们想让它在后台永久运行,您可以将 -it 替换为 -d 以在分离模式下运行此容器。

为了查看在后台运行的容器列表,您可以使用 docker ps 输出如下内容:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
70fcc9195865        my-go-app           "/app/main"              5 seconds ago       Up 3 seconds        0.0.0.0:8080->8081/tcp   silly_swirles


如果我们想杀死这个容器,我们可以使用 docker kill 命令并传入在终端中打印出来的容器 ID。

使用 Go 模块和 Docker


让我们看一个具有导入模块的更复杂的示例。在这种情况下,我们需要在 Dockerfile 中添加一个步骤,该步骤在执行 go build 命令之前完成下载依赖项的工作:

Dockerfile

FROM golang:1.12.0-alpine3.9
RUN mkdir /app
ADD . /app
WORKDIR /app
## Add this go mod download command to pull in any dependencies
RUN go mod download
## Our project will now successfully build with the necessary go libraries included.
RUN go build -o main .
## Our start command which kicks off
## our newly created binary executable
CMD ["/app/main"]


将我们的 Docker 应用程序部署到 DigitalOcean


现在我们有了一个功能齐全的容器化 Go 应用程序,是时候把它放在某个地方,让全世界都能看到它的辉煌!

到目前为止,我还没有太多机会使用 DigitalOcean,所以我将本教程作为尝试他们的一些服务和功能的机会,这样我就不会永远局限于 AWS 的世界.

第 1 步 - 推送到 Github 存储库


无论您在做什么,将源代码存储在 GitHub 存储库中始终是一种好习惯。进一步来说,如果我们开始使用诸如 Jenkins 或其他持续部署工具之类的工具来自动化部署任务,那么将您的代码放在源代码控制系统中是其中至关重要的一部分。

出于本教程的目的,我在这里创建了一个新存储库:TutorialEdge/go-docker-tutorial。接下来,我要提交并将我的代码推送到这个存储库,如下所示:

$ git init
$ git remote add origin https://github.com/TutorialEdge/go-docker-tutorial.git
$ git add .
$ git commit -m "Initial Commit"
$ git push origin master


当我们下次刷新我们的 GitHub 存储库时,我们应该看到我们的源代码已经成功提交并推送了!

第 2 步 - 创建一个 Droplet 并 ssh-ing 到该 Droplet


太棒了,所以下一步是在我们的 DigitalOcean 帐户中启动并运行 Droplet,然后我们可以将 Docker 容器部署到该帐户。

使用 One-click apps Docker 18.09.2~3 on 18.04 映像创建一个新的 droplet,计划为 5 美元/月,然后添加您的 ssh 密钥,以便您随后可以 ssh 到该新创建的服务器。

第 3 步 - 部署我们的应用程序


最后,获取新 Droplet 的 IP 地址并 ssh 进入其中。一旦你 ssh-ed 进入它,你可以部署我们新的 docker 化的 Go 应用程序,首先从 GitHub 拉取它,然后使用我们在本地机器上使用的相同的 2 个 docker 命令!

$ ssh root@1.2.3.4
$ git clone https://github.com/tutorialedge/go-docker-tutorial.git app/
$ docker build -t my-go-app .
$ docker run -d -p 8080:8081 my-go-app


运行这些命令后,您现在应该能够导航到 http://1.2.3.4:8080,将 1.2.3.4 替换为新启动的 Droplet 的 IPv4 地址。您现在应该会在浏览器中看到 Hello World 打印出来了!

结论


希望本教程对您有所帮助!如果您对可以改进的内容有任何建议,或者您希望看到哪些其他内容,请在下面的建议框中告诉我!

文章链接