문제 2003(HY000) 해결 방법: MySQL 서버 'db_mysql:3306'에 연결할 수 없습니다(111).
P粉178132828
2023-09-05 11:18:47
<p>저는 최근 FastAPI Python 서버 컨테이너화를 시도했습니다(복제/두배 목적으로도). 이전에는 Docker 컨테이너에 MySQL 서버만 있으면 모든 것이 괜찮았지만 웹 서버도 서비스로 만들었을 때 MySQL 서버에 연결할 수 없어 이제는 애플리케이션이 작동하지 않습니다.</p>
<p>다음은 애플리케이션의 서버 데이터베이스 초기화 커넥터에 대한 코드 조각입니다</p>
<pre class="lang-py Prettyprint-override"><code>from fastapi import FastAPI
mysql.connector 가져오기
앱 = FastAPI()
DB구성 = {
"호스트": "로컬호스트",
"데이터베이스": "server_db",
"사용자": "db_user",
"password": "사용자-비밀번호"
}
# 데이터베이스 연결 확인
노력하다:
init_cnx = mysql.connector.connect(
호스트='로컬호스트',
사용자='db_user',
비밀번호='사용자-비밀번호'
)
커서 = init_cnx.cursor()
cursor.execute("'server_db'와 같은 데이터베이스 표시")
커서.fetchone() == 없음인 경우:
# 데이터베이스가 존재하지 않으면 데이터베이스를 생성합니다.
커서.execute("CREATE DATABASE server_db")
커서.execute("서버_db 사용")
cursor.execute("CREATE TABLE 메시지("
"message_id INT NOT NULL AUTO_INCREMENT,"
"발신자_이름 VARCHAR(32),"
"message_text VARCHAR(64),"
"created_at DATE,"
"user_messages_count INT,"
"기본 키(message_id));")
print('데이터베이스가 생성되었습니다!')
커서.닫기()
init_cnx.close()
mysql.connector.Error를 err로 제외:
print("init_cnx에서 오류가 발생했습니다:", err)
# 데이터베이스 I/O 기능
비동기 defexecute_db_query(query,cursor_buffered=False):
cnx = mysql.connector.connect(**dbconfig)
노력하다:
커서 = cnx.cursor(buffered=cursor_buffered)
커서.execute("서버_db 사용")
커서.실행(쿼리)
결과 = 커서.fetchall()
cnx.커밋()
print("쿼리가 성공적으로 실행되었습니다!")
결과 반환
e와 같은 예외를 제외하고:
print("쿼리 실행 중 오류 발생:", e)
마지막으로:
만약 cnx라면:
cnx.닫기()
# 애플리케이션이 데이터베이스에 연결되어 있는지 확인하는 데 사용되는 루트 디렉터리 기능을 가져옵니다.
@app.get("/")
비동기 def get_root():
노력하다:
항목_카운트 = 실행 실행을 기다립니다_db_query("SELECT COUNT(*) FROM 메시지",cursor_buffered=True)
{"메시지 항목"을 반환합니다: 항목_수[0][0]}
e와 같은 예외를 제외하고:
{"오류": e}를 반환합니다.
<p>서버의 Dockerfile</p>
<pre class="brush:php;toolbar:false;">FROM python:3.11.4-slim-bookworm
WORKDIR/앱
요구사항.txt를 복사하세요.
실행 pip install --no-cache-dir -r 요구사항.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 OPTION을 사용하여 *.*에 대한 모든 권한을 'db_user'@'%'에 부여합니다.
플러시 권한;
<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"
네트워크:
-dummy_network
서버_1:
이미지: dummy_msg_server
포트:
- "8081:8000"
네트워크:
-dummy_network
#명령: sh -c "sleep 60s"
의존:
-db_mysql
서버_2:
이미지: dummy_msg_server
포트:
- "8082:8000"
네트워크:
-dummy_network
#명령: sh -c "sleep 60s"
의존:
-db_mysql
볼륨:
db_mysql_data: #외부: 참
네트워크:
dummy_network:
드라이버: 브릿지
<p>MySQL 컨테이너가 완전히 초기화되기 전에 API를 사용하려고 하면 오류가 발생할 수 있지만 MySQL 서버가 요청을 처리할 준비가 되었음을 나타낼 때까지 기다리기 때문에 이는 문제가 되지 않습니다. 그 외에는 MySQL 서버에 연결을 시도하지 않습니다. </p>
<p>호스트 이름/IP 주소를 사용하여 연결을 시도했습니다.
슬림 이미지를 사용하지 않고 dockerfile의 python:3.11.4 이미지를 이전 Debian 버전으로 변경해 보세요.컨테이너에 대해 공용 네트워크를 명시적으로 사용해 보십시오. Docker는 컨테이너가 네트워크에 있음을 계속 표시하고 서버 컨테이너의 컬 요청이 무언가를 반환합니다.
또한 docker-compose.yml은 이전에 db_mysql 서비스에 포트 3306:3306을 제공했습니다. 그것도 문제가 아닌 것 같아요. </p>
<p><strong>업데이트 1. </strong>조사 중에 데이터베이스가 이미 생성된 경우 애플리케이션이 해당 데이터베이스에 요청을 보내고 올바른 응답을 받는 데 아무런 문제가 없다는 사실이 발견되었습니다. 유일한 문제는 코드의 생성 스크립트를 사용하여 데이터베이스를 생성할 수 없다는 것입니다. </p><p>
(이제 프로젝트가 다른 단계에 있으므로 코드 블록을 업데이트해야 할 것 같습니다.)</p>
서버와 데이터베이스 컨테이너가 동시에 시작되어 문제가 발생하는 문제가 발생했습니다. 데이터베이스 서버에 대한 첫 번째(및 마지막) 연결 시도는 데이터베이스 서버가 연결을 수락할 준비가 되기 전에 발생합니다.
이 문제를 해결하기 위해 docker-compose.yml 파일에 상태 확인을 추가하기로 결정했습니다.
으아악이 구성을 사용하면 상태 확인을 통해 데이터베이스 서버가 준비되었음을 확인할 때까지 서버의 컨테이너가 시작되지 않습니다.
그러나 wait-for-it.sh스크립트를 사용하여 이 상황을 처리하는 더 나은 방법이 있습니다. 저는 개인적으로 Docker 컨테이너를 사용하여 애플리케이션을 마이크로서비스로 분할하는 숙련된 백엔드 개발자를 알고 있습니다. 그들은 이 스크립트 사용에 대해 긍정적인 의견을 표명했습니다. 개인적으로 시도하지는 않았지만 대체 솔루션으로 고려해 보는 것이 좋습니다.