Contents
1️⃣ Docker の基本概念と Go バイナリの相性
1-1 コンテナは「レイヤー」+「差分書き込み層」
Docker イメージは 読み取り専用レイヤー(ベース OS、ライブラリ、アプリ本体) と 書き込み可能な差分層 で構成されます。
コンテナ起動時に差分層だけが作られるため、同一イメージはどのホストでもほぼ同じ挙動を示します。
レイヤーは再利用できるので、ビルドキャッシュやプル時間が大幅に短縮されます。
1-2 Go バイナリは Docker 化に最適
go build -ldflags="-s -w"で 静的リンク かつシンボルテーブル削除したバイナリは、サイズが 10 ~ 15 MB 程度に収まります。- 静的バイナリはランタイムや共有ライブラリを必要としないため、最小のベースイメージ(Alpine など)だけで動作させられます。
※ 注意
記載しているサイズは執筆時点の概算です。公式イメージは随時更新されるので、実際に使用する前にdocker pull後のdocker imagesで最新サイズを確認してください。
2️⃣ 公式 golang イメージとベース OS の選び方
| イメージ | 主な特徴 | 想定用途 | 参考サイズ* |
|---|---|---|---|
golang:1.22-alpine |
Alpine + musl libc、パッケージは apk |
ビルドステージ(静的リンクが可能) | 約 150 MB |
golang:1.22-bullseye (Debian) |
glibc、パッケージは apt |
Cgo が必要なライブラリや外部バイナリを使う場合 | 約 350 MB |
alpine:latest |
5 ~ 6 MB 程度の最小実行環境 | ランタイムステージ(static バイナリだけ) | 約 6 MB |
*サイズは執筆時点の公式レポジトリ情報です。バージョンやタグが変わると増減します。
2-1 「常に最新版」表現を修正
Docker Hub のタグは “latest” が指すイメージは頻繁に更新されます が、必ずしも同一の内容になる保証はありません。CI パイプラインで使用する場合は 固定バージョン(例: golang:1.22-alpine) を指定し、必要に応じて手動で更新を検討してください。
|
1 2 3 4 |
# 推奨:明示的にバージョンタグを指定 docker pull golang:1.22-alpine docker pull alpine:3.19 # 例として特定の Alpine バージョン |
3️⃣ マルチステージビルドで超軽量コンテナを作る
3-1 全体構成とポイント
| ステージ | 主な役割 | 重要な Dockerfile 命令 |
|---|---|---|
| builder | ソースコード取得、依存解決、静的バイナリ生成 | COPY go.mod go.sum, RUN go mod download, RUN go build |
| runtime | 実行環境だけを残す(Alpine + バイナリ) | FROM alpine:latest, COPY --from=builder, USER 設定, HEALTHCHECK |
3-2 完成形 Dockerfile (コメント付き)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# ---------- Builder Stage ---------- FROM golang:1.22-alpine AS builder WORKDIR /src # ── 依存モジュールだけを先にコピーし、キャッシュを有効化 ── COPY go.mod go.sum ./ RUN go mod download # ── アプリ全体をコピーしてビルド(静的リンク) ── COPY . . RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ go build -ldflags="-s -w" -o /app/bin/app . # ---------- Runtime Stage ---------- FROM alpine:3.19 # 特定バージョンで安定運用を推奨 LABEL maintainer="dev@example.com" WORKDIR /app # ── 非 root ユーザー作成(セキュリティベストプラクティス) ── RUN addgroup -S appgrp && adduser -S appusr -G appgrp USER appusr # ── ビルドステージからバイナリだけをコピー ── COPY --from=builder /app/bin/app . EXPOSE 8080 # ── コンテナの健全性チェック(軽量な HTTP GET) ── HEALTHCHECK --interval=30s --timeout=5s \ CMD wget -qO- http://localhost:8080/health || exit 1 ENTRYPOINT ["./app"] |
補足ポイント
CGO_ENABLED=0により glibc 依存が除去され、Alpine の musl でも動作します。RUN addgroup ... && adduser ...は単一レイヤーにまとめて層数を削減しています。HEALTHCHECKは本番環境の自動復旧やオートスケールで有効です。
3-3 キャッシュ活用のコツ(go.mod の順序)
|
1 2 3 4 5 6 7 |
# キャッシュが最大限に利用できるよう、頻繁に変わらないファイルは先にコピー COPY go.mod go.sum ./ RUN go mod download # ← ここだけが再ビルド対象になる # ソースコード全体は最後にコピー COPY . . |
この書き方で、ソースコードの変更があっても 依存取得層 はキャッシュされ続けます。
4️⃣ 本番環境向けベストプラクティス
4-1 非 root 実行と権限設計
USER命令で作成した低権限ユーザーを必ず使用し、Kubernetes のrunAsNonRootポリシーに適合させます。- 必要最小限のファイル・ディレクトリだけに書き込み権限を付与すると、コンテナ侵害時の被害範囲が限定されます。
4-2 .dockerignore の正しい記述例
|
1 2 3 4 5 6 7 8 |
# .dockerignore(Dockerfile は除外しない) .git .gitignore node_modules/ vendor/ *.md README* |
Dockerfileを除外するとビルドコンテキストにイメージが送られず、ビルド自体が失敗します。必ずリストから外してください。
4-3 サイズ測定と継続的最適化
| 項目 | 確認コマンド例 | 推奨上限(参考) |
|---|---|---|
| イメージ総サイズ | docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}" |
20 MB 以下(Alpine + 静的バイナリ) |
| レイヤー数 | docker history <image> |
5 層以内に抑えるとキャッシュ効率が向上 |
| 不要ファイルの除外 | .dockerignore の網羅性をチェック |
ビルドコンテキストは < 10 MB が理想 |
Tip:CI パイプラインで
docker image ls --format "{{.Repository}}:{{.Tag}} {{.Size}}"を走らせ、サイズが閾値を超えたら自動で警告する仕組みを入れると肥大化防止に役立ちます。
4-4 セキュリティスキャンの実装例
|
1 2 3 |
# Trivy(オープンソースの脆弱性スキャナ)でイメージを検査 trivy image --severity HIGH,CRITICAL myorg/go-app:latest |
- 定期的にスキャンし、CVE が報告されたベースイメージは パッチが当たった最新タグ に更新します。
5️⃣ 開発・デプロイフローの自動化
5-1 Docker Compose とローカル開発環境
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# docker-compose.yml(簡易例) version: "3.9" services: app: build: context: . target: builder # ビルドステージだけを直接指定可能 ports: - "8080:8080" volumes: - ./:/src # ソースコードのリアルタイム同期 environment: GOFLAGS: "-mod=readonly" |
volumesによりローカル変更が即座にコンテナへ反映され、airなどのホットリロードツールと併用すれば開発速度が向上します。
5-2 VSCode DevContainer の設定
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// .devcontainer/devcontainer.json { "name": "Go on Docker", "dockerComposeFile": ["../docker-compose.yml"], "service": "app", "workspaceFolder": "/src", "settings": { "go.useLanguageServer": true, "go.formatTool": "gofmt" }, "extensions": [ "golang.go", "ms-azuretools.vscode-docker" ], "postCreateCommand": "go mod tidy && go build -v ./..." } |
- VSCode 起動時に自動でコンテナが立ち上がり、エディタ拡張やデバッグ設定が共有されます。
postCreateCommandで依存解決とビルドを走らせることで、チーム全員が同一の環境で作業できます。
5-3 GitHub Actions による CI/CD パイプライン
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# .github/workflows/ci-cd.yml name: CI / CD on: push: branches: [ main ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.22' - name: Run unit tests run: go test ./... build-and-push: needs: test runs-on: ubuntu-latest permissions: contents: read packages: write # GitHub Packages 用(Docker Hub でも同様に設定) steps: - uses: actions/checkout@v4 - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build & push multi‑stage image uses: docker/build-push-action@v5 with: context: . file: Dockerfile push: true tags: | ${{ secrets.DOCKERHUB_USERNAME }}/go-app:${{ github.sha }} ${{ secrets.DOCKERHUB_USERNAME }}/go-app:latest cache-from: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/go-app:cache cache-to: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/go-app:cache,mode=max |
- テスト → ビルド → プッシュ のシンプルなフローで、プルリクエストがマージされた瞬間に最新イメージがレジストリへデプロイされます。
cache-from / cache-toによりビルド時間を数分単位で短縮できます。
6️⃣ まとめと次のステップ
| 項目 | キーポイント |
|---|---|
| Docker の基礎 | レイヤー構造が再利用と高速起動を実現。Go の静的バイナリは最小イメージ化に最適。 |
| ベースイメージ選択 | golang:1.22-alpine(ビルド)+alpine:3.19(ランタイム)がサイズと速度のバランスが良い。glibc が必要なケースは Debian 系へ切り替える。 |
| マルチステージビルド | Builder と Runtime を分離し、go.mod の先行コピーでキャッシュを最大活用。最終イメージは約 12 ~ 15 MB に抑えられる(Alpine + static binary)。 |
| 本番ベストプラクティス | 非 root ユーザー、正しい .dockerignore、HEALTHCHECK、定期的な脆弱性スキャンで安全性と可観測性を確保。 |
| 開発・CI/CD 自動化 | Docker Compose + VSCode DevContainer でローカル環境統一、GitHub Actions がテスト・ビルド・デプロイの全工程を自動化。 |
| 運用上の留意点 | イメージサイズやタグは随時変わるため、docker pull 後に docker images で実測値を確認し、バージョン固定と定期更新のポリシーを策定する。 |
これらの手順・設定をプロジェクトに組み込めば、「最小サイズかつ本番品質」 の Go アプリ Docker コンテナがすぐに構築でき、開発からデプロイまで一貫したフローを実現できます。
次のアクション例
1. 本リポジトリに上記Dockerfileと.dockerignoreを追加し、git add . && git commit -m "Add production‑ready Docker setup"
2. CI 用シークレット(Docker Hub 認証情報)を GitHub リポジトリの Settings → Secrets に設定。
3.docker compose up --buildでローカル環境を起動し、curl http://localhost:8080/healthが 200 を返すことを確認。
これで本番に耐えうる軽量コンテナが完成です!