Skip to content

International Ferry — Cross-cloud Relay

Seamless point-to-point routing across regional boundaries or cloud providers via a persistent WoSP-secured gRPC tunnel.

Tags: Armored Tunnel | Multi-cluster | HTTP2/gRPC | 2 Pods


Overview

The International Ferry connects a gRPC Gateway (grpc-gateway) in Cluster A to a gRPC Sink (grpc-sink) in Cluster B. Both are boundary pods. The WoSP tunnel spans the cluster boundary using LoadBalancer IPs.

Armored Tunnel mode (xtra4) provides per-session key rotation optimized for persistent gRPC connections. The bundle includes generated protobuf files (lane7.proto, lane7_pb2.py, lane7_pb2_grpc.py) for the WoSP gRPC interface.

flowchart TD
    subgraph ClusterA["Cluster A"]
        A["Gateway / Initiator\n(grpc-gateway)\nPINHOLE_ENABLED=true"]
    end
    subgraph ClusterB["Cluster B"]
        B["Sink / Terminator\n(grpc-sink)\nPINHOLE_ENABLED=true"]
    end
    A -->|"WoSP xtra4\ngRPC / LoadBalancer IP"| B

Use Cases

  • Low-latency cross-cloud gRPC connectivity
  • Bi-directional streaming across cloud provider or organizational boundaries
  • Hybrid deployments where on-premises and cloud services must communicate over gRPC
  • Replacing VPN or service mesh cross-cluster gRPC with WoSP-secured tunneling

Cross-cluster port mapping required

Cross-cluster connections require LoadBalancer IPs and port mappings known at deploy time. Deploy Cluster B (sink) first so its LoadBalancer IP is available when configuring Cluster A. For k3d testing, set --port flags at cluster creation — you cannot add port mappings after cluster creation.

Bundle Contents

international-ferry/
├── gateway/              ← grpc-gateway (Cluster A, boundary)
│   └── app/
│       ├── app.py
│       ├── Dockerfile
│       ├── lane7.proto
│       ├── lane7_pb2.py
│       └── lane7_pb2_grpc.py
├── sink/                 ← grpc-sink (Cluster B, boundary)
│   └── app/
│       ├── app.py
│       ├── Dockerfile
│       ├── lane7.proto
│       ├── lane7_pb2.py
│       └── lane7_pb2_grpc.py
├── deploy-path0.sh
├── deploy-path1.sh
├── teardown.sh
├── blueprint.yaml
├── README.md
└── EULA.md

Deploy

Create two k3d clusters with port mappings:

k3d cluster create cluster-a --port "30300:30300@loadbalancer" --agents 1
k3d cluster create cluster-b --port "30400:30400@loadbalancer" --agents 1

Deploy Cluster B (sink) first:

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

Then deploy Cluster A (gateway):

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

Pre-provision static IPs in both clusters to avoid circular dependency. See Multi-Cluster Guide.

Verify

kubectl logs -n international-ferry-gateway-ns \
  deployment/gateway -c web-app -f

Expected output:

🔁 Auto-trigger starting — sending 5 messages
🔁 Auto-trigger complete — 5/5 messages sent.

The "trail" in results will include pod names from both clusters, confirming cross-cluster connectivity.

Customize

Hook functions for this blueprint:

  • on_trigger(payload, headers) — in gateway/app/app.py
  • on_receive_terminator(payload) — in sink/app/app.py

See Hook Functions Reference.

Pricing

2 WoSP units (1 per pod). See Commercial Licensing.