2. First deploy
Goal: Create a bucket, register one worker, deploy a hello job, and verify it on the worker.
Prerequisites: Chapter 1 — Introduction.
You need:
- CLI host:
maandbinary,bash,ssh,rsync,python3 - One worker: Linux with SSH,
python3,make,rsync,bash,timeoutonPATH - SSH key: private key authorized for your worker user
Step 1 — Create the bucket
mkdir my-cluster && cd my-cluster
maand init
You should see maand bucket initialized. Layout:
maand.conf data/ workspace/ secrets/ tmp/ logs/
Step 2 — Add your SSH key
cp ~/.ssh/id_ed25519 secrets/worker.key
chmod 600 secrets/worker.key
Edit maand.conf if your worker user is not agent:
ssh_user = "agent"
ssh_key = "worker.key"
use_sudo = true
The matching public key must be in ~/.ssh/authorized_keys on the worker.
Step 3 — Register one worker
Edit workspace/workers.json:
[
{
"host": "10.0.0.1",
"labels": ["worker"],
"memory": "4096 mb",
"cpu": "2000 mhz"
}
]
Replace 10.0.0.1 with your worker address.
Test SSH:
ssh -i secrets/worker.key agent@10.0.0.1 echo ok
Pin the host key:
maand worker trust
Step 4 — Create the hello job
maand job create hello --selectors worker
This creates workspace/jobs/hello/ with a starter manifest.json and Makefile.
Replace the Makefile with something minimal:
cat > workspace/jobs/hello/Makefile <<'EOF'
.PHONY: start stop restart status
start:
mkdir -p data logs
echo running > data/status
date >> logs/start.log
stop:
echo stopped > data/status
restart: stop start
status:
@cat data/status 2>/dev/null || echo not running
EOF
Ensure manifest.json has at least:
{
"version": "1.0.0",
"selectors": ["worker"],
"resources": {
"memory": { "min": "64 mb", "max": "256 mb" },
"cpu": { "min": "100 mhz", "max": "500 mhz" }
}
}
Do not put data/, logs/, or bin/ in the workspace job folder — those live on the worker at runtime.
Step 5 — Build the catalog
maand build
Build reads workspace and updates data/maand.db. It does not SSH to the worker.
Inspect:
maand cat workers
maand cat jobs
maand cat allocations
You should see one allocation: hello on 10.0.0.1.
Step 6 — Deploy to the worker
maand deploy
Deploy rsyncs files to /opt/maand/<bucket_id>/ on the worker and runs make start.
Optional — build and deploy in one command:
maand deploy --build
Step 7 — Verify on the worker
maand run_command "cat /opt/maand/*/jobs/hello/data/status"
Expected output includes running.
Or SSH directly:
ssh -i secrets/worker.key agent@10.0.0.1 "cat /opt/maand/*/jobs/hello/data/status"
Step 8 — Inspect from the CLI host
maand info
maand cat deployments --jobs hello
You now have a bucket, one worker, one job, and one running allocation.
What you learned
maand initcreates a bucket;workers.jsonlists SSH targets- A job lives under
workspace/jobs/<name>/withmanifest.jsonand a Makefile maand buildupdates the local catalog;maand deploypushes to workers- Deploy calls
make starton first deploy to a worker
Full manifest fields: Reference: manifest.
Next
Chapter 3 — The model: name the four ideas you just used.