如何在 Ubuntu 18.04 上使用 Docker 和 Nginx 部署 Go Web 应用程序

作为Write for DOnations计划的一部分,作者选择了免费和开源基金来接受捐赠

介绍

Docker是当今最常用的容器化软件。它使开发人员能够轻松地将应用程序与其环境打包在一起,从而实现更快的迭代周期和更高的资源效率,同时在每次运行时提供相同的所需环境。Docker Compose是一种容器编排工具,可满足现代应用程序的需求。它允许您同时运行多个互连的容器。与手动运行容器不同,编排工具使开发人员能够同时控制、扩展和扩展容器。

使用 Nginx 作为前端 Web 服务器的好处是它的性能、可配置性和 TLS 终止,这使应用程序无需完成这些任务。nginx-proxy是一个用于 Docker 容器的自动化系统,它极大地简化了配置 Nginx 作为反向代理的过程。它的Let’s Encrypt 插件可以伴随nginx-proxy代理容器证书的自动生成和更新。

在本教程中,您将部署一个示例 Go Web 应用程序,其中gorilla/mux作为请求路由器,Nginx 作为 Web 服务器,所有这些都在 Docker 容器内,由 Docker Compose 编排。您将使用nginx-proxyLet’s Encrypt 附加组件作为反向代理。在本教程结束时,您将部署一个 Go Web 应用程序,该应用程序可在您的域中使用多个路由访问,使用 Docker,并使用 Let’s Encrypt 证书进行保护。

先决条件

第 1 步 – 创建示例 Go Web 应用程序

在此步骤中,您将设置工作区并创建一个简单的 Go Web 应用程序,稍后您将对其进行容器化。Go 应用程序将使用强大的gorilla/mux请求路由器,因其灵活性和速度而被选中。

在本教程中,您将所有数据存储在~/go-docker. 运行以下命令来执行此操作:

  • mkdir ~/go-docker

导航到它:

  • cd ~/go-docker

您将示例 Go 网络应用程序存储在名为main.go. 使用文本编辑器创建它:

  • nano main.go

添加以下几行:

~/go-docker/main.go
package main

import (
    "fmt"
    "net/http"

    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()

    r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "<h1>This is the homepage. Try /hello and /hello/Sammy\n</h1>")
    })

    r.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "<h1>Hello from Docker!\n</h1>")
    })

    r.HandleFunc("/hello/{name}", func(w http.ResponseWriter, r *http.Request) {
        vars := mux.Vars(r)
        title := vars["name"]

        fmt.Fprintf(w, "<h1>Hello, %s!\n</h1>", title)
    })

    http.ListenAndServe(":80", r)
}

您首先导入net/httpgorilla/mux包,它们提供 HTTP 服务器功能和路由。

gorilla/mux包实现了更简单、更强大的请求路由器和调度程序,同时保持与标准路由器的接口兼容性。在这里,您实例化一个新mux路由器并将其存储在变量中r然后,定义三条路线://hello,和/hello/{name}第一个 ( /) 用作主页,您包含该页面的消息。第二个 ( /hello) 向访问者返回问候。对于第三个路由 ( /hello/{name}),您指定它应将名称作为参数并显示插入了名称的问候消息。

在文件的末尾,您启动 HTTP 服务器http.ListenAndServe并指示它80使用您配置的路由器侦听 port

保存并关闭文件。

在运行你的 Go 应用程序之前,你首先需要编译并打包它以在 Docker 容器中执行。Go 是一种编译语言,因此在程序运行之前,编译器会将编程代码翻译成可执行的机器代码。

您已经设置了工作区并创建了一个示例 Go Web 应用程序。接下来,您将nginx-proxy使用自动化的 Let’s Encrypt 证书供应进行部署

第 2 步 – 使用 Let’s Encrypt 部署 nginx-proxy

使用 HTTPS 保护您的应用程序非常重要。为此,您将nginx-proxy通过 Docker Compose 及其 Let’s Encrypt插件进行部署这可以保护使用 代理的 Docker 容器nginx-proxy,并通过自动处理 TLS 证书创建和更新来通过 HTTPS 保护您的应用程序。

