Skip to content

Commit b9c7047

Browse files
ilackarmsjmhbhEItanya
authored
add Helm chart (#2)
**Testing steps** - Download the `kmcp` cli to easily spin up a new mcp server. - Add kmcp binary location to your path `export PATH="<path_to_kmcp_bin>:$PATH"` - Run the following script in the root directory of the repository to test out the published helm chart and controller image alongside an mcp server with the echo tool. Assumes you have npx installed and your docker config is located at `~/.docker/config.json`. (demo script still wip) [kmcp.zip](https://github.com/user-attachments/files/21324828/kmcp.zip) --------- Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io> Co-authored-by: JM Huibonhoa <jm.huibonhoa@solo.io> Co-authored-by: Eitan Yarmush <eitan.yarmush@solo.io>
1 parent 14a2829 commit b9c7047

58 files changed

Lines changed: 3430 additions & 989 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/lint.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ name: Lint
22

33
on:
44
push:
5+
branches: [main]
56
pull_request:
7+
branches: [main]
68

79
jobs:
810
lint:

.github/workflows/tag.yaml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
name: Tag and Push
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*.*.*"
7+
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: 'Version number'
11+
12+
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#release
13+
# GITHUB_SHA = Last commit in the tagged release
14+
# GITHUB_REF = Tag ref of release refs/tags/<tag_name>
15+
jobs:
16+
push-images:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: read
20+
packages: write
21+
steps:
22+
- name: 'Checkout GitHub Action'
23+
uses: actions/checkout@main
24+
25+
- name: Login to GitHub Container Registry
26+
uses: docker/login-action@v3
27+
with:
28+
registry: ghcr.io
29+
username: ${{ github.actor }}
30+
password: ${{ secrets.GITHUB_TOKEN }}
31+
32+
- name: Set up QEMU
33+
uses: docker/setup-qemu-action@v3
34+
- name: Set up Docker Buildx
35+
uses: docker/setup-buildx-action@v3
36+
with:
37+
name: kmcp-builder-v0.23.0
38+
platforms: linux/amd64,linux/arm64
39+
version: v0.23.0
40+
use: 'true'
41+
- name: 'Build Images'
42+
env:
43+
DOCKER_BUILDER: "docker buildx"
44+
DOCKER_BUILD_ARGS: "--push --platform linux/amd64,linux/arm64"
45+
run: |
46+
# if workflow_dispatch is used, use the version input
47+
if [ -n "${{ github.event.inputs.version }}" ]; then
48+
export VERSION=${{ github.event.inputs.version }}
49+
else
50+
export VERSION=$(echo "$GITHUB_REF" | cut -c12-)
51+
fi
52+
echo "Building Docker image with version: ${VERSION}"
53+
make docker-build VERSION=${VERSION}
54+
push-helm-chart:
55+
needs:
56+
- push-images
57+
runs-on: ubuntu-latest
58+
permissions:
59+
contents: read
60+
packages: write
61+
steps:
62+
- name: 'Checkout GitHub Action'
63+
uses: actions/checkout@main
64+
65+
- name: Login to GitHub Container Registry
66+
uses: docker/login-action@v3
67+
with:
68+
registry: ghcr.io
69+
username: ${{ github.actor }}
70+
password: ${{ secrets.GITHUB_TOKEN }}
71+
72+
- name: 'Build and Publish Helm Chart'
73+
run: |
74+
# if workflow_dispatch is used, use the version input
75+
if [ -n "${{ github.event.inputs.version }}" ]; then
76+
export VERSION=${{ github.event.inputs.version }}
77+
else
78+
export VERSION=$(echo "$GITHUB_REF" | cut -c12-)
79+
fi
80+
echo "Publishing Helm chart with version: ${VERSION}"
81+
make helm-publish VERSION=${VERSION}
82+
release:
83+
# Only run release after images and helm chart are pushed
84+
# In the future we can take the chart from the helm action,
85+
# and build the CLI beforehand.
86+
needs:
87+
- push-helm-chart
88+
runs-on: ubuntu-latest
89+
permissions:
90+
contents: write
91+
steps:
92+
- name: Checkout
93+
uses: actions/checkout@v4
94+
- name: Build
95+
run: |
96+
# if workflow_dispatch is used, use the version input
97+
if [ -n "${{ github.event.inputs.version }}" ]; then
98+
export VERSION=${{ github.event.inputs.version }}
99+
else
100+
export VERSION=$(echo "$GITHUB_REF" | cut -c12-)
101+
fi
102+
echo "Building release artifacts with version: ${VERSION}"
103+
make build VERSION=${VERSION}
104+
make helm-package VERSION=${VERSION}
105+
- name: Release
106+
uses: softprops/action-gh-release@v2
107+
if: startsWith(github.ref, 'refs/tags/')
108+
# TODO: Add kmcp binary to the release
109+
with:
110+
files: |
111+
dist/kmcp-*.tgz
112+

.github/workflows/test-e2e.yml

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ name: E2E Tests
22

33
on:
44
push:
5+
branches: [main]
56
pull_request:
7+
branches: [main]
68

79
jobs:
810
test-e2e:
@@ -17,19 +19,10 @@ jobs:
1719
with:
1820
go-version-file: go.mod
1921

20-
- name: Install the latest version of kind
21-
run: |
22-
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
23-
chmod +x ./kind
24-
sudo mv ./kind /usr/local/bin/kind
25-
26-
- name: Verify kind installation
27-
run: kind version
28-
29-
- name: Create kind cluster
30-
run: kind create cluster
31-
22+
- name: Create k8s Kind Cluster
23+
uses: helm/kind-action@v1
3224
- name: Running Test e2e
3325
run: |
26+
kind create cluster
3427
go mod tidy
3528
make test-e2e

.github/workflows/test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ name: Tests
22

33
on:
44
push:
5+
branches: [main]
56
pull_request:
7+
branches: [main]
68

79
jobs:
810
test:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ go.work
2525
*.swp
2626
*.swo
2727
*~
28+
# helm
29+
dist/

Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build the manager binary
2-
FROM docker.io/golang:1.24 AS builder
2+
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.24 AS builder
33
ARG TARGETOS
44
ARG TARGETARCH
55

@@ -31,4 +31,9 @@ WORKDIR /
3131
COPY --from=builder /workspace/manager .
3232
USER 65532:65532
3333

34+
35+
LABEL org.opencontainers.image.source=https://github.com/kagent-dev/kmcp
36+
LABEL org.opencontainers.image.description="KMCP is the Kubernetes MCP Server Controller."
37+
LABEL org.opencontainers.image.authors="KAgent Creators 🤖"
38+
3439
ENTRYPOINT ["/manager"]

Makefile

Lines changed: 80 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
1-
# Image URL to use all building/pushing image targets
2-
IMG ?= controller:latest
1+
2+
# Image configuration
3+
DOCKER_REGISTRY ?= ghcr.io
4+
BASE_IMAGE_REGISTRY ?= cgr.dev
5+
DOCKER_REPO ?= kagent-dev/kmcp
6+
HELM_REPO ?= oci://ghcr.io/kagent-dev
7+
HELM_DIST_FOLDER ?= dist
8+
9+
BUILD_DATE := $(shell date -u '+%Y-%m-%d')
10+
GIT_COMMIT := $(shell git rev-parse --short HEAD || echo "unknown")
11+
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null | sed 's/-dirty//' | grep v || echo "v0.0.1+$(GIT_COMMIT)")
12+
13+
# Local architecture detection to build for the current platform
14+
LOCALARCH ?= $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
15+
16+
# Docker buildx configuration
17+
BUILDKIT_VERSION = v0.23.0
18+
BUILDX_NO_DEFAULT_ATTESTATIONS=1
19+
BUILDX_BUILDER_NAME ?= kmcp-builder-$(BUILDKIT_VERSION)
20+
DOCKER_BUILDER ?= docker buildx
21+
DOCKER_BUILD_ARGS ?= --builder $(BUILDX_BUILDER_NAME) --pull --load --platform linux/$(LOCALARCH)
22+
23+
# Image configuration
24+
CONTROLLER_IMAGE_NAME ?= controller
25+
CONTROLLER_IMAGE_TAG ?= $(VERSION)
26+
CONTROLLER_IMG ?= $(DOCKER_REGISTRY)/$(DOCKER_REPO)/$(CONTROLLER_IMAGE_NAME):$(CONTROLLER_IMAGE_TAG)
27+
28+
# Image URL to use all building/pushing image targets (backward compatibility)
29+
IMG ?= $(CONTROLLER_IMG)
30+
DIST_FOLDER ?= dist
331

432
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
533
ifeq (,$(shell go env GOBIN))
@@ -8,12 +36,6 @@ else
836
GOBIN=$(shell go env GOBIN)
937
endif
1038

11-
# CONTAINER_TOOL defines the container tool to be used for building images.
12-
# Be aware that the target commands are only tested with Docker which is
13-
# scaffolded by default. However, you might want to replace it to use other
14-
# tools. (i.e. podman)
15-
CONTAINER_TOOL ?= docker
16-
1739
# Setting SHELL to bash allows bash commands to be executed by recipes.
1840
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
1941
SHELL = /usr/bin/env bash -o pipefail
@@ -45,6 +67,51 @@ help: ## Display this help.
4567
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
4668
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
4769

70+
.PHONY: helm-lint
71+
helm-lint:
72+
helm lint helm/kmcp
73+
74+
.PHONY: helm-package
75+
helm-package:
76+
mkdir -p $(DIST_FOLDER)
77+
@echo "Packaging Helm chart with version $(VERSION)..."
78+
@cp helm/kmcp/Chart.yaml helm/kmcp/Chart.yaml.bak
79+
@sed "s/^version: .*/version: $(VERSION)/" helm/kmcp/Chart.yaml.bak > helm/kmcp/Chart.yaml
80+
@helm package helm/kmcp --version $(VERSION) -d $(DIST_FOLDER)
81+
@mv helm/kmcp/Chart.yaml.bak helm/kmcp/Chart.yaml
82+
83+
.PHONY: helm-cleanup
84+
helm-cleanup: ## Clean up Helm chart packages
85+
rm -f $(DIST_FOLDER)/*.tgz
86+
87+
.PHONY: helm-build
88+
helm-build: helm-lint helm-package ## Build and package the Helm chart
89+
@echo "Helm chart built successfully"
90+
91+
.PHONY: helm-publish
92+
helm-publish: helm-package ## Publish Helm chart to OCI registry
93+
@echo "Publishing Helm chart to $(HELM_REPO)/kmcp/helm..."
94+
@helm push $(HELM_DIST_FOLDER)/kmcp-$(VERSION).tgz $(HELM_REPO)/kmcp/helm
95+
@echo "Helm chart published successfully"
96+
97+
.PHONY: helm-test
98+
helm-test:
99+
@echo "Running Helm chart unit tests..."
100+
@command -v helm >/dev/null 2>&1 || { \
101+
echo "Helm is not installed. Please install Helm manually."; \
102+
exit 1; \
103+
}
104+
@helm plugin list | grep -q 'unittest' || { \
105+
echo "Installing helm-unittest plugin..."; \
106+
helm plugin install https://github.com/quintush/helm-unittest; \
107+
}
108+
@helm unittest helm/kmcp
109+
@echo "Helm chart unit tests completed successfully"
110+
111+
.PHONY: manifests-all
112+
manifests-all: manifests ## Generate Kustomize from source definitions.
113+
@echo "All manifests (Kustomize and Helm) updated successfully"
114+
48115
.PHONY: generate
49116
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
50117
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
@@ -105,57 +172,15 @@ run: manifests generate fmt vet ## Run a controller from your host.
105172
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
106173
.PHONY: docker-build
107174
docker-build: ## Build docker image with the manager.
108-
$(CONTAINER_TOOL) build -t ${IMG} .
175+
- $(DOCKER_BUILDER) create --name $(BUILDX_BUILDER_NAME)
176+
$(DOCKER_BUILDER) use $(BUILDX_BUILDER_NAME)
177+
$(DOCKER_BUILDER) build $(DOCKER_BUILD_ARGS) -t ${CONTROLLER_IMG} .
178+
- $(DOCKER_BUILDER) rm $(BUILDX_BUILDER_NAME)
109179

110180
.PHONY: docker-push
111181
docker-push: ## Push docker image with the manager.
112-
$(CONTAINER_TOOL) push ${IMG}
113-
114-
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
115-
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
116-
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
117-
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
118-
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
119-
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
120-
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
121-
.PHONY: docker-buildx
122-
docker-buildx: ## Build and push docker image for the manager for cross-platform support
123-
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
124-
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
125-
- $(CONTAINER_TOOL) buildx create --name kmcp-builder
126-
$(CONTAINER_TOOL) buildx use kmcp-builder
127-
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
128-
- $(CONTAINER_TOOL) buildx rm kmcp-builder
129-
rm Dockerfile.cross
130-
131-
.PHONY: build-installer
132-
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
133-
mkdir -p dist
134-
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
135-
$(KUSTOMIZE) build config/default > dist/install.yaml
136-
137-
##@ Deployment
138-
139-
ifndef ignore-not-found
140-
ignore-not-found = false
141-
endif
142-
143-
.PHONY: install
144-
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
145-
$(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f -
146-
147-
.PHONY: uninstall
148-
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
149-
$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
150-
151-
.PHONY: deploy
152-
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
153-
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
154-
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -
182+
$(DOCKER_BUILDER) push ${CONTROLLER_IMG}
155183

156-
.PHONY: undeploy
157-
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
158-
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
159184

160185
##@ Dependencies
161186

@@ -180,10 +205,6 @@ ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller
180205
ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')
181206
GOLANGCI_LINT_VERSION ?= v1.63.4
182207

183-
.PHONY: kustomize
184-
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
185-
$(KUSTOMIZE): $(LOCALBIN)
186-
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
187208

188209
.PHONY: controller-gen
189210
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.

config/crd/bases/kagent.dev_mcpservers.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ spec:
7171
description: HTTPTransport defines the configuration for a Streamable
7272
HTTP transport.
7373
properties:
74+
path:
75+
description: the target path where MCP is served
76+
type: string
7477
targetPort:
7578
description: target port is the HTTP port that serves the MCP
7679
server.over HTTP

config/crd/kustomization.yaml

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)