將 go 代碼打包成 docker 鏡像

概述

在本教程中,你將生成一個容器映像。該映像包括運行應用程序所需的一切:編譯的應用程序二進制文件、運行時、庫以及應用程序所需的所有其他資源。

前置條件

若要完成本教程,需要滿足以下條件:

程序

該應用程序提供兩個 HTTP endpoint:

應用程序偵聽由環境變量 PORT 定義的 TCP 端口。缺省值爲 8080

該應用程序的完整源代碼位於 GitHub 上:github.com/docker/docker-gs-ping。我們鼓勵您 fork 它並隨心所欲地嘗試它。

要繼續,請將應用程序存儲庫克隆到本地計算機:

git clone https://github.com/docker/docker-gs-ping

如果您熟悉 Go,該應用程序 main.go 的文件非常簡單

package main

import (
 "net/http"
 "os"

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

func main() {

 e := echo.New()

 e.Use(middleware.Logger())
 e.Use(middleware.Recover())

 e.GET("/", func(c echo.Context) error {
  return c.HTML(http.StatusOK, "Hello, Docker! <3")
 })

 e.GET("/health", func(c echo.Context) error {
  return c.JSON(http.StatusOK, struct{ Status string }{Status: "OK"})
 })

 httpPort := os.Getenv("PORT")
 if httpPort == "" {
  httpPort = "8080"
 }

 e.Logger.Fatal(e.Start(":" + httpPort))
}

// Simple implementation of an integer minimum
// Adapted from: https://gobyexample.com/testing-and-benchmarking
func IntMin(a, b int) int {
 if a < b {
  return a
 }
 return b
}

冒煙測試應用程序

啓動應用程序並確保它正在運行。打開終端並導航到將項目存儲庫克隆到的目錄。從現在開始,本指南將此目錄稱爲項目目錄

go run main.go

這應該將服務器編譯並啓動爲前臺應用程序,輸出橫幅,如下圖所示。

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

通過訪問 上的 http://localhost:8080 應用程序來運行快速冒煙測試。您可以使用自己喜歡的 Web 瀏覽器,甚至可以在終端中使用 curl 命令:

curl http://localhost:8080/
Hello, Docker! <3

現在,您可以將其容器化了。

爲應用程序創建 Dockerfile

告訴 Docker 要爲應用程序使用哪個基礎映像:

# syntax=docker/dockerfile:1

FROM golang:1.19

Docker 鏡像可以從其他鏡像繼承。因此,您可以使用已經具有所有必要工具和庫的官方 Go 映像來編譯和運行 Go 應用程序,而不是從頭開始創建自己的基礎映像。

現在,您已經爲即將推出的容器映像定義了基礎映像,可以開始在它之上進行構建

若要在運行其餘命令時簡化操作,請在要生成的映像中創建一個目錄。這也指示 Docker 使用此目錄作爲所有後續命令的默認目標。這樣你就不必在 中鍵入完整的文件路徑 Dockerfile ,相對路徑將基於此目錄

WORKDIR /app

通常,一旦你下載了一個用 Go 編寫的項目,你要做的第一件事就是安裝編譯它所需的模塊。請注意,基礎映像已包含工具鏈,但源代碼尚未包含在其中。

因此,在運行映像 go mod download 之前,需要將 go.mod 和 go.sum 文件複製到其中。使用命令 COPY 執行此操作。

在最簡單的形式中,該 COPY 命令採用兩個參數。第一個參數告訴 Docker 要將哪些文件複製到映像中。最後一個參數告訴 Docker 您希望將該文件複製到何處。

將 go.mod and go.sum 文件複製到您的項目目錄中,由於您使用了 WORKDIR ,該目錄是映像中的當前目錄 /app ( ./ )。與一些現代 shell 似乎對尾部斜槓的使用漠不關心 ( ),並且可以弄清楚用戶的意思(大多數時候 / ),Docker COPY 的命令在解釋尾部斜槓時非常敏感。

COPY go.mod go.sum ./

現在,您已經在要構建的 Docker 映像中擁有模塊文件,也可以使用該命令在該命令中運行該 RUN 命令 go mod download 。這與在計算機上本地運行 go 的工作方式完全相同,但這次這些 Go 模塊將安裝到映像中的目錄中。

RUN go mod download

接下來需要做的是將源代碼複製到映像中。您將像之前使用模塊文件一樣使用該 COPY 命令。

COPY *.go ./

此 COPY 命令使用通配符將主機上當前目錄(所在的 Dockerfile 目錄)中擴展 .go 名的所有文件複製到映像內的當前目錄中。

RUN CGO_ENABLED=GOOS=linux go build -o /docker-gs-ping

該命令將代碼編譯成一個二進制文件,該二進制文件被命名 docker-gs-ping 並位於您正在構建的映像的文件系統的根目錄中。您可以將二進制文件放入該映像中您想要的任何其他位置。

現在,剩下要做的就是告訴 Docker 在使用鏡像啓動容器時要運行什麼命令。您可以使用以下 CMD 命令執行此操作:

CMD ["/docker-gs-ping"]

以下是完整的 Dockerfile :

# syntax=docker/dockerfile:1

FROM golang:1.19

# Set destination for COPY
WORKDIR /app

# Download Go modules
COPY go.mod go.sum ./
RUN go mod download

# Copy the source code. Note the slash at the end, as explained in
# https://docs.docker.com/engine/reference/builder/#copy
COPY *.go ./

# Build
RUN CGO_ENABLED=GOOS=linux go build -o /docker-gs-ping

# Optional:
# To bind to a TCP port, runtime parameters must be supplied to the docker command.
# But we can document in the Dockerfile what ports
# the application is going to listen on by default.
# https://docs.docker.com/engine/reference/builder/#expose
EXPOSE 8080

# Run
CMD ["/docker-gs-ping"]

生成映像

現在,您已經創建了 Dockerfile ,讓我們來生成鏡像。 build context 是位於指定路徑或 URL 中的一組文件。Docker 構建過程可以訪問 context 中的任何文件, 在這裏我們用 . 來標識當前 context 爲同級目錄。

build 命令可以選擇採用標誌 --tag 。此標誌用於使用字符串值標記圖像,如果不傳遞 , --tag Docker 將用作 latest 默認值

構建您的第一個 Docker 映像。

docker build --tag docker-gs-ping .

查看本地鏡像

docker image ls

REPOSITORY                       TAG       IMAGE ID       CREATED         SIZE
docker-gs-ping                   latest    7f153fbcc0a8   2 minutes ago   1.11GB
...

給鏡像打 tag

鏡像名稱由以斜槓分隔的名稱組件組成。名稱組件可以包含小寫字母、數字和分隔符。分隔符定義爲句點、一個或兩個下劃線或一個或多個破折號。名稱組件不能以分隔符開頭或結尾。

您可以爲圖像設置多個 tag,事實上,大多數圖像都有多個標籤。爲您構建的鏡像打第二個 tag 。使用 docker image tag (或 docker tag 速記)命令爲鏡像創建新標籤。此命令採用兩個參數; 第一個參數是源圖像,第二個參數是要創建的新標記。以下命令爲您構建的 docker-gs-ping:latest 創建一個新 docker-gs-ping:v1.0 標籤:

docker image tag docker-gs-ping:latest docker-gs-ping:v1.0

現在再次運行查看本地鏡像命令,你會看到 tag = v1.0 的鏡像。

docker image ls

REPOSITORY                       TAG       IMAGE ID       CREATED         SIZE
docker-gs-ping                   latest    7f153fbcc0a8   6 minutes ago   1.11GB
docker-gs-ping                   v1.0      7f153fbcc0a8   6 minutes ago   1.11GB
...

我是南哥,日常分享高質量文章、架構設計、前沿資訊,加微信拉粉絲交流羣,和大家交流!

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/i5fltG0lHpMWN45FnzudOg