FastAPI和PostgreSQL在docker-compose文件中的连接错误

3
这个问题已经被问过了,例如Docker:服务器是否在主机“localhost”(::1)上运行,并在端口5432上接受TCP/IP连接?,但我仍然无法弄清如何正确地将应用程序连接到数据库。
文件:
Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY . .
RUN pip install --upgrade pip
RUN pip install "fastapi[all]" sqlalchemy psycopg2-binary

docker-compose.yml

version: '3.8'
services:
  ylab:
    container_name: ylab
    build:
      context: .
    entrypoint: >
      sh -c "uvicorn main:app --reload --host 0.0.0.0"
    ports:
      - "8000:8000"
  postgres:
    container_name: postgr
    image: postgres:15.1-alpine
    environment:
        POSTGRES_DB: "fastapi_database"
        POSTGRES_PASSWORD: "password"
    ports:
      - "5433:5432"

main.py

import fastapi as _fastapi
import sqlalchemy as _sql
import sqlalchemy.ext.declarative as _declarative
import sqlalchemy.orm as _orm

DATABASE_URL = "postgresql://postgres:password@localhost:5433/fastapi_database"
engine = _sql.create_engine(DATABASE_URL)
SessionLocal = _orm.sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = _declarative.declarative_base()

class Menu(Base):
    __tablename__ = "menu"
    id = _sql.Column(_sql.Integer, primary_key=True, index=True)
    title = _sql.Column(_sql.String, index=True)
    description = _sql.Column(_sql.String, index=True)

app = _fastapi.FastAPI()

# Create table 'menu'
Base.metadata.create_all(bind=engine)

如果我只将postgres数据库托管在容器中而我的应用程序在本地运行,则此方法有效,但是如果数据库和应用程序位于它们自己的容器中,无论我如何更改设置,错误都会出现:

"sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) 连接到位于“localhost”(127.0.0.1),端口5433的服务器失败:连接被拒绝 ylab | 该服务器是否正在运行并接受TCP / IP连接? ylab | connection to server at "localhost" (::1), port 5433 failed: Cannot assign requested address ylab | 该服务器是否正在运行并接受TCP / IP连接?"

这个错误会在以下位置出现:

Base.metadata.create_all(bind=engine)

我也尝试过

DATABASE_URL = "postgresql://postgres:password@postgres:5433/fastapi_database"

但仍然出现错误:

"sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) 连接到服务器“postgres”(172.23.0.2),端口5433失败:连接被拒绝 ylab | 该主机上是否正在运行服务器并接受TCP/IP连接?"

在上面的答案中提到了某种配置文件或其他内容,但我无法弄清楚如何管理该配置。


1
如果将配置尝试为DATABASE_URL = "postgresql:// postgres:password @ postgres:5432 / fastapi_database",那会发生什么呢? 在应用程序在本地运行且postgres在容器中的第一个示例中,这可行,因为您将“localhost:5433”映射到postgres容器端口“5432”。 当您尝试在应用程序容器中执行此操作时,它不起作用,因为数据库不在应用程序容器中本地运行。 当您将“localhost”更改为“postgres”时,这将开始以正确的容器对准db,但是容器内运行的db端口为5432而不是5433。 - Chris Doyle
我按照你的建议尝试了一下,它确实有效!但是我想说的是,从昨天早上开始,我尝试了每一个可能和不可能的组合,包括你的方法。结果发现,第二次尝试时它才能正常工作,也就是说,我使用“docker-compose up”命令创建容器时出现错误。我停止服务器,再次使用相同的“docker-compose up”命令启动它,不知何故它就可以正常工作了。无论如何,你对我帮助很大,我非常感激你。 - Evgeny Romensky
您可能需要查看 https://docs.docker.com/compose/startup-order/,因为很有可能 FastAPI 将在数据库之前启动并出现连接错误。您可以使用 depends_on 来告诉应用程序在数据库正常运行之前不要启动。我会为您输入答案以供接受。 - Chris Doyle
1个回答

3
你应该更新你的配置文件,以便在容器内部引用postgres服务的名称和数据库运行的端口。
DATABASE_URL = "postgresql://postgres:password@postgres:5432/fastapi_database"

当应用程序在本地机器上运行,数据库运行在容器中时,localhost:5433可以使用,因为主机的端口 5433 被映射到db容器内部的 5432 端口。
当您将应用程序放入自己的容器中但仍然引用localhost时,它会寻找与应用程序位于同一容器中的Postgres数据库,这是不正确的。
当您提供正确的服务名称但使用端口5433时,您也会收到错误,因为仅将端口5433从运行容器的主机映射到容器内部而非容器本身。
因此,在应用程序容器中,您要做的就是针对端口5432目标数据库服务,因为那是Postgres在容器内部运行的端口。
您还可能想查看一个depends on脚本,该脚本将在db准备就绪之前不启动fast api应用程序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接