2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

failed to initialize database, got error dial tcp 127.0.0.1:3306: connect: connection refusedの対処法[Go,MySQL,Docker]

Posted at

Go+MySQLをDockerで立ち上げようとしたら下のようなエラーが出ました。

failed to initialize database, got error dial tcp 127.0.0.1:3306: connect: connection refused

これはdatabaseの初期化がうまくいかず、コネクションができなかったというエラーです。

解決方法

dsnを確認する

dsnは、Data Source Nameの略称で、データベースの識別子のことです。

例えばMySQLだと以下のようなdsnになります。

[user]:[password]@tcp([IPアドレス]:3306)/[database_name]?charset=utf8mb4&parseTime=True

まず上手くいかなかった例を紹介します。

私は、ymlファイルにMySQLの設定を下のように記述していました。

docker-compose.yml
services:
  server:
    build:
      context: .
      dockerfile: ./docker/go/Dockerfile
    tty: true
    depends_on:
      - db
    ports:
      - 8080:8080
  db:
    image: mysql:8.0
    container_name: db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      TZ: Asia/Tokyo
      LANG: ja_JP.UTF-8
    ports:
      - 3306:3306
    volumes:
      - db-volume:/var/lib/mysql

volumes:
  db-volume:

この場合、dsnは下のようになると思っていましたが、そうではありませんでした。

user:password@tcp(127.0.0.1:3306)/db?charset=utf8mb4&parseTime=True

このdsnがうまくいかなかった理由は、dockerで作成されたネットワークでは、mysqlのコンテナは必ずしも127.0.0.1にはならず、動的にIPアドレスが変更されていってしまうからでした。

実際には下のようにすると、接続できました。

user:password@tcp(db:3306)/db?charset=utf8mb4&parseTime=True

docker composeを使用すると、プロジェクト毎にブリッジネットワークが自動作成され、同一ymlファイルに書かれているサービス同士はコンテナ名でIPアドレス解決ができるようになります。

もし、同一ymlファイルに書かれていない場合にコンテナ名解決をしたい場合は、docker network createでネットワークを定義する必要があります。

↓この記事で同じymlに書いていないコンテナ同士の通信の仕方を書いています。

なので、実際にGoでは下のような実装でdb接続しました。

func ConnectDB() (*gorm.DB, error) {
	var db *gorm.DB
	var err error

	dsn := "user:password@tcp(db:3306)/db?charset=utf8mb4&parseTime=True"

	return db, nil
}

リトライ処理をつける

ymlファイルで、dbのコンテナを依存関係として明示していても、起動した後にサーバーアプリケーションのコンテナが立ち上がるので、dbが接続できるようになる前に接続動作が行われ、アプリケーションが接続できない場合もあります。

その場合は下のようなリトライ接続ができる仕組みを作成します。

func ConnectDB() (*gorm.DB, error) {
	var db *gorm.DB
	var err error

	dsn := "user:password@tcp(db:3306)/db?charset=utf8mb4&parseTime=True"

	count := 5

	for count > 1 {
		if db, err = gorm.Open(mysql.Open(dsn)); err != nil {
			time.Sleep(2 * time.Second)
			count--
			log.Printf("retry... count:%v\n", count)
			continue
		}
		break
	}

	return db, nil
}

こうすることで5回まで接続動作をリトライしてくれます。

2
2
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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?