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
21 changes: 16 additions & 5 deletions deploy/helm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,20 @@ For a dev/latest install, set `operator.image.useLatest=true`, `console.image.us

After the chart is running you can create a cluster by applying a `KafscaleCluster` resource (see `config/samples/` for an example). The console service is exposed as a ClusterIP by default; enable ingress by toggling `.Values.console.ingress`.

### External Broker Access
### External Kafka Access

Broker Services are created by the operator. For external clients, configure the
`KafscaleCluster` spec to expose a LoadBalancer or NodePort and set the advertised
address/port so Kafka clients learn the reachable endpoint.
**Recommended:** enable the chart proxy (`proxy.enabled=true`) and set
`proxy.advertisedHost` to the address external clients should use. The proxy is
the single Kafka entrypoint and supports broker scaling without client
reconfiguration. For production, use `proxy.service.type=LoadBalancer`. For
local clusters (kind), pin `proxy.service.nodePort` — see
`deploy/helm/kafscale/README.md`.

See `docs/operations.md` for a full example and TLS termination guidance.
**Optional:** broker Services are created by the operator. To expose brokers
directly (bypassing the proxy), configure `KafscaleCluster` `spec.brokers.service`
and `advertisedHost` / `advertisedPort`.

See `docs/operations.md` for full examples and TLS termination guidance.

### MCP

Expand All @@ -61,6 +68,10 @@ The MCP service is optional and disabled by default. Enable it with `mcp.enabled
| `operator.etcdEndpoints` | List of etcd endpoints the operator will connect to. | `["http://etcd:2379"]` |
| `console.service.type` | Kubernetes service type for the console. | `ClusterIP` |
| `console.ingress.*` | Optional ingress configuration for exposing the console. | disabled |
| `proxy.enabled` | Deploy the Kafka-aware proxy for external client access. | `false` |
| `proxy.advertisedHost` | Address Kafka clients should connect to (public DNS or node IP). | `""` |
| `proxy.service.type` | Proxy Service type (`LoadBalancer`, `NodePort`, `ClusterIP`). | `LoadBalancer` |
| `proxy.service.nodePort` | Pin NodePort when `type=NodePort` (range `30000–32767`). | `""` |
| `mcp.enabled` | Deploy the MCP service. | `false` |
| `mcp.namespace.name` | Namespace to deploy the MCP service into. | `kafscale-mcp` |
| `mcp.ingress.*` | Optional ingress configuration for exposing the MCP service. | disabled |
Expand Down
155 changes: 52 additions & 103 deletions deploy/helm/kafscale/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ limitations under the License.

# KafScale Helm Chart

Helm chart for deploying KafScale components including the operator, console, proxy, LFS proxy, and MCP server.
Helm chart for deploying KafScale components including the operator, console,
Kafka proxy, and MCP server. LFS is configured on the `KafscaleCluster` CRD
(`spec.lfsProxy`) and deployed by the operator.

## Prerequisites

Expand Down Expand Up @@ -47,8 +49,7 @@ helm upgrade --install kafscale ./deploy/helm/kafscale \
|-----------|-------------|---------|
| **Operator** | KafScale cluster operator | Enabled |
| **Console** | Web-based management UI | Enabled |
| **Proxy** | Kafka protocol proxy | Disabled |
| **LFS Proxy** | Large File Support proxy | Disabled |
| **Proxy** | Kafka protocol proxy (recommended external entrypoint) | Disabled |
| **MCP** | Model Context Protocol server | Disabled |

