在 Java 测试中使用 Podman 测试容器

Testcontainers with Podman in Java tests

是否可以在 Java 测试中将 Testcontainers 与 Podman 一起使用? 截至 2022 年 3 月,Testcontainers 库未将已安装的 Podman 检测为有效的 Docker 环境。

Podman 可以 Docker 替代 MacOS 和 Apple silicon(本地开发环境)和 Linux x86_64(CI/CD 环境)吗?

可以在 Java 项目中使用 Podman 和 Testcontainer,在 Linux 和 MacOS(x86_64 和 Apple silicon)上使用 Gradle。

先决条件

启用 Podman 服务

Testcontainers 库使用套接字文件与 Podman 通信。

Linux

为普通用户(无根)启动 Podman 服务并使其监听套接字:

systemctl --user enable --now podman.socket

检查 Podman 服务状态:

systemctl --user status podman.socket

检查套接字文件是否存在:

ls -la /run/user/$UID/podman/podman.sock

MacOS

Podman 套接字文件 /run/user/1000/podman/podman.sock 可以在 Podman-managed Linux VM 中找到。可以使用 SSH 隧道将 MacOS 上的本地套接字转发到 Podman-managed VM 上的远程套接字。

Podman-managed虚拟机的端口可以通过命令podman system connection list --format=json找到。

安装jq解析JSON:

brew install jq

创建一个 shell 别名以将本地套接字 /tmp/podman.sock 转发到远程套接字 /run/user/1000/podman/podman.sock:

echo "alias podman-sock=\"rm -f /tmp/podman.sock && ssh -i ~/.ssh/podman-machine-default -p $(podman system connection list --format=json | jq '.[0].URI' | sed -E 's|.+://.+@.+:([[:digit:]]+)/.+||') -L'/tmp/podman.sock:/run/user/1000/podman/podman.sock' -N core@localhost\"" >> ~/.zprofile
source ~/.zprofile

打开 SSH 隧道:

podman-sock

在使用 Testcontainers 执行测试之前,请确保 SSH 隧道已打开。

配置 Gradle 构建脚本

build.gradle

test {
    OperatingSystem os = DefaultNativePlatform.currentOperatingSystem;
    if (os.isLinux()) {
        def uid = ["id", "-u"].execute().text.trim()
        environment "DOCKER_HOST", "unix:///run/user/$uid/podman/podman.sock"
    } else if (os.isMacOsX()) {
        environment "DOCKER_HOST", "unix:///tmp/podman.sock"
    }
    environment "TESTCONTAINERS_RYUK_DISABLED", "true"
}

根据操作系统将 DOCKER_HOST 环境变量设置为 Podman 套接字文件。

使用环境变量 TESTCONTAINERS_RYUK_DISABLED.

禁用 Ryuk

Moby Ryuk helps you to remove containers/networks/volumes/images by given filter after specified delay.

Ryuk 是 Docker 的一项技术,不支持 Podman。参见 testcontainers/moby-ryuk#23

Testcontainers 库使用 Ruyk 删除容器。我们将使用 JVM 关闭挂钩显式删除容器,而不是依赖 Ryuk 隐式删除容器:

Runtime.getRuntime().addShutdownHook(new Thread(container::stop));

传递环境变量

作为在 Gradle 构建脚本中配置测试容器的替代方法,您可以将环境变量传递给 Gradle。

Linux

DOCKER_HOST="unix:///run/user/$UID/podman/podman.sock" \
TESTCONTAINERS_RYUK_DISABLED="true" \
./gradlew clean build -i

MacOS

DOCKER_HOST="unix:///tmp/podman.sock" \
TESTCONTAINERS_RYUK_DISABLED="true" \
./gradlew clean build -i

完整示例

查看完整示例https://github.com/evgeniy-khist/podman-testcontainers

对于 Linux,它确实有效,尽管官方 testcontainers 文档对此并不十分清楚。

# Enable socket
systemctl --user enable podman.socket --now

# Export env var expected by Testcontainers
export DOCKER_HOST=unix:///run/user/${UID}/podman/podman.sock
export TESTCONTAINERS_RYUK_DISABLED=true

来源:

我能够以 Evginiy 的出色答案为基础,因为 Podman 自最初的答案以来已经有所改进。在 Mac OS 上,这些步骤对我来说已经足够了,并且让测试容器满意:

brew install podman
podman machine init
sudo /opt/homebrew/Cellar/podman/4.0.3/bin/podman-mac-helper install
podman machine start
export TESTCONTAINERS_RYUK_DISABLED="true"

我认为仍然有必要使用 Evginiy 的关闭挂钩建议手动整理容器:

Runtime.getRuntime().addShutdownHook(new Thread(container::stop));