您将把 Docker Compose 配置存储nginx-proxy在一个名为nginx-proxy-compose.yaml. 通过运行创建它:

  • nano nginx-proxy-compose.yaml

将以下行添加到文件中:

~/go-docker/nginx-proxy-compose.yaml
version: '2'

services:
  nginx-proxy:
    restart: always
    image: jwilder/nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/etc/nginx/vhost.d"
      - "/usr/share/nginx/html"
      - "/var/run/docker.sock:/tmp/docker.sock:ro"
      - "/etc/nginx/certs"

  letsencrypt-nginx-proxy-companion:
    restart: always
    image: jrcs/letsencrypt-nginx-proxy-companion
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    volumes_from:
      - "nginx-proxy"

在这里,您定义了两个容器:一个用于nginx-proxy其 Let’s Encrypt 插件 ( letsencrypt-nginx-proxy-companion)。对于代理,您指定 image jwilder/nginx-proxy,公开并映射 HTTP 和 HTTPS 端口,最后定义容器可访问的卷,用于持久化 Nginx 相关数据。

在第二个块中,您为 Let’s Encrypt 附加配置命名图像。然后,您通过定义一个卷来配置对 Docker 套接字的访问,然后从代理容器继承现有的卷。两个容器的restart属性都设置为always,这指示 Docker 始终保持它们的运行(在崩溃或系统重新启动的情况下)。

保存并关闭文件。

nginx-proxy通过运行部署

  • docker-compose -f nginx-proxy-compose.yaml up -d

Docker Compose 通过-f标志接受自定义命名文件up命令运行容器,-d分离模式标志指示它在后台运行容器。

您的最终输出将如下所示:

Output
Creating network "go-docker_default" with the default driver Pulling nginx-proxy (jwilder/nginx-proxy:)... latest: Pulling from jwilder/nginx-proxy a5a6f2f73cd8: Pull complete 2343eb083a4e: Pull complete ... Digest: sha256:619f390f49c62ece1f21dfa162fa5748e6ada15742e034fb86127e6f443b40bd Status: Downloaded newer image for jwilder/nginx-proxy:latest Pulling letsencrypt-nginx-proxy-companion (jrcs/letsencrypt-nginx-proxy-companion:)... latest: Pulling from jrcs/letsencrypt-nginx-proxy-companion ... Creating go-docker_nginx-proxy_1 ... done Creating go-docker_letsencrypt-nginx-proxy-companion_1 ... done

您已经nginx-proxy使用 Docker Compose部署了它的 Let’s Encrypt 伴侣。接下来,您将为 Go Web 应用程序创建 Dockerfile。

第 3 步 – Docker 化 Go Web 应用程序

在本节中,您将创建一个 Dockerfile,其中包含有关 Docker 如何为您的 Go Web 应用程序创建不可变映像的说明。Docker 使用 Dockerfile 中的指令构建一个不可变的应用程序映像(类似于容器的快照)。每次运行基于特定图像的容器时,图像的不变性保证了相同的环境。

Dockerfile用你的文本编辑器创建

  • nano Dockerfile

添加以下几行:

~/go-docker/Dockerfile
FROM golang:alpine AS build
RUN apk --no-cache add gcc g++ make git
WORKDIR /go/src/app
COPY . .
RUN go mod init webserver
RUN go mod tidy
RUN GOOS=linux go build -ldflags="-s -w" -o ./bin/web-app ./main.go

FROM alpine:3.13
RUN apk --no-cache add ca-certificates
WORKDIR /usr/bin
COPY --from=build /go/src/app/bin /go/bin
EXPOSE 80
ENTRYPOINT /go/bin/web-app --port 80

这个 Dockerfile 有两个阶段。第一阶段使用golang:alpine基础,其中包含在 Alpine Linux 上预安装的 Go。

然后安装gccg++makegit作为 Go 应用程序的必要编译工具。您将工作目录设置为/go/src/app,它位于默认的GOPATH 下您还将当前目录的内容复制到容器中。第一阶段以递归方式从代码中获取使用的包并编译main.go文件以在没有符号和调试信息的情况下发布(通过传递-ldflags="-s -w")。当你编译一个 Go 程序时,它会保留一个单独的二进制部分,用于调试,但是,这些额外的信息使用内存,在部署到生产环境时不需要保留。