## Quick Start Examples
Expand All @@ -59,32 +60,30 @@ helm upgrade --install kafscale ./deploy/helm/kafscale \
helm upgrade --install kafscale ./deploy/helm/kafscale
```

### With LFS Proxy and MinIO
### With Kafka Proxy (external access)

```bash
helm upgrade --install kafscale ./deploy/helm/kafscale \
--set lfsProxy.enabled=true \
--set lfsProxy.http.enabled=true \
--set lfsProxy.s3.bucket=kafscale \
--set lfsProxy.s3.endpoint=http://minio:9000 \
--set lfsProxy.s3.accessKey=minioadmin \
--set lfsProxy.s3.secretKey=minioadmin \
--set lfsProxy.s3.forcePathStyle=true
--set proxy.enabled=true \
--set proxy.replicaCount=2 \
--set proxy.service.type=LoadBalancer \
--set proxy.advertisedHost=kafka.example.com \
--set proxy.etcdEndpoints[0]=http://kafscale-etcd-client.kafscale.svc.cluster.local:2379
```

### LFS Demo Stack

Deploy the full LFS demo stack with browser UI:
Deploy the browser demo UI (`lfsDemos`) and enable LFS on your cluster CRD:

```bash
helm upgrade --install kafscale ./deploy/helm/kafscale \
-n kafscale-demo --create-namespace \
-f ./deploy/helm/kafscale/values-lfs-demo.yaml \
--set lfsProxy.s3.endpoint=http://minio:9000 \
--set lfsProxy.s3.accessKey=minioadmin \
--set lfsProxy.s3.secretKey=minioadmin
-f ./deploy/helm/kafscale/values-lfs-demo.yaml
```

Then apply a `KafscaleCluster` with `spec.lfsProxy.enabled=true` and S3 settings.
See the [LFS on KafscaleCluster](#lfs-on-kafscalecluster) section below.

## Values Files

| File | Description |
Expand All @@ -102,14 +101,12 @@ See [values.yaml](values.yaml) for the full list of configurable parameters.
|---------|-------------|
| `operator.*` | KafScale operator settings |
| `console.*` | Console UI settings |
| `proxy.*` | Kafka proxy settings |
| `lfsProxy.*` | LFS proxy settings |
| `lfsProxy.http.*` | HTTP API settings |
| `lfsProxy.http.cors.*` | CORS configuration |
| `lfsProxy.s3.*` | S3 storage backend |
| `lfsProxy.ingress.*` | HTTP ingress |
| `lfsDemos.*` | Demo applications |
| `proxy.*` | Kafka proxy settings (external entrypoint) |
| `lfsDemos.*` | Optional LFS browser demo UI |
| `mcp.*` | MCP server settings |
| `<component>.podSecurityContext` | Pod-level PSA `restricted` defaults (UID/GID `10001`, `runAsNonRoot`, `seccompProfile`) |
| `<component>.containerSecurityContext` | Container hardening (`readOnlyRootFilesystem`, dropped capabilities) |
| `proxy.affinity` | Pod affinity override; when empty the chart applies soft hostname anti-affinity |

### Proxy Service

Expand All @@ -136,9 +133,12 @@ proxy:
nodePort: 30092
```

## LFS Proxy
## LFS on KafscaleCluster

The LFS Proxy implements the claim-check pattern for large Kafka messages:
Large File Support (LFS) uses the claim-check pattern: blobs land in S3 and Kafka
carries a pointer. The operator deploys an LFS proxy Deployment when you enable
`spec.lfsProxy` on your `KafscaleCluster` (not via Helm `lfsProxy.*` values —
that chart surface was removed in v1.6).

```
┌─────────┐ ┌───────────┐ ┌─────────┐
Expand All @@ -153,59 +153,40 @@ The LFS Proxy implements the claim-check pattern for large Kafka messages:
└───────────┘
```

### Enable HTTP API
Example (`KafscaleCluster` fragment):

```yaml
lfsProxy:
enabled: true
http:
spec:
lfsProxy:
enabled: true
port: 8080
cors:
http:
enabled: true
allowOrigins: ["*"]
port: 8080
s3:
bucket: my-lfs-bucket
region: us-east-1
credentialsSecretRef: s3-credentials
```

### S3 Configuration

```yaml
lfsProxy:
s3:
bucket: my-lfs-bucket
region: us-east-1
endpoint: "" # Leave empty for AWS S3
existingSecret: s3-credentials # Recommended for production
```

For detailed LFS proxy documentation, see [docs/lfs-proxy/helm-deployment.md](../../../docs/lfs-proxy/helm-deployment.md).
`bucket` and `region` are required. Do not use the blocklisted default bucket
name `kafscale-lfs`.

### HTTP API Specification (OpenAPI/Swagger)

The LFS Proxy HTTP API is documented using OpenAPI 3.0:

