Django.db.utils.OperationalError при запуске MySQL/MariaDB в Docker: Потеряно соединение с сервером MySQL на этапе 'чтение начального пакета связи'

Запуск Django версии 4 локально с:

manage.py runserver 127.0.0.1:8000

Запуск MySQL/MariaDB в контейнере Docker:

docker run -p 3306:3306 --name $(DATABASE_NAME) -v /tmp/mysql:/var/lib/mysql -e MYSQL_DATABASE=$(DATABASE_NAME) -e MYSQL_USER=$(DATABASE_USER) -e MYSQL_ROOT_PASSWORD=$(DATABASE_PASSWORD) -d mariadb:latest > /dev/null

Ошибка

django.db.utils.OperationalError: (2013, "Lost connection to MySQL server at 'reading initial communication packet', system error: 2")

Я могу успешно подключиться к базе данных с помощью MySQL Workbench, а также команды:

mysql -h 127.0.0.1 -P 3306 -u root -p <database>

Я запускаю Django и контейнер MySQL/MariaDB Docker из Makefile.

Makefile

SHELL := /bin/bash

.PHONY: dj-start-local
dj-start-local: start-mysql
    PYTHONPATH=. django_project/src/manage.py runserver 127.0.0.1:8000

.PHONY: start-mysql
start-mysql:
    docker run -p 3306:3306 --name $(DATABASE_NAME) -v /tmp/mysql:/var/lib/mysql -e MYSQL_DATABASE=$(DATABASE_NAME) -e MYSQL_USER=$(DATABASE_USER) -e MYSQL_ROOT_PASSWORD=$(DATABASE_PASSWORD) -d mariadb:latest > /dev/null

Проблема может быть вызвана состоянием гонки, когда Django пытается подключиться к базе данных до того, как она будет готова. Попробуйте подождать несколько секунд после запуска контейнера Docker.

Makefile

.PHONY: start-mysql
start-mysql:
    docker run -p 3306:3306 --name $(DATABASE_NAME) -v /tmp/mysql:/var/lib/mysql -e MYSQL_DATABASE=$(DATABASE_NAME) -e MYSQL_USER=$(DATABASE_USER) -e MYSQL_ROOT_PASSWORD=$(DATABASE_PASSWORD) -d mariadb:latest > /dev/null
    sleep 4

Используйте healthcheck.sh в контейнере. Используйте MARIADB_MYSQL_LOCALHOST_USER=1 для создания mysql@localhost пользователя, которого сценарий может использовать для доступа к базе данных,

Проверка здоровья ждет до полного запуска, независимо от времени.

Makefile:

.PHONY: start-mariadb
start-mariadb:
    docker run -p 3306:3306 --name $(DATABASE_NAME) \
        -e MARIADB_DATABASE=$(DATABASE_NAME) \
        -e MARIADB_USER=$(DATABASE_USER) \
        -e MARIADB_PASSWORD=$(DATABASE_PASSWORD) \
        -e MARIADB_ROOT_PASSWORD=$(DATABASE_PASSWORD) \
        -e MARIADB_MYSQL_LOCALHOST_USER=1 \
        -v /tmp/mysql:/var/lib/mysql \
        -d mariadb:latest
    while ! docker exec $(DATABASE_NAME) healthcheck.sh --su=mysql --connect --innodb_initialized; do sleep 1; done
    docker exec --user mysql $(DATABASE_NAME) mariadb -e 'select "hello world"'

Выполнение теста:

$ make start-mariadb 
docker run -p 3306:3306 --name dd \
    -e MARIADB_DATABASE=dd \
    -e MARIADB_USER=dd \
    -e MARIADB_PASSWORD=dd \
    -e MARIADB_ROOT_PASSWORD=dd \
    -e MARIADB_MYSQL_LOCALHOST_USER=1 \
    -d mariadb:latest
53066fffa293ed061743024e387bd7fb6f1c664efd603c7a657ba88e307be308
while ! docker exec dd healthcheck.sh --su=mysql --connect --innodb_initialized; do sleep 1; done
healthcheck connect failed
healthcheck connect failed
healthcheck connect failed
healthcheck connect failed
docker exec --user mysql dd mariadb -e 'select "hello world"'
hello world
hello world

Примечание: добавлено MARIADB_PASSWORD иначе база данных/пользователь не будут созданы.

Вернуться на верх