第二阶段基于alpine:3.13(Alpine Linux 3.13)。它安装受信任的 CA 证书,将编译的应用程序二进制文件从第一阶段复制到当前映像,公开端口80,并将应用程序二进制文件设置为映像入口点。

保存并关闭文件。

你已经为你的 Go 应用程序创建了一个 Dockerfile,它将获取它的包,编译它以发布,并在容器创建时运行它。在下一步中,您将创建 Docker Composeyaml文件并通过在 Docker 中运行它来测试应用程序。

第 4 步 – 创建并运行 Docker Compose 文件

现在,您将创建 Docker Compose 配置文件并编写运行您在上一步中创建的 Docker 映像所需的配置。然后,您将运行它并检查它是否正常工作。通常,Docker Compose 配置文件指定应用程序所需的容器、它们的设置、网络和卷。您还可以指定这些元素可以同时作为一个开始和停止。

您将把 Go Web 应用程序的 Docker Compose 配置存储在一个名为go-app-compose.yaml. 通过运行创建它:

  • nano go-app-compose.yaml

将以下行添加到此文件中:

~/go-docker/go-app-compose.yaml
version: '2'
services:
  go-web-app:
    restart: always
    build:
      dockerfile: Dockerfile
      context: .
    environment:
      - VIRTUAL_HOST=your_domain
      - LETSENCRYPT_HOST=your_domain

请记住your_domain用您的域名替换两次。保存并关闭文件。

此 Docker Compose 配置包含一个容器 ( go-web-app),这将是您的 Go Web 应用程序。它使用您在上一步中创建的 Dockerfile 构建应用程序,并将包含源代码的当前目录作为构建上下文。此外,它还设置了两个环境变量:VIRTUAL_HOSTLETSENCRYPT_HOSTnginx-proxy用于VIRTUAL_HOST知道从哪个域接受请求。LETSENCRYPT_HOST指定生成TLS证书的域名,必须与 相同VIRTUAL_HOST,除非指定了通配符域。

现在,您将使用以下命令通过 Docker Compose 在后台运行 Go Web 应用程序:

  • docker-compose -f go-app-compose.yaml up -d

您的最终输出将如下所示:

Output
Creating network "go-docker_default" with the default driver Building go-web-app Step 1/12 : FROM golang:alpine AS build ---> b97a72b8e97d ... Successfully tagged go-docker_go-web-app:latest WARNING: Image for service go-web-app was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`. Creating go-docker_go-web-app_1 ... done

如果您查看运行命令后显示的输出,Docker 会根据 Dockerfile 中的配置记录构建应用程序映像的每个步骤。

您现在可以导航到查看您的主页。在您的 Web 应用程序的家庭地址中,您会看到作为您在第一步中定义路线的结果的页面https://your_domain//

这是主页。 试试 /hello 和 /hello/Sammy

现在导航到. 您将看到您在代码中为步骤 1 中路由定义的消息https://your_domain/hello/hello

来自 Docker 的你好!

最后,尝试追加一个名称到您的Web应用程序的地址来测试其他途径,如:https://your_domain/hello/Sammy

你好,萨米!

注意:如果您收到有关无效 TLS 证书的错误,请等待几分钟,让 Let’s Encrypt 加载项配置证书。如果您在短时间内仍然收到错误消息,请根据此步骤中显示的命令和配置仔细检查您输入的内容。

您已经创建了 Docker Compose 文件并编写了用于在容器内运行 Go 应用程序的配置。最后,您导航到您的域以检查gorilla/mux路由器设置是否正确地为您的 Dockerized Go Web 应用程序提供请求。

结论

您现在已经在 Ubuntu 18.04 上成功部署了带有 Docker 和 Nginx 的 Go Web 应用程序。使用 Docker,维护应用程序变得不那么麻烦,因为每次运行应用程序时,执行的环境都保证相同。大猩猩/ MUX封装具有出色的文档,并提供更先进的功能,如命名和路由服务静态文件。如需对 Go HTTP 服务器模块的更多控制,例如定义自定义超时,请访问官方文档

觉得文章有用?

点个广告表达一下你的爱意吧 !😁