首頁  >  文章  >  後端開發  >  Go + Docker:如何為 Golang 應用程式建立最佳的 Docker 映像

Go + Docker:如何為 Golang 應用程式建立最佳的 Docker 映像

WBOY
WBOY原創
2024-08-14 22:49:02346瀏覽

誰從未懷疑過自己是否為應用程式建立了正確的 Docker 映像?嗯,這個問題我已經問過好幾次了,但我幾乎總是不知道自己這樣做是對還是錯。

因此,在本文中,我們將探索為Go 應用程式創建高效且優化的Docker 映像的高級實踐,我們將比較不同的方法,例如使用alpine 和scrap 基礎鏡像,並透過程式碼討論每種方法的優點。範例和性能分析。

專案結構

首先,讓我們為容器化 Go 應用程式建立一個典型的專案結構。

舉個例子,我正在使用這個應用程序,它是一個 URL 縮短器:

url_shortener
├── cmd
│   └── main.go
├── internal
│   ├── monitoring
│   │   └── prometheus.go
│   ├── server
│   │   └── server.go
│   └── shortener
│       ├── model.go
│       ├── repository.go
│       ├── service.go
│       └── service_test.go
├── pkg
│   ├── api
│   │   └── shortener
│   │       ├── handler.go
│   │       └── handler_integration_test.go
│   └── utils
│       └── base62
│           ├── hash.go
│           └── hash_test.go
├── Dockerfile
├── Dockerfile.alpine
├── Dockerfile.golang
├── README.md
├── compose.yml
├── go.mod
├── go.sum
└── prometheus.yml

1. 編寫Dockerfile

很少人知道我們不需要在生產環境中執行「完整」的鏡像。例如,Ubuntu 具有我們語言的所有軟體包、原始碼、擴充和 SDK。我們可以簡單地使用 SDK 在系統中建立我們的應用程序,然後將建置複製到僅運行該建置的較小的最佳化映像。這就是多階段發揮作用的地方。

多階段構建

在 Dockerfile 中,您可以定義多個建置階段,每個階段都會以 FROM 語句開始。第一階段可用於編譯程式碼、安裝依賴項、執行測試等。在後續階段,您可以僅將必要的工件(例如編譯的二進位檔案)複製到最終映像,丟棄執行應用程式不需要的所有內容。

# syntax=docker/dockerfile:1

# Build stage
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN go mod download
RUN go build -o url-shortener ./cmd

# Final stage
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/url-shortener .
CMD ["./url-shortener"]

該死的Rafa,但是你用「這兩張圖」做什麼?首先,我使用映像作為建構器,這是我們創建應用程式執行檔的地方:

第一階段(建造階段):

  • 使用 golang:1.22-alpine 作為基礎鏡像。
  • 將原始碼複製到容器中。
  • 下載依賴項並編譯 Go 應用程式二進位。

然後,我使用一個較小的映像來運行我們在第一步中產生的可執行檔:

第二階段(最後階段):

  • 使用 alpine:latest 作為基礎鏡像,它要小得多,並且只需要運行二進位檔案所需的工具。
  • 將編譯後的二進位檔案從前一階段(建構器)複製到新映像。
  • 定義應用程式執行命令。

如果我們想確認到底發生了什麼,在 Docker Desktop 中可以分析映像的層次結構。在裡面我們可以看到他使用的東西:

Go + Docker: Como criar as melhores imagens Docker para aplicações Golang

現在我們也可以分析剛剛產生的圖片的大小,在本例中是 url-shortener:alpine,約 30mb:

$ docker images
REPOSITORY            TAG         IMAGE ID       CREATED              SIZE
url-shortener                 alpine          aa99d6a2c028   3 minutes ago    29.9MB

但什麼是阿爾卑斯山?

Alpine 是一個極簡、安全、輕量級的 Linux 發行版,因其高效和簡單而廣泛應用於容器環境。它為建立可擴展的應用程式提供了堅實的基礎,而無需其他較重的 Linux 發行版的開銷。

