尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Testcontainers Java Cassandra 模块实战指南:容器化 Cassandra 测试环境搭建与配置详解

发布时间:2026/9/16 18:00:52

资讯中心
01
ARTICLE

Testcontainers Java Cassandra 模块实战指南:容器化 Cassandra 测试环境搭建与配置详解

Testcontainers Java Cassandra 模块实战指南:容器化 Cassandra 测试环境搭建与配置详解
Testcontainers Java Cassandra 模块实战指南容器化 Cassandra 测试环境搭建与配置详解【免费下载链接】testcontainers-javaTestcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.项目地址: https://gitcode.com/GitHub_Trending/te/testcontainers-javaTestcontainers 为 Java 生态提供基于 Docker 的轻量级、一次性测试环境而testcontainers-cassandra模块则专门封装了 Apache Cassandra只需几行代码即可在测试中拉起一个真实的单节点 Cassandra并支持自定义cassandra.yaml、初始化 CQL 脚本、认证Authentication与 TLS 安全连接等企业级场景。阅读本文后你将掌握如何定义 Cassandra 容器、通过 DataStax Java Driver 构建CqlSession连接集群、覆盖默认配置并打通带认证与 SSL 的测试链路同时理解其底层等待策略与脚本执行机制。Cassandra 模块能做什么该模块以官方cassandraDocker 镜像为基础在 CassandraContainer 中完成了对 GenericContainer 的封装。从类注释与源码可以确认以下默认行为支持镜像cassandra构造时会通过DockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME)校验镜像名称兼容性暴露端口CQL 原生传输端口9042源码常量CQL_PORT 9042默认本地数据中心datacenter1常量DEFAULT_LOCAL_DATACENTER可通过环境变量CASSANDRA_DC覆盖默认凭据cassandra/cassandra常量USERNAME/PASSWORD仅在启用PasswordAuthenticator时生效启动即就绪探测默认使用CassandraQueryWaitStrategy等待集群可执行查询而不是简单地等待端口开放。构造器还会预设一系列环境变量让容器以适合单节点测试的配置启动withEnv(CASSANDRA_SNITCH, GossipingPropertyFileSnitch); withEnv(JVM_OPTS, -Dcassandra.skip_wait_for_gossip_to_settle0 -Dcassandra.initial_token0); withEnv(HEAP_NEWSIZE, 128M); withEnv(MAX_HEAP_SIZE, 1024M); withEnv(CASSANDRA_ENDPOINT_SNITCH, GossipingPropertyFileSnitch); withEnv(CASSANDRA_DC, DEFAULT_LOCAL_DATACENTER);上述代码片段来自 CassandraContainer.java#L55-L60其中MAX_HEAP_SIZE1024M与HEAP_NEWSIZE128M控制了容器的堆内存分配CASSANDRA_SNITCH指定 gossip 类型的 snitch 以适配容器网络。快速上手定义容器并建立 CqlSession1. 定义容器在测试中最简单的用法与官方文档示例一致对应 CassandraContainerTest.java#L35-L37try ( CassandraContainer cassandraContainer new CassandraContainer(cassandra:3.11.15) ) { cassandraContainer.start(); // 执行测试逻辑 }CassandraContainer实现了AutoCloseable配合 try-with-resources 可在测试结束后自动停止并销毁容器这也是 Testcontainers 推荐的生命周期管理方式。如果需要指定其他版本可以显式解析镜像名并打上版本标签对应 CassandraContainerTest.java#L46-L59String cassandraVersion 3.0.15; try ( CassandraContainer cassandraContainer new CassandraContainer( DockerImageName.parse(cassandra).withTag(cassandraVersion) ) ) { cassandraContainer.start(); // 查询 system.local 可验证运行版本与目标版本一致 }从 CompatibleCassandraImageTest.java 的参数化测试可以看出该模块覆盖了cassandra:3.11.2、cassandra:4.1.1与cassandra:5等新旧版本线因此不必为镜像版本担忧。2. 构建 CqlSession容器启动后通过 DataStax Java Driver4.x构建CqlSession连接集群对应 CassandraContainerTest.java#L221-L230final CqlSession cqlSession CqlSession .builder() .addContactPoint(cassandraContainer.getContactPoint()) .withLocalDatacenter(cassandraContainer.getLocalDatacenter()) .build();这里用到了CassandraContainer提供的两个关键方法getContactPoint()返回InetSocketAddress封装了宿主机地址与映射后的 9042 端口实现见 CassandraContainer.java#L199-L201驱动据此直连容器getLocalDatacenter()返回CASSANDRA_DC环境变量的值缺省为datacenter1实现见 CassandraContainer.java#L208-L210。DataStax Driver 4.x 要求必须显式指定本地数据中心否则无法完成控制连接。一个典型的连通性验证查询是SELECT release_version FROM system.local常量BASIC_QUERY测试通过resultSet.one().getString(0)拿到 Cassandra 版本号并断言其与镜像 tag 一致见 CassandraContainerTest.java#L31。自定义 cassandra.yamlwithConfigurationOverride默认镜像附带的cassandra.yaml未必满足测试需求。模块提供withConfigurationOverride(String configLocation)方法将 classpath 下某个目录中的配置整体覆盖容器内的 Cassandra 配置实现见 CassandraContainer.java#L119-L132CassandraContainer cassandraContainer new CassandraContainer(CASSANDRA_IMAGE) .withConfigurationOverride(cassandra-test-configuration-example)其底层行为在configure()方法中CassandraContainer.java#L66-L83Optional .ofNullable(configLocation) .map(MountableFile::forClasspathResource) .ifPresent(mountableFile - withCopyFileToContainer(mountableFile, CONTAINER_CONFIG_LOCATION));其中CONTAINER_CONFIG_LOCATION /etc/cassandra。务必注意Docker 的目录映射是整体替换语义——指定目录中的内容会完全替换容器内/etc/cassandra的全部内容。也就是说你的覆盖目录中必须包含一份完整、合法的cassandra.yaml以及配套的cassandra-rackdc.properties等文件若cassandra.yaml缺失或损坏Cassandra 将无法启动容器会启动失败。这一点在类的 Javadoc 中有明确警告并且有对应的反向测试testEmptyConfigurationOverride使用一个不含有效配置的目录断言启动会抛出ContainerLaunchException见 CassandraContainerTest.java#L139-L147。以仓库中的测试资源 cassandra-test-configuration-example/cassandra.yaml 为例它把cluster_name改为Test Cluster Integration Test。测试testConfigurationOverride随后执行SELECT cluster_name FROM system.local并断言返回值与自定义配置一致CassandraContainerTest.java#L61-L74从而验证覆盖确实生效。初始化脚本withInitScriptwithInitScript(String initScriptPath)允许在容器启动完成之后自动执行一份 CQL 脚本实现见 CassandraContainer.java#L134-L146CassandraContainer cassandraContainer new CassandraContainer(CASSANDRA_IMAGE) .withInitScript(initial.cql)脚本执行发生在containerIsStarted()回调中CassandraContainer.java#L85-L88即等待策略确认就绪之后。执行过程CassandraContainer.java#L93-L117大致为从 classpath 加载脚本资源复制为容器内的init.cql常量DEFAULT_INIT_SCRIPT_FILENAME通过CassandraDatabaseDelegate.execute(...)在容器内调用cqlsh -f init.cql执行若脚本资源不存在抛出ScriptLoadException若语句执行失败抛出UncategorizedScriptException。测试资源 initial.cql 给出了一个完整可用的初始化示例CREATE KEYSPACE keySpaceTest WITH replication {class: SimpleStrategy, replication_factor : 1}; USE keySpaceTest; CREATE TABLE catalog_category (id bigint primary key, name text); INSERT INTO catalog_category (id, name) VALUES (1, test_category);对应测试testInitScript会查询SELECT * FROM keySpaceTest.catalog_category断言插入的数据(1, test_category)完整存在CassandraContainerTest.java#L205-L219。值得注意的是初始化脚本同样支持老版本镜像testInitScriptWithLegacyCassandra使用cassandra:2.2.11配合同一份脚本验证兼容性CassandraContainerTest.java#L194-L203。另外如果脚本本身包含错误语句启动同样会失败——testInitScriptWithError与testNonexistentInitScript两个用例分别覆盖了这两种失败路径。启用认证自定义配置 凭据访问默认情况下Cassandra 使用AllowAllAuthenticator不校验身份。若你的测试需要模拟生产环境的认证可以通过自定义配置将认证器切换为PasswordAuthenticator。仓库中的 cassandra-auth-required-configuration/cassandra.yaml 正是这样一份配置authenticator: PasswordAuthenticator authorizer: AllowAllAuthorizer role_manager: CassandraRoleManager官方文档给出的组合用法是自定义配置 初始化脚本同时上阵对应 CassandraContainerTest.java#L171-L182CassandraContainer cassandraContainer new CassandraContainer(CASSANDRA_IMAGE) .withConfigurationOverride(cassandra-auth-required-configuration) .withInitScript(initial.cql)此时容器内cqlsh执行初始化脚本也需要认证。源码中CassandraDatabaseDelegate.execute()会检测容器是否为CassandraContainer并自动追加-u cassandra -p cassandra参数见 CassandraDatabaseDelegate.java#L44-L52因此脚本执行无需你额外操心。客户端连接时则需要显式带上凭据通过cassandraContainer.getUsername()与getPassword()取得默认账号密码CassandraContainerTest.java#L232-L240final CqlSession cqlSession CqlSession .builder() .addContactPoint(cassandraContainer.getContactPoint()) .withLocalDatacenter(cassandraContainer.getLocalDatacenter()) .withAuthCredentials(cassandraContainer.getUsername(), cassandraContainer.getPassword()) .build();关于凭据CassandraContainer.java#L170-L192 的 Javadoc 特别说明cassandra/cassandra是 Cassandra 镜像内置的默认超级用户适用于刚启用PasswordAuthenticator的场景生产环境应通过 CQL 自行管理用户不要沿用默认凭据。使用安全连接TLSwithSsl何时需要 TLS 配置如果你覆盖的cassandra.yaml将client_encryption_options.optional设为false即强制要求加密连接那么客户端必须提供合法的证书与私钥PEM 格式才能完成握手。官方文档与测试资源 cassandra-ssl-configuration/cassandra.yaml 中的对应配置为client_encryption_options: enabled: true optional: false keystore: /etc/cassandra/keystore.p12 keystore_password: cassandra require_client_auth: true truststore: /etc/cassandra/truststore.p12 truststore_password: cassandra store_type: PKCS12其中optional: false意味着所有客户端连接都必须走 TLS且require_client_auth: true意味着服务端也会校验客户端证书。配置容器端 SSL此时调用withSsl(clientCertFile, clientKeyFile)传入客户端证书与私钥的 classpath 路径对应 CassandraContainerTest.java#L95-L101CassandraContainer cassandraContainer new CassandraContainer(CASSANDRA_IMAGE) .withConfigurationOverride(cassandra-ssl-configuration) .withSsl(client-ssl/cassandra.cer.pem, client-ssl/cassandra.key.pem)方法签名与语义见 CassandraContainer.java#L149-L161。当同时设置了证书与密钥后isSslRequired()返回 trueconfigure()会做三件事CassandraContainer.java#L75-L82将客户端证书复制到容器内ssl/user_cert.pem将客户端密钥复制到容器内ssl/user_key.pem复制一份cqlshrc配置到/root/.cassandra/cqlshrc使容器内cqlsh命令自动携带 SSL 参数。这份cqlshrc会让CassandraDatabaseDelegate以cqlsh --ssl -u cassandra -p cassandra ...的方式执行初始化脚本保证在强制加密的环境下脚本也能跑通CassandraDatabaseDelegate.java#L48-L50。配置客户端驱动 SSL客户端测试进程内的 DataStax Driver也需要配置信任库/密钥库才能建立 TLS 连接。测试中的完整做法是使用ProgrammaticDriverConfigLoaderBuilder构造驱动配置CassandraContainerTest.java#L242-L265final ProgrammaticDriverConfigLoaderBuilder driverConfigLoaderBuilder DriverConfigLoader.programmaticBuilder(); driverConfigLoaderBuilder.withBoolean(DefaultDriverOption.SSL_HOSTNAME_VALIDATION, false); driverConfigLoaderBuilder.withString(DefaultDriverOption.SSL_TRUSTSTORE_PATH, trustStoreUrl.getFile()); driverConfigLoaderBuilder.withString(DefaultDriverOption.SSL_TRUSTSTORE_PASSWORD, cassandra); driverConfigLoaderBuilder.withString(DefaultDriverOption.SSL_KEYSTORE_PATH, keyStoreUrl.getFile()); driverConfigLoaderBuilder.withString(DefaultDriverOption.SSL_KEYSTORE_PASSWORD, cassandra); final DriverContext driverContext new DefaultDriverContext( driverConfigLoaderBuilder.build(), ProgrammaticArguments.builder().build() ); final CqlSession cqlSession CqlSession.builder() .addContactPoint(cassandraContainer.getContactPoint()) .withLocalDatacenter(cassandraContainer.getLocalDatacenter()) .withSslEngineFactory(new DefaultSslEngineFactory(driverContext)) .build();测试资源目录cassandra-ssl-configuration/下提供了对应的keystore.p12与truststore.p12而client-ssl/目录存放 PEM 格式的客户端证书与密钥cassandra.cer.pem、cassandra.key.pem两者配套使用。证书生成参考命令测试源码注释中记录了证书的生成链路CassandraContainerTest.java#L78-L94可作参考用keytool生成服务端密钥库并导出证书keytool -genkey -keyalg RSA -validity 36500 -alias localhost -keystore keystore.p12 -storepass cassandra \ -keypass cassandra -dname CNlocalhost, OUTestcontainers, OTestcontainers, LNone, CNone keytool -export -alias localhost -file cassandra.cer -keystore keystore.p12 keytool -import -v -trustcacerts -alias localhost -file cassandra.cer -keystore truststore.p12将密钥库转换为 PKCS12 并用openssl导出 PEM 格式的客户端证书与私钥keytool -importkeystore -srckeystore keystore.p12 -destkeystore test_node.p12 -deststoretype PKCS12 \ -srcstorepass cassandra -deststorepass cassandra openssl pkcs12 -in test_node.p12 -nokeys -out cassandra.cer.pem -passin pass:cassandra openssl pkcs12 -in test_node.p12 -nodes -nocerts -out cassandra.key.pem -passin pass:cassandra生成证书属于本地开发操作应使用 JDK 自带keytool与系统openssl完成对应官方指引见 DataStax 的 secureSSL 文档本文不再展开。底层原理就绪等待与脚本执行CassandraQueryWaitStrategy以查询代替端口探测模块默认的等待策略不是简单轮询端口而是真正执行查询。CassandraQueryWaitStrategy.java 的waitUntilReady()会在startupTimeout内反复执行SELECT release_version FROM system.local直到查询成功才判定容器就绪超时则抛出ContainerLaunchException(Timed out waiting for Cassandra to be accessible for query execution)。选择查询式等待策略的原因在构造器中写得很清楚CassandraContainer.java#L62-L63当自定义配置启用了认证后单纯的端口/日志探测无法确认鉴权链路是否可用而真实查询是最可靠的信号。CassandraDatabaseDelegate容器内 cqlsh 执行初始化脚本与等待探测最终都汇聚到 CassandraDatabaseDelegate.java。它继承AbstractDatabaseDelegate但并未使用 JDBC 连接而是在容器内直接调用cqlsh命令执行语句有具体语句时使用cqlsh -e statement无语句时使用cqlsh -f scriptPath执行整个脚本对于CassandraContainer自动追加-u cassandra -p cassandra若启用了 SSL还会追加--ssl。这一设计让初始化脚本与就绪探测共享同一套鉴权/TLS 上下文也解释了为何认证配置下脚本能自动通过凭据执行。执行失败时抛出ScriptStatementFailedException最终由runInitScriptIfRequired()包装为UncategorizedScriptException使容器启动失败——这正是配置错误早暴露的测试友好行为。将模块加入项目依赖在pom.xml/build.gradle中加入以下依赖test作用域即可 Gradlegroovy testImplementation org.testcontainers:testcontainers-cassandra:{{latest_version}} Mavenxml dependency groupIdorg.testcontainers/groupId artifactIdtestcontainers-cassandra/artifactId version{{latest_version}}/version scopetest/scope /dependency 其中{{latest_version}}为当前最新的 Testcontainers 版本号。该模块位于本仓库的 modules/cassandra 目录实际发布坐标即org.testcontainers:testcontainers-cassandra。此外由于客户端代码直接使用 DataStax Java Driver 的CqlSession项目中还需引入对应的驱动依赖本仓库测试中使用的 DataStax Driver 4.x API。注意事项与最佳实践配置覆盖是整目录替换withConfigurationOverride会替换容器内/etc/cassandra全部内容务必提供完整的cassandra.yaml否则启动必然失败。镜像版本兼容性模块测试覆盖 2.2.x、3.0.x、3.11.x、4.1.x 与 5.x 等多条版本线但不同版本的cassandra.yaml默认参数有差异自定义配置最好与目标镜像版本匹配。凭据管理默认cassandra/cassandra仅用于开箱即用的测试一旦在生产式配置中启用PasswordAuthenticator应通过初始化脚本创建专用用户。SSL 是双向配置服务端cassandra.yaml的client_encryption_options与客户端驱动的 truststore/keystore必须成对配置缺少任何一方都会握手失败。失败即快速反馈初始化脚本缺失、脚本语句报错、配置目录无效都会以ContainerLaunchException或脚本异常的形式让测试立即失败便于在 CI 中尽早发现配置问题。通过 CassandraContainerTest.java 中覆盖上述全部场景的测试用例你可以直接复用其中的配置目录与 CQL 脚本均位于 modules/cassandra/src/test/resources快速搭建起属于自己的 Cassandra 集成测试环境。【免费下载链接】testcontainers-javaTestcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.项目地址: https://gitcode.com/GitHub_Trending/te/testcontainers-java创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。