tutorial

How to Monitor Testcontainers with Vigilmon

Testcontainers spins up real Docker containers for integration tests — here's how to monitor container health, test pipeline reliability, and catch flaky infrastructure before it breaks your CI.

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.

  1. Log in to vigilmon.online and click Add Monitor.
  2. Choose Cron Heartbeat.
  3. Set the expected ping interval to match your test schedule (e.g. 60 minutes for hourly CI runs, or 1440 minutes for nightly runs).
  4. 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):

  1. In Vigilmon, click Add MonitorHTTP / HTTPS.
  2. Enter the runner health URL: http://runner.internal:9100/health (or your Prometheus node exporter endpoint).
  3. Set Check interval to 5 minutes.
  4. 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

  1. In Vigilmon, open the heartbeat monitor created in Step 1.
  2. Click AlertingAdd Alert Channel.
  3. Choose Email, Slack, or PagerDuty.
  4. Set the alert trigger: missed 1 heartbeat (for CI pipelines) or down for 5 minutes (for always-on monitors).
  5. Click Save.

For teams using Slack:

  • Create a #ci-alerts channel.
  • 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.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →