Prove your service drains before you deploy it.

Draincheck starts a Docker or Podman container, holds real work across SIGTERM, and turns readiness withdrawal, request draining, telemetry flushes, and clean exit into one repeatable contract.

Docker + PodmanHTTP · gRPC · commandsJSON · JUnit · debug bundles
pipeline / lifecycle
$ draincheck verify checkout:local
 container ready in 182ms
 4 requests active at SIGTERM
 readiness withdrawn in 41ms
 in-flight work completed
 exited cleanly in 326ms

PASS lifecycle contract satisfied

Why Draincheck

Shutdown behavior is part of the artifact.

Draincheck is not a load tester or orchestrator. It verifies the lifecycle behavior of one final image using bounded traffic and stable evidence that any pipeline can retain.

Final-image testing

Exercise the exact entrypoint, PID 1 behavior, runtime environment, and image contents.

Pipeline native

Use stable exit codes plus JSON, JUnit, and bounded debug artifacts in ordinary CI jobs.

Real work adapters

Drive HTTP, gRPC, streams, or a repository-owned command while termination begins.

Exact cleanup

Label every resource, bind random loopback ports, and remove only the container created for the run.

One run, one decision

See the whole termination boundary.

The useful question is not whether a container stops. It is whether it stops accepting work, finishes what it already owns, flushes critical signals, and exits before its budget expires.

  1. 01

    Start the final image

    Use the same entrypoint, environment, and image contents the pipeline may release.

  2. 02

    Prove readiness

    Wait for HTTP, gRPC Health, or an image-owned command to report ready.

  3. 03

    Hold real work

    Keep requests, streams, or repository-owned command traffic active.

  4. 04

    Terminate and drain

    Send the configured signal and observe withdrawal, completion, and exit.

  5. 05

    Keep the evidence

    Return a CI verdict and write machine-readable reports for every outcome.

A small, reviewable contract

Describe the behavior your service already owns.

Keep the lifecycle expectation beside the application. Draincheck supplies strict defaults, validates unknown fields, and lets explicit YAML override every meaningful deadline or assertion.

  • Point at the locally built image and its container port.
  • Choose a readiness check and one safe unit of meaningful work.
  • Set the termination signal, deadline, and acceptable outcomes.
Build your first contract
draincheck.yaml
version: 1

target:
  image: checkout:local
  container_port: 8080

readiness:
  path: /ready
  startup_timeout: 10s

traffic:
  request:
    path: /work?delay=2s
  count: 4
  concurrency: 4
  shutdown_after: 200ms

shutdown:
  signal: SIGTERM
  deadline: 15s

Evidence that survives the job

A failure should explain itself.

Console output stays concise. Deeper evidence is written atomically, bounded before capture, and ready for the CI system your team already uses.

JSON report

A stable automation contract with events, assertions, timings, and final runtime state.

JUnit XML

Assertion-level test cases that appear naturally in existing CI test-report views.

Debug bundle

Bounded logs, redacted configuration, timeline, and container state in one artifact.

One CLI step. One YAML file. No control plane.

Make shutdown behavior part of your release evidence.

Start with a non-blocking service pilot, keep the reports, and promote the check only when the scenario exercises work your team considers meaningful.