mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 02:26:12 +02:00
208 lines
7.1 KiB
Markdown
208 lines
7.1 KiB
Markdown
---
|
|
title: Kubernetes Execution — Quickstart
|
|
summary: First-time setup guide for operators connecting a Kubernetes cluster to Paperclip and provisioning a tenant namespace
|
|
---
|
|
|
|
This guide walks an operator through connecting a Kubernetes cluster to a Paperclip M1 deployment and provisioning the first tenant namespace. By the end you will have a verified cluster connection and a namespace that passes `kubectl describe namespace` — ready for agent execution when M2 ships.
|
|
|
|
**M1 scope:** This release delivers tenant namespace provisioning only. Agent execution (running adapter pods) is an M2 feature. See [What's not in M1](#whats-not-in-m1) for the full boundary.
|
|
|
|
## Prerequisites
|
|
|
|
| Tool | Version | Notes |
|
|
|------|---------|-------|
|
|
| `kubectl` | 1.28+ | Must be on `$PATH` |
|
|
| `kind` | 0.22+ | Only if using a local kind cluster |
|
|
| Docker | 24+ | Required to run kind |
|
|
| Paperclip server | M1 build | `PAPERCLIP_K8S_DRIVER=true` env var must be set |
|
|
| `paperclipai` CLI | M1 build | `pnpm paperclipai --version` should print a version |
|
|
|
|
A PostgreSQL database with the M1 migrations applied (`packages/db/src/migrations/0082_cluster_connections.sql`) is required before any cluster commands work.
|
|
|
|
## First-time cluster setup
|
|
|
|
### 1. Start a kind cluster (if you don't have one)
|
|
|
|
```bash
|
|
kind create cluster --name paperclip-dev
|
|
kubectl cluster-info --context kind-paperclip-dev
|
|
```
|
|
|
|
For a production cluster, ensure it has:
|
|
- A default `StorageClass` (used for agent PVCs in M2)
|
|
- `NetworkPolicy` enforcement (Calico, Cilium, or compatible CNI)
|
|
|
|
### 2. Apply the reference ClusterRole
|
|
|
|
The Paperclip driver needs a `ClusterRole` that allows it to manage tenant namespaces and the objects inside them.
|
|
|
|
```bash
|
|
kubectl apply -f packages/adapters/kubernetes-execution/manifests/paperclip-tenant-manager-clusterrole.yaml
|
|
```
|
|
|
|
Verify it was created:
|
|
|
|
```bash
|
|
kubectl get clusterrole paperclip-tenant-manager
|
|
```
|
|
|
|
### 3. Create the driver ServiceAccount and bind the ClusterRole
|
|
|
|
For an **in-cluster** topology (Paperclip server running inside the same cluster), create the ServiceAccount in the `paperclip-system` namespace:
|
|
|
|
```yaml
|
|
# paperclip-system-sa.yaml
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: paperclip-system
|
|
---
|
|
apiVersion: v1
|
|
kind: ServiceAccount
|
|
metadata:
|
|
name: paperclip-driver
|
|
namespace: paperclip-system
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRoleBinding
|
|
metadata:
|
|
name: paperclip-driver
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: paperclip-driver
|
|
namespace: paperclip-system
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: paperclip-tenant-manager
|
|
apiGroup: rbac.authorization.k8s.io
|
|
```
|
|
|
|
```bash
|
|
kubectl apply -f paperclip-system-sa.yaml
|
|
```
|
|
|
|
For a **cross-cluster** topology (Paperclip server is elsewhere), the kubeconfig user must already be bound to the same `ClusterRole` on the workload cluster. See [cluster-rbac.md](./cluster-rbac.md) for details on both topologies.
|
|
|
|
### 4. Store the kubeconfig as a Paperclip secret
|
|
|
|
Paperclip resolves cluster credentials through its secret provider abstraction. The `kubeconfig_secret_ref` field on a `cluster_connections` row holds a `{ provider, name }` pair. Supported providers in M1:
|
|
|
|
| Provider string | Where the secret lives |
|
|
|-----------------|----------------------|
|
|
| `env` | Environment variable (e.g. `env:KUBECONFIG_KIND`) |
|
|
| `aws_secrets` | AWS Secrets Manager secret ARN or name |
|
|
| `gcp_secret` | GCP Secret Manager resource path |
|
|
| `vault` | HashiCorp Vault path (`vault:secret/data/paperclip/kind-cfg`) |
|
|
|
|
For a local kind cluster, the simplest path is the `env` provider. Export the kubeconfig and set an environment variable on the Paperclip server:
|
|
|
|
```bash
|
|
kind get kubeconfig --name paperclip-dev > /tmp/kind-cfg.yaml
|
|
export KUBECONFIG_KIND=$(cat /tmp/kind-cfg.yaml)
|
|
```
|
|
|
|
Then reference it as `env:KUBECONFIG_KIND` in the `--kubeconfig-secret` flag below.
|
|
|
|
> **Note:** `local_encrypted` (a Paperclip-managed encrypted store) is planned for M2. Until then, use one of the providers listed above.
|
|
|
|
## Add a cluster connection
|
|
|
|
```bash
|
|
paperclipai cluster add \
|
|
--label kind \
|
|
--kind kubeconfig \
|
|
--kubeconfig-secret env:KUBECONFIG_KIND
|
|
```
|
|
|
|
The command probes the cluster for capabilities (Cilium presence, default StorageClass, node architectures) and writes a row to `cluster_connections`. The printed `id` is the `<clusterId>` used in subsequent commands.
|
|
|
|
Additional flags:
|
|
|
|
| Flag | Purpose |
|
|
|------|---------|
|
|
| `--paperclip-public-url <url>` | Override the Paperclip server URL agents use to call back (cross-cluster only) |
|
|
| `--image-registry <url>` | Override the image registry for agent runtime images |
|
|
|
|
## Verify the connection
|
|
|
|
```bash
|
|
# Check reachability, RBAC, and cluster capabilities
|
|
paperclipai cluster doctor <id>
|
|
|
|
# List all registered cluster connections
|
|
paperclipai cluster list
|
|
```
|
|
|
|
`cluster doctor` checks:
|
|
- API server reachability via the stored kubeconfig
|
|
- `paperclip-tenant-manager` ClusterRole exists
|
|
- Default StorageClass is present
|
|
- Cilium CRD presence (informational)
|
|
|
|
## Provision a tenant for a company
|
|
|
|
```bash
|
|
paperclipai cluster ensure-tenant <clusterId> <companyId>
|
|
```
|
|
|
|
Expected output:
|
|
|
|
```
|
|
Provisioned namespace paperclip-<companySlug> (cilium=false)
|
|
```
|
|
|
|
Or, if Cilium is present on the cluster:
|
|
|
|
```
|
|
Provisioned namespace paperclip-<companySlug> (cilium=true)
|
|
```
|
|
|
|
`ensure-tenant` is **idempotent** — running it twice is safe and brings any drifted objects back to the desired state. The driver refuses to touch a namespace that lacks the `paperclip.ai/managed-by=paperclip` label.
|
|
|
|
## Verify the namespace with kubectl
|
|
|
|
```bash
|
|
kubectl get ns,sa,resourcequota,limitrange,networkpolicy \
|
|
-l paperclip.ai/managed-by=paperclip
|
|
```
|
|
|
|
You should see:
|
|
- `Namespace` named `paperclip-<companySlug>`
|
|
- `ServiceAccount` named `paperclip-agent`
|
|
- `ResourceQuota` named `paperclip-tenant-quota`
|
|
- `LimitRange` named `paperclip-tenant-limits`
|
|
- `NetworkPolicy` objects `default-deny-ingress`, `default-deny-egress`, `paperclip-agent-egress`
|
|
|
|
```bash
|
|
kubectl describe namespace paperclip-<companySlug>
|
|
```
|
|
|
|
Check that the PSS labels are present:
|
|
|
|
```
|
|
Labels: pod-security.kubernetes.io/enforce=restricted
|
|
pod-security.kubernetes.io/audit=restricted
|
|
pod-security.kubernetes.io/warn=restricted
|
|
paperclip.ai/managed-by=paperclip
|
|
paperclip.ai/company-id=<uuid>
|
|
```
|
|
|
|
## What's not in M1
|
|
|
|
| Feature | Milestone |
|
|
|---------|-----------|
|
|
| Agent execution (running adapter pods as Kubernetes Jobs) | M2 |
|
|
| Web UI for cluster management and health | M3 |
|
|
| Per-company BYO cluster (one cluster connection per company) | V2 |
|
|
| VolumeSnapshot-based agent workspace cloning | V2 |
|
|
| `local_encrypted` secret provider | M2 |
|
|
| `paperclipai cluster purge` (namespace teardown) | M2 |
|
|
|
|
For the full V1/V2 scope split see the [design spec](../superpowers/specs/2026-05-08-paperclip-cloud-adapter-design.md#non-goals-v1).
|
|
|
|
## Next steps
|
|
|
|
- [Security model](./security-model.md) — understand the isolation primitives applied to each namespace
|
|
- [Multi-tenant onboarding](./multi-tenant-onboarding.md) — operator playbook for provisioning multiple companies
|
|
- [Cluster RBAC](./cluster-rbac.md) — full ClusterRole reference and binding templates
|