問題 2003 (HY000) を修正する方法: MySQL サーバー 'db_mysql:3306' に接続できません (111)
P粉178132828
2023-09-05 11:18:47
<p>最近、FastAPI Python サーバーをコンテナ化してみました (レプリケーション/二重化の目的でもあります)。以前は、Docker コンテナーに MySQL サーバーだけを入れてすべて問題なかったのですが、Web サーバーもサービスにしたところ、MySQL サーバーに接続できなくなり、アプリケーションが動作しなくなりました。</p>
<p>以下は、アプリケーション内のサーバー データベース初期化コネクタのコード スニペットです</p>
<pre class="lang-py prettyprint-override"><code>fastapi import FastAPI から
mysql.connectorをインポートする
app = FastAPI()
dbconfig = {
"ホスト": "ローカルホスト"、
"データベース": "server_db"、
"ユーザー": "db_user",
"パスワード": "ユーザーパスワード"
}
# データベース接続を確認する
試す:
init_cnx = mysql.connector.connect(
ホスト='ローカルホスト',
ユーザー='db_user',
パスワード='ユーザーパスワード'
)
カーソル = init_cnx.cursor()
Cursor.execute(「'server_db' のようなデータベースを表示」)
カーソル.fetchone() == なしの場合:
# データベースが存在しない場合はデータベースを作成します
Cursor.execute("データベースサーバーの作成")
Cursor.execute("サーバーデータベースを使用")
Cursor.execute("CREATE TABLE メッセージ ("
「message_id INT NOT NULL AUTO_INCREMENT」
「送信者名 VARCHAR(32)」
"message_text VARCHAR(64),"
「作成日: DATE」
「user_messages_count INT」
"主キー (message_id));")
print('データベースが作成されました!')
カーソル.クローズ()
init_cnx.close()
エラーとしての mysql.connector.Error を除く:
print("init_cnx でエラーが発生しました:", err)
# データベースI/O機能
async defexecute_db_query(クエリ、cursor_buffered=False):
cnx = mysql.connector.connect(**dbconfig)
試す:
カーソル = cnx.cursor(buffered=cursor_buffered)
Cursor.execute("サーバーデータベースを使用")
カーソル.実行(クエリ)
結果 = カーソル.fetchall()
cnx.commit()
print("クエリは正常に実行されました!")
結果を返す
e としての例外を除く:
print("クエリの実行中にエラーが発生しました:", e)
ついに:
cnxの場合:
cnx.close()
# ルート ディレクトリ関数を取得します。アプリケーションがデータベースに接続されているかどうかを確認するためにのみ使用されます。
@app.get("/")
非同期デフォルト get_root():
試す:
Entry_count = awaitexecute_db_query("SELECT COUNT(*) FROM Messages",cursor_buffered=True)
return {"メッセージ エントリ":entrys_count[0][0]}
e としての例外を除く:
戻り値 {"エラー": e}
</code></pre>
<p>サーバーの Dockerfile</p>
<pre class="brush:php;toolbar:false;">Python:3.11.4-slim-bookworm より
WORKDIR/アプリ
要件.txt をコピーします。
pip install --no-cache-dir -rrequirements.txt を実行します。
server.py をコピーします。
エクスポーズ8000
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8000"]</pre>
<p>init.sql スクリプト</p>
<pre class="lang-sql prettyprint-override"><code>CREATE USER 'db_user'@'%' IDENTIFIED BY 'user-password';
GRANT オプションを使用して、*.* のすべての権限を 'db_user'@'%' に付与します。
フラッシュ特権;
</code></pre>
<p>およびdocker-compose.yml</p>
<pre class="lang-yaml prettyprint-override"><code>バージョン: "3.8"
サービス:
db_mysql:
画像: mysql:8
再起動: 常に
環境:
MYSQL_ROOT_PASSWORD: "ルート"
ボリューム:
- "./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql"
- "./mysql/db_mysql_data:/var/lib/mysql"
- 「./mysql/mysql_logs:/var/log/mysql」
ネットワーク:
-ダミー_ネットワーク
サーバー_1:
画像: dummy_msg_server
ポート:
- 「8081:8000」
ネットワーク:
-ダミー_ネットワーク
#command: sh -c "60秒スリープ"
依存:
-db_mysql
サーバー_2:
画像: dummy_msg_server
ポート:
- 「8082:8000」
ネットワーク:
-ダミー_ネットワーク
#command: sh -c "60秒スリープ"
依存:
-db_mysql
ボリューム:
db_mysql_data: #external: true
ネットワーク:
ダミーネットワーク:
ドライバー:ブリッジ
</code></pre>
<p>MySQL コンテナが完全に初期化される前に API を使用しようとするとエラーが発生する可能性がありますが、MySQL サーバーがリクエストを処理する準備ができたことを示すまで待機するため、これは問題ではありません。それ以外は、MySQL サーバーに接続しようとしていません。 </p>
<p>ホスト名/IPアドレスを使用して接続しようとしました。
スリム イメージを使用せずに、dockerfile 内の python:3.11.4 イメージを以前の Debian バージョンに変更してみてください。
コンテナにはパブリック ネットワークを明示的に使用してみてください。 Docker はコンテナーがネットワーク内にあることを示し続け、サーバー コンテナーからのcurl リクエストは何かを返します。
さらに、docker-compose.yml は以前、db_mysql サービスにポート 3306:3306 を提供していました。それも問題ないと思います。 </p>
<p><strong>アップデート 1。 </strong>調査中に、データベースがすでに作成されている場合、アプリケーションは問題なくデータベースにリクエストを送信し、正しい応答を取得できることが判明しました。唯一の問題は、コード内の作成スクリプトを使用してデータベースを作成できないことです。 </p><p>
(プロジェクトは現在別のフェーズにあるため、コード ブロックを更新する必要があると思います。)</p>
サーバーとデータベース コンテナーが同時に起動され、問題が発生するという問題が発生しました。データベース サーバーへの最初 (そして最後の) 接続試行は、データベース サーバーが接続を受け入れる準備ができる前に行われます。
この問題を解決するために、docker-compose.yml ファイルにヘルス チェックを追加することにしました:
リーリーこの構成では、データベース サーバーの準備ができていることがヘルス チェックで確認されるまで、サーバーのコンテナは起動しません。
ただし、この状況を処理するには、wait-for-it.sh スクリプトを使用する、より良い方法がある可能性があります。私は個人的に、Docker コンテナを使用してアプリケーションをマイクロサービスに分割している経験豊富なバックエンド開発者を何人か知っています。彼らは、このスクリプトの使用について肯定的なコメントを表明しました。私は個人的に試したことはありませんが、代替ソリューションとして検討することをお勧めします。