Skip to content

Commit 0a284bb

Browse files
authored
docs: refines ingress docs for local testing (#103)
Signed-off-by: ChrisJBurns <29541485+ChrisJBurns@users.noreply.github.com>
1 parent d164ff7 commit 0a284bb

File tree

5 files changed

+72
-44
lines changed

5 files changed

+72
-44
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@ go.work
3030

3131
.roo/
3232
thv
33+
34+
kconfig.yaml

Taskfile.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,21 @@ tasks:
5656
IMAGE:
5757
sh: ko build --platform linux/amd64 --local -B ./cmd/thv | tail -n 1
5858
cmds:
59+
# gets the local kind kubeconfig
60+
- kind get kubeconfig > kconfig.yaml
5961
# Load the image into kind
6062
- echo "Loading image {{.IMAGE}} into kind..."
6163
- kind load docker-image {{.IMAGE}}
6264
# Apply the Kubernetes manifest
6365
- echo "Applying Kubernetes manifest..."
64-
- kubectl apply -f <(KO_DOCKER_REPO=kind.local ko resolve --platform linux/amd64 -f deploy/k8s/thv.yml)
65-
# Wait for the deployment to be available
66+
- kubectl apply -f <(KO_DOCKER_REPO=kind.local ko resolve --platform linux/amd64 -f deploy/k8s/thv.yaml) --kubeconfig kconfig.yaml
67+
# Create RoleBinding for ToolHive until (TODO: https://github.com/StacklokLabs/toolhive/issues/102) is done
68+
- kubectl create clusterrolebinding default-view --clusterrole=cluster-admin --serviceaccount=default:default --kubeconfig kconfig.yaml
69+
- echo "Applying Kubernetes Ingress manifest..."
70+
- kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/deploy-ingress-nginx.yaml --kubeconfig kconfig.yaml
71+
# we want to wait until the nginx controlle is ready before we apply our ingress object
72+
- kubectl wait --namespace=ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/component=controller --timeout=120s --kubeconfig kconfig.yaml
73+
- kubectl apply -f deploy/k8s/ingress.yaml --kubeconfig kconfig.yaml
74+
# We do the below commands because of some inconsistency between the secret and webhook caBundle. ref: https://github.com/kubernetes/ingress-nginx/issues/5968#issuecomment-849772666
75+
- CA=$(kubectl -n ingress-nginx get secret ingress-nginx-admission -ojsonpath='{.data.ca}' --kubeconfig kconfig.yaml)
76+
- kubectl patch validatingwebhookconfigurations ingress-nginx-admission --type='json' --patch='[{"op":"add","path":"/webhooks/0/clientConfig/caBundle","value":"'$CA'"}]' --kubeconfig kconfig.yaml

deploy/k8s/ingress.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
apiVersion: networking.k8s.io/v1
3+
kind: Ingress
4+
metadata:
5+
name: example-ingress
6+
spec:
7+
ingressClassName: nginx
8+
rules:
9+
- http:
10+
paths:
11+
- pathType: Prefix
12+
path: /sse
13+
backend:
14+
service:
15+
name: toolhive
16+
port:
17+
number: 8080
18+
- pathType: Prefix
19+
path: /messages
20+
backend:
21+
service:
22+
name: toolhive
23+
port:
24+
number: 8080

deploy/k8s/thv.yml renamed to deploy/k8s/thv.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ spec:
2222
- name: toolhive
2323
image: ko://github.com/stacklok/toolhive/cmd/thv
2424
args: ["run", "--foreground=true", "--port=8080", "--name=mcp-fetch", "docker.io/mcp/fetch"]
25+
env:
26+
- name: UNSTRUCTURED_LOGS
27+
value: "false"
2528
resources:
2629
limits:
2730
cpu: "100m"

docs/ingress.md

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,40 @@
22

33
> Disclaimer: ChrisB to refine when back home.
44
5-
Prereqs:
6-
- have a local kind cluster running and working, and running an MCP server with the proxy workload fronting it
5+
Prerequisites:
6+
- Have a local Kind Cluster running
7+
- Have an MCP server with the proxy workload fronting it (this can be achieved by running the `test-k8s-apply` Taskfile task. `task test-k8s-apply`)
78

8-
Run the local Kind Go binary that acts as a small LoadBalancer that gives IPs to ingress controllers inside of the cluster. This mimicks the behaviour of Cloud LBs
9+
There should now be a local Kind cluster with an MCP server running and a ToolHive proxy running, in addition to an Nginx Ingress controller running and pending an ExternalIP.
10+
11+
To give the ingress controller an IP, we will run a local Kind Go binary that acts as a small LoadBalancer that gives IPs to ingress controllers inside of the Kind Cluster. This binary mimicks Cloud Providers LoadBalancers functionality for local Kind setups.
912

1013
```
1114
go install sigs.k8s.io/cloud-provider-kind@latest
1215
sudo ~/go/bin/cloud-provider-kind
1316
```
1417

15-
Install the Nginx controller
16-
```
17-
kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/deploy-ingress-nginx.yaml
18-
```
19-
20-
When the ingress controller is running, you should have an external IP set for it. Take not of this IP.
21-
22-
Add the following Ingress yaml that points to your toolhive service:
23-
```yaml
24-
---
25-
apiVersion: networking.k8s.io/v1
26-
kind: Ingress
27-
metadata:
28-
name: example-ingress
29-
spec:
30-
ingressClassName: nginx
31-
rules:
32-
- http:
33-
paths:
34-
- pathType: Prefix
35-
path: /sse
36-
backend:
37-
service:
38-
name: toolhive
39-
port:
40-
number: 8080
41-
- pathType: Prefix
42-
path: /messages
43-
backend:
44-
service:
45-
name: toolhive
46-
port:
47-
number: 8080
48-
```
49-
50-
Now, you _should_ be able to curl the endpoint via `curl http://$EXTERNAL_IP/sse` and see a connection.
51-
52-
## Chris To Do
53-
- adds the docs for the addition of a host name to make it look more ingressy, this avoids the IP requirement.g
18+
After a few moments, the ingress controller should be running and the service should have an external IP set for it. Run the below to get the IP and store it in a variable, and then curl the MCP server endpoint to see a connection.
19+
20+
```
21+
$ LB_IP=$(kubectl get svc/ingress-nginx-controller -n ingress-nginx -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
22+
$ curl $LB_IP/sse
23+
event: endpoint
24+
data: http://172.20.0.3/messages?session_id=637d766e-354a-45b6-bc91-e153a35bc49f
25+
```
26+
27+
## Ingress with Local Hostname
28+
29+
In order to avoid using of the IP you can use a hostname instead of preferred. This can be achieved by modifying the `/etc/hosts` file to include a mapping for the load balancer IP to a friendly hostname.
30+
31+
```
32+
sudo sh -c "echo '$LB_IP mcp-server.dev' >> /etc/hosts"
33+
```
34+
35+
Now when you curl that endpoint, it should connect as it did with the IP
36+
37+
```
38+
$ curl mcp-server.dev/sse
39+
event: endpoint
40+
data: http://mcp-server.dev/messages?session_id=337e4d34-5fb0-4ccc-9959-fc382d5b4800
41+
```

0 commit comments

Comments
 (0)