Docker命令转Compose文件后,Flask连接PostgreSQL报表不存在错误
我通过两种方式运行Flask应用:使用docker run命令和Docker Compose文件。执行以下docker run命令时一切正常:
docker container run --name flask-database -d --network flask_network -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=admin -e POSTGRES_DB=flask_db -v postgres_data:/var/lib/postgresql/data -p 5432:5432 postgres:13 docker container run -p 5000:5000 --network flask_network flask_app
但使用Compose文件执行docker compose up时,出现如下错误:
File "/app/main_python_files/routes.py", line 11, in home web | cur.execute('SELECT * FROM books;') web | psycopg2.errors.UndefinedTable: relation "books" does not exist web | LINE 1: SELECT * FROM books;
我的Compose文件内容如下:
version: '3.7' services: flask-database: container_name: flask-database image: postgres:13 restart: always ports: - 5432:5432 networks: - flask_network environment: - POSTGRES_USER=admin - POSTGRES_PASSWORD=admin - POSTGRES_DB=flask_db volumes: - postgres_data:/var/lib/postgresql/data web: container_name: web #build: web image: flask_app restart: always ports: - 5000:5000 networks: - flask_network depends_on: - flask-database links: - flask-database networks: flask_network: {} volumes: postgres_data: {}
问题原因与修改方案
核心原因
depends_on仅能保证web容器在flask-database容器启动后再启动,但无法确保Postgres数据库服务已经完全就绪(Postgres容器启动后通常需要几秒时间完成初始化,才能接受连接和执行SQL)。而使用docker run时,你手动启动数据库后可能等待了一段时间才启动Flask,此时数据库已经准备完毕,表也正常存在。
修改方案
1. 给Web服务添加数据库就绪检查
在web服务的启动命令前加入等待逻辑,确保Postgres可以正常连接后再启动Flask应用。Postgres镜像自带pg_isready工具,可直接用来检查服务状态:
web: container_name: web #build: web image: flask_app restart: always ports: - 5000:5000 networks: - flask_network depends_on: - flask-database # 添加启动命令,等待数据库就绪 command: > sh -c "until pg_isready -h flask-database -p 5432 -U admin; do echo waiting for postgres; sleep 2; done; python your_flask_entrypoint.py" # 替换成你实际的Flask启动命令
如果你的Flask镜像没有pg_isready,可以在镜像的Dockerfile中安装postgresql-client包。
2. 确认Flask应用的数据库连接配置
确保Flask应用中数据库连接的主机名是flask-database(容器名),而非localhost。例如数据库URI应类似:
SQLALCHEMY_DATABASE_URI = 'postgresql://admin:admin@flask-database:5432/flask_db'
3. 确保数据库表已正确初始化
如果表是通过Flask应用初始化(比如用Flask-SQLAlchemy的db.create_all()),需确保这段逻辑在应用启动时执行,且在数据库连接成功后运行。
如果表是通过外部SQL脚本初始化,可将脚本挂载到Postgres容器的/docker-entrypoint-initdb.d/目录下,Postgres会在第一次启动时自动执行:
flask-database: # 其他配置不变 volumes: - postgres_data:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql # 挂载初始化脚本
内容的提问来源于stack exchange,提问作者Kuba Szuber

