Run a local process as if it were inside your cluster: prefix any command
with plug and it resolves the cluster DNS and reaches the cluster services like
any workload of the stack - no code change, no proxy configuration in your app. One
tiny agent container on the cluster side, one static CLI on yours. Docker, Swarm, Kubernetes
and OpenShift.
From your build tool
plug runs in front of the command that starts your service:
plug -s my-api:8080:3000 npm run start:dev. Most build tools already have a
place to keep such a command next to the project, so nobody types it twice and the whole team
runs the same thing. Nothing to install beyond plug itself: each recipe below uses what the
tool provides.
Every recipe takes the place of my-api, listening locally on the port given last.
Replace the name and the ports with yours; the
CLI reference has every option a command can carry.
Node.js (npm, pnpm, Yarn, Bun)
A script in package.json:
{
"scripts": {
"start:dev": "nest start --watch",
"dev:cluster": "plug -s my-api:8080:3000 npm run start:dev"
}
}npm run dev:clusterMaven
An execution of exec-maven-plugin, under <build><plugins>.
It runs only when you ask for it, never during a build:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<id>cluster</id>
<goals><goal>exec</goal></goals>
<configuration>
<executable>plug</executable>
<arguments>
<argument>-s</argument>
<argument>my-api:8080:8080</argument>
<argument>./mvnw</argument>
<argument>spring-boot:run</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>mvn exec:exec@cluster
On Windows, write mvnw.cmd in place of ./mvnw. Maven starts twice,
once for the goal and once for the application: a second or two more at startup.
Gradle
A task of type Exec in build.gradle.kts:
tasks.register<Exec>("bootRunCluster") {
group = "application"
description = "Runs the app in place of my-api in the cluster"
commandLine("plug", "-s", "my-api:8080:8080", "./gradlew", "bootRun")
}./gradlew bootRunClusterOn Windows, write gradlew.bat in place of ./gradlew.
PHP (Composer)
A script in composer.json. The first line matters: Composer stops any script
after 300 seconds, a server included, unless it is told not to.
{
"scripts": {
"dev:cluster": [
"Composer\\Config::disableProcessTimeout",
"plug -s my-api:8080:8000 php -S 0.0.0.0:8000 -t public"
]
}
}composer run dev:clusterDeno
A task in deno.json:
{
"tasks": {
"dev:cluster": "plug -s my-api:8080:8000 deno run -A main.ts"
}
}deno task dev:clusterPython (PDM, Hatch)
A script in pyproject.toml. It runs inside the project's environment, so the
server it starts is the one installed there.
[tool.pdm.scripts]
dev-cluster = "plug -s my-api:8080:8000 uvicorn app:app --port 8000"pdm run dev-clusterWith Hatch, the same line under the environment's scripts:
[tool.hatch.envs.default.scripts]
dev-cluster = "plug -s my-api:8080:8000 uvicorn app:app --port 8000"hatch run dev-cluster
uv and Poetry have no script runner of this kind: use the command itself
(plug -s my-api:8080:8000 uv run uvicorn app:app), or a Makefile.
Everything else: Make, just, Taskfile
Go, Rust, .NET and most other languages start from a plain command
(go run ., cargo run, dotnet run). A
Makefile keeps it with the project:
dev-cluster:
plug -s my-api:8080:8080 go run .Or a justfile:
dev-cluster:
plug -s my-api:8080:8080 cargo runRunning it from the IDE, and debugging
plug has to start your service: that is how the service receives the deployed one's configuration and how its traffic finds its way. A Run or Debug button that starts the program on its own leaves plug out. Run the recipe instead: every IDE can run an npm script, a Maven goal or a Gradle task from its own run configurations.
To debug, start the service with its debugger listening, then attach the IDE to it:
-
Node.js: add
--inspectto the command that starts node, and attach to port 9229. -
Spring Boot with Maven: add the argument
-Dspring-boot.run.jvmArguments=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005afterspring-boot:run, and attach to port 5005. -
Spring Boot with Gradle: add
"--debug-jvm"after"bootRun"; the application waits for the debugger on port 5005. -
Python: start the server through debugpy
(
python -m debugpy --listen 5678 -m uvicorn app:app) and attach to port 5678.