在Docker中运行MySQL/MariaDB时出现操作错误:在“读取初始通信数据包”时与MySQL服务器的连接丢失

ijnw1ujt  于 2022-11-08  发布在  Docker
关注(0)|答案(2)|浏览(170)

在Docker容器中运行MySQL/MariaDB:

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版本4:

manage.py runserver 127.0.0.1:8000

错误

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>

我将从Makefile启动Django和MySQL/MariaDB Docker容器。

生成文件

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
u59ebvdq

u59ebvdq1#

在容器中使用healthcheck.sh,使用MARIADB_MYSQL_LOCALHOST_USER=1创建一个mysql@localhost用户,脚本可以使用该用户访问数据库,
运行状况检查将一直等待,直到完全启动,而不考虑时间。
生成文件:

.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,否则将不会创建数据库/用户。

pqwbnv8z

pqwbnv8z2#

这个问题可能是由于争用条件造成的,Django试图在数据库准备好之前连接到数据库。请尝试在启动Docker容器后等待几秒钟。

简单的解决方案

生成文件

.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
    sleep 4

使用www.example.com的更好解决方案healthcheck.sh

Dan Black's answer中,他指出MariaDB docker容器包含一个脚本healthcheck.sh
如果您只想检查MariaDB容器是否可以接收连接,则可以在不指定用户的情况下运行healthcheck.sh(避免授权复杂化)。
下面的Makefile将每秒检查一次数据库连接,直到数据库就绪。

Makefile(高级版本)

.PHONY: mysql-start
mysql-start: mysql-stop
    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
    while ! docker exec $(DATABASE_NAME) healthcheck.sh --connect 2> /dev/null; do sleep 1; done

相关问题