在我們的應用程式中使用 Alpine 的一些優勢主要與以下 3 個支柱相關:

  • 靈活性:alpine 鏡像(~5MB)很小,並且包含一個 apk 套件管理器,可讓您安裝其他所需的依賴項。
  • 相容性:支援動態函式庫,適合依賴外部函式庫的應用。
  • 安全性:定期更新,alpine 包含安全補丁,降低漏洞風險。

好的,但是如果我使用相同的 SDK 版本(在本例中為 golang:1.22-alpine)怎麼辦?我的應用程式有多大?

REPOSITORY                    TAG             IMAGE ID       CREATED         SIZE
url-shortener                 golang-alpine   d615d75c3aff   25 minutes ago   251MB

好吧,在這種情況下,我們最終得到了大約 250mb 的圖像...而與阿爾卑斯山相比,我們純粹去了大約 30mb,這已經是一個很大的差異了。還能進一步改進嗎?

答案是肯定的,讓我們來詳細了解

2. 進階優化

2.1 刮痕

Scratch 是 Docker 中一個特殊且非常簡約的映像。它實際上是您可以使用的最簡單、最空的基礎映像。它絕對不包含任何內容:沒有作業系統、沒有函式庫、沒有工具——它實際上是一個空容器。

Essa abordagem minimalista traz benefícios significativos, especialmente em termos de segurança. Ao usar Scratch, você minimiza drasticamente a superfície de ataque, já que não há pacotes ou ferramentas adicionais que possam introduzir vulnerabilidades. Seu contêiner contém apenas o essencial para a execução do aplicativo, garantindo um ambiente imutável e previsível em qualquer situação.

# syntax=docker/dockerfile:1

# Build stage
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN go mod download
RUN go build -o url-shortener ./cmd

# Final stage with Scratch
FROM scratch
WORKDIR /app
COPY --from=builder /app/url-shortener .
CMD ["./url-shortener"]

E o resultado após criar as 3 imagens, nosso ranking de menor imagem ficou assim:

  1. url-shortener:scratch - 21.1MB
  2. url-shortener:alpine - 29.9MB
  3. url-shortener:golang-alpine - 251MB

O Scratch conseguiu baixar mais alguns megas no tamanho final de nossa aplicação. Isso impacta no tamanho de arquivos transferidos pela rede, hoje algumas empresas cobram pela banda que trafegamos dentro dos servidores, e também pode influenciar em nosso Horizontal Scaling da aplicação.

Deixei os 3 Dockerfiles dentro do repositório do github caso você queira testar em seu próprio pc ?

Quando devo usar o scratch

A resposta mais tranquila para essa é "quase sempre", uma dica de cara é: ele vai muito bem com linguagens como Go, Rust, ou C/C++. Mas qui estão alguns pontos para levar em consideração na hora de escolher se deve ou não usar o scratch:

  • Aplicações Statically Linked: Se sua aplicação não depende de bibliotecas dinâmicas e pode ser compilada de forma estática, Scratch é uma excelente escolha.
  • Segurança: Quando a segurança é uma prioridade e você quer minimizar a quantidade de software no contêiner.
  • Eficiência: Para criar imagens Docker extremamente pequenas e eficientes.

2.2 Reduzindo o Tempo de Build (Cache)

Usar o cache do Docker para otimizar o tempo de build é uma técnica essencial para evitar recompilar ou baixar dependências desnecessariamente em cada build. O Docker armazena em cache as camadas de cada etapa do Dockerfile, reutilizando-as sempre que possível.

Em projetos Go, baixar dependências com go mod download pode ser um processo demorado, especialmente se houver muitas dependências. Se você recompilar todas as dependências em cada build, isso aumenta significativamente o tempo de build.

Como arrumar isso?

Ao copiar apenas os arquivos go.mod e go.sum em uma etapa separada antes de copiar o código-fonte completo, você permite que o Docker use o cache dessa etapa se os arquivos go.mod e go.sum não tiverem mudado. Veja como fica nosso Docker file com as mudanças:

# syntax=docker/dockerfile:1

