Argus is a single-node command-line deployment tool for Docker: point it at a directory with a Dockerfile, and argus apply builds the image, swaps the running container for the new one, verifies it actually came up, and rolls back automatically if it didn't — with every attempt logged to a local history file.
It's a systems-engineering learning project — an exercise in building the pieces (a hand-rolled Docker Unix-socket HTTP client, a verification/rollback state machine, an append-only history log) that a real deployment tool needs, rather than wrapping the docker CLI. It is explicitly not trying to be a Kubernetes replacement, or anything multi-node — Phase 1 (this release) is single-node only; a planned Phase 2 would add a coordinator across a small fleet of machines, but that work hasn't started (see "What's next" below).
For the full internal picture — component-by-component status against the design, exact test coverage, and known divergences — see docs/current_state.md and docs/architecture.md. For what changed in this release, see docs/RELEASE_NOTES.md.
- Java 21
- Maven — the repo includes the
./mvnwwrapper, so a system-wide install isn't required - A reachable Docker daemon over its Unix domain socket at
/var/run/docker.sock— Argus talks to it directly via a hand-rolled HTTP client, not the Docker CLI or a client library
Argus currently runs on the JVM. There's a native Maven profile for a GraalVM native-image build, but it hasn't been exercised — see Known Limitations.
# Show all commands
./mvnw compile exec:java -Dexec.mainClass=io.github.kritharthshetty.argus.Main -Dexec.args="--help"
# Build an image from a directory with a Dockerfile, without deploying it
./mvnw compile exec:java -Dexec.mainClass=io.github.kritharthshetty.argus.Main \
-Dexec.args="build -d . -t myapp:latest"
# Deploy it: build, swap, verify, roll back on failure
./mvnw compile exec:java -Dexec.mainClass=io.github.kritharthshetty.argus.Main \
-Dexec.args="apply -a myapp -d . -p 8080"
# Check what's running
./mvnw compile exec:java -Dexec.mainClass=io.github.kritharthshetty.argus.Main -Dexec.args="status -a myapp"
# Check what happened on past deploys
./mvnw compile exec:java -Dexec.mainClass=io.github.kritharthshetty.argus.Main -Dexec.args="history -a myapp"Run the test suite:
./mvnw test| Command | What it does |
|---|---|
build -d <dir> -t <tag> |
Compresses <dir> and streams it to Docker's /build API to produce an image tagged <tag>. Doesn't touch any running containers. |
apply -a <app> -d <dir> -p <port> [-e KEY=VALUE ...] |
The full lifecycle: acquire a per-app lock, resolve config, build, stop the previous container for <app> (if any), start the new one, verify it, and either remove the old container (success) or restart it (rollback). Exits 0 on success, 1 on a failure that was cleanly rolled back (or had nothing to roll back to), 2 if the rollback itself also failed — see the printed CRITICAL: message in that case. |
status -a <app> |
Prints the currently running container for <app> (id, generation, image, port, status), or explicitly calls out an interrupted-swap state if a previous apply was killed mid-flight. |
history -a <app> |
Prints one line per past apply attempt for <app>, oldest first, with the first line of the failure diagnosis where relevant. |
version |
Prints the Argus version. |
Run any command with --help for its full flag list — apply in particular has several optional flags (--image, --container-port, the Verification Engine's timing knobs) not shown above.
apply doesn't require every flag on every invocation. Its options resolve with CLI flag > ~/.argus/config/<app>.properties > hardcoded default precedence, so a redeploy can be as short as apply -a myapp -d . if a config file already has the rest:
# ~/.argus/config/myapp.properties
port=8080
container-port=8080
image=argus/myapp:latest
env.GREETING=helloenv.<KEY> entries merge with any -e flags passed on the command line; the CLI flag wins on a key conflict. -a/--app itself always has to be a CLI flag (it's what selects which config file to read), and -p/--port has to come from somewhere — a flag or the config file — or apply fails cleanly rather than guessing.
This is a first release of a learning project — the list below is real and current, not hedging. Full detail and reproduction notes are in docs/RELEASE_NOTES.md and docs/current_state.md.
- Verification can report PASS on a container that isn't actually serving anything, if
container-portis misconfigured. Without a declaredHEALTHCHECK, verification falls back to a bare TCP connect on the published port — but Docker's userland-proxy completes that handshake before confirming anything is actually listening inside the container, so a wrong--container-portcan produce a "healthy" deployment that serves nothing. - Diagnosis log output (shown on a failed deploy) can be silently corrupted by an unsound byte filter in the log-frame-stripping code.
- An invalid
--appname crashes with a raw Java stack trace instead of a clean error message. - The double-failure ("rollback also failed") message can mislabel a deleted previous container as merely "(stopped)."
build/applyuse Docker's legacy/buildAPI rather than shelling out todocker buildx, and don't decode Docker's HTML-escaped</>in build output (cosmetic — step arrows print as literal text instead of--->).- No buildpack/Railpack support for Dockerfile-less projects.
- No native-image packaging yet — Argus runs on a JVM via Maven today, not as a standalone binary.
- Phase 2 (§4 of the design doc) — a hub-and-spoke coordinator, heartbeats, and generation-numbered fencing across a small fleet — hasn't started, and shouldn't until the Phase 1 gaps above are closed.
- Within Phase 1: fixing the TCP-probe false positive, deciding on
buildxvs. the legacy/buildAPI, and revisiting whetherapplyneeds to stop the previous container when the new deploy's port doesn't actually conflict with it. - See
docs/current_state.md's "Next milestones" section for the full, current list.