这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions .github/workflows/go-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
name: Go CI

on:
push:
branches: [ "main" ]
paths:
- "kubechain/**"
- ".github/workflows/go-ci.yml"
pull_request:
branches: [ "main" ]
paths:
- "kubechain/**"
- ".github/workflows/go-ci.yml"

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
cache: true
cache-dependency-path: kubechain/go.sum

- name: Cache kubechain tools
uses: actions/cache@v4
with:
path: kubechain/bin
key: ${{ runner.os }}-kubechain-bin-${{ hashFiles('kubechain/Makefile') }}

- name: Install golangci-lint
working-directory: kubechain
run: make golangci-lint

- name: Check formatting
working-directory: kubechain
run: |
make fmt
if [[ -n $(git diff) ]]; then
echo "::error::Code is not properly formatted. Run 'make fmt' locally."
git diff
exit 1
fi

- name: Run linter
working-directory: kubechain
run: make lint

test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
cache: true
cache-dependency-path: kubechain/go.sum

- name: Cache kubechain tools
uses: actions/cache@v4
with:
path: kubechain/bin
key: ${{ runner.os }}-kubechain-bin-${{ hashFiles('kubechain/Makefile') }}

- name: Run tests
working-directory: kubechain
run: make test

- name: Upload test coverage
uses: actions/upload-artifact@v4
with:
name: test-coverage
path: kubechain/cover.out
retention-days: 7

build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
cache: true
cache-dependency-path: kubechain/go.sum

- name: Cache kubechain tools
uses: actions/cache@v4
with:
path: kubechain/bin
key: ${{ runner.os }}-kubechain-bin-${{ hashFiles('kubechain/Makefile') }}

- name: Build
working-directory: kubechain
run: make build

# E2E tests are temporarily disabled due to configuration issues
#
# Issues encountered:
# 1. The e2e test suite has a hardcoded image name "example.com/kubechain:v0.0.1" in e2e_suite_test.go
# 2. The test expects controller-manager pods to be created in the kubechain-system namespace
# 3. Attempts to fix:
# - Setting KIND_CLUSTER environment variable to match the KinD cluster name
# - Modifying the Makefile to check for the correct cluster name
# - Trying to use the same image name that's hardcoded in the tests
# 4. The controller-manager pods never get created successfully during CI
#
# TODO:
# - Fix the e2e test configuration to work properly in CI
# - Consider making the test image name configurable instead of hardcoded
# - Debug why the controller-manager pods aren't being created/started correctly
#
# e2e-test:
# name: E2E Tests
# runs-on: ubuntu-latest
# needs: [build]
# steps:
# - name: Checkout repository
# uses: actions/checkout@v4
#
# - name: Set up Go
# uses: actions/setup-go@v5
# with:
# go-version: '1.24'
# cache: true
# cache-dependency-path: kubechain/go.sum
#
# - name: Setup KinD
# uses: helm/kind-action@v1.9.0
# with:
# cluster_name: kubechain-example-cluster
# config: kubechain-example/kind/kind-config.yaml
#
# - name: Set timestamp
# id: timestamp
# run: echo "TIMESTAMP=$(date +%Y%m%d%H%M)" >> $GITHUB_ENV
#
# - name: Fix test-e2e check for cluster
# working-directory: kubechain
# run: |
# # Temporarily modify the Makefile to check for kubechain-example-cluster instead of 'kind'
# sed -i 's/@kind get clusters | grep -q '"'"'kind'"'"'/@kind get clusters | grep -q '"'"'kubechain-example-cluster'"'"'/' Makefile
#
# - name: Build and load controller image
# working-directory: kubechain
# env:
# IMG: controller:${{ env.TIMESTAMP }}
# run: make docker-build && kind load docker-image controller:${{ env.TIMESTAMP }} --name kubechain-example-cluster
#
# - name: Run e2e tests
# working-directory: kubechain
# env:
# KIND_CLUSTER: kubechain-example-cluster
# IMG: controller:${{ env.TIMESTAMP }}
# run: make test-e2e

docker:
name: Docker Build
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [lint, test, build]
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
working-directory: kubechain
run: make docker-build
28 changes: 25 additions & 3 deletions kubechain/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,33 @@ RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot
# Install uv/uvx
FROM debian:bookworm-slim AS uv-installer
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates
ADD https://astral.sh/uv/install.sh /uv-installer.sh
RUN sh /uv-installer.sh && rm /uv-installer.sh

# Python slim image provides both Python and a minimal Debian
FROM python:3.12-slim-bookworm
WORKDIR /

# Install Node.js and NPM/NPX
RUN apt-get update && apt-get install -y --no-install-recommends \
nodejs npm \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Copy our manager binary from the builder stage
COPY --from=builder /workspace/manager .

