当数据库在容器中运行时,如何使用 alembic 自动生成和应用迁移?
How to autogenerate and apply migrations with alembic when the database runs in a container?
我发现在容器化环境中处理数据库迁移的工作流程令人困惑。我有一个带有附加数据库的网站 API。 API 运行 在一个容器中,数据库在另一个容器中。项目文件结构如下
.
├── docker-compose.yml
├── Dockerfile
└── app
| ├── __init__.py
| ├── database
| | ├── alembic/
| | ├── __init__.py
| | ├── db.py
| | └── models.py
| ├── other
| ├── source
| └── files
├── other
└── files
为了让 API 容器能够访问数据库,ini 文件中的 sqlalchemy.url 设置为:
postgresql://{username}:{password}@db:5432/{database}
然而,当我想进行迁移时,例如添加一个 table 列,我将更改 app/database/models.py
中的模型,将目录更改为 app/database
和 运行 alembic revision --autogenerate -m "Description"
。这是问题发生的地方,我得到错误:
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) could not translate host name "db" to address: Name or service not known
如果我将主机名更改为 localhost,它可以工作,但是 docker-compose 会中断,因为它必须引用容器名称。
这个工作流程好像不太对。人们如何在使用容器的项目中使用数据库?
docker-compose.yml
文件如下所示:
version: "3"
services:
db:
image: postgres
ports:
- "5432:5432"
environment:
- POSTGRES_USER=username
- POSTGRES_PASSWORD=password
- POSTGRES_DB=database
app:
build: .
command: bash -c "cd app/database && alembic upgrade head && cd ../.. && python app/main.py"
volumes:
- .:/code
ports:
- "5000:5000"
depends_on:
- db
由于您的数据库已发布 ports:
,您可以直接从主机访问它。主机上容器外的应用运行和Compose设置中的同一个应用运行是不同的环境,用环境变量来指定是合适的。不要在您的应用程序中对数据库位置进行硬编码。
如果您可以使用 standard PostgreSQL environment variables,那么指定它就相当容易了。
# To run migrations:
cd app/database
PGUSER=username PGPASSWORD=password PGDATABASE=database \
alembic revision --autogenerate -m "Description"
# (assumes default PGHOST=localhost)
# To run the application:
version: '3.8'
services:
db: { ... }
app:
build: .
environment:
PGHOST: db
PGUSER: username
PGPASSWORD: password
PGDATABASE: database
ports:
- "5000:5000"
depends_on:
- db
您似乎缺少连接到两个容器的网络,因此 DNS 可以解析为数据库。因此,将相同的网络添加到两个容器中,如下所示:
services:
db:
image: postgres
ports:
- "5432:5432"
environment:
- POSTGRES_USER=username
- POSTGRES_PASSWORD=password
- POSTGRES_DB=database
networks:
- app-network
app:
build: .
command: bash -c "cd app/database && alembic upgrade head && cd ../.. && python app/main.py"
volumes:
- .:/code
ports:
- "5000:5000"
depends_on:
- db
networks:
- app-network
networks:
app-network:
附带说明一下,您已将端口映射到本地主机上的 5432。有一个特殊的 docker DNS 指向容器所在的本地主机 运行,因此您可以在应用程序容器内使用 host.docker.internal
,它将解析为您的本地主机。
我发现在容器化环境中处理数据库迁移的工作流程令人困惑。我有一个带有附加数据库的网站 API。 API 运行 在一个容器中,数据库在另一个容器中。项目文件结构如下
.
├── docker-compose.yml
├── Dockerfile
└── app
| ├── __init__.py
| ├── database
| | ├── alembic/
| | ├── __init__.py
| | ├── db.py
| | └── models.py
| ├── other
| ├── source
| └── files
├── other
└── files
为了让 API 容器能够访问数据库,ini 文件中的 sqlalchemy.url 设置为:
postgresql://{username}:{password}@db:5432/{database}
然而,当我想进行迁移时,例如添加一个 table 列,我将更改 app/database/models.py
中的模型,将目录更改为 app/database
和 运行 alembic revision --autogenerate -m "Description"
。这是问题发生的地方,我得到错误:
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) could not translate host name "db" to address: Name or service not known
如果我将主机名更改为 localhost,它可以工作,但是 docker-compose 会中断,因为它必须引用容器名称。
这个工作流程好像不太对。人们如何在使用容器的项目中使用数据库?
docker-compose.yml
文件如下所示:
version: "3"
services:
db:
image: postgres
ports:
- "5432:5432"
environment:
- POSTGRES_USER=username
- POSTGRES_PASSWORD=password
- POSTGRES_DB=database
app:
build: .
command: bash -c "cd app/database && alembic upgrade head && cd ../.. && python app/main.py"
volumes:
- .:/code
ports:
- "5000:5000"
depends_on:
- db
由于您的数据库已发布 ports:
,您可以直接从主机访问它。主机上容器外的应用运行和Compose设置中的同一个应用运行是不同的环境,用环境变量来指定是合适的。不要在您的应用程序中对数据库位置进行硬编码。
如果您可以使用 standard PostgreSQL environment variables,那么指定它就相当容易了。
# To run migrations:
cd app/database
PGUSER=username PGPASSWORD=password PGDATABASE=database \
alembic revision --autogenerate -m "Description"
# (assumes default PGHOST=localhost)
# To run the application:
version: '3.8'
services:
db: { ... }
app:
build: .
environment:
PGHOST: db
PGUSER: username
PGPASSWORD: password
PGDATABASE: database
ports:
- "5000:5000"
depends_on:
- db
您似乎缺少连接到两个容器的网络,因此 DNS 可以解析为数据库。因此,将相同的网络添加到两个容器中,如下所示:
services:
db:
image: postgres
ports:
- "5432:5432"
environment:
- POSTGRES_USER=username
- POSTGRES_PASSWORD=password
- POSTGRES_DB=database
networks:
- app-network
app:
build: .
command: bash -c "cd app/database && alembic upgrade head && cd ../.. && python app/main.py"
volumes:
- .:/code
ports:
- "5000:5000"
depends_on:
- db
networks:
- app-network
networks:
app-network:
附带说明一下,您已将端口映射到本地主机上的 5432。有一个特殊的 docker DNS 指向容器所在的本地主机 运行,因此您可以在应用程序容器内使用 host.docker.internal
,它将解析为您的本地主机。