Contents
1. Go プロジェクトの依存管理
1.1 go.mod の基本設定
Go Modules はビルド再現性を担保するための中心的な仕組みです。正しく宣言された go.mod があることで、CI 環境とローカル環境で同一バイナリが生成されます。
|
1 2 3 4 5 6 7 8 9 |
module github.com/acme/example-app go 1.22 require ( github.com/gin-gonic/gin v1.9.0 golang.org/x/sync v0.3.0 // indirect ) |
- Go バージョン固定:
go 1.22により、将来の互換性問題を防げます。 - 依存バージョン明示:
require行に具体的なタグやコミット SHA を書くことで、外部パッケージの突然の破壊的変更から保護します。
1.2 CI キャッシュの活用
GitHub Actions や GitLab CI のキャッシュ機能を使うと go mod download が毎回走らず、ビルド時間が 30 % 程度短縮されます。以下は GitHub Actions 用例です。
|
1 2 3 4 5 6 7 8 |
- name: Cache Go modules uses: actions/cache@v3 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} |
2. マルチステージ Dockerfile の作成
2.1 ビルダー Stage(依存取得+バイナリ生成)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# syntax=docker/dockerfile:1.4 # BuildKit 対応 FROM golang:1.22-alpine AS builder WORKDIR /src # ── キャッシュを最大限活用するために go.mod と go.sum だけ先にコピー COPY go.mod go.sum ./ RUN go mod download # ── ソース全体をコピーし、静的リンクバイナリを生成 COPY . . RUN CGO_ENABLED=0 GOOS=linux \ go build -ldflags="-s -w" -o /app/app . |
- Alpine は 5 MB 程度のベースサイズで、ビルドツールだけをインストールすれば十分です。
CGO_ENABLED=0と-ldflags="-s -w"により、実行バイナリは 10 MB 未満 に圧縮できます。
2.2 ランタイム Stage(最小・安全)
|
1 2 3 4 5 6 7 8 9 10 |
FROM alpine:3.20 AS runtime # 非特権ユーザー作成 (UID/GID は 10001 系で他プロジェクトと衝突しにくい) RUN addgroup -S appgrp && adduser -S -G appgrp appusr COPY --from=builder /app/app /usr/local/bin/app USER appusr EXPOSE 8080 ENTRYPOINT ["/usr/local/bin/app"] |
scratchを選択するとさらにサイズは減りますが、Alpine の場合は脆弱性スキャンツール(Trivy, Grype 等)がすぐに利用できる点が利点です。- 非特権ユーザーで実行することで、コンテナが侵害された際の被害範囲を最小化します。
3. ローカルでのビルド・テストフロー
3.1 BuildKit の有効化とキャッシュ確認
|
1 2 3 4 5 |
DOCKER_BUILDKIT=1 docker build \ --progress=plain \ -t ghcr.io/acme/example-app:dev \ . |
--progress=plainはビルドログを詳細に出力し、レイヤーキャッシュの挙動を把握しやすくします。--target runtimeを付与すると、ビルダーイメージが生成されず最小イメージだけが作成されます。
3.2 本番に近い条件でのローカルテスト
|
1 2 3 4 5 6 7 |
docker run --rm -d \ --name example-app-test \ -p 8080:8080 \ --read-only \ --user 10001:10001 \ ghcr.io/acme/example-app:dev |
--read-onlyによりファイルシステムは書き込み禁止に。ログや一時データが必要な場合は named volume をマウントして例外を作ります。
|
1 2 3 4 5 6 |
docker run --rm -d \ -p 8080:8080 \ --read-only \ -v app-data:/tmp \ ghcr.io/acme/example-app:dev |
4. レジストリへのプッシュとタグ戦略
4.1 Git コミット SHA を活用したバージョニング
|
1 2 3 4 |
VERSION=$(git rev-parse --short HEAD) docker tag ghcr.io/acme/example-app:dev \ ghcr.io/acme/example-app:${VERSION} |
- メリット:デプロイ履歴がコミット単位で追跡でき、ロールバック時に正確なイメージを指定できます。
4.2 複数レジストリへの同時プッシュ(GitHub Container Registry & Docker Hub)
|
1 2 3 4 5 6 7 8 9 |
# GitHub Container Registry echo $GHCR_TOKEN | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin docker push ghcr.io/acme/example-app:${VERSION} # Docker Hub docker login -u $DOCKERHUB_USER -p $DOCKERHUB_TOKEN docker tag ghcr.io/acme/example-app:${VERSION} acme/example-app:${VERSION} docker push acme/example-app:${VERSION} |
- 認証情報は GitHub Secrets や CI/CD の環境変数 に格納し、平文でコードに残さないよう徹底します。
5. 本番環境デプロイパターン
5.1 Docker Compose(小規模・ステートレスサービス向け)
|
1 2 3 4 5 6 7 8 9 10 11 12 |
version: "3.9" services: app: image: ghcr.io/acme/example-app:${VERSION} restart: always ports: - "8080:8080" read_only: true user: "10001:10001" environment: - LOG_LEVEL=info |
restart: alwaysにより、コンテナが異常終了した場合でも自動復旧します。- 環境変数は
.envファイル で管理し、コードベースから分離してください。
5.2 単体 docker run(シンプルなマイクロサービス)
|
1 2 3 4 5 6 |
docker run -d --name example-app \ -p 8080:8080 \ --read-only \ --user 10001:10001 \ ghcr.io/acme/example-app:${VERSION} |
- この形は エッジデバイス や オンプレミスの小規模サーバー に最適です。
5.3 Kubernetes(大規模・高可用性シナリオ)
|
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 |
apiVersion: apps/v1 kind: Deployment metadata: name: example-app spec: replicas: 3 selector: matchLabels: app: example-app template: metadata: labels: app: example-app spec: containers: - name: app image: ghcr.io/acme/example-app:${VERSION} ports: - containerPort: 8080 securityContext: runAsNonRoot: true readOnlyRootFilesystem: true allowPrivilegeEscalation: false resources: limits: cpu: "500m" memory: "256Mi" # PodSecurityContext により全コンテナ共通の安全設定を付与 securityContext: runAsUser: 10001 fsGroup: 10001 |
- PodSecurityPolicy が有効になっているクラスターでは、上記
securityContextが必須です。 - リソースリミットは Horizontal Pod Autoscaler (HPA) と組み合わせて自動スケールを実装します。
6. CI/CD パイプラインへの統合
6.1 GitHub Actions 完全サンプル
|
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 49 50 51 52 53 |
name: Build & Deploy on: push: branches: [ main ] jobs: build-and-push: runs-on: ubuntu-latest permissions: contents: read packages: write env: IMAGE_NAME: ghcr.io/acme/example-app VERSION: ${{ github.sha }} steps: - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.22' - name: Cache Go modules uses: actions/cache@v3 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - name: Build & push Docker image uses: docker/build-push-action@v5 with: context: . push: true tags: | ${{ env.IMAGE_NAME }}:${{ env.VERSION }} ${{ env.IMAGE_NAME }}:latest cache-from: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache cache-to: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache,mode=max buildkitd-flags: --allow-insecure-entitlement network.host - name: Deploy to Kubernetes (optional) if: github.ref == 'refs/heads/main' uses: azure/k8s-deploy@v4 with: namespace: production manifests: | k8s/deployment.yaml images: ${{ env.IMAGE_NAME }}:${{ env.VERSION }} |
- キャッシュ戦略:
cache-from/cache-toによりビルド時間が 40 % 程度短縮。 docker/build-push-actionが内部で BuildKit を利用し、マルチステージの最適化を自動的に適用します。
6.2 GitLab CI(自己ホスト型レジストリ向け)
|
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 |
stages: - build - push variables: DOCKER_BUILDKIT: "1" IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA build: stage: build image: docker:latest services: - docker:dind script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker build -t $IMAGE . artifacts: paths: - .docker push: stage: push script: - docker push $IMAGE |
docker:dind(Docker-in-Docker)で BuildKit が有効になるよう環境変数を設定しています。
7. 高度なテクニック
7.1 マルチアーキテクチャビルド
|
1 2 3 4 5 |
docker buildx create --use docker buildx bake \ --set *.platform=linux/amd64,linux/arm64 \ -t ghcr.io/acme/example-app:${VERSION} . |
- 結果:
manifest listが生成され、AMD64 と ARM64 の両方で同一イメージタグが利用可能になります。 - Edge デバイスや Apple Silicon 環境へのデプロイに必須です。
7.2 脆弱性スキャンの自動化
|
1 2 |
trivy image ghcr.io/acme/example-app:${VERSION} --severity HIGH,CRITICAL --exit-code 1 |
- CI パイプラインに組み込むことで、Critical な脆弱性が検出されたらビルドを失敗させます。
- Acme Cloud の Security Guard と連携すれば、レポートの自動集約・通知も可能です。
7.3 Observability(可観測性)組み込み
| 機能 | 実装例 |
|---|---|
| ログ出力 | logrus や zap を使い、JSON フォーマットで標準出力へ送信 |
| メトリクス | prometheus/client_golang で /metrics エンドポイントを公開 |
| トレース | OpenTelemetry SDK と OTEL_EXPORTER_OTLP_ENDPOINT 環境変数で外部 APM に送信 |
Dockerfile の ENTRYPOINT は変更せずに、環境変数だけで有効化/無効化できる設計が推奨されます。
8. トラブルシューティング
| 現象 | 原因例 | 対策 |
|---|---|---|
ビルドが途中で失敗し go: downloading が止まる |
ネットワークプロキシ未設定、または Go モジュールキャッシュの破損 | 環境変数 GOPROXY=https://proxy.golang.org,direct を設定し、ローカルキャッシュを削除 (go clean -modcache) |
コンテナ起動時に permission denied が出る |
非特権ユーザーが必要なファイルへ書き込もうとしている | 必要なディレクトリに ボリュームマウント し、chown を実行した上でマウント (docker run -v data:/app/data) |
| CI がキャッシュを使い続けて古い依存が残る | go.sum の更新忘れ、またはキャッシュキーが不適切 |
hashFiles('**/go.mod') と併用し、go mod tidy を必ず実行 |
| 脆弱性スキャンで false positive が多数出る | Alpine の musl ライブラリが誤検知されるケース |
--ignore-unfixed フラグで一時的に除外し、定期的にベースイメージを更新 (docker pull alpine:3.20) |
ポイント:エラーメッセージはそのまま検索すると同様事例が多数ヒットします。Docker 公式ドキュメント・GitHub Issue は必ず参照してください。
9. まとめ & 次のステップ
- 依存管理:
go.modと CI キャッシュでビルド再現性を確保。 - マルチステージ Dockerfile:Builder → Runtime の二段構成でイメージサイズと攻撃面を最小化。
- ローカルテスト:Read‑Only FS・非特権ユーザーで本番に近い条件を再現。
- タグ戦略:Git SHA を利用したバージョニングでデプロイ履歴を追跡可能。
- デプロイパターン:Compose、単体
docker run、Kubernetes の各シナリオに共通のセキュリティベストプラクティス(read‑only、runAsNonRoot)を適用。 - CI/CD 統合:GitHub Actions / GitLab CI で BuildKit とキャッシュを活かした自動化パイプラインを構築。
- 高度なテクニック:マルチアーキ、脆弱性スキャン、Observability の組み込みで本番品質を向上。
🚀 次の一歩
Acme Cloud では、Docker 化した Go アプリケーションのフルマネージドデプロイサービス を提供しています。今すぐ無料トライアルにサインアップし、以下のベストプラクティスを実際の環境で体感してください。
参考文献
- Docker Docs – Best practices for writing Dockerfiles (2024). https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
- Go Blog – Modules: version selection (2023). https://go.dev/blog/using-go-modules
- Trivy – Vulnerability scanner for containers (2024). https://github.com/aquasecurity/trivy
(※ 以前引用していた「Docker 公式ブログ 2025」および「Zenn 記事 2025」は実在が確認できなかったため、公式ドキュメント・Go ブログに置き換えました。)