Skip to content

Create Your First Environment

An Environment is where a tenant's workloads live: a Namespace owned by a Capsule Tenant, plus the VPC and subnet its clusters attach to. A Tenant is a collector of Environments, so one tenant can hold several (one per stage, per region, per workload) each with a network of its own.

This page adds an Environment called dynamo-prod to the dynamo tenant from Create First Tenant.

Prerequisites

  • A Tenant, and the identity that owns it (see Create First Tenant).
  • A CIDR for the Environment's subnet that does not overlap another subnet in the same VPC.

Create the Environment

An Environment is a plain Namespace that belongs to a Tenant. There is no Environment CRD: the Namespace is the Environment, and Capsule adopts it into the Tenant.

apiVersion: v1
kind: Namespace
metadata:
  name: dynamo-prod

Create it as the tenant's owner, so Capsule assigns it to that Tenant:

kubectl create namespace dynamo-prod \
  --as=system:serviceaccount:kmetal-tenants:dynamo

Capsule stamps the namespace with the Tenant it belongs to, and sets the Tenant as its owner so the Environment is cleaned up with it:

$ kubectl get namespace dynamo-prod --show-labels
NAME          STATUS   AGE   LABELS
dynamo-prod   Active   3s    capsule.clastix.io/tenant=dynamo

$ kubectl get tenant dynamo
NAME     STATE    NAMESPACE QUOTA   NAMESPACE COUNT   NODE SELECTOR   READY   STATUS       AGE
dynamo   Active                     1                                 True    reconciled   28h

A Tenant may own as many Environments as it needs (one per stage, per region, per workload) and each gets its own network below.

Claim a VPC

The Environment's network is declared with two namespaced claims. The tenant writes intent; the platform owns the routing rules that make it safe.

Exactly one VpcClaim may exist per Environment. It reconciles into a cluster-scoped Kube-OVN Vpc named after the namespace:

apiVersion: network.kmetal.io/v1alpha1
kind: VpcClaim
metadata:
  name: main
  namespace: dynamo-prod
spec:
  # Egress to the outside world. The static route and the isolation
  # policy routes that go with it are injected by the platform, not
  # written here.
  externalAccess: true

With externalAccess: true the controller enables external access on the VPC, adds the administrator-configured default route, and injects the drop rule that keeps this VPC off the provider segment and away from other tenants. It also creates the well-known external EipClaim the VPC's router port needs — that is not yours to write.

Per-tenant egress isolation

A VpcClaim can also name a specific provider network to egress through, instead of the cluster default — which is how a tenant is given a network segment of its own. That is an advanced setup, and is covered separately.

Claim specs are immutable

Both VpcClaim.spec and SubnetClaim.spec are rejected on update. Getting the CIDR or the external-access decision wrong means deleting the claim and re-creating it — which takes the Kube-OVN objects with it. Decide before applying.

Check it landed:

$ kubectl get vpcclaim -n dynamo-prod
NAME   VPC           EXTERNAL   PROVIDERNETWORK   READY   AGE
main   dynamo-prod   true                         True    12s

Claim a subnet

Each SubnetClaim reconciles into one Kube-OVN Subnet inside that VPC. An Environment may hold several — one per cluster, for instance.

apiVersion: network.kmetal.io/v1alpha1
kind: SubnetClaim
metadata:
  name: primary
  namespace: dynamo-prod
spec:
  cidrBlock: 10.100.0.0/24
  # Defaults to the first usable address in cidrBlock when omitted.
  gateway: 10.100.0.1
  protocol: IPv4
  excludeIps:
    - 10.100.0.1
  # Creates the NetworkAttachmentDefinition worker VMs attach through,
  # in this namespace. On by default.
  attachment:
    managed: true
  # SNATs this subnet's egress through the VPC's router-port EIP.
  # Requires externalAccess on the VpcClaim above.
  enableSnatRule: true

The VPC and the namespace binding are derived from the Environment's VpcClaim — they are deliberately absent from the claim's spec, so a tenant cannot attach a subnet to a VPC that is not theirs. The CIDR must not overlap another subnet in the same VPC.

The claim reports the cluster-scoped objects it bound:

$ kubectl get subnetclaim -n dynamo-prod
NAME      SUBNET                VPC           CIDR            READY   AGE
primary   dynamo-prod-primary   dynamo-prod   10.100.0.0/24   True    8s

SUBNET is the cluster-scoped Subnet the claim created, derived from the namespace and the claim name. A SubnetClaim that reports WaitingForVpc is in an Environment whose VpcClaim is not Ready yet.

A Cluster joins this subnet by the claim's own name — primary — not by the derived name in the SUBNET column.

What the tenant has now

Tenant dynamo
└── Environment dynamo-prod                     (Namespace, Capsule-adopted)
    ├── VpcClaim main       → Vpc dynamo-prod
    └── SubnetClaim primary → Subnet dynamo-prod-primary
                              NetworkAttachmentDefinition primary-net

Everything a Cluster needs to exist: a namespace to be created in, and a subnet for its worker VMs to attach to.

Next Steps

Create a cluster in this Environment — Create First Cluster.