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 打印出来了!
结论
希望本教程对您有所帮助!如果您对可以改进的内容有任何建议,或者您希望看到哪些其他内容,请在下面的建议框中告诉我!
- 登录 发表评论