Skip to content

Commit 151c627

Browse files
authored
Merge pull request #183 from kaisoz/update-kind-site-doc
docs(site): update local kind development guide
2 parents dcc5789 + 0b1337b commit 151c627

2 files changed

Lines changed: 143 additions & 33 deletions

File tree

site/content/docs/development/_index.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,13 @@ make test-e2e-container
7777

7878
## Local Kubernetes Test Setup
7979

80-
For end-to-end integration testing in a local Kubernetes environment:
81-
82-
1. **Start Kind Cluster**:
83-
Ensure you have a Kind cluster running.
84-
2. **Build and Load Images**:
85-
```bash
86-
make docker-build-node
87-
make docker-build-hub
88-
kind load docker-image sam-node:local
89-
kind load docker-image sam-hub:local
90-
```
91-
3. **Deploy Config Templates**:
92-
Deploy and template configuration files located under `.github/k8s/` or `development/kind/` to spin up local nodes and vLLM inference engines.
80+
For end-to-end integration testing in a local Kubernetes environment, the repository provides `make` targets that stand up a complete mesh in `kind` with a single command:
81+
82+
```bash
83+
make kind-up # create the sam-kind cluster, build+load images, deploy hub + nodes
84+
make kind-local-node # enroll a locally-built ./bin/sam-node into the mesh
85+
make kind-e2e-mesh # run the end-to-end discover-and-call check
86+
make kind-down # tear the cluster down
87+
```
88+
89+
`make kind-up` builds the `sam-hub:local` and `sam-node:local` images, creates a `sam-kind` cluster, and deploys the hub plus the nodes declared in `development/kind/mesh-config.yaml`. See the [Kubernetes Deployment and Local Testing Guide](kubernetes-deployment/#1-local-testing-with-kind) for details.

site/content/docs/development/kubernetes-deployment.md

Lines changed: 133 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,147 @@
22
title: "Kubernetes Deployment and Local Testing Guide"
33
linkTitle: "Kubernetes Deployment and Local Testing Guide"
44
---
5-
This guide explains how to deploy the `sam-hub` in a Kubernetes cluster and how to test it locally using `kind` and `cloud-provider-kind`.
5+
This guide explains how to deploy the `sam-hub` in a Kubernetes cluster and how to test it locally with `kind`using the bundled `make kind-*` targets for a one-command mesh, or a manual setup with `cloud-provider-kind`.
66

77
> [!TIP]
88
> This guide focuses on local development sandboxing. For production-grade Kubernetes deployments (GKE, EKS, AKS), see the [Production Kubernetes Deployment](../../user/kubernetes-deployment/) guide.
99
10-
This guide supports using either **Google OIDC** or a **Mock OIDC Provider** for authentication. The mock provider is recommended for quick local testing as it does not require creating external credentials.
10+
---
11+
12+
## 1. Local Testing with Kind
13+
14+
The repository ships a one-command local mesh under `development/kind/`, driven by `make` targets. This is the fastest way to get a running hub and a few nodes on your machine.
15+
16+
### Automated Mesh (Recommended)
17+
18+
```bash
19+
make kind-up
20+
```
21+
22+
This creates a `sam-kind` cluster (one control-plane plus workers for the hub and `node-a`, `node-b`, `node-c`), builds the `sam-hub:local` and `sam-node:local` images, loads them into the cluster, and deploys:
23+
24+
- The **hub**, configured to trust the cluster's own OIDC issuer.
25+
- Three **nodes** declared in `development/kind/mesh-config.yaml`: `node-a` (bare), `node-b` (hosts the `calc-mcp` example service), and `node-c` (hosts the `greeter-mcp` example service).
26+
27+
Nodes authenticate to the hub via **Workload Identity Federation** (projected ServiceAccount tokens), so no static secrets or mock OIDC provider are needed. The hub is exposed to the host on `127.0.0.1:9090` (HTTP enroll) and `127.0.0.1:4001` (libp2p) via a NodePort and the cluster's `extraPortMappings``cloud-provider-kind` is not required.
28+
29+
Once everything is up, `make kind-up` opens a tmux session with live per-pod logs (hub and each node in its own pane). Manage the mesh with:
30+
31+
```bash
32+
make kind-up ARGS=-s # bring the mesh up without attaching the log view
33+
make kind-logs # (re)attach the live-logs tmux session
34+
make kind-down # delete the sam-kind cluster
35+
```
36+
37+
### Mesh Layout (`mesh-config.yaml`)
38+
39+
The nodes that make up the dev mesh are declared in `development/kind/mesh-config.yaml`. Each entry maps a node to an optional service:
40+
41+
```yaml
42+
# node -> service. A blank value means a bare node (no service, e.g. a caller).
43+
# The service value is a folder name under development/examples/.
44+
node-a:
45+
node-b: calc-mcp
46+
node-c: greeter-mcp
47+
```
48+
49+
- The key is the node's name. The cluster currently ships with a hub plus these **three** agent nodes; each is pinned to a matching worker via the `sam-role` labels in `kind-config.yaml`.
50+
- A **blank** value is a bare node — a `sam-node` with no local service, useful as a caller/consumer.
51+
- A **non-blank** value is a folder name under `development/examples/`. That service is built and deployed as a **sidecar** next to the node, and the node is configured to advertise it to the mesh.
52+
53+
When a node has a service, `make kind-up` builds the service image from its `Dockerfile`, loads it into the cluster, and mounts the service's `sam-node-config.yaml` into the node. Because `make kind-up` only runs against a fresh cluster (it refuses if `sam-kind` already exists), **services are (re)deployed on cluster recreation** — after editing `mesh-config.yaml` or a service, run `make kind-down && make kind-up` to pick up the change.
54+
55+
### Adding and Testing a New Service
56+
57+
A service is any backend a node advertises to the mesh. Its kind is set by the `type` field in `sam-node-config.yaml`. SAM currently supports `mcp` (an MCP server) and `inference` (an LLM inference endpoint). The repository ships example MCP services under `development/examples/` (`calc-mcp`, `greeter-mcp`, `code-reviewer-mcp`, and `everything-mcp`) which are the easiest starting point. Using `calc-mcp` as a template:
58+
59+
1. **Create the service folder** `development/examples/my-mcp/` with:
60+
- The service backend (e.g. `my_server.py`) listening on a local port, plus a `Dockerfile` and any `requirements.txt`.
61+
- A `sam-node-config.yaml` declaring the service. Set `type` to the service kind and point `target_url` at the backend's local port:
62+
```yaml
63+
version: "v1alpha1"
64+
attenuation:
65+
policies:
66+
services:
67+
- type: "mcp"
68+
name: "my-service"
69+
description: "What it does"
70+
target_url: "http://127.0.0.1:7779/mcp"
71+
```
72+
The sidecar and `sam-node` share the pod's network, so `target_url` is always `127.0.0.1:<port>`, where `<port>` matches the port your service listens on.
73+
74+
2. **Assign it to a node** in `mesh-config.yaml` — replace an existing mapping or use a free node slot (`node-a`, `node-b`, `node-c`):
75+
```yaml
76+
node-a: my-mcp
77+
node-b: calc-mcp
78+
node-c: greeter-mcp
79+
```
80+
> [!NOTE]
81+
> There are three node slots because `kind-config.yaml` defines three workers labeled `sam-role: node-a|node-b|node-c`. To host more than three services at once, add a matching labeled worker there too.
82+
83+
3. **Recreate the cluster** so the new service is built and deployed:
84+
```bash
85+
make kind-down && make kind-up
86+
```
87+
88+
4. **Discover and call it** from another node — enroll a local node and use the MCP client:
89+
```bash
90+
make kind-local-node
91+
# in another shell:
92+
./bin/mcp-client -url http://127.0.0.1:9099/mcp -token devtoken -tool find_remote_tools -args '{}'
93+
```
94+
`find_remote_tools` lists the discovered tools (e.g. `mcp://my-service/...`) and the peer hosting them; pass that `peer_id` and `tool_name` to `call_remote_tool` to invoke it.
95+
96+
### Enrolling a Local Node
97+
98+
To iterate on `sam-node` without rebuilding the image, enroll a locally-built binary into the running mesh:
99+
100+
```bash
101+
make build # produce ./bin/sam-node
102+
make kind-local-node
103+
```
104+
105+
This mints a ServiceAccount token and runs `./bin/sam-node` against the hub at `127.0.0.1:9090`, exposing its MCP API on `127.0.0.1:9099` with the API token `devtoken`. Extra flags pass through via `ARGS`, e.g. to host an example service:
106+
107+
```bash
108+
make kind-local-node ARGS="--config development/examples/calc-mcp/sam-node-config.yaml"
109+
```
110+
111+
You can then drive it with the bundled MCP client:
112+
113+
```bash
114+
./bin/mcp-client -url http://127.0.0.1:9099/mcp -token devtoken -tool find_remote_tools -args '{}'
115+
```
116+
117+
### End-to-End Mesh Check
118+
119+
To verify the full discovery-and-call path against a freshly built mesh:
120+
121+
```bash
122+
make kind-e2e-mesh
123+
```
124+
125+
This enrolls a local node, waits for it to discover `mcp://calculator/add` (hosted by `node-b`), calls `add(2, 3)`, and asserts the result is `5`.
11126

12127
---
13128

14-
## 1. Mock OIDC Provider Manifests (Optional)
129+
## 2. Manual Deployment
130+
131+
If you'd rather deploy the pieces by hand — for example to exercise the Mock OIDC provider or wire up Google OIDC — you can apply the manifests below to a cluster yourself. SAM supports either a **Mock OIDC Provider** (recommended for quick local testing, since it needs no external credentials) or **Google OIDC** for authentication. The local `kind` path below uses `cloud-provider-kind` to allocate LoadBalancer IPs.
132+
133+
### Mock OIDC Provider Manifests (Optional)
15134

16135
The manifests for the mock OIDC provider are available in [mock-oidc.yaml](manifests/mock-oidc.yaml).
17136

18137
[mock-oidc.yaml](manifests/mock-oidc.yaml ':include')
19138

20-
---
21-
22-
## 2. SAM Hub Manifests
139+
### SAM Hub Manifests
23140

24141
The manifests for the SAM Hub are available in [sam-hub.yaml](manifests/sam-hub.yaml).
25142

26143
[sam-hub.yaml](manifests/sam-hub.yaml ':include')
27144

28-
---
29-
30-
## 3. Configuring Google OIDC (Optional)
145+
### Configuring Google OIDC (Optional)
31146

32147
To use Google as the OIDC provider instead of the mock provider:
33148

@@ -39,28 +154,26 @@ To use Google as the OIDC provider instead of the mock provider:
39154
SAM_OIDC_SECRET: "<your-client-secret>"
40155
```
41156

42-
---
43-
44-
## 4. Local Testing with Kind
157+
### Deploying to Kind
45158

46-
### Step 1: Create a Kind Cluster
159+
#### Step 1: Create a Kind Cluster
47160
```bash
48161
kind create cluster --name sam-test
49162
```
50163

51-
### Step 2: Run cloud-provider-kind
164+
#### Step 2: Run cloud-provider-kind
52165
Run it in a separate terminal:
53166
```bash
54167
cloud-provider-kind
55168
```
56169

57-
### Step 3: Load Images into Kind
170+
#### Step 3: Load Images into Kind
58171
```bash
59172
kind load docker-image sam-hub:local --name sam-test
60173
kind load docker-image sam-node:local --name sam-test
61174
```
62175

63-
### Step 4: Apply Manifests
176+
#### Step 4: Apply Manifests
64177

65178
If using the **Mock OIDC Provider**:
66179
```bash
@@ -73,7 +186,7 @@ If using **Google OIDC**:
73186
kubectl apply -f sam-hub.yaml
74187
```
75188

76-
### Step 5: Get the External IP
189+
#### Step 5: Get the External IP
77190
You can use the following command to extract the allocated IP into an environment variable:
78191

79192
```bash
@@ -82,7 +195,7 @@ HUB_IP=$(kubectl get svc sam-hub -o jsonpath='{.status.loadBalancer.ingress[0].i
82195

83196
---
84197

85-
## 5. Connecting an Agent
198+
## 3. Connecting an Agent
86199

87200
To connect a `sam-node` to the hub, you just need the hub's external IP and port.
88201

@@ -120,7 +233,7 @@ sam-node run
120233

121234
---
122235

123-
## 6. Automating Node Deployment
236+
## 4. Automating Node Deployment
124237

125238
To automate the deployment of `sam-nodes` in Kubernetes and have them fetch the JWT token automatically, you can use a standard Kubernetes `Deployment` or `StatefulSet`.
126239

@@ -213,7 +326,7 @@ sam-node run \
213326

214327
---
215328

216-
## 7. Configuring Workload Identity in Kubernetes
329+
## 5. Configuring Workload Identity in Kubernetes
217330

218331
Workload Identity allows `sam-node` pods to authenticate with the `sam-hub` using their Kubernetes ServiceAccount token, removing the need for static credentials.
219332

0 commit comments

Comments
 (0)