ZetCode

Go Docker

最后修改时间 2024 年 4 月 11 日

在本文中,我们将介绍如何为 Golang 应用程序使用 Docker。

应用程序容器化是一种操作系统级别的虚拟化方法,用于部署和运行分布式应用程序,而无需为每个应用程序创建完整的虚拟机。通过容器,可以在单个主机上运行多个隔离的应用程序或服务,并访问相同的操作系统内核。容器可以在裸机系统、云实例或虚拟机上运行。

Docker

Docker 是一个供开发人员和系统管理员使用容器构建、运行和共享应用程序的平台。Docker 促进了应用程序的可移植性和可伸缩性。Docker 提供应用程序隔离,从而消除了许多由库和环境差异引起的问题。它有助于自动化开发和部署。借助预定义的社区镜像,开发人员可以节省时间并提高整体体验。

一个 Docker 镜像 是一个只读模板,其中包含创建 Docker 容器的说明。一个 Docker 容器 是镜像的一个可运行实例。

Docker 镜像存储在仓库中。 Docker Hub 是官方 Docker 仓库。 Docker Engine 是底层的客户端-服务器技术,它使用 Docker 的组件和服务来构建和运行容器。

一个 Dockerfile 是一个特殊的文件,其中包含构建 Docker 镜像所需的指令。

$ docker --version
Docker version 20.10.17, build 100c701

这是我们使用的 Docker 版本。

Go Docker hello 示例

在下面的示例中,我们将创建并运行一个非常简单的 Docker 镜像。当我们运行镜像时,将执行一个简单的 Go 应用程序。

main.go
package main

import (
    "fmt"
    "runtime"
)

func main() {

    fmt.Println("Hello there!")

    osv := runtime.GOOS
    fmt.Printf("The OS is: %s\n", osv)
}

这是一个简单的控制台应用程序,它会打印一条消息和底层操作系统的版本。

Dockerfile
# syntax=docker/dockerfile:1

FROM golang:1.18

WORKDIR /app

COPY go.mod .

RUN go mod download

COPY *.go .

RUN go build -o /hello

CMD [ "/hello" ]

Dockerfile 是一系列构建镜像的命令。

# syntax=docker/dockerfile:1

第一行是一个可选的语法解析器指令。该指令指示 Docker 构建器在解析 Dockerfile 时要使用的语法。

FROM golang:1.18

我们将镜像基于社区 `golang:1.18`。

WORKDIR /app

我们需要设置一个构建目录。 `WORKDIR` 命令指示 Docker 将指定目录用作所有后续命令的默认目标。

COPY go.mod .

我们使用 `COPY` 将 `go.mod` 文件复制到我们的项目目录 (/app)。

RUN go mod download

使用 `RUN` 指令,我们运行 `go mod download` 命令来下载我们的 Go 模块。

COPY *.go .

使用 `COPY` 命令,我们将 Go 源代码复制到构建目录。

RUN go build -o /hello

我们构建 Go 程序。我们将可执行文件放在文件系统的根目录。

CMD [ "/hello" ]

使用 `CMD` 命令,我们告诉 Docker 在使用我们的镜像启动容器时要执行什么命令。

$ docker build -t hello .

我们构建镜像并将其命名为 `hello`。

$ docker image ls
REPOSITORY               TAG       IMAGE ID       CREATED          SIZE
hello                    latest    1525ae981450   52 seconds ago   966MB
docker/getting-started   latest    cb90f98fd791   8 weeks ago      28.8MB

我们使用 `docker image ls` 命令列出可用镜像。

$ docker run hello
Hello there!
The OS is: linux

我们运行 hello 镜像。

多阶段构建

多阶段构建允许我们使用多个镜像来构建最终产品。在多阶段构建中,我们在单个 Dockerfile 中拥有多个镜像。

$ docker image ls
REPOSITORY               TAG       IMAGE ID       CREATED          SIZE
hello                    latest    1525ae981450   52 seconds ago   966MB
docker/getting-started   latest    cb90f98fd791   8 weeks ago      28.8MB

当我们查看 hello 镜像的大小,我们会发现它相当大。这是因为镜像包含了构建应用程序所需的所有 Go 工具和库。然而,一旦应用程序构建完成,这些可能就不再需要了。为了解决这个问题,我们使用多阶段构建。

main.go
package main

import (
    "fmt"
    "runtime"
)

func main() {

    fmt.Println("multi-stage build")

    osv := runtime.GOOS
    fmt.Printf("The OS is: %s\n", osv)
}

我们有相同的控制台应用程序。

Dockerfile
# syntax=docker/dockerfile:1

# Build

FROM golang:1.18 AS build

WORKDIR /app

COPY go.mod .

RUN go mod download

COPY *.go .

RUN go build -o /hello

# Deploy 

FROM scratch

WORKDIR /

COPY --from=build /hello /hello

CMD [ "/hello" ]

现在,我们有两个 `FROM` 命令,形成了两个阶段。

FROM golang:1.18 AS build

使用 `AS` 指令,我们创建了一个名为 `build` 的阶段。

FROM scratch

我们为下一个阶段使用了一个最小的 `scratch` 镜像。

COPY --from=build /hello /hello

我们从构建阶段复制构建程序。

CMD [ "/hello" ]

最后,我们设置要运行的程序。

$ docker build -t hello:multistage .

我们构建镜像并为其打上 `multistage` 标签。

$ docker run hello:multistage
multi-stage build
The OS is: linux

我们运行新镜像。

$ docker image ls
REPOSITORY               TAG          IMAGE ID       CREATED          SIZE
hello                    multistage   28c2d0b534eb   6 minutes ago    1.77MB
hello                    latest       1525ae981450   23 minutes ago   966MB
docker/getting-started   latest       cb90f98fd791   8 weeks ago      28.8MB

大小有巨大差异。

Go Docker echo 示例

在下一个示例中,我们将使用 echo 框架创建一个简单的 Web 应用程序。

main.go
package main

import (
    "net/http"

    "github.com/labstack/echo/v4"
)

func main() {

    e := echo.New()

    e.GET("/", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello there!")
    })

    e.Logger.Fatal(e.Start(":8080"))
}

该应用程序有一个文本端点。它监听在 8080 端口。

Dockerfile
# syntax=docker/dockerfile:1

# Build

FROM golang:1.18 AS build

WORKDIR /app

COPY go.mod .
COPY go.sum .

RUN go mod download

COPY *.go .

RUN go build -o /hello

# Deploy 

FROM debian:latest

WORKDIR /

COPY --from=build /hello /usr/local/bin/hello

EXPOSE 8080

ENTRYPOINT [ "/usr/local/bin/hello" ]

`EXPOSE` 指令通知 Docker 容器在运行时监听指定的网络端口。

FROM debian:latest

我们将镜像基于 Debian 镜像。


$ docker build -t web .

Web 构建镜像。

$ docker run -p 8080:8080 web

    ____    __
   / __/___/ /  ___
  / _// __/ _ \/ _ \
 /___/\__/_//_/\___/ v4.7.2
 High performance, minimalist Go web framework
 https://echo.labstack.com
 ____________________________________O/_______
                                     O\
 ⇨ http server started on [::]:8080
 

我们运行镜像。容器的 8080 端口映射到我们计算机的 8080 端口。

$ curl localhost:8080
Hello there!

我们使用 curl 发送一个 GET 请求。

来源

Go Docker 镜像

在本文中,我们学习了 Go 和 Docker。

作者

我叫 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Go 教程