ホームページ  >  記事  >  バックエンド開発  >  Go + Docker: Golang アプリケーションに最適な Docker イメージを作成する方法

Go + Docker: Golang アプリケーションに最適な Docker イメージを作成する方法

WBOY
WBOYオリジナル
2024-08-14 22:49:02343ブラウズ

自分のアプリケーションに適切な Docker イメージを作成しているかどうかについて疑問を抱いたことがない人はいないでしょうか?そうですね、私はこの質問を何度か受けましたが、ほとんどの場合、自分のやり方が正しいのか間違っているのかわかりませんでした。

この記事では、Go アプリケーション用に効率的で最適化された Docker イメージを作成するための高度な実践方法について説明します。アルパインベースイメージとスクラッチベースイメージの使用など、さまざまなアプローチを比較し、それぞれの利点についてコードを使用して説明します。例とパフォーマンス分析。

プロジェクトの構造

まず、コンテナ化された 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の作成

ほとんどの人が知っていることですが、運用環境で「完全な」イメージを実行する必要はないということです。たとえば、すべてのパッケージ、ソース、拡張機能、および言語の SDK を備えた Ubuntu です。 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"]

くそー、ラファ、でも「この 2 枚の画像」で何をしているの?まず、イメージをビルダーとして使用し、ここでアプリケーションの実行可能ファイルを作成します。

最初のステージ (ビルドステージ):

  • 基本イメージとして golang:1.22-alpine を使用します。
  • ソース コードをコンテナにコピーします。
  • 依存関係をダウンロードし、Go アプリケーションのバイナリをコンパイルします。

それでは、最初のステップで生成したこの実行可能ファイルを実行する小さなイメージを使用します。

第 2 ステージ (最終ステージ):

  • 基本イメージとして 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 つの柱に関連しています:

  • 柔軟性: アルパイン イメージ (~5MB) は小さく、apk パッケージ マネージャーが含まれているため、追加の必要な依存関係をインストールできます。
  • 互換性: 動的ライブラリをサポートし、外部ライブラリに依存するアプリケーションに適しています。
  • セキュリティ: 定期的に更新される alpine にはセキュリティ パッチが含まれており、脆弱性のリスクが軽減されます。

わかりましたが、同じ SDK バージョン (この場合は golang:1.22-alpine) を使用した場合はどうなるでしょうか。私のアプリケーションのサイズはどれくらいですか?

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

そうですね、この場合、画像のサイズは最大 250 MB になりました。アルパインと比較すると、純粋に最大 30 MB になりましたが、これはすでに大きな違いです。そしてそれをさらに改善することはできるのでしょうか?

答えは「はい」です。詳細を見ていきましょう

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 デスクトップでの Docker Scout の使用

  1. Docker デスクトップにアクセスします: Docker デスクトップを開き、「イメージ」タブに移動します。ここには、ローカルにあるすべてのイメージのリストが表示されます。この例では、例として使用できる脆弱性が含まれている 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 イメージを作成し、イメージ サイズを削減し、アルパインやスクラッチなどのベース イメージを選択してセキュリティを強化し、また、Docker Scout を使用して脆弱性を監視することで、アプリケーションが効率的かつ安全に実行されていることを確認できます。

これらの実践は、技術的なパフォーマンスを向上させるだけでなく、日常生活や会社に直接的な利益をもたらし、時間とリソースを節約します。

次回 Docker イメージを構築するときは、これらの戦略を念頭に置いてください。それらを適用して結果を観察してください。 ?

以上がGo + Docker: Golang アプリケーションに最適な Docker イメージを作成する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。