diff --git a/Makefile b/Makefile index 6863d2e..9360f80 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,12 @@ NPM_VERSION ?= $(shell echo $(shell git describe --tags --always) | sed 's/^v//' OSES = darwin linux windows ARCHS = amd64 arm64 +CONTAINER_ENGINE ?= podman +CONTAINER_REGISTRY ?= quay.io +CONTAINER_REPO ?= foo/kubernetes-mcp-server +CONTAINER_TAG ?= latest +CONTAINER_IMAGE := $(CONTAINER_REGISTRY)/$(CONTAINER_REPO):$(CONTAINER_TAG) + CLEAN_TARGETS := CLEAN_TARGETS += '$(BINARY_NAME)' CLEAN_TARGETS += $(foreach os,$(OSES),$(foreach arch,$(ARCHS),$(BINARY_NAME)-$(os)-$(arch)$(if $(findstring windows,$(os)),.exe,))) @@ -43,6 +49,8 @@ help: ## Display this help clean: ## Clean up all build artifacts rm -rf $(CLEAN_TARGETS) +##@ Build Targets + .PHONY: build build: clean tidy format ## Build the project go build $(COMMON_BUILD_ARGS) -o $(BINARY_NAME) ./cmd/kubernetes-mcp-server @@ -54,6 +62,19 @@ build-all-platforms: clean tidy format ## Build the project for all platforms GOOS=$(os) GOARCH=$(arch) go build $(COMMON_BUILD_ARGS) -o $(BINARY_NAME)-$(os)-$(arch)$(if $(findstring windows,$(os)),.exe,) ./cmd/kubernetes-mcp-server; \ )) +.PHONY: image-build +image-build: + $(CONTAINER_ENGINE) build -t $(CONTAINER_IMAGE) . + +.PHONY: image-push +image-push: + $(CONTAINER_ENGINE) push $(CONTAINER_IMAGE) + +.PHONY: image +image: image-build image-push + +##@ NPM Targets + .PHONY: npm-copy-binaries npm-copy-binaries: build-all-platforms ## Copy the binaries to each npm package $(foreach os,$(OSES),$(foreach arch,$(ARCHS), \ @@ -79,6 +100,8 @@ npm-publish: npm-copy-binaries ## Publish the npm packages jq '.optionalDependencies |= with_entries(.value = "$(NPM_VERSION)")' ./npm/kubernetes-mcp-server/package.json > tmp.json && mv tmp.json ./npm/kubernetes-mcp-server/package.json; \ cd npm/kubernetes-mcp-server && npm publish +##@ Python Targets + .PHONY: python-publish python-publish: ## Publish the python packages cd ./python && \ @@ -86,6 +109,15 @@ python-publish: ## Publish the python packages uv build && \ uv publish +##@ Deployment Targets + +.PHONY: kube-deploy +kube-deploy: + @echo "Deploying $(CONTAINER_IMAGE) to Kubernetes..." + IMAGE_TO_DEPLOY="$(CONTAINER_IMAGE)" envsubst '$$IMAGE_TO_DEPLOY' < deploy/kubernetes/deploy.yaml | kubectl apply -f - + +##@ Utility Targets + .PHONY: test test: ## Run the tests go test -count=1 -v ./... diff --git a/README.md b/README.md index 93364ae..6c74460 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,9 @@ extensions: ``` +### Native Kubernetes Application +[Deploy in Kubernetes.](./deploy/kubernetes/README.md) + ## 🎥 Demos ### Diagnosing and automatically fixing an OpenShift Deployment @@ -156,7 +159,7 @@ uvx kubernetes-mcp-server@latest --help ### Configuration Options | Option | Description | -|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--sse-port` | Starts the MCP server in Server-Sent Event (SSE) mode and listens on the specified port. | | `--log-level` | Sets the logging level (values [from 0-9](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md)). Similar to [kubectl logging levels](https://kubernetes.io/docs/reference/kubectl/quick-reference/#kubectl-output-verbosity-and-debugging). | | `--kubeconfig` | Path to the Kubernetes configuration file. If not provided, it will try to resolve the configuration (in-cluster, default location, etc.). | diff --git a/deploy/kubernetes/README.md b/deploy/kubernetes/README.md new file mode 100644 index 0000000..8fb59bf --- /dev/null +++ b/deploy/kubernetes/README.md @@ -0,0 +1,90 @@ +# Kubernetes MCP Server Deployment + +This guide explains how to deploy the "Kubernetes MCP Server" to a Kubernetes cluster. + +## Prerequisites + +1. **`envsubst`:** A utility for substituting environment variables in shell-format strings. + * Verify with: `envsubst --version` + + +## Deployment Steps + +1. **Navigate to the Project Directory:** + Open your terminal and change to the root directory of this project where the `Makefile` is located. + +1. **Set the Container Image (Optional):** + The `Makefile` is designed to use a `CONTAINER_IMAGE` variable. + * **Default Image:** If not specified, it defaults to `quay.io/foo/kubernetes-mcp-server:latest`. + * **Override Image:** You can specify a different container image and tag by setting the `CONTAINER_IMAGE` variable when running `make`. + +1. **Build the Image:** +This command builds the container image and pushes it into the registry. + + ```bash + make image + ``` + +1. **Deploy to Kubernetes:** + Run the following command: + ```bash + make kube-deploy + ``` + Or, if overriding the image: + ```bash + make kube-deploy CONTAINER_IMAGE=your-registry/your-image-name:your-tag + ``` + +## Verifying the Deployment + +Once the deployment is complete, you can verify that the application is running: + +1. **Check Pods:** + The application runs in the `mcp-system` namespace. + ```bash + kubectl get pods -n mcp-system + ``` + You should see a pod with a name like `kubernetes-mcp-server-xxxxxxxxxx-xxxxx` in a `Running` state. + +2. **Check Service:** + ```bash + kubectl get svc -n mcp-system + ``` + You should see the `kubernetes-mcp-server` service listed. + +3. **View Logs:** + ```bash + kubectl logs -n mcp-system -l app=kubernetes-mcp-server -f + ``` + +## Accessing the Application + +The `kubernetes-mcp-server` service is typically exposed within the cluster. To access it from your local machine, you can use `kubectl port-forward`. + +**Port Forwarding:** + +1. Open a new terminal window. +2. Run the following command to forward a local port (e.g., 8081) to the service's port (8080): + ```bash + kubectl port-forward svc/kubernetes-mcp-server -n mcp-system 8081:8080 + ``` + * `8081:8080`: Maps local port `8081` to the service's target port `8080`. + + Keep this terminal window open. While `kubectl port-forward` is running, your server will be accessible on `http://localhost:8081`. + + +## Goose SSE Configuration + +If you are using [Goose](https://block.github.io/goose/) to connect to Server-Sent Events (SSE) provided by the `kubernetes-mcp-server`, you can configure it as follows. + +```yaml +extensions: + kubernetes-remote: + description: null + enabled: true + envs: {} + name: kubernetes-remote + timeout: 200 # Timeout in seconds for the SSE connection + type: sse + uri: http://localhost:8081/sse # Points to the local port forwarded to the k8s service +``` \ No newline at end of file diff --git a/deploy/kubernetes/deploy.yaml b/deploy/kubernetes/deploy.yaml new file mode 100644 index 0000000..f0c26fc --- /dev/null +++ b/deploy/kubernetes/deploy.yaml @@ -0,0 +1,68 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: mcp-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kubernetes-mcp-server + namespace: mcp-system +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: kubernetes-mcp-server + namespace: mcp-system +subjects: + - kind: ServiceAccount + name: kubernetes-mcp-server + namespace: mcp-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: edit +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: kubernetes-mcp-server + namespace: mcp-system + labels: + app: kubernetes-mcp-server +spec: + selector: + matchLabels: + app: kubernetes-mcp-server + replicas: 1 + template: + metadata: + labels: + app: kubernetes-mcp-server + deployment: kubernetes-mcp-server + spec: + serviceAccountName: kubernetes-mcp-server + containers: + - name: server + image: ${IMAGE_TO_DEPLOY} + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: kubernetes-mcp-server + namespace: mcp-system + labels: + app: kubernetes-mcp-server +spec: + selector: + app: kubernetes-mcp-server + deployment: kubernetes-mcp-server + ports: + - port: 8080 + targetPort: http + protocol: TCP