# Copy uv/uvx from the installer stage
COPY --from=uv-installer /root/.local/bin/uv /usr/local/bin/uv
COPY --from=uv-installer /root/.local/bin/uvx /usr/local/bin/uvx

# Create non-root user to match the 65532 UID from distroless
RUN groupadd -g 65532 nonroot && \
useradd -u 65532 -g nonroot -s /bin/bash -m nonroot

USER 65532:65532

ENTRYPOINT ["/manager"]
5 changes: 4 additions & 1 deletion kubechain/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Generate timestamp once and store it
TIMESTAMP := $(shell date +%Y%m%d%H%M)

# Image URL to use all building/pushing image targets
IMG ?= controller:$(shell date +%Y%m%d%H%M)
IMG ?= controller:$(TIMESTAMP)

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand Down
69 changes: 67 additions & 2 deletions kubechain/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# kubechain
// TODO(user): Add simple overview of use/purpose

Kubechain is a Kubernetes operator for managing Large Language Model (LLM) workflows.

## Description
// TODO(user): An in-depth paragraph about your project and overview of use

Kubechain provides Custom Resource Definitions (CRDs) for defining and managing LLM-based agents, tools, and tasks within a Kubernetes cluster. It enables you to define reusable components for AI/LLM workflows, including the Model Control Protocol (MCP) integration for tool extensibility.

## Getting Started

Expand Down Expand Up @@ -117,6 +119,69 @@ is manually re-applied afterwards.

More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html)

## Documentation

- [MCP Server Guide](./docs/mcp-server.md) - Detailed guide for working with MCP servers
- [CRD Reference](./docs/crd-reference.md) - Complete reference for all Custom Resource Definitions

## Resource Types

### MCPServer

Model Control Protocol (MCP) servers provide a way to extend the functionality of LLMs with custom tools. The MCPServer resource supports:

- **Transport Types:**
- `stdio`: Communicate with an MCP server via standard I/O
- `http`: Communicate with an MCP server via HTTP

- **Environment Variables:** MCPServer resources support environment variables with:
- Direct values: `value: "some-value"`
- Secret references: `valueFrom.secretKeyRef` pointing to a Kubernetes Secret

Example with secret reference:
```yaml
apiVersion: kubechain.humanlayer.dev/v1alpha1
kind: MCPServer
metadata:
name: mcp-server-with-secret
spec:
transport: stdio
command: "/usr/local/bin/mcp-server"
env:
- name: API_KEY
valueFrom:
secretKeyRef:
name: my-secret
key: api-key
```

For full examples, see the `config/samples/` directory.

### LLM

The LLM resource defines a language model configuration, including:
- Provider information (e.g., OpenAI)
- API key references (using Kubernetes Secrets)
- Model configurations

### Agent

The Agent resource defines an LLM agent with:
- A reference to an LLM
- System prompt
- Available tools

### Tool

The Tool resource defines a capability that can be used by an Agent, such as:
- Function-based tools
- MCP-provided tools
- Human approval tools

### Task

The Task resource represents a request to an Agent, which starts a conversation.

## License

Copyright 2025.
Expand Down
18 changes: 18 additions & 0 deletions kubechain/api/v1alpha1/agent_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ type AgentSpec struct {
// +optional
Tools []LocalObjectReference `json:"tools,omitempty"`

// MCPServers is a list of MCP servers this agent can use
// +optional
MCPServers []LocalObjectReference `json:"mcpServers,omitempty"`

// System is the system prompt for the agent
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
Expand Down Expand Up @@ -43,6 +47,10 @@ type AgentStatus struct {
// ValidTools is the list of tools that were successfully validated
// +optional
ValidTools []ResolvedTool `json:"validTools,omitempty"`

// ValidMCPServers is the list of MCP servers that were successfully validated
// +optional
ValidMCPServers []ResolvedMCPServer `json:"validMCPServers,omitempty"`
}

type ResolvedTool struct {
Expand All @@ -55,6 +63,16 @@ type ResolvedTool struct {
Name string `json:"name"`
}

type ResolvedMCPServer struct {
// Name of the MCP server
// +kubebuilder:validation:Required
Name string `json:"name"`

// Tools available from this MCP server
// +optional
Tools []string `json:"tools,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Ready",type="boolean",JSONPath=".status.ready"
Expand Down
2 changes: 1 addition & 1 deletion kubechain/api/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ var (
)

func init() {
SchemeBuilder.Register(&LLM{}, &LLMList{}, &Tool{}, &ToolList{}, &Agent{}, &AgentList{}, &Task{}, &TaskList{}, &TaskRun{}, &TaskRunList{})
SchemeBuilder.Register(&LLM{}, &LLMList{}, &Tool{}, &ToolList{}, &Agent{}, &AgentList{}, &Task{}, &TaskList{}, &TaskRun{}, &TaskRunList{}, &TaskRunToolCall{}, &TaskRunToolCallList{}, &MCPServer{}, &MCPServerList{})
}
Loading