0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VS Code DevContainer + Go + Postgres + Air で作るGo開発コンテナ構成まとめ【backend直下版】

0
Posted at

golang:1.26-alpine ベースで、VS Code DevContainer からそのまま開発・デバッグ・ホットリロード・マイグレーションまで回す構成です。

1. 前提・バージョン

項目 バージョン / 内容
Go go1.26 / image golang:1.26-alpine
DB postgres:15-alpine (local port 5433:5432)
Backend module backend/go.mod (goquery, chromedp, pgx/v5)
HotReload github.com/air-verse/air@v1.61.1 + .air.toml
Migration golang-migrate/migrate v4.17.0
Scraping chromium + 日本語フォント (font-noto-cjk 等)
VS Code拡張 golang.go, HashiCorp.terraform, saoudrizwan.claude-dev
Go Tools gopls, dlv (postCreateCommandで自動導入)

2. フォルダ構成

.
├── .devcontainer/
│   ├── devcontainer.json      # VS Code DevContainer定義 (service: go)
│   └── docker-compose.yml     # DevContainer用オーバーライド (sleep infinity + SYS_PTRACE)
├── docker-compose.yml         # 本体: db / api / go サービス定義
└── backend/
    ├── Dockerfile             # api + go 共用 (Air + migrate + Chromium入り)
    ├── docker-entrypoint.sh   # migrate up してから CMD を実行
    ├── .air.toml              # Air設定
    ├── go.mod
    ├── go.sum
    ├── main.go
    ├── sql/
    └── db/
        └── migrations/        # *.up.sql / *.down.sql

3. 必要ファイル全文(機密値はマスク済み)

3.1 .devcontainer/devcontainer.json

DevContainerの本体。service: go にアタッチします。

{
  "name": "Go Dev Container",
  "dockerComposeFile": [
    "../docker-compose.yml",
    "docker-compose.yml"
  ],
  "service": "go",
  "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
  "customizations": {
    "vscode": {
      "extensions": [
        "golang.go",
        "HashiCorp.terraform",
        "saoudrizwan.claude-dev"
      ],
      "settings": {
        "go.toolsManagement.autoUpdate": true,
        "go.useLanguageServer": true,
        "go.gopath": "/go",
        "go.goroot": "/usr/local/go"
      }
    }
  },
  "postCreateCommand": "go install golang.org/x/tools/gopls@latest && go install github.com/go-delve/delve/cmd/dlv@latest"
}

解説:

  • dockerComposeFile を2段重ねにして本体 + オーバーライドを合成
  • gopls + dlv はコンテナ作成後に自動インストール

3.2 .devcontainer/docker-compose.yml

DevContainer用の差分だけ書きます。

services:
  go:
    volumes:
      - ..:/workspaces:cached
    # Go のデバッガ (dlv) に必要
    cap_add:
      - SYS_PTRACE
    security_opt:
      - seccomp:unconfined
    # コンテナを常時起動状態にする
    command: sleep infinity

3.3 docker-compose.yml(ルート)

backend/ 直下前提なので context: ./backendworking_dir: /app に統一しています。

services:
  db:
    image: postgres:15-alpine
    restart: always
    environment:
      POSTGRES_USER: ${YOUR_USERNAME}
      POSTGRES_PASSWORD: ${YOUR_PASSWORD} 
      POSTGRES_DB: ${YOUR_DBNAME}
    ports:
      - "5433:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U YOUR_USERNAME -d YOUR_DBNAME"]
      interval: 5s
      timeout: 5s
      retries: 5

  api:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    volumes:
      - ./backend:/app
    environment:
      DB_DSN: ${DB_DSN}
    depends_on:
      db:
        condition: service_healthy

  # VS Code DevContainerがアタッチするサービス
  # 同じDockerfileを使い回し、commandだけ上書きして常駐させる
  go:
    build:
      context: ./backend
      dockerfile: Dockerfile
    entrypoint: []
    working_dir: /app # backend/go.mod がある場所
    volumes:
      - ./backend:/app
    depends_on:
      - db
    environment:
      DB_DSN: ${DB_DSN}
    command: sleep infinity