# Build stage
FROM golang:1.22-alpine AS builder
WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN go build -o url-shortener ./cmd

# Final stage
FROM scratch
WORKDIR /app
COPY --from=builder /app/url-shortener .
CMD ["./url-shortener"]

Só de fazer esta pequena mudança já ganhamos dois pontos bem interessantes quando se trata de desenvolvimento de software, que são:
Menor tempo de build: Se não houver alterações nos arquivos go.mod e go.sum, o Docker reutiliza o cache, evitando o download das dependências e economizando tempo.
Eficiência no CI/CD: Em pipelines de integração contínua, essa técnica reduz o tempo de execução dos pipelines, aumentando a eficiência do desenvolvimento e entrega.

Então bora usar isso a nosso favor no dia-a-dia :)

2.3 Melhorando a Segurança (Docker Scout)

Docker Scout é uma ferramenta da Docker integrada ao Docker Desktop que analisa suas imagens para identificar vulnerabilidades de segurança. Ele fornece insights sobre as dependências presentes em suas imagens e alerta sobre possíveis problemas, permitindo que você tome medidas corretivas antes de implantar suas aplicações.

Por que é importante? Manter suas imagens Docker seguras é fundamental para proteger suas aplicações contra ataques e exploração de vulnerabilidades. O Docker Scout automatiza o processo de análise, tornando mais fácil manter suas imagens seguras e atualizadas.

Como funciona?

O Scout funciona praticamente com 2 passos, ele examina a imagem Docker, mapeia todas as dependências incluídas na imagem e verifica essas dependências em uma base de dados de vulnerabilidades conhecidas. Por fim, classifica as vulnerabilidades encontradas por severidade e fornece recomendações para corrigir ou mitigar os problemas.

實際範例:在 Docker Desktop 上使用 Docker Scout

  1. 存取 Docker 桌面: 打開 Docker Desktop 並轉到“Images”選項卡。在這裡您將看到本地所有圖像的清單。在此範例中,我使用了 postgres:16-alpine 映像,因為它包含我們可以用作範例的漏洞。 Go + Docker: Como criar as melhores imagens Docker para aplicações Golang
  2. 執行漏洞分析: 選擇您要分析的影像。 Docker Scout 將自動顯示所選映像中的已知漏洞。 您將在每個圖像旁邊看到一個安全狀態圖標,指示是否有需要解決的漏洞。 Go + Docker: Como criar as melhores imagens Docker para aplicações Golang
  3. 查看漏洞詳細資料: 按一下圖像以查看已發現漏洞的詳細儀表板。這包括受影響的軟體包版本、CVE 描述和嚴重性。 您也可以查看掃描和變更的歷史記錄,幫助您追蹤影像安全性隨時間的演變。 Go + Docker: Como criar as melhores imagens Docker para aplicações Golang
  4. 應用修復: 根據 Docker Scout 建議,您可以決定更新軟體套件、使用更安全的基礎重建映像或採取其他緩解措施。 修復可以直接應用於您的 Dockerfile 或 CI/CD 管道。 Go + Docker: Como criar as melhores imagens Docker para aplicações Golang

透過這種方式,我們將進行主動預防,在將映像部署到生產環境之前識別並修正漏洞,以幫助防止可能的安全漏洞,並且我們還可以獲得營運效率,這是什麼意思?我們可以自動化漏洞分析,讓 DevOps 或安全團隊專注於糾正措施,而不是手動調查。

結論

透過我們探索的實踐,您現在可以使用多階段建置等技術為Go 應用程式建立Docker 映像,這些技術可以減少映像大小,選擇alpine 或scrap 等基礎映像來提高安全性和效率,透過使用Docker Scout 來監控漏洞,您可以確保您的應用程式有效率且安全地運行。

這些做法不僅提高了技術性能,還為您的日常生活和公司帶來直接的效益,節省時間和資源。

因此,下次建立 Docker 映像時,請記住這些策略。應用它們並觀察結果。 ?

以上是Go + Docker:如何為 Golang 應用程式建立最佳的 Docker 映像的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn