Cara untuk membetulkan isu 2003 (HY000): Tidak dapat menyambung ke pelayan MySQL 'db_mysql:3306' (111)
P粉178132828
2023-09-05 11:18:47
<p>Baru-baru ini saya cuba menyimpan pelayan Python FastAPI saya (juga untuk tujuan replikasi/penggandaan). Sebelum ini, saya hanya mempunyai pelayan MySQL dalam bekas Docker dan semuanya baik-baik saja, tetapi apabila saya juga menjadikan pelayan web saya sebagai perkhidmatan, ia tidak dapat menyambung ke pelayan MySQL, jadi kini aplikasi itu tidak berfungsi.</p>
<p>Berikut ialah coretan kod untuk penyambung permulaan pangkalan data pelayan dalam aplikasi</p>
<pre class="lang-py prettyprint-override"><kod>dari fastapi import FastAPI
import mysql.connector
app = FastAPI()
dbconfig = {
"hos": "localhost",
"pangkalan data": "server_db",
"pengguna": "db_user",
"kata laluan": "kata laluan pengguna"
}
# Semak sambungan pangkalan data
cuba:
init_cnx = mysql.connector.connect(
hos='localhost',
pengguna='db_user',
kata laluan='kata laluan pengguna'
)
kursor = init_cnx.cursor()
cursor.execute("TUNJUKKAN PANGKALAN DATA SEPERTI 'server_db'")
jika cursor.fetchone() == Tiada:
# Jika pangkalan data tidak wujud, buat pangkalan data
cursor.execute("CIPTA PANGKALAN DATA pelayan_db")
cursor.execute("GUNAKAN pelayan_db")
cursor.execute("BUAT Mesej JADUAL ("
"id_mesej INT BUKAN NULL AUTO_INCREMENT,"
"nama_pengirim VARCHAR(32),"
"teks_mesej VARCHAR(64),"
"dicipta_pada DATE,"
"pengguna_messages_count INT,"
"KUNCI UTAMA (message_id));")
print('Pangkalan data telah dibuat!')
cursor.close()
init_cnx.close()
kecuali mysql.connector.Error as err:
print("Ralat berlaku dalam init_cnx:", err)
# Fungsi I/O pangkalan data
async def execute_db_query(query, cursor_buffered=False):
cnx = mysql.connector.connect(**dbconfig)
cuba:
kursor = cnx.cursor(buffered=cursor_buffered)
cursor.execute("GUNAKAN pelayan_db")
cursor.execute(query)
hasil = cursor.fetchall()
cnx.commit()
print("Pertanyaan berjaya dilaksanakan!")
pulangan hasil
kecuali Pengecualian sebagai e:
print("Ralat semasa melaksanakan pertanyaan:", e)
akhirnya:
jika cnx:
cnx.close()
# Dapatkan fungsi direktori akar, hanya digunakan untuk menyemak sama ada aplikasi disambungkan ke pangkalan data
@app.get("/")
async def get_root():
cuba:
entries_count = tunggu execute_db_query("PILIH COUNT(*) DARI Messages", cursor_buffered=True)
kembalikan {"Entri mesej": entries_count[0][0]}
kecuali Pengecualian sebagai e:
kembalikan {"Ralat": e}
</code></pre>
<p>Fail Docker Pelayan</p>
<pre class="brush:php;toolbar:false;">FROM python:3.11.4-slim-bookworm
WORKDIR/apl
SALINAN keperluan.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY server.py .
DEDAH 8000
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8000"]</pre>
<p>skrip init.sql</p>
<pre class="lang-sql prettyprint-override"><kod>BUAT PENGGUNA 'db_user'@'%' DIKENAL PASTI OLEH 'kata laluan pengguna';
BERIKAN SEMUA KEISTIMEWAAN PADA *.* KEPADA 'db_user'@'%' DENGAN PILIHAN GERAN;
KEISTIMEWAAN FLUSH;
</code></pre>
<p>dan docker-compose.yml</p>
<pre class="lang-yaml prettyprint-override"><code>versi: "3.8"
perkhidmatan:
db_mysql:
imej: mysql:8
mulakan semula: sentiasa
persekitaran:
MYSQL_ROOT_PASSWORD: "root"
jilid:
- "./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql"
- "./mysql/db_mysql_data:/var/lib/mysql"
- "./mysql/mysql_logs:/var/log/mysql"
rangkaian:
-dummy_network
pelayan_1:
imej: dummy_msg_server
pelabuhan:
- "8081:8000"
rangkaian:
-dummy_network
#perintah: sh -c "tidur 60-an"
bergantung kepada:
-db_mysql
pelayan_2:
imej: dummy_msg_server
pelabuhan:
- "8082:8000"
rangkaian:
- dummy_network
#perintah: sh -c "tidur 60-an"
bergantung kepada:
-db_mysql
jilid:
db_mysql_data: #external: true
rangkaian:
dummy_network:
pemandu:jambatan
</code></pre>
<p>Walaupun cuba menggunakan API sebelum bekas MySQL telah dimulakan sepenuhnya mungkin mengakibatkan ralat, ini tidak menjadi masalah kerana saya menunggu sehingga pelayan MySQL menunjukkan ia bersedia untuk mengendalikan permintaan. Selain itu, saya tidak cuba menyambung ke pelayan MySQL. </p>
<p>Saya cuba menyambung menggunakan nama hos/alamat IP.
Cuba tukar imej python:3.11.4 dalam fail docker kepada versi debian yang lebih awal dan tidak menggunakan imej tipis.Cuba gunakan rangkaian awam secara eksplisit untuk bekas. Docker terus menunjukkan bahawa bekas itu berada dalam rangkaian, dan permintaan curl daripada bekas pelayan mengembalikan sesuatu.
Selain itu, docker-compose.yml sebelum ini menyediakan port 3306:3306 untuk perkhidmatan db_mysql. Rasanya itu bukan masalah juga. </p>
<p><strong>Kemas kini 1. </strong>Semasa penyiasatan, didapati bahawa jika pangkalan data telah dibuat, aplikasi tidak mempunyai masalah menghantar permintaan kepadanya dan mendapat respons yang betul. Satu-satunya masalah dengannya ialah pangkalan data tidak boleh dibuat menggunakan skrip cipta dalam kod. </p><p>
(Rasanya, saya patut mengemas kini blok kod kerana projek itu dalam fasa lain sekarang.)</p>
Saya menghadapi masalah di mana pelayan dan bekas pangkalan data dimulakan pada masa yang sama, menyebabkan masalah. Percubaan pertama (dan terakhir) untuk menyambung ke pelayan pangkalan data berlaku sebelum pelayan pangkalan data bersedia untuk menerima sambungan.
Untuk menyelesaikan masalah ini, saya memutuskan untuk menambah pemeriksaan kesihatan dalam fail docker-compose.yml:
Dengan konfigurasi ini, bekas pelayan tidak akan bermula sehingga pemeriksaan kesihatan mengesahkan bahawa pelayan pangkalan data sudah sedia.
Walau bagaimanapun, terdapat cara yang lebih baik untuk mengendalikan situasi ini, yang melibatkan penggunaan skrip wait-for-it.sh. Saya secara peribadi mengenali beberapa pembangun bahagian belakang berpengalaman yang juga menggunakan bekas Docker untuk memisahkan aplikasi mereka kepada perkhidmatan mikro. Mereka menyatakan komen positif tentang penggunaan skrip ini. Walaupun saya belum mencubanya secara peribadi, saya mengesyorkan mempertimbangkannya sebagai penyelesaian alternatif.