LoginSignup
0
0

【Mysql x Docker】エラー「MySQLdb._exceptions.OperationalError: (2002, "Can't connect to MySQL server on 'db' (115)")」の原因

Posted at

概要

docker-composeでdockerコンテナを起動時、「たまに」以下のエラーが出る状態でした。
なぜこれが「たまに」だったのか、またどうすればでなるくなるかわかったので紹介します。

MySQLdb._exceptions.OperationalError: (2002, "Can't connect to MySQL server on 'db' (115)")

とか

sqlalchemy.exc.OperationalError: (MySQLdb._exceptions.OperationalError) (2002, "Can't connect to MySQL server on 'db' (115)")

(Background on this error at: https://sqlalche.me/e/14/e3q8)

原因

原因は、アプリサーバのサービスがMySQLサービスよりも先に起動してしまい、MySQLサーバーがまだ準備ができていないため。

Docker Composeはサービスを並行して起動するのですが、毎回このエラーが出るわけではないのは、MySQLサービスが先に起動してくれることもあるからなのでしょう。

docker-compose.yamlの以下の箇所を追加したら、エラーが出なくなりました。

version: "3.8"

services:
  sample_server:
    build:
      context: ../../
      dockerfile: ./docker/Dockerfile
    volumes:
      - ../../web_app:/xxx/web_app
    image: sample_server
    container_name: sample_server
    hostname: sample-server
    privileged: true
    restart: always
    tty: true
    ports:
      - "80:80"
    networks:
      fixed_compose_network:
        aliases:
          - backend
    depends_on:  # 追加
      mysql:  # 追加
        condition: service_healthy  # 追加

  mysql:
    image: mysql:8.0
    container_name: mysql-container
    restart: always
    volumes:
      - ./database/sql:/sql
    ports:
      - "3306:3306"
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    networks:
      fixed_compose_network:
        aliases:
          - db
    healthcheck: # 追加
        test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] # 追加
        interval: 10s # 追加
        timeout: 5s # 追加
        retries: 5 # 追加

networks:
  fixed_compose_network:

最初はdepends_onオプションでmysqlを指定したのですが、それだけではエラーが解決しませんでした。起動の順番は制御できるようですが、正常起動したかどうかまではみてくれない?ようです。

depends_on expresses startup and shutdown dependencies between services.
引用元:https://docs.docker.com/compose/compose-file/05-services/#depends_on

そこで、healthcheckを組み合わせて、依存先のサービスがhealthy(=操作可能)になるまで待つように追加してみました。これで実行したところ、エラーが出ることは無くなりました。

healthcheckとは

healthcheckキーは、サービスが正常に動作しているかどうかを定期的に確認するもの。

test: ...がヘルスチェックのテストコマンド。このコマンドが成功(終了コード0)を返すと、サービスはhealthyと見なされます。
interval: 10sは、ヘルスチェックが10秒ごとに実行されますよ、という間隔。
timeout: 5sは、ヘルスチェックがタイムアウトするまでの時間。
retries: 5は、ヘルスチェックが連続して失敗するとサービスがunhealthyと見なされるまでの回数を定義します。

以前postgresでも似た事象があったのでご参考までに。

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