OpenSearch¶
modules::OpenSearchImage → modules::OpenSearchContainer — pinned
opensearchproject/opensearch:3.7.0 (the active 3.x line; the hub publishes no
minor-line tags, so the pin is patch-level), REST port 9200, security plugin disabled:
plain HTTP, no credentials — http_url() is all a REST client needs. Readiness is HTTP 200
from /_cluster/health through the published port: the root endpoint answers from the
local node, while cluster health answers only once a cluster manager is elected — what the
first index or search call actually needs.
Quick start¶
#include "testcontainers/modules/OpenSearch.hpp"
using namespace testcontainers;
const modules::OpenSearchContainer search = modules::OpenSearchImage().start();
search.host(); // "localhost" for a local daemon
search.port(); // published host port for 9200
search.http_url(); // "http://localhost:<port>" — point any HTTP client at it
Seeding and asserts work driver-free through the in-image curl:
search.container().exec({"curl", "-s", "-XPUT",
"http://localhost:9200/idx/_doc/1?refresh=true",
"-H", "Content-Type: application/json",
"-d", R"({"msg":"hello"})"});
// ?refresh=true makes the document searchable immediately.
Configuration¶
const modules::OpenSearchContainer search =
modules::OpenSearchImage()
.with_env("cluster.name", "it-cluster") // dotted key = a setting
.with_env("OPENSEARCH_JAVA_OPTS", "-Xms1g -Xmx1g") // your duplicate wins
.start();
- The module manages four env keys:
discovery.type=single-node(forms a one-node cluster and bypasses the bootstrap checks — novm.max_map_countsysctl needed),DISABLE_SECURITY_PLUGIN=true+DISABLE_INSTALL_DEMO_CONFIG=true(plain HTTP, no demo certs/passwords), and a 512 MB heap (OPENSEARCH_JAVA_OPTS— the image default is 1 GB). Yourwith_enventries land after them, so on a duplicate key you win — these are engine tuning, not credential mirrors, and overriding the heap or discovery is fair game. - Keys shaped like
section.settingbecome real OpenSearch settings — the entrypoint turns them into-Eoptions, sowith_envis the settings API. - Re-enabling security flips 9200 to https with self-signed demo certs, which the
plain-HTTP readiness probe can never pass. Replace it via
with_waitthen — the working recipe iswait_for::successful_shell_command("curl -sk --fail -u admin:<password> https://localhost:9200/"). A typed secure variant is a planned follow-up.
Connecting¶
http_url() feeds any HTTP client or opensearch-cpp; there are no credentials to pass.
Peer containers on a shared docker network dial http://<alias>:9200. No accounts exist
in this mode, so there are deliberately no username()/password() getters — the secure
follow-up will introduce them with real values.
Behavior notes¶
- Startup budget is 120s by default (not the family 60s): a JVM engine booting a gigabyte of plugins takes 10–20s warm and more on loaded CI.
- Right after
start()the cluster status may still be yellow (an internal shard initializing) — the probe's promise is that the health endpoint answers, which is what index/search calls need; don't assertgreenin your own tests. - Only 9200 is published. The performance-analyzer ports (9600/9650) and the transport
port (9300) stay unpublished — reach them via
with_customizer([](GenericImage& g) { g.with_exposed_port(tcp(9600)); }). - A reused (adopted) server keeps its indices; a changed env (say, the heap) changes the reuse hash and builds a fresh container.