| Resource | Location |
|----------|----------|
| **OpenAPI Spec** | [`api/lfs-proxy/openapi.yaml`](../../../api/lfs-proxy/openapi.yaml) |
| **Swagger UI** | Import the spec into [Swagger Editor](https://editor.swagger.io) or [Stoplight](https://stoplight.io) |

**API Endpoints:**
| **Proxy spec (embedded)** | [`cmd/proxy/openapi.yaml`](../../../cmd/proxy/openapi.yaml) |

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/lfs/produce` | POST | Upload blob to S3, produce pointer to Kafka |
| `/lfs/download` | POST | Get presigned URL or stream blob from S3 |
| `/readyz` | GET | Kubernetes readiness probe |
| `/livez` | GET | Kubernetes liveness probe |
| `/metrics` | GET | Prometheus metrics (port 9095) |

**Example: View API spec locally:**
```bash
# Using Swagger UI Docker
docker run -p 8081:8080 -e SWAGGER_JSON=/spec/openapi.yaml \
-v $(pwd)/api/lfs-proxy:/spec swaggerapi/swagger-ui
| `/readyz` | GET | Readiness probe |
| `/livez` | GET | Liveness probe |

# Open http://localhost:8081
```
For local development without Kubernetes, see
[`deploy/docker-compose/README.md`](../../docker-compose/README.md).

## Browser Demo (E72)

Expand Down Expand Up @@ -269,58 +250,27 @@ helm upgrade --install kafscale ./deploy/helm/kafscale \

Note: if you set `global.imageRegistry`, individual component image repositories inherit it.

## Monitoring

### Enable ServiceMonitor

```yaml
lfsProxy:
metrics:
enabled: true
serviceMonitor:
enabled: true
interval: 30s
```

### Enable PrometheusRule

```yaml
lfsProxy:
metrics:
prometheusRule:
enabled: true
```

## Security

### Credentials Best Practices

1. **Use existing secrets** instead of inline values:
1. **Use Kubernetes secrets** for S3 credentials on the `KafscaleCluster`:
```bash
kubectl create secret generic s3-creds \
--from-literal=AWS_ACCESS_KEY_ID=xxx \
--from-literal=AWS_SECRET_ACCESS_KEY=xxx
```
```yaml
lfsProxy:
s3:
existingSecret: s3-creds
spec:
lfsProxy:
s3:
credentialsSecretRef: s3-creds
```

2. **Enable API key** for HTTP endpoints:
```yaml
lfsProxy:
http:
apiKey: "your-secure-key"
```
2. **Enable HTTP API key** via `spec.lfsProxy.http.apiKeySecretRef`.

3. **Restrict CORS origins** in production:
```yaml
lfsProxy:
http:
cors:
allowOrigins: ["https://app.example.com"]
```
3. **Restrict external Kafka access** with `proxy.service.loadBalancerSourceRanges`
or cloud LB annotations.

## Uninstall

Expand All @@ -330,7 +280,6 @@ helm uninstall kafscale -n kafscale-system

## Documentation

- [LFS Proxy Helm Deployment](../../../docs/lfs-proxy/helm-deployment.md)
- [LFS Proxy Data Flow](../../../docs/lfs-proxy/data-flow.md)
- [LFS SDK Documentation](../../../docs/lfs-proxy/sdk-solution.md)
- [Operations Guide](../../../docs/operations.md)
- [Operations Guide](../../../docs/operations.md) — external access, proxy, TLS
- [Docker Compose (local LFS)](../../docker-compose/README.md)
- [OpenAPI spec](../../../api/lfs-proxy/openapi.yaml)
19 changes: 10 additions & 9 deletions deploy/helm/kafscale/values-lfs-demo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,21 @@
# =============================================================================
# LFS Demo Stack Values
# =============================================================================
# This values file enables the LFS proxy with HTTP endpoint and browser demo.
# This values file enables the LFS browser demo UI (lfsDemos).
#
# LFS itself is configured on your KafscaleCluster CRD (spec.lfsProxy), not via
# Helm lfsProxy values — see deploy/helm/kafscale/README.md.
#
# Usage:
# helm upgrade --install kafscale ./deploy/helm/kafscale \
# -f ./deploy/helm/kafscale/values-lfs-demo.yaml \
# --set lfsProxy.s3.bucket=my-bucket \
# --set lfsProxy.s3.endpoint=http://minio:9000 \
# --set lfsProxy.s3.accessKey=minioadmin \
# --set lfsProxy.s3.secretKey=minioadmin
# -f ./deploy/helm/kafscale/values-lfs-demo.yaml
#
# Then apply a KafscaleCluster with spec.lfsProxy.enabled=true and S3 settings.
#
# For local development with port-forward:
# kubectl port-forward svc/kafscale-lfs-proxy 8080:8080 &
# kubectl port-forward svc/kafscale-lfs-demo-e72 3000:80 &
# open http://localhost:3000
# kubectl port-forward svc/<cluster>-lfs-proxy 8080:8080 &
# kubectl port-forward svc/kafscale-lfs-demo-e72 30072:80 &
# open http://localhost:30072
# =============================================================================

# Enable LFS Proxy with HTTP endpoint
Expand Down
Loading
Loading