如何在不同的(依赖的)容器启动后对 docker 容器运行 .sql 脚本?
Posted
技术标签:
【中文标题】如何在不同的(依赖的)容器启动后对 docker 容器运行 .sql 脚本?【英文标题】:How to run .sql script against docker container after a different (dependent) container starts? 【发布时间】:2022-01-02 01:31:56 【问题描述】:我有一个 SpringBoot 应用程序容器myApi
,它依赖于另一个 SpringBoot 应用程序容器configApi
,它们都使用 flyway。它们也都依赖于postgres
容器。 configApi
公开了一个端点,myApi
使用它来获取所有相关配置(数据库详细信息等)。
目前发生的情况是:
postgres
容器启动并初始化相应的数据库和用户
configApi
容器启动
a) 它连接到postgres
b) 它运行一个 flyway 迁移(创建所需的模式和表)
c) api 启动并准备就绪
myApi
容器启动
a) 它到达configApi
公开的配置端点
b) 请求失败,因为configApi
在postgres
中找不到任何有用的数据,因为没有插入任何数据
我的限制是:
我无法修改configApi
代码以包含任何特定于 myApi
或环境的内容
configApi
启动期间的 Flyway 迁移是创建包含任何所需数据的表的原因
当postgres
启动(使用init.sql
)时,我无法创建表并填充它们,因为那样configApi
flyway 迁移将失败
myApi
不能包含有关 postgres
的任何硬编码或环境信息,因为它们都应该从 configApi
端点获取
问题总结 TLDR:
如何在configApi
启动之后但在myApi
启动之前对postgres
容器执行一个sql 脚本,而不修改configApi
或myApi
以包含任何特定于彼此环境的内容?
我有以下 docker-compose 文件:
version: "3"
volumes:
db_data:
services:
postgres:
image: postgres:10.14
volumes:
- ./init-local.sql:/docker-entrypoint-initdb.d/init.sql
- db_data:/var/lib/postgresql
ports:
- 5432:5432
configApi:
image: org/config-api:latest
ports:
- 8234:8234
environment:
- DB_PORT=5432
- DB_HOST=postgres
depends_on:
- postgres
myApi:
build: ./my-api
image: org/my-api:latest
container_name: my-api
ports:
- 9080:9080
environment:
- CONFIG_MANAGER_API_URL=http://configApi:8234/
depends_on:
- postgres
- configApi
注释(我会在有问题时添加更多内容):
我正在使用单个 postgres 容器,因为这是用于本地/测试的,两个 api 都使用该 postgres 实例中的唯一数据库【问题讨论】:
我过去看到的一个解决方案是创建一个轻量级、自终止的应用程序,它将在configApi
和myApi
之间启动,仅用于数据加载,我不喜欢这个解决方案。维护开销太大。
该应用程序可以是 Flyway 本身,它可以作为 docker 镜像使用:hub.docker.com/r/flyway/flyway。我用它来建立一个完整的本地开发数据库。您可以使用它仅插入数据。不知道这是否对你有用,我有点迷失在你的限制中。老实说,我宁愿打破限制也不愿绕过它们,最有意义的是将数据作为配置 API 设置的一部分插入。
@Gimby 谢谢,我去看看。限制来自 configApi 作为通用应用程序,我无法修改它以包含特定于产品的配置。这会破坏它的通用性。
【参考方案1】:
所以这是我的解决方案。
我修改了我的 flyway 代码以动态包含额外的脚本(如果它们存在),如下所示。
在configApi
的我的数据库java 配置中,我读取了一个环境变量,该变量指定了任何带有额外/应用程序外部脚本的目录:
// on class level
@Value("$FLYWAY_FOLDER")
private String externalFlywayFolder;
//when creating DataSource bean
List<String> flywayFolders = new ArrayList<>();
flywayFolders.add("classpath:db/migrations");
if (externalFlywayFolder != null && !externalFlywayFolder.isEmpty())
flywayFolders.add("filesystem:"+externalFlywayFolder);
String[] flywayFoldersArray = new String[flywayFolders.size()];
flywayFolders.toArray(flywayFoldersArray);
Flyway flyway = Flyway
.configure()
.dataSource(dataSource)
.baselineOnMigrate(true)
.schemas("flyway")
.mixed(true)
.locations(flywayFoldersArray)
.load();
flyway.migrate();
然后我修改了 docker compose 以将额外的文件附加到容器并设置 FLYWAY_FOLDER
env 变量:
configApi:
image: org/config-api:latest
volumes:
- ./scripts/flyway/configApi:/flyway #attach scripts to container
ports:
- 8234:8234
environment:
- DB_PORT=5432
- DB_HOST=postgres
- FLYWAY_FOLDER=flyway #specify script dir for api
depends_on:
- postgres
然后只是添加文件的情况,但诀窍是将它们设为repeatable migrations,这样它们就不会干扰可能为 configApi 本身完成的任何版本化迁移。
在版本化迁移之后应用可重复迁移,如果它们的校验和发生变化,它们也会重新应用。
【讨论】:
以上是关于如何在不同的(依赖的)容器启动后对 docker 容器运行 .sql 脚本?的主要内容,如果未能解决你的问题,请参考以下文章