0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DockerとGormを使ってデータベース(Postgres)への接続とMigrationを実行しよう!

Posted at

概要

Docker環境でGormを使ってデータベースへの接続とマイグレーションを行う方法について解説します

前提

  • WebフレームワークはGin、DBはPostgresを使用
  • GormとPostgresのドライバーをインストール済み
  • Docker環境を構築している前提で解説するので今回はDockerfileとdocker-compose.ymlの書き方については解説しませんのでご了承ください

ディレクトリ構成

❯ tree
.
├── .env
├── .gitignore
├── Makefile
├── README.md
├── application
│   ├── .air.toml
│   ├── config
│   │   └── database.go
│   ├── go.mod
│   ├── go.sum
│   ├── main.go
│   ├── models.go
├── containers
│   ├── go
│   │   └── Dockerfile
│   └── postgres
│       └── Dockerfile
└── docker-compose.yml

Docker環境の構築

GolangとPostgresのコンテナを用意します

docker-compose.yml
version: '3.9'

services:
  app:
    container_name: app
    build:
      context: .
      dockerfile: containers/go/Dockerfile
    volumes:
      - ./application:/usr/local/go/src/go-practice
    ports:
      - '8000:8000'
    command: air -c .air.toml
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
    networks:
      - proxynet
  db:
    container_name: db
    image: postgres:16.2
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: pg_isready -U "${POSTGRES_USER:-postgres}" || exit 1
      interval: 10s
      timeout: 5s
      retries: 5
    environment:
      - POSTGRES_NAME
      - POSTGRES_USER
      - POSTGRES_PASSWORD
    ports:
      - '5432:5432' # デバッグ用
    networks:
      - proxynet
networks:
  proxynet:
    name: testnet
    external: false
volumes:
  db_data:

環境変数は.envに記載します

.env
POSTGRES_NAME=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_PORT=5432
POSTGRES_HOST=db

main.go

main.goにDBへ接続する設定を記載します

db, err := config.StartDatabase()

からDBのインスタンスかエラーを取得し、
エラーが出力されたら処理を終了させます

application/main.go
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/shun198/go-practice/config"
)

func main() {
	r := gin.Default()
	r.Use(gin.Logger())
	r.Use(gin.Recovery())
	db, err := config.StartDatabase()

	if err != nil {
		panic(err)
	}
	r.GET("/api/health", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "pass",
		})
	})
	routes.GetUserRoutes(r, db)
	routes.GetEventRoutes(r, db)
	r.Run(":8000")
}

データベースへの接続とMigrationの実行

Postgresのコンテナへ接続するよう設定します
以下のようにdsnにDBへ接続するための情報を代入します
コンテナを使用するときのホストはdocker-compose.ymlで設定したdbを使用しています

dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s",
		host, user, password, dbName, port)

 
その後、DBをopenにした後、Migrationを実行します

application/config/database.go
package config

import (
	"fmt"
	"os"

	"github.com/shun198/go-practice/models"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

func StartDatabase() (*gorm.DB, error) {
	host := os.Getenv("POSTGRES_HOST")
	user := os.Getenv("POSTGRES_USER")
	password := os.Getenv("POSTGRES_PASSWORD")
	dbName := os.Getenv("POSTGRES_NAME")
	port := os.Getenv("POSTGRES_PORT")

	dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s",
		host, user, password, dbName, port)
	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
	if err != nil {
		return nil, err
	}
	if err := migrateDatabase(db); err != nil {
		return nil, err
	}
	return db, err
}

func migrateDatabase(db *gorm.DB) error {
	return db.AutoMigrate(
		models.User{},
	)
}

Modelの作成

今回はUser用のModelを作成します

applicatin/models.go
package models

import (
	"time"
)

type User struct {
	ID             uint      `gorm:"primaryKey" json:"id"`
	EmployeeNumber string    `gorm:"uniqueIndex;not null;size:8" json:"employeeNumber"`
	Email          string    `gorm:"uniqueIndex;not null;size:255" json:"email"`
	Name           string    `gorm:"not null;size:255" json:"name"`
	Password       string    `gorm:"not null;size:255" json:"-"`
	Verified       bool      `gorm:"not null" json:"verified"`
	Role           uint8     `gorm:"not null" json:"role"`
	Disabled       bool      `gorm:"not null;default:false"`
	CreatedAt      time.Time `gorm:"- autoCreateTime" json:"-"`
	UpdatedAt      time.Time `gorm:"- autoUpdateTime" json:"-"`
	CreatedByID    *uint     `gorm:"" json:"-"`
	CreatedBy      *User     `gorm:"not null" json:"-"`
	UpdatedByID    *uint     `gorm:"" json:"-"`
	UpdatedBy      *User     `gorm:"not null" json:"-"`
}

実際にMigrationを実行してみよう!

GOのコンテナを起動すると自動的にmigrationが実行されます
以下のようにUserテーブルが作成されていたら成功です

postgres=# \d users
                                         Table "public.users"
     Column      |           Type           | Collation | Nullable |              Default              
-----------------+--------------------------+-----------+----------+-----------------------------------
 id              | bigint                   |           | not null | nextval('users_id_seq'::regclass)
 employee_number | character varying(8)     |           | not null | 
 email           | character varying(255)   |           | not null | 
 name            | character varying(255)   |           | not null | 
 password        | character varying(255)   |           | not null | 
 verified        | boolean                  |           | not null | 
 role            | smallint                 |           | not null | 
 disabled        | boolean                  |           | not null | false
 created_at      | timestamp with time zone |           |          | 
 updated_at      | timestamp with time zone |           |          | 
 created_by_id   | bigint                   |           |          | 
 updated_by_id   | bigint                   |           |          | 
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "idx_users_email" UNIQUE, btree (email)
    "idx_users_employee_number" UNIQUE, btree (employee_number)
Foreign-key constraints:

参考

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?