Create a Zone
For the concept and isolation model, see Zone. For configuration options and the cluster-wide settings that apply to every Zone, see Zone Management.
A Zone separates different teams or products that share the same Kubernetes cluster. Access permissions, policies, network rules, and dedicated compute together give far stronger isolation than Namespaces alone — the two main reasons to use Zones are security and cost savings.
A demo video of Zones walks through the concepts below.
What a Zone Gives You
- Compute placement — A Zone contains Namespaces and can create Node Pools (NodeGroups in AWS). Pods in a Zone's Namespace automatically get the right NodeSelectors and land on the correct pool. With multiple Namespaces and pools, you can pin each Namespace to a specific pool; per-Pod affinity is supported and applied automatically unless you set it manually, with validations enforcing the rules.
- Pod security — The Zone controls each Namespace's Pod Security Admission (PSA), preventing privileged containers from starting. The enforcement level is set at the cluster level.
- Networking — With
granularNamespaceNetworkPolicyset tofalse(default), Namespaces in the same Zone can reach each other freely. Traffic between different Zones must be allowed with a standard Kubernetes NetworkPolicy — only ingress rules are needed, since egress is open by default. When you create an Ingress object, the NetworkPolicy that lets the load balancer reach your Service Pods is created automatically. - GitOps — Each Zone creates an ArgoCDProject scoped to its Namespaces, so teams can use the "app-of-apps" pattern while staying inside the Zone.
- Access control — Contributor groups restrict access to only the Zone's Namespaces, enforced in both ArgoCD and the Kubernetes API.
Example of a Zone
The example below creates a Zone with two Node Pools in AWS: default (on-demand) and myspot (spot).
Apply it from a Git repository (recommended) or directly with kubectl. Managing Zones through GitOps — the same way you deploy applications — keeps them versioned and reviewable.
Naming rule: a Zone cannot be named
default. Each Zone gets an ArgoCDProject of the same name, anddefaultis already ArgoCD's own project, so the request is rejected with'default' zone cannot be created.
# Example zone
apiVersion: tenancy.entigo.com/v1alpha1
kind: Zone
metadata:
name: example-zone
labels:
tenancy.entigo.com/default-zone: "true"
spec:
roleMapping:
- groups:
- 123456789-1234-1234-1234-123456789
roleRef: contributor
pools:
- name: default
requirements:
- key: instance-type
values:
- t3.large
- key: capacity-type
value: ON_DEMAND
- key: min-size
value: 1
- key: max-size
value: 2
- name: myspot
requirements:
- key: instance-type
values:
- t3.large
- key: capacity-type
value: SPOT
- key: min-size
value: 2
- key: max-size
value: 2
Example for Zonal NodeGroups
To keep a workload available when a cloud availability zone (AZ) fails — for example a StatefulSet whose replicas must tolerate the loss of a single AZ — distribute it across AZs in two steps:
- Give the Zone a separate Node Pool in each AZ.
- Configure the workload to spread its Pods across AZs, so they land on different pools.
In this section "zonal" refers to cloud availability zones (
eu-north-1a,eu-north-1b), not Entigo Zones. Thezonerequirement key pins each Node Pool to one AZ.
The Zone below defines two on-demand pools, default-a and default-b, each pinned to a different AZ:
# Example zone
apiVersion: tenancy.entigo.com/v1alpha1
kind: Zone
metadata:
name: example-zonal
spec:
pools:
- name: default-a
requirements:
- key: instance-type
values:
- t3.large
- key: capacity-type
value: ON_DEMAND
- key: min-size
value: 1
- key: max-size
value: 1
- key: zone
values:
- eu-north-1a
- name: default-b
requirements:
- key: instance-type
values:
- t3.large
- key: capacity-type
value: ON_DEMAND
- key: min-size
value: 1
- key: max-size
value: 1
- key: zone
values:
- eu-north-1b
Then give the workload a podAntiAffinity rule with topology key topology.kubernetes.io/zone. The scheduler then places each replica in a different AZ, so the two pools above host one replica each.
The example uses requiredDuringSchedulingIgnoredDuringExecution: if no AZ is free, the replica stays Pending instead of doubling up. Switch to preferredDuringSchedulingIgnoredDuringExecution to let it schedule anyway.
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: example
name: example
spec:
replicas: 2
selector:
matchLabels:
app: example
serviceName: example
template:
metadata:
labels:
app: example
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- example
topologyKey: topology.kubernetes.io/zone
containers:
- image: nginxinc/nginx-unprivileged
name: nginx
Create a Zone Using ArgoCD
Instead of applying the manifest with kubectl, you can manage Zones through ArgoCD:
- Commit the Zone manifest (see Example of a Zone) to a Git repository.
- Create an ArgoCD
Applicationthat points at it, in thezoneproject. This project is created automatically and is the one allowed to manageZoneresources. - Sync the Application. ArgoCD applies the manifest, and the Zone's Node Pools, ArgoCDProject, and apps Namespace are provisioned.
The demo video shows this end to end.
The ArgoCD App-of-Apps Pattern
When a Zone is created, it automatically gets a Namespace named <zone-name>-apps for ArgoCD Application and ApplicationSet objects. This makes the app-of-apps pattern easy to use with Zones — without it, you would have to create this Namespace manually.
Create your ArgoCD Applications in this Namespace and let them create the subsequent Namespaces for your application resources. A few things happen automatically:
- Zone assignment — Any Namespace created by an Application in the Zone's ArgoCD project is assigned to the same Zone. (The Application's destination namespace is tracked for this.)
- Namespace metadata — An Application can set the labels and annotations of the Namespace it deploys to. See Namespace Labels and Annotations from an Application.
The apps Namespace itself is managed by the Zone:
- It cannot be moved to another Zone.
- It is deleted when the Zone is deleted, so no other resources are allowed inside it.
- To skip creating it, set
createAppsNamespacetofalsein the platform-api Helm values.
This pattern is also shown in the demo video.
Assign a Namespace to a Zone
A Namespace belongs to exactly one Zone, decided by its tenancy.entigo.com/zone label. If you omit the label, the Namespace is assigned to a default Zone; you can also set it when you create the Namespace, or change it afterwards.
Default assignment. Create a Namespace without the label and it is assigned automatically — to the Zone labelled tenancy.entigo.com/default-zone: "true", or, if no Zone has that label, to the first available Zone.
$ kubectl create ns example-ns
Change the Zone. Update the tenancy.entigo.com/zone label to move a Namespace to another Zone:
$ kubectl label ns example-ns tenancy.entigo.com/zone=another-zone --overwrite
Assign at creation. Set the labels directly on the Namespace to choose its Zone (and optionally its Pool) up front:
apiVersion: v1
kind: Namespace
metadata:
name: a2
labels:
tenancy.entigo.com/zone: example-zone
tenancy.entigo.com/pool: myspot
Pool selection. The tenancy.entigo.com/pool label schedules this Namespace's Pods onto a specific Pool. The value must name one of the Zone's own Pools — otherwise Pods are rejected as they are created, with an error listing the valid Pools.
Once the Namespace exists, its permissions are also added to the Zone's ArgoCDProject, so it can be used from ArgoCD.
Give it a moment. A Zone doesn't finish setting up a new Namespace instantly — allow a few minutes before assuming something is wrong. The objects it adds (the Namespace's permissions, and the NetworkPolicies that let a load balancer reach an Ingress's Pods) arrive shortly after the Namespace itself, because a Zone watches many objects and pauses briefly under bursts of change. Until the permissions land, actions on the new Namespace may be refused.
Assign via an ArgoCD Application. Instead of kubectl, create an Application in a Zone's project. Its destination Namespace is created automatically and assigned to the same Zone:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: a3
namespace: a-apps
spec:
destination:
server: https://kubernetes.default.svc
namespace: a3
project: example-zone
source:
...
If the a3 Namespace did not exist, it is created and assigned to the example-zone Zone.