はじめに
GolangアプリケーションをDockerで運用する際、適切なDockerfileの設計はパフォーマンスやセキュリティに大きく影響します。
本記事では、マルチステージビルドを活用した効率的なDockerfile について解説し、コンテナサイズの削減や最適化のポイント を紹介します。
書こうと思ったきっかけ
GolangアプリケーションのDocker化を行う中で、ビルド環境の分離やコンテナサイズの最適化が重要 だと感じました。
特に、シンプルかつ軽量な構成を実現するためのポイント を整理し、他の開発者にも役立つ情報を共有したいと思い、本記事を書くことにしました。
実際に作成したDockerfileについて
実際のDockerfileについて
このDockerfileは、Golangアプリケーションを効率的にコンテナ化するためのものです。
FROM golang:1.23.5-alpine3.21 AS builder
WORKDIR /usr/src/app
# go.mod と go.sum を先にコピーし、依存関係をダウンロード
COPY go.mod go.sum ./
RUN go mod download
# アプリケーションのソースコードをコピー
COPY . .
# メインアプリケーションのビルド
RUN CGO_ENABLED=0 GOOS=linux go build -o server .
# マイグレーション用のバイナリを作成
RUN CGO_ENABLED=0 GOOS=linux go build -o migrate_app migrate/migrate.go
# 軽量なAlpineベースのイメージを使用
FROM alpine:3.21
WORKDIR /app
# 必要なバイナリをコピー
COPY --from=builder /usr/src/app/server .
COPY --from=builder /usr/src/app/migrate_app .
# マイグレーションを実行してからアプリケーションを起動
CMD ["/bin/sh", "-c", "/app/migrate_app && /app/server"]
マルチステージビルドを利用して、軽量なコンテナイメージを作成し、アプリケーションのパフォーマンスやセキュリティを向上させています。
1. ビルドステージ (builder)
まず、Golangの公式イメージ(Alpine Linuxベース)を使い、ビルド用の環境を構築します。
FROM golang:1.23.5-alpine3.21 AS builder
WORKDIR /usr/src/app
-
golang:1.23.5-alpine3.21を使用して、軽量なビルド環境を用意 -
WORKDIR /usr/src/appで作業ディレクトリを/usr/src/appに設定
次に、依存関係のインストールを行います。
COPY go.mod go.sum ./
RUN go mod download
-
go.modとgo.sumをコピーし、go mod downloadを実行 - これにより、依存パッケージを事前にダウンロードし、キャッシュを活用して不要な再インストールを防ぐ
続いて、アプリケーションのソースコードをコピーし、ビルドを行います。
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server .
-
CGO_ENABLED=0を設定して、C言語の依存を無効化し、静的リンクされたバイナリを作成 -
GOOS=linuxを指定し、Linux向けのバイナリを生成 -
-o serverで出力ファイル名をserverに指定
また、データベースマイグレーション用のバイナリも作成します。
RUN CGO_ENABLED=0 GOOS=linux go build -o migrate_app migrate/migrate.go
-
migrate/migrate.goをビルドし、マイグレーション実行用のmigrate_appバイナリを作成
この段階で、アプリケーション本体 (server) と、マイグレーションツール (migrate_app) の2つのバイナリが完成しました。
2. ランタイムステージ
アプリケーションの実行環境として、軽量な Alpine イメージを使います。
FROM alpine:3.21
WORKDIR /app
-
Alpine Linux 3.21をベースイメージとして使用し、実行環境を構築 -
WORKDIR /appで作業ディレクトリを/appに設定
次に、ビルドステージで作成したバイナリをコピーします。
COPY --from=builder /usr/src/app/server .
COPY --from=builder /usr/src/app/migrate_app .
-
COPY --from=builderにより、ビルド済みのバイナリ (serverとmigrate_app) を取得し、実行環境へコピー - Golangの開発環境 (約1GB) を削減し、数MBの軽量なコンテナを実現
最後に、マイグレーションを実行してからアプリケーションを起動するよう設定します。
CMD ["/bin/sh", "-c", "/app/migrate_app && /app/server"]
-
/app/migrate_appを実行し、データベースのマイグレーションを適用 - マイグレーションが完了したら
/app/serverを起動
3. 最適化ポイント
このDockerfileには、パフォーマンス向上やイメージの軽量化を考慮した工夫がいくつか含まれています。
マルチステージビルドの活用
- Golangのビルド環境 (
golang:1.23.5-alpine3.21) はサイズが大きいため、本番環境に不要なものは含めず、軽量なAlpineイメージに最小限のバイナリのみを配置 - これにより、最終的なコンテナサイズを数MB程度に抑えられる
依存関係のキャッシュを活用
-
go.modを先にコピーし、go mod downloadを実行することで、ソースコードの変更がない限り、依存関係の再インストールを回避
CGO無効化 & 静的リンク
-
CGO_ENABLED=0を設定することで、C言語の依存をなくし、シンプルなスタンドアロンバイナリを作成 -
GOOS=linuxを指定することで、Linux環境でも動作するバイナリを生成
軽量なAlpineイメージの採用
-
Alpine Linuxは、公式のGolangイメージよりも数百MBも軽量 - 余分なパッケージがなく、セキュリティリスクも低減
まとめ
このDockerfileでは、Golangアプリケーションのビルドとデプロイの最適化を行っています。特に、以下のポイントが重要です。
- マルチステージビルドにより、ビルド環境を分離し、最終的なコンテナを軽量化
-
go.modを先にコピーし、キャッシュを活用してビルドの高速化 -
CGO_ENABLED=0による静的バイナリ化で、余計なライブラリを削減 -
Alpine Linuxを利用して、最小限のランタイム環境を構築
このような工夫を取り入れることで、効率的でセキュアなDockerコンテナを作成できます。
Golangアプリケーションをコンテナ化する際の参考にしてください。