---
title: "Kubernetes"
description: "Give each project its own Kubernetes cluster on your servers, plan every change before it applies, and deploy workloads from Git through the cluster's own Frazer GitOps."
url: https://frazer.ai/docs/kubernetes
index: https://frazer.ai/docs/llms.txt
tokens: 8234
---

> For agents: this page is indexed at https://frazer.ai/docs/llms.txt, and every page at https://frazer.ai/llms.txt. Copy commands from this file exactly.

# Kubernetes

Kubernetes gives each project its own cluster: virtual machines spread over your servers, built by Frazer’s cluster controller from one cluster resource that you plan and apply. Every cluster arrives with Frazer GitOps, eBPF networking, gateways, certificates, secrets and monitoring installed, and deploys what you keep in Git. Clusters have no fee of their own; their VMs use cores you already pay for.

Product overview: [Kubernetes](https://frazer.ai/kubernetes).

## How it works

The servers of a server pool form a **pool substrate** that Frazer runs for you: Kubernetes, the VM layer and Frazer’s cluster controller on bare metal, with an image cache for the site. A cluster is a set of virtual machines on that substrate, and each VM is one Kubernetes node running Ubuntu. Your containers never run on the bare host, and you never manage the substrate.

The cluster resource lives in Frazer with its revision history. When you apply a plan, Frazer renders the cluster objects from the new revision and sends them signed to the substrate, which creates, repairs and replaces the VMs. Inside the cluster, one GitOps Application, `frazer-platform`, installs the platform set from a signed chart. From then on the cluster’s own Frazer GitOps keeps everything in place.

> **Note:** If Frazer is unreachable, the cluster keeps running. Its GitOps engine keeps applying the last values and chart, and each cluster encrypts its Secrets with a local key, so they stay readable. Frazer keeps only an escrow copy of that key.

Key concepts:

-   **Pool substrate**: the servers of one pool, run by Frazer. The pool’s host project sees its site capacity; your project sees its own share: guaranteed, limit and used.
-   **Cluster**: a set of VMs in one project and one location, such as `us-virginia1`. A cluster lives in one site.
-   **Class**: the cluster’s shape: `small`, `production` or `dedicated`.
-   **Node pool**: a group of identical VMs, such as `control-plane`, `general` or `db`. Each node pool names the server pool it runs on, one of the project’s own or one shared with it.
-   **Plan**: what an apply would do: quota, placement, ranges, cost and the rendered objects as a diff. Nothing changes until you apply it, and in a production project a second person approves it first.
-   **Revision**: each applied plan. Rolling back is applying an earlier revision.
-   **Profile**: the versioned set of platform components every cluster runs.
-   **Environment**: a path in a Git repository connected to the cluster. The cluster’s Frazer GitOps deploys everything in it.

### Classes

The same stack runs in every class.

| Class | Shape | For | Survives | Upgrades | Needs |
| --- | --- | --- | --- | --- | --- |
| `small` | One control-plane VM and workers | Staging and small projects | A failed worker, replaced automatically | Machines replaced | One server |
| `production` | Three control-plane VMs on three servers, dedicated-CPU workers | Production services | The loss of one server | Machines replaced, one surge VM, control plane first | Three servers |
| `dedicated` | Whole servers from a dedicated-node pool | Large databases, GPUs, full NIC speed | The loss of one server | In place, so local disks survive | Servers you give to one cluster |

### Capacity rules

Frazer applies these rules to every plan:

-   Control-plane VMs get their full CPU and the highest priority. A production cluster’s three control-plane VMs sit on three different servers.
-   Workers share CPU 1:1 in production, up to 2:1 in staging and up to 4:1 for previews. Memory is never overcommitted.
-   Each server keeps 8 cores and 32 GiB for itself and the substrate.
-   Quota is checked when you plan, with one spare VM per node pool held for upgrades and repairs.
-   A node that is not ready for 10 minutes is replaced; 15 minutes for database pools, and never two of three at once.

### Where a cluster runs

**Create cluster** lists the places a cluster can run, cheapest first: the project’s own server pools, then pools shared with the project (for example `vint-hill-default`, shared from `acme-infra`), then the Frazer fleet when the project may use it. A cluster on your own servers is never stopped by a budget cap. To bring servers and share pools, see [Servers and pools](https://frazer.ai/docs/servers).

## Create a cluster

You need:

-   A project, such as `acme-production`, and a role in it that may create clusters (`kubernetes.clusters.create`).
-   A server pool the project owns or that is shared with it: one server for `small`, three for `production`.
-   The `frazer` CLI, signed in with `frazer login` ([CLI](https://frazer.ai/docs/cli)), if you use the command line.

1.  **Plan the cluster.** Nothing is created yet.
    
    ### CLI
    
    ```sh
    frazer kubernetes clusters create acme-production-2 \
      --project acme-production \
      --location us-virginia1 \
      --class production \
      --dry-run
    ```
    
    ```text title="Output"
      Pool       vint-hill-default · shared from acme-infra
      Quota      48 vCPU, 180 GiB of your share · surge VM held
      Servers    a control-plane VM on each of Atlas, Borealis, Cobalt
      Objects    + 11 cluster objects · + Application frazer-platform
      Network    pods 10.64.192.0/18 · services 10.96.48.0/20
      Cost       no cluster fee · runs on Acme's own servers (expected)
      Approval   production: a reviewer other than you
    ```
    
    ### Console
    
    Open **Compute › Kubernetes clusters › Create cluster**. The flow has five steps: **Configure**, **Prerequisites**, **Plan**, **Validate** and **Apply**. In **Configure**, name the cluster, choose its class, where it runs and its node pools. The **Plan** step shows the rendered changes, the placement on each server and what will exist.
    
2.  **Read the plan.** It lists the quota the cluster takes from your share of the pool, the surge VM, the servers that host the control plane, the subnet with its pod and service ranges, the addresses and DNS records it takes, the monthly cost and the rendered objects as a diff. Validation checks the project quota, the pool’s capacity, free address ranges, version skew, placement, the secrets mount and Git access.
    
    If losing one server would leave no room to recreate its VMs, the plan warns **Spare capacity (N+1)**. Add a server to the pool, or acknowledge the warning.
    
3.  **Apply it.** Run the same command without `--dry-run`. In a production project the call is held for approval: it prints the approval’s console page, and `--wait` follows the approval until the cluster is created.
    
    ```sh
    frazer kubernetes clusters create acme-production-2 \
      --project acme-production \
      --location us-virginia1 \
      --class production \
      --wait
    ```
    
    A second person approves on that page, or with `frazer approvals approve` after `frazer login --step-up`. Nobody approves their own plan, and agents and service accounts never approve.
    
4.  **Watch it reach Ready.** The cluster’s operation moves through ten phases: Requested, Accepted, Creating machines, Control plane starting, Control plane ready, Nodes joining, Seeding, Platform syncing, Environments syncing and Ready. If a phase times out, the console shows the message of the object that failed.
    

To keep clusters in code instead, use `frazer export` and `frazer apply -f`, or the `frazer_kubernetes_cluster` and `frazer_kubernetes_node_pool` resources of the [Terraform and OpenTofu provider](https://frazer.ai/docs/terraform). `terraform plan` shows the same quota impact, policy violations and cost as the Frazer plan.

## Connect with kubectl

Write a kubeconfig, then use kubectl as usual:

```sh
frazer kubernetes clusters get-credentials acme-production-1
kubectl get nodes
```

```text title="Output"
✓ kubeconfig written · context acme-production-1 · no secret in the file
NAME            STATUS  ROLES               AGE  VERSION
cp-4k2xq        Ready   control-plane       12d  v1.36.4
cp-9wd7m        Ready   control-plane       12d  v1.36.4
cp-h3n5t        Ready   control-plane       12d  v1.36.4
general-7hk2p   Ready   <none>              12d  v1.36.4
general-b8s4v   Ready   <none>              12d  v1.36.4
general-m2q9c   Ready   <none>              12d  v1.36.4
general-x5r1d   Ready   <none>              3d   v1.36.4
```

The kubeconfig holds no secret. On each call, kubectl asks `frazer` for a 10-minute token for that one cluster, and the traffic reaches the API server through Frazer Link, so there is no VPN to install. Your Frazer role maps to Kubernetes RBAC groups in every cluster.

-   **GitOps and dashboards**: open them from the cluster page with **Open GitOps** and **Open dashboards**, behind Frazer sign-in.
-   **Logs and metrics**: `frazer logs` and `frazer monitoring metrics` read the monitoring cell, so they work without cluster access.
-   **Terraform**: the ephemeral resource `frazer_cluster_credentials` gives the kubernetes and helm providers a short-lived token.

## Deploy workloads from Git

Nobody presses “new app”: a new service is a folder in your environment repository. An **environment** is a repository, a revision, a path, a set of namespaces and a permission profile. A cluster connects any number of environments from any number of repositories, and a namespace belongs to exactly one environment.

First install the read-only GitHub App **Frazer Reader** on the repositories you want to connect. Then connect an environment:

### CLI

```sh
frazer releases environments connect data \
  --project acme-production \
  --cluster acme-production-1 \
  --repo acme/data-platform-envs \
  --path envs/production \
  --namespaces data-airflow,data-clickhouse \
  --profile platform \
  --dry-run
```

```text title="Output"
Plan: connect environment "data" to cluster acme-production-1
  + Namespaces     env-data, data-airflow, data-clickhouse
  + AppProject     env-data · profile platform (elevated)
  + Applications   4 from commit 3f9c2e1
  ~ Git token      the cluster also reads acme/data-platform-envs
  ✓ Namespaces     no conflict with environment "platform"
  ✓ Policy         Policy dry run: 0 violations · schemas valid
    Cost           +6 vCPU, +24 GiB requested · no fee (expected)
    Approval       org admin (profile platform)
```

### Console

Open the cluster, then **Environments › Connect**. Pick a repository from the Frazer Reader installation, then the branch, path, namespaces, profile, sync policy and hostnames. The plan is computed from the repository’s current contents.

The connected path follows one convention. Frazer’s generators read it and create one GitOps Application per app folder:

-   Directory envs/production/ the connected path
    
    -   environment.yaml optional: labels, namespace defaults, chart versions
    -   \_shared-values.yaml Helm values for the whole environment
    -   Directory apps/
        
        -   Directory core/ a family, which is a chart
            
            -   Directory api/
                
                -   values.yaml written by people
                -   images.yaml written by CI only: the image digest
                
            
        
    -   Directory databases/
        
        -   Directory orders/
            
            -   database.yaml a managed Postgres database
            
        
    -   Directory manifests/
        
        -   Directory clickhouse-operator/ raw YAML or a Kustomization
            
            -   …
            
        
    

Your CI builds once, pushes to [Frazer Registry](https://frazer.ai/docs/registry), which signs the digest on push, and writes the digest into `images.yaml`: staging by commit, production by pull request. Frazer GitOps syncs, and admission checks the signature. The console follows each rollout by digest: **Built**, **Written to Git**, **Synced**, **Rolled out**, **Verified**.

-   **Permission profiles**: `standard`, the default, allows namespaced kinds in the environment’s own namespaces. Org admins approve `platform`, which also allows CRDs and operator webhooks. `preview` runs a namespace per pull request.
-   **Secrets stay out of Git**: the repository holds `ExternalSecret` objects only, and values live in [Secrets](https://frazer.ai/docs/secrets), write-only for people. A `Secret` with data is refused.
-   **Pull-request check**: the Frazer Reviewer App posts a check per environment with the rendered diff, policy results, signature checks and the change in requests and cost.

Layouts, profiles and sync settings in depth: [Environments and GitOps](https://frazer.ai/docs/gitops).

## Expose services

Gateways are Frazer resources, because they take things from outside the cluster: an address from the site’s IP pool, DNS records and a certificate.

```sh
frazer kubernetes gateways create public --cluster acme-production-1
```

Routes stay in your Git: set `gateway.hostnames` and `parentRef` in a service’s `values.yaml`, and the chart renders the `HTTPRoute`. A policy checks that the hostname is one the environment may claim. The cluster’s `ops` gateway, where Frazer GitOps opens, sits behind Frazer sign-in.

Use your own domain in one of three ways:

| Way | How | Certificates |
| --- | --- | --- |
| Delegate a subdomain to Frazer DNS | Point `apps.acme.example` at Frazer’s name servers. Frazer manages the records from gateways and routes. | DNS-01 inside the zone |
| Keep your DNS provider | The cluster’s DNS controller and certificate manager use your provider’s token, stored in your project’s secrets and limited to one zone. | DNS-01 at your provider |
| Manage records yourself | The console shows the exact A, AAAA and CNAME records to create. | One `_acme-challenge` CNAME into Frazer’s challenge zone, so no provider token is needed |

For gRPC between services, `frazer-xds` serves every Service labeled `xds.frazer.ai/enabled` under the names in its `xds.frazer.ai/hostnames` annotation, with only ready endpoints. Clients balance per request, with no sidecar. The cluster’s **Networking › Service routing** tab shows it. More: [Load balancers](https://frazer.ai/docs/load-balancers) and [DNS and certificates](https://frazer.ai/docs/dns).

## Change a cluster

Every change has the same shape as a create: a node pool’s replicas, the Kubernetes version, the profile version or an add-on switch, each a plan you apply. Rolling back is applying an earlier revision; the cluster’s **Activity** tab lists them.

**The platform set.** Each piece has exactly one owner:

-   **The Kubernetes distribution** installs the control plane, its datastore, cluster DNS, resource metrics and volume snapshots, with no ingress controller. They move with the Kubernetes version.
-   **The seed** installs, once, what the nodes need to start: `frazer-cloud-controller-manager`, the secret sync, the cluster’s keys registered with Frazer Secrets, the `frazer-secrets` store, Git and registry credentials, Frazer GitOps and the `frazer-platform` Application.
-   **The cluster’s own Frazer GitOps** then installs and upgrades everything else, in waves: the GitOps engine itself, the secret sync, `frazer-clusterlet`, a default-deny network policy, Gateway API and the cluster’s gateway, Frazer Policy, the certificate manager, local NVMe volumes, `frazer-xds`, the metrics and log agents, node lifecycle, config reload, the optional add-ons and, last, your environments.

**Optional add-ons** are switches on the cluster’s **Platform** tab, each applied by a plan: managed Postgres with backups to Frazer Storage, cluster backups, event-driven autoscaling, progressive rollouts, the DNS controller, GPU drivers, sandbox runtimes, runtime threat detection and the OpenTelemetry collector. Anything else, such as your own operators, comes through an environment: raw manifests or a Kustomization under `manifests/`, with the `platform` profile when it brings CRDs.

**Guaranteed components** (eBPF networking, the Frazer Policy rules, the certificate manager, the agent, the monitoring agents and the security sensors: the eBPF runtime sensor, the vulnerability scanner and CIS benchmark checks) change only through the cluster’s settings. Environments cannot edit them.

**Profile versions** roll out by ring: Frazer’s canary clusters first, then staging-labeled projects, then production-labeled ones, each after the clusters are synced, healthy and have soaked. Production moves only inside its maintenance window. A project can pin a profile version for up to one release cycle.

## Upgrade a cluster

A cluster runs one of the three newest Kubernetes minors Frazer certifies, on one of two channels: **Rapid** or **Regular**, the default. A version reaches your production only after Frazer’s canary clusters and the staging projects ran it healthy; any failure holds it everywhere. Production node pools stay within one minor of their control plane.

### Set a maintenance window

Upgrade steps start only inside your maintenance window. A maintenance policy belongs to a project and attaches to clusters, node pools, databases, VMs and server pools. Its fields:

```yaml title="Maintenance policy"
window: { rrule: "FREQ=WEEKLY;BYDAY=SA,SU", start: "02:00", duration: 6h, timeZone: America/New_York }
exclusions:
  - { name: peak, start: 2026-11-20, end: 2026-12-01, scope: NO_UPGRADES }
  - { name: hold-minor, scope: NO_MINOR, until: END_OF_SUPPORT }
order: { after: [maintenancePolicies/staging], soak: 7d }
notice: { lead: 7d, reminders: [72h, 1h], channels: [email, webhook, slack] }
```

Create one with `frazer maintenance policies create --rrule …`, or with the `frazer_maintenance_policy` resource. A window is at least 4 hours long and leaves at least 48 hours of availability every 32 days outside exclusions. To hold minor upgrades, add a `NO_MINOR` exclusion; patches still flow. `frazer maintenance events list --next 30d` lists what is planned, and every project has a maintenance calendar with an iCal feed.

### Plan, rehearse and run an upgrade

```sh
# Restore the cluster's state at the target version on a clone, dry-run every
# object and call the webhooks. Reports what would break.
frazer kubernetes clusters upgrade acme-production-1 --to 1.37 --rehearse

# The steps, preflight results, risk to each workload, duration, surge cost
# and the slot it will run in.
frazer kubernetes clusters upgrade acme-production-1 --to 1.37 --dry-run

# Run it in the next maintenance window, as an operation you can pause,
# resume or roll back.
frazer kubernetes clusters upgrade acme-production-1 --to 1.37 --at next-window
```

In the console, open the cluster’s **Upgrades** tab. A minor upgrade runs these steps:

1.  **Preflight** names the client still calling a deprecated API, and flags disruption budgets that allow no eviction, single-replica workloads and node-local volumes. An error blocks the upgrade; a warning is shown.
2.  **Anchor**: a control-plane snapshot before anything changes.
3.  **Control plane**: replaced one VM at a time with a surge VM, then a soak of 24 hours in production and 1 hour in staging.
4.  **Node pools**: surge, or blue-green in batches with the old VMs parked and their disks kept, so a pool rollback starts them again. Drains wait for disruption budgets for up to 60 minutes, then hold the node and tell you; nothing is force-evicted by default.
5.  **Profile**: the platform profile moves too, when the new minor needs it.
6.  **Postflight**: conformance checks and your own synthetic checks.

Pause, resume, roll back or finish early from the **Upgrades** tab, or from the CLI:

```sh
frazer kubernetes clusters upgrade pause acme-production-1
frazer kubernetes clusters upgrade resume acme-production-1
frazer kubernetes clusters upgrade rollback acme-production-1
```

What a rollback gives you:

-   **Node pools**: supported, with no data loss. The parked VMs start again and the new ones drain.
-   **Control-plane patch downgrade** within a minor: supported where the patch notes allow it.
-   **Control-plane minor rollback during the soak**: experimental, for staging and opt-in clusters only. The supported recovery is a forward fix, or a restore to the anchor snapshot. A restore loses the writes made after the snapshot; the operation lists them for you to approve first.

> **Caution:** VM workers are replaced at each upgrade, so their local volumes are created again and a database replica clones from its primary. Run large databases on the `dedicated` class, which upgrades in place. Either way, durability comes from three instances on three servers and from backups, not from the disk.

## Attach a cluster you already run

Attach a cluster you run elsewhere, at a cloud provider or on premises, through the same outbound-only agent. Start in **Infrastructure › Attached clusters**. The agent dials out, so the cluster needs no inbound port and no load balancer. Registration is double opt-in: the install token only makes the cluster appear as pending until you accept it.

| Mode | Frazer can | Rights in your cluster | Workloads |
| --- | --- | --- | --- |
| Observed | Inventory, health, metrics, logs and cost; read views in the console and MCP | A read-only ClusterRole, no Secrets | Yours, untouched |
| Connected | Also the console and kubectl through the tunnel | Impersonation of mapped users and groups; your RBAC decides | Yours, untouched |
| Managed | Also environments: Frazer GitOps from your Git, or adopt the GitOps you run | A GitOps engine per namespace or per cluster, your choice | From your Git, through GitOps |

When connected, each request runs as the person who made it, never as cluster-admin, and your audit log records it. Change the mode at any time. **Detach** removes the agent’s namespace and nothing else; the cluster’s lifecycle stays with you.

## Delete a cluster

Deletion is soft, with a restore window. You type the project ID to confirm, Frazer takes a final database backup, and production clusters carry a deletion lock.

```sh
frazer kubernetes clusters delete acme-staging-1 --project acme-staging
```

To bring it back within the restore window, run `frazer kubernetes clusters undelete acme-staging-1 --project acme-staging`.

## Access and audit

| Who | What they can do |
| --- | --- |
| Kubernetes viewer, developer and admin (`roles/kubernetes.viewer`, `.developer`, `.admin`) | Map to RBAC groups in every cluster of the project; kubectl acts with your role |
| Developers | Connect environments with the `standard` profile: namespaced kinds in their own namespaces |
| Org admins | Approve the `platform` profile for environments that bring CRDs and operator webhooks |
| A second person | Approves production plans. Nobody approves their own; agents and service accounts never approve |
| Org owners | Hold a break-glass kubeconfig for each cluster |
| Agents through MCP | Read by default; a write becomes a plan that waits for a person’s approval |

What is logged:

-   Every plan and apply, with the revision it made.
-   Every kubectl call through Frazer Link, as the person who made it.
-   Live actions from the console: restart, cordon, drain and replace machine.
-   Kubernetes events, kept in the project’s logs for 30 days.
-   Any use of break-glass access.

> **Break-glass access:**
> 
> Using the break-glass kubeconfig marks the cluster `tainted` until its CA is rotated.

A capped budget never stops workloads on your own servers; it refuses only new billable items. Your guaranteed share of a pool is held for you and never lent, and bursts above it are never preempted. A full pool fails the plan, never a running cluster, and the plan offers to request more.

## Limits and quotas

| Limit | Default |
| --- | --- |
| Servers needed | `small`: 1 · `production`: 3 |
| Control-plane VMs | `small`: 1 · `production`: 3, on three different servers |
| Reserve on each server | 8 cores and 32 GiB for the host and the substrate |
| Worker CPU sharing | Production 1:1 · staging up to 2:1 · previews up to 4:1 · memory never overcommitted |
| Surge capacity | One spare VM per node pool, counted at plan time |
| Node replaced after not ready for | 10 minutes · 15 for database pools, never two of three at once |
| kubectl token | 10 minutes, for one cluster |
| Git read token of a cluster | 60 minutes, refreshed every 20 minutes, only the repositories connected to it |
| Kubernetes versions | The three newest minors Frazer certifies; production pools within one minor of their control plane |
| Control-plane soak in a minor upgrade | 24 hours in production, 1 hour in staging |
| Drain wait | 60 minutes, then the node is cordoned and held |
| Maintenance window | At least 4 hours; at least 48 hours of availability every 32 days outside exclusions |
| Maintenance exclusions | Up to 30 days each, 3 active |
| Upgrade order across policies | Up to 5 stages and 30 days of soak |
| Profile version pin | Up to one release cycle |
| Kubernetes events in logs | 30 days |

Project quota covers cluster and node-pool vCPU, memory and disk, including the surge VM, and is checked when you plan. Quotas inside the cluster are yours to set.

## Pricing

A cluster has no fee of its own. Its VMs run on your servers, which pay the per-core server fee, and the platform set comes with every cluster. Attached clusters are free when observed; connected and managed clusters are billed per node core, as the [Kubernetes page](https://frazer.ai/kubernetes) lists.

| Kubernetes | On your servers | On the Frazer fleet |
| --- | --- | --- |
| Price | $0 per cluster | $0 per cluster |

Every line, with the estimator: [pricing](https://frazer.ai/pricing#lines).

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| The plan fails with `POOL_NOT_SHARED` | The server pool is not shared with your project | Ask an admin of the pool’s host project to share it ([Servers and pools](https://frazer.ai/docs/servers)) |
| The plan fails with `POOL_CAPACITY_EXHAUSTED` | The cluster would take the project past its limit, or the pool is full | Use the plan’s offer to request more guaranteed capacity, place on the Frazer fleet where allowed, or add servers |
| The plan fails with `POOL_NO_FIT` | The VMs do not fit on the servers’ free capacity with the placement rules | Add servers to the pool, or plan fewer or smaller VMs. A production cluster needs three servers |
| The plan fails with `QUOTA_EXCEEDED` | The project is at its quota | Delete what you no longer use, or ask for more quota |
| The plan warns **Spare capacity (N+1)** | Losing one server would leave no room to recreate its VMs | Add a server to the pool, or acknowledge the warning |
| The create answers `APPROVAL_REQUIRED` | The project is production, so a second person must approve | Share the approval page with a reviewer, and use `--wait` to follow it |
| A phase does not finish | An object failed while the cluster was being built | Open the cluster’s operation in the console; it shows the failing object’s message |
| Upgrade preflight names a client | The client still calls an API the target version removes | Update that client, then plan the upgrade again |
| Upgrade preflight blocks on node-local volumes | VM workers lose local disks when they are replaced | Replicate the workload, acknowledge the warning, or move the database to the `dedicated` class |
| An upgrade waits on a node | A disruption budget allows no eviction, so the node is cordoned and held | Raise the workload’s replicas or relax its disruption budget |
| Connecting an environment fails on a namespace | Another environment already owns that namespace | Choose other namespaces; a namespace belongs to one environment |
| GitOps refuses an object | The environment’s profile does not allow it: a Gateway, another environment’s namespace, a cluster-scoped kind under `standard`, or a `Secret` with data | Use a gateway resource, ask an org admin for the `platform` profile, or use an `ExternalSecret` |
| A pod’s image is refused | Admission found no valid signature on the digest | Push the image through Frazer Registry, which signs each digest on push |
| kubectl reports an authentication error | `frazer` could not mint a token for you | Run `frazer login`, then `frazer kubernetes clusters get-credentials` again |
| The cluster shows `tainted` | Someone used the break-glass kubeconfig | Rotate the cluster’s CA |

## Reference

### CLI

| Command | What it does |
| --- | --- |
| `frazer kubernetes clusters create` | Create a cluster in a project. With --dry-run, print the plan and create nothing. |
| `frazer kubernetes clusters list` | List the clusters in a project. |
| `frazer kubernetes clusters get` | Show one cluster with its class, version, channel, node pools and state. |
| `frazer kubernetes clusters get-credentials` | Write a kubeconfig with no secret in it. kubectl then asks frazer for a 10-minute token for that one cluster. |
| `frazer kubernetes clusters upgrade` | Upgrade a cluster to a Kubernetes version. --rehearse tries it on a clone, --dry-run prints the plan, --at next-window schedules it. |
| `frazer kubernetes clusters upgrade pause` | Pause a running upgrade. |
| `frazer kubernetes clusters upgrade resume` | Resume a paused upgrade. |
| `frazer kubernetes clusters upgrade rollback` | Roll back a running upgrade. |
| `frazer kubernetes clusters upgrade complete` | Finish an upgrade early, skipping the rest of its soak. |
| `frazer kubernetes clusters delete` | Delete a cluster. Deletion is soft, with a restore window and a final database backup. |
| `frazer kubernetes clusters undelete` | Restore a deleted cluster within its restore window. |
| `frazer versions list` | List the Kubernetes versions of each channel with their end-of-support dates. |
| `frazer maintenance policies create` | Create a maintenance policy with a recurring window, exclusions, an order and notices. |
| `frazer maintenance events list` | List planned maintenance events, for example those of the next 30 days. |
| `frazer insights list` | List insights, for example with --category upgrade the deprecated API calls that block an upgrade. |

All of them: [CLI reference](https://frazer.ai/docs/cli).

### Terraform and OpenTofu

| Resource | What it manages |
| --- | --- |
| `frazer_kubernetes_cluster` | A Kubernetes cluster in a project, with its release channel, maintenance policy and upgrade settings. |
| `frazer_kubernetes_node_pool` | A node pool of a cluster, placed on a server pool of the project or one shared with it. |
| `frazer_maintenance_policy` | A project's maintenance window, exclusions, order and notices, attached to clusters and node pools. |
| `frazer_cluster_credentials` | Ephemeral. A short-lived kubeconfig token for the kubernetes and helm providers. |

All of them: [Terraform and OpenTofu reference](https://frazer.ai/docs/terraform).

### MCP tools

| Tool | What it does |
| --- | --- |
| `kubernetes_versions_list` | List the Kubernetes versions of each channel with their end-of-support dates. |
| `kubernetes_clusters_upgrade_plan` | Plan an upgrade with its steps, preflight results, risk to each workload, duration and slot. |
| `kubernetes_clusters_rehearse_upgrade` | Rehearse an upgrade on a clone of the cluster's state and report what would break. |
| `maintenance_events_list` | List planned maintenance events. |
| `maintenance_insights_list` | List insights, such as deprecated API calls that block an upgrade. |

All of them: [MCP tools reference](https://frazer.ai/docs/mcp).

### Events

| Event type | When it is sent |
| --- | --- |
| `frazer.cluster.created.v1` | A cluster was created. |
| `frazer.cluster.ready.v1` | A cluster reached Ready. |
| `frazer.cluster.upgrade.started.v1` | An upgrade of a cluster started. |
| `frazer.cluster.upgrade.completed.v1` | An upgrade of a cluster completed. |
| `frazer.cluster.degraded.v1` | A cluster's health degraded. |

All of them: [Events reference](https://frazer.ai/docs/webhooks).

## Related

-   [Create a Kubernetes cluster](https://frazer.ai/docs/quickstarts/kubernetes-cluster): plan, apply, open GitOps.
-   [Servers and pools](https://frazer.ai/docs/servers): bring servers and share pools with projects.
-   [Environments and GitOps](https://frazer.ai/docs/gitops): repositories, profiles and the pull-request check.
-   [Load balancers](https://frazer.ai/docs/load-balancers): gateways, addresses and TLS.
-   [Secrets](https://frazer.ai/docs/secrets): values your workloads read through the cluster’s secret sync.
-   [Kubernetes product page](https://frazer.ai/kubernetes).

## Pages in Compute

- [Servers and pools](https://frazer.ai/docs/servers.md)
- [Kubernetes](https://frazer.ai/docs/kubernetes.md) (this page)
- [Serverless](https://frazer.ai/docs/serverless.md)
- [VMs](https://frazer.ai/docs/vms.md)
- [Devboxes](https://frazer.ai/docs/devboxes.md)