volumes:
  postgres_data:

3.4 backend/Dockerfileapi + go 共用)

FROM golang:1.26-alpine

WORKDIR /app

# build tools + Chromium for headless scraping + 日本語フォント
RUN apk add --no-cache git build-base chromium \
    && apk add --no-cache \
       font-noto-cjk \
       font-noto-emoji \
       font-freefont \
       harfbuzz \
       nss \
       freetype \
       fontconfig \
       dbus \
       ca-certificates \
       curl

# ホットリロード用 Air
RUN go install github.com/air-verse/air@v1.61.1

# migrate CLI
RUN curl -fsSL "https://github.com/golang-migrate/migrate/releases/download/v4.17.0/migrate.linux-amd64.tar.gz" | tar xz \
    && mv migrate /usr/local/bin/migrate

COPY go.mod go.sum ./
ENV GOPROXY=direct
RUN go mod download

COPY . .

COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh

ENV CHROME_PATH=/usr/bin/chromium-browser

ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["air", "-c", ".air.toml"]

go サービスでは entrypoint: [] + command: sleep infinityENTRYPOINT/CMD を無効化しているので、同じイメージで「実行用」と「開発常駐用」を兼ねられます。

3.5 backend/docker-entrypoint.sh

#!/bin/sh
set -e

if [ -d "/app/db/migrations" ]; then
    MAX_RETRIES=30
    RETRY_COUNT=0
    until migrate -path /app/db/migrations -database "$DB_DSN" up; do
        RETRY_COUNT=$((RETRY_COUNT + 1))
        if [ "$RETRY_COUNT" -ge "$MAX_RETRIES" ]; then
            echo "❌ Migrations failed after $MAX_RETRIES attempts."
            exit 1
        fi
        echo "⏳ DB not ready yet. Retrying migrations ($RETRY_COUNT/$MAX_RETRIES)..."
        sleep 2
    done
    echo "✅ Migrations completed."
else
    echo "⚠️ Migration directory not found. Skipping."
fi

exec "$@"

depends_on: service_healthy + リトライループの二重保険でDB起動待ち問題を回避。
backend/client が無い分、パスは /app/db/migrations に統一。

3.6 backend/.air.toml

root = "."
tmp_dir = "tmp"

[build]
  cmd = "go build -o ./tmp/main ."
  bin = "./tmp/main"
  delay = 1000
  exclude_dir = ["assets", "tmp", "vendor"]
  include_ext = ["go", "tpl", "tmpl", "html"]
  exclude_regex = ["_test.go"]
  exclude_unchanged = false
  follow_symlink = false
  log = "build-errors.log"
  send_interrupt = false
  stop_on_error = true

[color]
  app = ""
  build = "yellow"
  main = "magenta"
  runner = "green"
  watcher = "cyan"

[log]
  time = false

[misc]
  clean_on_exit = true

3.7 backend/go.mod(例)

module example.com/myapp/backend

go 1.26

require (
    github.com/PuerkitoBio/goquery v1.12.0
    github.com/chromedp/chromedp v0.16.0
    github.com/jackc/pgx/v5 v5.10.0
)

5. ハマりポイントと対策(backend直下版)

  1. go.mod が無いと言われる: working_dir: /app + volumes: ./backend:/app のセットを忘れると backend/ の中身が見えない。
  2. DB接続前にアプリが起動して落ちる: healthcheck + condition: service_healthy + docker-entrypoint.sh のリトライで解決。
  3. Chromiumで日本語文字化け: font-noto-cjk 必須。CHROME_PATH=/usr/bin/chromium-browser を統一。
  4. dlvが operation not permitted: .devcontainer/docker-compose.ymlSYS_PTRACE + seccomp:unconfined が必要。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?