1
0

More than 1 year has passed since last update.

gin + mysql + dockerでconnection refusedエラー

Last updated at Posted at 2023-02-04

gin + mysql + dockerで環境を構築した際に遭遇したconnection refusedエラーと対応について記載する。

問題の概要

docker-compose.ymlでdepends_onを使い、mysql → goの順に起動するよう制御しているつもりが、
mysqlの起動を待たずにgoが起動してしまい、connection refusedで落ちる。

TL;DR

docker-composeのconditonとhealthcheckを使うことでmysqlの起動を待ってからgoを起動させることに成功。
下記のようにapp/depends_onのconditionとdbのhealthcheckを追記した。

対処前のdocker-compose.ymlのdepends_on
services:
  go:
    depends_on:
      - db

  db:
    (通常通りの設定)
対処後のdocker-compose.ymlのdepends_on
services:
  go:
    depends_on:
      db:
        condition: service_healthy

  db:
    healthcheck:
      test: mysqladmin ping -h 127.0.0.1 -u$$MYSQL_USER -p$$MYSQL_PASSWORD

問題が発生した時の状況

環境

Mac M1
OS Monterey
Docker 20.10.22

構成

root
  ├ .env
  ├ docker-compose.yml
  ├ Dockerfile
  ├ go.mod
  ├ go.sum
  └ main.go

main.go

main.go
func main() {
	config := mysql.Config{
		User:                 os.Getenv("MYSQL_USER"),
		Passwd:               os.Getenv("MYSQL_PASSWORD"),
		Net:                  "tcp",
		Addr:                 os.Getenv("MYSQL_HOST") + ":3306",
		DBName:               os.Getenv("MYSQL_DATABASE"),
		AllowNativePasswords: true,
	}

	var err error
	db, err = sql.Open("mysql", config.FormatDSN())
	if err != nil {
		log.Fatal(err)
	}

	pingErr := db.Ping()
	if pingErr != nil {
		log.Fatal(pingErr)
	}
	fmt.Println("Connected!")

	router := gin.Default()
	router.Run()
}

発生したエラー

docker-compopse up時に発生。
途中db側の起動が終わる前にgoのログ(connection refused)が吐かれている。
デバッグしてみるとわかるが、main.goのdb.Ping()での疎通確認で発生している。

Attaching to golang-docker-app-1, golang-docker-db-1
db-1   | 2023-02-04 19:52:47+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.32-1.el8 started.
(...まずはdb側が起動している様子のログ...)
app-1  | 2023/02/04 19:52:55 dial tcp 172.21.0.2:3306: connect: connection refused
app-1  | exit status 1
app-1 exited with code 1
(...以降引き続きdb側のログ...)

原因

詳細はわかっていないが、どうやらMacだとdepends_onで「起動した」と判定するタイミングが早いようで、
mysqlの準備が整う前に「起動したよ」と判断してしまう様子。
ちなみにこれはIntel Macでも発生。

上記の通りconditionとhealthcheckを利用することで解決。

ちなみにlinuxだと発生しなかった。

Tips:override.yml

Macのためだけにdocker-compose.ymlにhealthcheckつけるの嫌だよねという意見もありそう。
そんな時はdocker-compose.override.ymlを使うという手がある。

docker-compose.override.ymlは、その名の通りdocker-compose.ymlの設定を上書き変更するための設定ファイル。
docker起動時にdocker-compose.ymlと一緒に読み込まれる。

使い方としては、

  • 基本の設定はdocker-comopse.ymlに記述
  • 上書き・追記したい部分だけをdocker-compose.override.ymlに記述して、同じディレクトリに置いておく。
  • docker-compose.override.ymlをgitignoreに入れておく

という感じかなと。

今回の問題に当てはめてみた場合はこちら。

docker-compose.yml
services:
  go:
    depends_on:
      - db

  db:
    (通常通りの設定)
docker-compose.override.yml
services:
  go:
    depends_on:
      db:
        condition: service_healthy

  db:
    healthcheck:
      test: mysqladmin ping -h 127.0.0.1 -u$$MYSQL_USER -p$$MYSQL_PASSWORD

詳しくはこちら

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