【问题标题】:How to autogenerate and apply migrations with alembic when the database runs in a container?当数据库在容器中运行时,如何使用 alembic 自动生成和应用迁移?
【发布时间】:2021-09-14 10:43:37
【问题描述】:

我发现在容器化环境中处理数据库迁移的工作流程令人困惑。我有一个带有附加数据库的 Web 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}

但是当我想进行迁移时,例如添加一个表列,我会将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

【问题讨论】:

    标签: python docker sqlalchemy alembic


    【解决方案1】:

    由于您的数据库已发布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
    

    【讨论】:

      【解决方案2】:

      您似乎缺少连接到两个容器的网络,因此 DNS 可以解析到 DB。因此,将相同的网络添加到两个容器中,如下所示:

      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,它将解析到您的本地主机。

      【讨论】:

        猜你喜欢
        • 2012-06-26
        • 1970-01-01
        • 2015-09-20
        • 1970-01-01
        • 2020-11-05
        • 2022-06-14
        • 2019-04-25
        • 2013-06-16
        • 1970-01-01
        相关资源
        最近更新 更多