Skip to content

Commit de88e80

Browse files
ilackarmsjmhbhEItanya
committed
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 9e6e92d commit de88e80

57 files changed

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

538
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
639
ifeq (,$(shell go env GOBIN))
@@ -9,12 +42,6 @@ else
942
GOBIN=$(shell go env GOBIN)
1043
endif
1144

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

49-
.PHONY: helm-crd
50-
helm-crd: manifests ## Generate Helm CRD template from the generated CRD definition.
51-
@echo "Generating Helm CRD template from config/crd/bases/kagent.dev_mcpservers.yaml"
52-
@mkdir -p helm/kmcp/templates/crds
53-
@echo '{{- if .Values.crd.create }}' > helm/kmcp/templates/crds/mcpserver-crd.yaml
54-
@awk '/^ name: mcpservers.kagent.dev$$/ { \
55-
print; \
56-
print " labels:"; \
57-
print " {{- include \"kmcp.labels\" . | nindent 4 }}"; \
58-
next; \
59-
} \
60-
{ print }' config/crd/bases/kagent.dev_mcpservers.yaml >> helm/kmcp/templates/crds/mcpserver-crd.yaml
61-
@echo '{{- end }}' >> helm/kmcp/templates/crds/mcpserver-crd.yaml
62-
@echo "Helm CRD template generated at helm/kmcp/templates/crds/mcpserver-crd.yaml"
63-
64-
.PHONY: helm-templates
65-
helm-templates: helm-crd ## Generate all Helm templates from source definitions.
66-
@echo "All Helm templates updated successfully"
76+
.PHONY: helm-lint
77+
helm-lint:
78+
helm lint helm/kmcp
79+
80+
.PHONY: helm-package
81+
helm-package:
82+
mkdir -p $(DIST_FOLDER)
83+
@echo "Packaging Helm chart with version $(VERSION)..."
84+
@cp helm/kmcp/Chart.yaml helm/kmcp/Chart.yaml.bak
85+
@sed "s/^version: .*/version: $(VERSION)/" helm/kmcp/Chart.yaml.bak > helm/kmcp/Chart.yaml
86+
@helm package helm/kmcp --version $(VERSION) -d $(DIST_FOLDER)
87+
@mv helm/kmcp/Chart.yaml.bak helm/kmcp/Chart.yaml
88+
89+
.PHONY: helm-cleanup
90+
helm-cleanup: ## Clean up Helm chart packages
91+
rm -f $(DIST_FOLDER)/*.tgz
92+
93+
.PHONY: helm-build
94+
helm-build: helm-lint helm-package ## Build and package the Helm chart
95+
@echo "Helm chart built successfully"
96+
97+
.PHONY: helm-publish
98+
helm-publish: helm-package ## Publish Helm chart to OCI registry
99+
@echo "Publishing Helm chart to $(HELM_REPO)/kmcp/helm..."
100+
@helm push $(HELM_DIST_FOLDER)/kmcp-$(VERSION).tgz $(HELM_REPO)/kmcp/helm
101+
@echo "Helm chart published successfully"
102+
103+
.PHONY: helm-test
104+
helm-test:
105+
@echo "Running Helm chart unit tests..."
106+
@command -v helm >/dev/null 2>&1 || { \
107+
echo "Helm is not installed. Please install Helm manually."; \
108+
exit 1; \
109+
}
110+
@helm plugin list | grep -q 'unittest' || { \
111+
echo "Installing helm-unittest plugin..."; \
112+
helm plugin install https://github.com/quintush/helm-unittest; \
113+
}
114+
@helm unittest helm/kmcp
115+
@echo "Helm chart unit tests completed successfully"
67116

68117
.PHONY: manifests-all
69-
manifests-all: manifests helm-templates ## Generate both Kustomize and Helm manifests from source definitions.
118+
manifests-all: manifests ## Generate Kustomize from source definitions.
70119
@echo "All manifests (Kustomize and Helm) updated successfully"
71120

72121
.PHONY: generate
@@ -133,61 +182,19 @@ run: manifests generate fmt vet ## Run a controller from your host.
133182
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
134183
.PHONY: docker-build
135184
docker-build: ## Build docker image with the manager.
136-
$(CONTAINER_TOOL) build -t ${IMG} .
185+
- $(DOCKER_BUILDER) create --name $(BUILDX_BUILDER_NAME)
186+
$(DOCKER_BUILDER) use $(BUILDX_BUILDER_NAME)
187+
$(DOCKER_BUILDER) build $(DOCKER_BUILD_ARGS) -t ${CONTROLLER_IMG} .
188+
- $(DOCKER_BUILDER) rm $(BUILDX_BUILDER_NAME)
137189

138190
.PHONY: kind-load-images
139191
kind-load-images: ## Load images into Kind cluster. Defaults to current kind cluster.
140192
kind load docker-image ${IMG} $(ADDITIONAL_IMAGES)
141193

142194
.PHONY: docker-push
143195
docker-push: ## Push docker image with the manager.
144-
$(CONTAINER_TOOL) push ${IMG}
145-
146-
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
147-
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
148-
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
149-
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
150-
# - 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)
151-
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
152-
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
153-
.PHONY: docker-buildx
154-
docker-buildx: ## Build and push docker image for the manager for cross-platform support
155-
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
156-
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
157-
- $(CONTAINER_TOOL) buildx create --name kmcp-builder
158-
$(CONTAINER_TOOL) buildx use kmcp-builder
159-
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
160-
- $(CONTAINER_TOOL) buildx rm kmcp-builder
161-
rm Dockerfile.cross
162-
163-
.PHONY: build-installer
164-
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
165-
mkdir -p dist
166-
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
167-
$(KUSTOMIZE) build config/default > dist/install.yaml
168-
169-
##@ Deployment
170-
171-
ifndef ignore-not-found
172-
ignore-not-found = false
173-
endif
174-
175-
.PHONY: install
176-
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
177-
$(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f -
178-
179-
.PHONY: uninstall
180-
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.
181-
$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
182-
183-
.PHONY: deploy
184-
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
185-
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
186-
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -
196+
$(DOCKER_BUILDER) push ${CONTROLLER_IMG}
187197

188-
.PHONY: undeploy
189-
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.
190-
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
191198

192199
##@ Dependencies
193200

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

215-
.PHONY: kustomize
216-
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
217-
$(KUSTOMIZE): $(LOCALBIN)
218-
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
219222

220223
.PHONY: controller-gen
221224
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.

0 commit comments

Comments
 (0)