在PostgreSQL Docker容器中运行SQLAlchemy遇连接拒绝问题
Postgres容器内Python连接数据库失败:Connection refused
问题详情
Dockerfile代码
FROM postgres RUN apt-get update && \ apt-get install \ --yes \ --no-install-recommends \ python3-pip libpq-dev RUN pip3 install \ --default-timeout=100 \ sqlalchemy sqlalchemy-utils psycopg2-binary COPY database.py . CMD python3 database.py
database.py代码
from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from sqlalchemy_utils import database_exists, create_database SQLALCHEMY_DATABASE_URL = ( "postgresql+psycopg2://postgres:password@localhost/mydb" ) # SQLALCHEMY_DATABASE_URL = "postgresql:///mydb" engine = create_engine(SQLALCHEMY_DATABASE_URL) if not database_exists(engine.url): print("Database did not exit. Creating it.") create_database(engine.url) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base()
容器运行命令
docker run --name <SOME_NAME> -p 5432:5432 -e POSTGRES_PASSWORD=password -d <BUILD_TAG>
报错信息
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) 连接服务器 "localhost" (127.0.0.1) 端口5432失败:Connection refused 服务器是否在该主机上运行并接受TCP/IP连接? 连接服务器 "localhost" (::1) 端口5432失败:Cannot assign requested address 服务器是否在该主机上运行并接受TCP/IP连接?
已尝试切换端口(如5433)、移除-p 5432:5432参数,问题依旧,推测容器内部无法访问5432端口。
问题根源
- Postgres服务未启动:你用
CMD python3 database.py覆盖了Postgres官方镜像默认的启动命令,容器启动后直接运行Python脚本,根本没启动Postgres服务。 - localhost指向问题:容器内的
localhost是容器自身,即使Postgres服务启动,若未就绪就执行连接,也会触发拒绝错误。
解决方案
方案1:修复启动逻辑,先启动Postgres再执行脚本
- 创建启动脚本
entrypoint.sh:
#!/bin/bash # 启动Postgres服务 docker-entrypoint.sh postgres & # 等待Postgres就绪 until pg_isready -U postgres; do echo "等待Postgres服务启动..." sleep 2 done # 执行Python脚本 python3 database.py
- 给脚本添加执行权限:
chmod +x entrypoint.sh - 修改Dockerfile,替换CMD为ENTRYPOINT:
FROM postgres RUN apt-get update && \ apt-get install \ --yes \ --no-install-recommends \ python3-pip libpq-dev RUN pip3 install \ --default-timeout=100 \ sqlalchemy sqlalchemy-utils psycopg2-binary COPY database.py . COPY entrypoint.sh . ENTRYPOINT ["./entrypoint.sh"]
方案2:调整数据库连接字符串(配合方案1使用)
用Unix套接字连接Postgres,修改database.py中的连接地址:
SQLALCHEMY_DATABASE_URL = "postgresql+psycopg2://postgres:password@/mydb?host=/var/run/postgresql"
或者简化为:
SQLALCHEMY_DATABASE_URL = "postgresql:///mydb"
方案3:拆分容器(最佳实践)
将Postgres和Python应用拆分为两个独立容器,用Docker Compose管理:
- 创建
docker-compose.yml:
version: '3.8' services: db: image: postgres environment: POSTGRES_PASSWORD: password POSTGRES_DB: mydb volumes: - postgres_data:/var/lib/postgresql/data/ app: build: . depends_on: - db environment: DATABASE_URL: "postgresql+psycopg2://postgres:password@db/mydb" volumes: postgres_data:
- 修改
database.py读取环境变量:
import os from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from sqlalchemy_utils import database_exists, create_database SQLALCHEMY_DATABASE_URL = os.getenv("DATABASE_URL", "postgresql+psycopg2://postgres:password@db/mydb") engine = create_engine(SQLALCHEMY_DATABASE_URL) if not database_exists(engine.url): print("数据库不存在,正在创建...") create_database(engine.url) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base()
- 启动容器:
docker-compose up --build -d
内容的提问来源于stack exchange,提问作者J Agustin Barrachina
相关产品推荐
相关产品推荐

