Skip to content

Path 0 — Local k3d

Local deployment using k3d. No external registry required. Best for development, learning, and CI pipelines.

When to use

  • First-time deployment of a blueprint
  • Development and iteration on Section 1 business logic
  • CI/CD pipelines where you want a clean Kubernetes environment per run
  • Testing before promoting to cloud

Prerequisites

  • Docker Desktop (running)
  • k3d >= 5.0 (k3d version to check)
  • kubectl

k3d version requirement

k3d versions below 5.0 do not support host.k3d.internal DNS. Cross-cluster blueprints will fail with a DNS resolution error on older versions.

Single-cluster deployment

1. Create the cluster

Blueprints use specific NodePort values pre-configured in the manifests. Create your cluster with matching port mappings:

k3d cluster create wosp-cluster \
  --port "30011:30011@loadbalancer" \
  --port "30012:30012@loadbalancer" \
  --agents 1

Check the cluster is ready:

kubectl get nodes

2. Build and import images

For each pod in the blueprint, build and import the app image:

cd gateway/app/
docker build -t serial-app-wosp-node:latest .
k3d image import serial-app-wosp-node:latest

Repeat for every pod directory. The tag serial-app-wosp-node:latest is referenced by imagePullPolicy: Never in the deployment manifests — use this exact tag unless you update the YAML.

3. Deploy

bash deploy.sh

Wait for completion before verifying. deploy.sh applies manifests in order and waits for pod readiness.

4. Verify

Check all pods are running with 3/3 containers:

kubectl get pods -A

Each blueprint pod should show 3/3 Ready. The three containers are web-app, xtra-wasm, and web-retriever.

Check the auto-trigger on the gateway pod:

kubectl logs -n <blueprint>-gateway-ns deployment/gateway -c web-app -f

Expected: 🔁 Auto-trigger complete — 5/5 messages sent.


Multi-cluster k3d deployment

Cross-cluster blueprints (Fast International Ferry, International Ferry) require two k3d clusters that can reach each other.

The isolation problem

Two separate k3d clusters run in separate Docker bridge networks by default and cannot reach each other's IPs directly.

The solution: host.k3d.internal + port mappings

k3d >= 5.0 provides host.k3d.internal as a DNS name that resolves to the Docker host IP from inside any container. Combined with --port flags that map host ports to cluster LoadBalancers, pods in different clusters can communicate via the host machine.

# Create both clusters with port mappings at creation time
# (Port mappings cannot be added after cluster creation)
k3d cluster create cluster-a \
  --port "30100:30100@loadbalancer" \
  --agents 1

k3d cluster create cluster-b \
  --port "30200:30200@loadbalancer" \
  --agents 1

Deploy processor cluster first

The processor/sink cluster must be deployed before the gateway cluster, because the gateway's configuration references the processor's LoadBalancer address.

# 1. Deploy the processor/sink cluster
kubectl config use-context k3d-cluster-b
cd terminator/app/ && docker build -t serial-app-wosp-node:latest . && k3d image import serial-app-wosp-node:latest -c cluster-b
cd ../..
bash deploy-cluster-b.sh

# 2. Deploy the gateway cluster
kubectl config use-context k3d-cluster-a
cd initiator/app/ && docker build -t serial-app-wosp-node:latest . && k3d image import serial-app-wosp-node:latest -c cluster-a
cd ../..
bash deploy-cluster-a.sh

Verify cross-cluster

Check the gateway logs for the auto-trigger completion. Then check the result trail:

curl http://localhost:8000/output

The "trail" in each result should contain pod names from both clusters, confirming the cross-cluster connection is live.


Troubleshooting

Symptom Cause Fix
ImagePullBackOff Image not imported into k3d Run k3d image import <image> -c <cluster>
ErrImageNeverPull Tag mismatch between import and manifest Ensure you built with the exact tag in 03-deployment.yaml
CrashLoopBackOff on xtra-wasm Empty or missing Hopr credential in 02-secrets.yaml Check all four fields: HOPR_LICENSE, HOPR_KEY, CHIPS_ALGORITHM, HOPR_API_TOKEN
No 🔁 Auto-trigger complete in logs Pod not yet ready, or WoSP failed to authenticate Wait 60s after kubectl apply, then check xtra-wasm logs
Connection refused on host.k3d.internal Port not mapped at cluster creation Delete cluster and recreate with correct --port flags
DNS failure on cross-cluster blueprint k3d < 5.0 Upgrade k3d to >= 5.0
CYCLE COMPLETE missing in trail Cross-cluster routing misconfigured Verify host.k3d.internal resolves inside the pod and port is mapped

Teardown

bash teardown.sh

To delete the cluster entirely:

k3d cluster delete wosp-cluster