[Go, Gin, Gorm, Docker] 🚀〜データベース接続からマイグレーションまで、これ一本で丸わかり！〜🚀



## はじめに

- このGolangバックエンドプロジェクトでは、PostgreSQLデータベースとの接続を`GORM`を使用して管理している
- 本記事では、データベースの初期化から接続、マイグレーションまでの実装について解説する

## 環境構成

主要な技術スタック
- Go v1.23.3
- Gin Web Framework v1.10.0
- GORM v1.25.12
- PostgreSQL v17.0
Docker / Docker Compose v2.x

## データベース接続の実装

### 1. データベース設定

`database.go`にてデータベース接続の設定を管理している

```database.go
package database

import (
	"fmt"
	"log"
	"os"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

// データベース接続用のグローバル変数
var DB *gorm.DB

// データベース接続情報の構造体
type DBConfig struct {
	User     string
	Password string
	Host     string
	Port     string
	DBName   string
}

// 環境変数からDB設定を取得
func getDBConfig() *DBConfig {
	return &DBConfig{
		User:     os.Getenv("POSTGRES_USER"),
		Password: os.Getenv("POSTGRES_PASSWORD"),
		Host:     os.Getenv("POSTGRES_HOST"),
		Port:     os.Getenv("POSTGRES_PORT"),
		DBName:   os.Getenv("POSTGRES_NAME"),
	}
}

// DSN文字列を生成
func (c *DBConfig) buildDSN() string {
	return fmt.Sprintf(
		"postgres://%s:%s@%s:%s/%s?sslmode=disable",
		c.User, c.Password, c.Host, c.Port, c.DBName,
	)
}

// データベース初期化
func InitDB() {
	config := getDBConfig()
	dsn := config.buildDSN()

	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
		TranslateError: true, // エラー翻訳機能を有効化
	})
	if err != nil {
		log.Fatalf("データベース接続に失敗しました: %v", err)
	}

	DB = db
	log.Println("データベース接続に成功しました")
}

```

## アプリケーションの起動設定

`main.go`でのデータベース初期化の呼び出しを行う

```main.go
package main

import (
	"log"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/sample_project/internal/adapter/database"
	"github.com/sample_project/internal/adapter/middleware"
	"github.com/sample_project/internal/adapter/routes"
)


func main() {
	// データベース初期化
	database.InitDB()

	// Ginエンジンの初期化
	r := gin.Default()

	// ルーティングの設定
	routes.SetupRoutes(r)

	// サーバーの起動
	if err := r.Run(":8000"); err != nil {
		log.Fatalf("サーバの起動に失敗しました: %v", err)
	}
}
```

## マイグレーションの実装

`migration.go`でのテーブル作成を行う：

```migration.go
package main

import (
	"fmt"
	"log"

	"github.com/sample_project/internal/adapter/database"
	"github.com/sample_project/internal/domain/models"
)

func performMigration() error {
	if err := database.DB.AutoMigrate(&models.Operator{}); err != nil {
		return fmt.Errorf("マイグレーションに失敗しました: %w", err)
	}
	return nil
}

func main() {
	database.InitDB()

	if err := performMigration(); err != nil {
		log.Fatal(err)
	}

	fmt.Println("マイグレーションが正常に完了しました")
}
```

## 環境の構築

`docker-compose.yml`での設定を行う：

```docker-compose.yml
services:
  app:
    container_name: app
    build:
      context: .
      dockerfile: backend/containers/golang/Dockerfile
    volumes:
      - ./backend:/usr/local/go/src/sample_project/backend
    working_dir: /usr/local/go/src/sample_project/backend
    ports:
      - "8000:8000"
    command: air
    env_file:
      - backend/.env
    depends_on:
      db:
        condition: service_healthy

  db:
    container_name: db
    build:
      context: .
      dockerfile: backend/containers/postgres/Dockerfile
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: pg_isready -U "${POSTGRES_USER:-postgres}" || exit 1
      interval: 10s
      timeout: 5s
      retries: 5
    env_file:
      - backend/.env
    ports:
      - "5432:5432" # デバッグ用

  nginx:
    container_name: web
    build:
      context: .
      dockerfile: backend/containers/nginx/Dockerfile
    ports:
      - 80:80
    depends_on:
      - app
    volumes:
      - ./backend/containers/nginx/nginx.conf:/etc/nginx/nginx.conf

volumes:
  db_data:
```

## 重要なポイント

1. **環境変数による設定管理**
   - データベース接続情報は環境変数で管理する
   - 開発/本番環境で柔軟に設定変更が可能である

2. **エラーハンドリング**
   - 接続失敗時の適切なエラーログを出力する
   - アプリケーション起動時の早期エラーを検出する

3. **ヘルスチェック**
   - Dockerコンテナのヘルスチェック機能を実装する
   - データベース接続の安定性を確保する

4. **マイグレーション管理**
   - GORMのAutoMigrate機能を使用する
   - テーブルスキーマを自動生成する

## 使用方法

1. 環境変数の設定を行う
```env
POSTGRES_USER=your_user
POSTGRES_PASSWORD=your_password
POSTGRES_HOST=db
POSTGRES_PORT=5432
POSTGRES_NAME=your_db_name
```

2. アプリケーション起動を実行する
```bash
# コンテナのビルドと起動（バックグラウンド実行）
docker compose up -d --build
```

これにより、以下の処理が自動的に実行されます
1. Dockerイメージのビルド
2. コンテナの起動
3. データベースの初期化
4. マイグレーションの実行（`entrypoint.sh`により自動実行）

なお、`entrypoint.sh`の内容：
```bash
#!/bin/sh
set -eu

# マイグレーションの実行
go run ./internal/infrastructure/db/migrations/migration.go

# アプリケーションの起動（ホットリロード有効）
exec air -c .air.toml -d
```

## まとめ

- 本実装では、GORMを使用したPostgreSQLとの接続管理を、環境変数による設定と適切なエラーハンドリングを含めて実現している
- Dockerコンテナによる開発環境の統一性も確保されており、チーム開発に適した構成となっている