Testcontainers is the go-to library for writing integration tests that use real dependencies — real databases, real message brokers, real caches — spun up as Docker containers for each test run. When Testcontainers works, your tests are rock-solid. When Docker daemon connectivity fails, image pulls time out, or containers refuse to start, your entire CI pipeline silently crumbles. Vigilmon gives you the monitoring layer to detect those infrastructure failures before developers start blaming their tests.
What You'll Set Up
- Cron heartbeat monitoring for integration test suite runs
- HTTP health checks for shared Testcontainers Ryuk/infrastructure services
- Alerting when CI test pipelines go silent or fail to complete
- Docker daemon availability checks on self-hosted runners
Prerequisites
- A project using Testcontainers (Java, Go, Node.js, Python, or Rust)
- Docker running on CI runners or locally
- A free Vigilmon account
Step 1: Heartbeat Monitor for Your Integration Test Suite
The most important signal from a Testcontainers-based test suite is whether it ran at all. A container startup failure often causes tests to hang or exit early — with a passing exit code in some configurations — rather than fail loudly. A Vigilmon cron heartbeat catches this.
- Log in to vigilmon.online and click Add Monitor.
- Choose Cron Heartbeat.
- Set the expected ping interval to match your test schedule (e.g.
60minutes for hourly CI runs, or1440minutes for nightly runs). - Copy the heartbeat URL (e.g.
https://vigilmon.online/heartbeat/abc123).
Add the ping to the end of your test script, after a successful run:
Maven / Gradle (Java)
<!-- pom.xml -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>vigilmon-heartbeat</id>
<phase>post-integration-test</phase>
<goals><goal>exec</goal></goals>
<configuration>
<executable>curl</executable>
<arguments>
<argument>-fsS</argument>
<argument>--max-time</argument>
<argument>10</argument>
<argument>https://vigilmon.online/heartbeat/abc123</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
Go
// TestMain — send heartbeat after suite passes
func TestMain(m *testing.M) {
code := m.Run()
if code == 0 {
http.Get("https://vigilmon.online/heartbeat/abc123")
}
os.Exit(code)
}
Node.js / Jest (globalTeardown)
// jest.globalTeardown.js
const https = require('https');
module.exports = async () => {
await new Promise((resolve) => {
https.get('https://vigilmon.online/heartbeat/abc123', resolve).on('error', resolve);
});
};
Step 2: Monitor the Docker Daemon on Self-Hosted Runners
Testcontainers requires a reachable Docker daemon. On self-hosted GitHub Actions or GitLab runners, the Docker service can stop silently. Add a monitor for the Docker TCP socket or the runner's management endpoint.
If your runner exposes a health endpoint (e.g. via a monitoring sidecar):
- In Vigilmon, click Add Monitor → HTTP / HTTPS.
- Enter the runner health URL:
http://runner.internal:9100/health(or your Prometheus node exporter endpoint). - Set Check interval to
5 minutes. - Set Expected HTTP status to
200.
For Docker daemon TCP exposure (use with caution on internal networks only):
# Enable Docker daemon TCP on the runner host (internal network only)
# /etc/docker/daemon.json
{
"hosts": ["unix:///var/run/docker.sock", "tcp://127.0.0.1:2375"]
}
Then monitor http://runner-ip:2375/version — a 200 response means Docker is up.
Step 3: Export Test Results Metrics from Testcontainers Runs
Testcontainers itself doesn't emit HTTP metrics, but your test framework does. Configure your CI to publish a results endpoint after each run that Vigilmon can check.
A minimal Express.js status server that CI can update:
// test-status-server.js
const express = require('express');
const app = express();
let lastRun = null;
app.use(express.json());
app.post('/run', (req, res) => {
lastRun = { ...req.body, timestamp: new Date().toISOString() };
res.sendStatus(200);
});
app.get('/health', (req, res) => {
if (!lastRun) return res.status(503).json({ status: 'no_run_recorded' });
const age = Date.now() - new Date(lastRun.timestamp).getTime();
const stale = age > 2 * 60 * 60 * 1000; // 2 hours
res.status(stale ? 503 : 200).json({ ...lastRun, stale });
});
app.listen(3001);
Post to it from CI after each Testcontainers run:
curl -X POST http://status-server:3001/run \
-H 'Content-Type: application/json' \
-d '{"passed": true, "containers": ["postgres:15", "redis:7"]}'
Add an HTTP monitor in Vigilmon pointing at http://status-server:3001/health.
Step 4: Alert on Container Image Pull Failures
Testcontainers pulls images on first use. Slow or broken Docker Hub access causes container startup to time out. You can detect this at the CI level by monitoring pull timing.
Add a pre-test script that probes Docker Hub connectivity:
#!/bin/bash
# pre-test-check.sh
start=$(date +%s)
docker pull hello-world:latest > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Docker Hub unreachable — skipping integration tests"
# Notify Vigilmon of the failure via a status endpoint
curl -fsS -X POST https://vigilmon.online/api/status-push \
-d '{"status":"down","message":"Docker Hub pull failed"}'
exit 1
fi
end=$(date +%s)
echo "Pull took $((end - start))s"
Step 5: Set Up Alerting
- In Vigilmon, open the heartbeat monitor created in Step 1.
- Click Alerting → Add Alert Channel.
- Choose Email, Slack, or PagerDuty.
- Set the alert trigger: missed 1 heartbeat (for CI pipelines) or down for 5 minutes (for always-on monitors).
- Click Save.
For teams using Slack:
- Create a
#ci-alertschannel. - Add the Vigilmon Slack integration and direct heartbeat alerts there.
- Set a second alert channel (email) as a backup for on-call engineers.
Conclusion
Testcontainers integration tests are only as reliable as the Docker infrastructure they run on. A hung container startup, a Docker daemon crash, or a stale image cache can silently invalidate your test suite — leaving you with false confidence in your build. Vigilmon's cron heartbeats catch suite-level failures, HTTP monitors catch infrastructure problems, and alerting ensures the right people know immediately when something goes wrong.
Start with the heartbeat monitor for your integration test suite — it's a five-minute setup that catches the most common failure mode. Add the Docker daemon health monitor on self-hosted runners next, and you'll have the observability layer your Testcontainers setup deserves.