The Security and Resource Risks of a Flat Cluster
If you run different environments (like Development, Testing, and Production) on a single cluster without boundaries, you face operational risks. For instance, developers might choose conflicting resource names, preventing workloads from launching.
Additionally, you risk accidental resource deletion. A team member attempting to clean up a test pod might run a delete command inside the wrong context and remove a production service.
There is also the threat of resource starvation. A memory leak or a runaway container in a development test environment could consume all host RAM, starving your production systems of resources.
Virtual Isolation and Quotas
Kubernetes addresses this risk using Namespaces, which act as virtual partitions inside your cluster.
By default, Kubernetes initializes with four namespaces:
* default: The home for resources created without an explicit namespace.
* kube-system: Reserved for internal control plane resources.
* kube-public: Accessible by all users, commonly used for public cluster bootstrap details.
* kube-node-lease: Holds heartbeat lease objects for active nodes.
To manage resource usage within these boundaries, you can configure a ResourceQuota to limit the total CPU, memory, or object counts allowed inside a namespace. You can also configure a LimitRange to apply default resource requests and limits to individual containers if a developer forgets to specify them:
* Default Request: The baseline memory/CPU allocated to a container when it launches.
* Default Limit: The maximum limit the container can consume before being throttled (CPU) or terminated with an Out of Memory (OOM) error (memory).
For service discovery, pods within the same namespace resolve services using short names (e.g., db-service). To access a service in a different namespace, append the namespace name to resolve the domain:
<service-name>.<namespace-name>.svc.cluster.local
Creating and Restricting a Namespace
Let’s create a namespace and apply resource restrictions. First, create the namespace:
$ kubectl create namespace engineering
namespace/engineering created
Now, let’s configure a quota to limit the namespace to a maximum of two pods, two CPUs, and 4GB of RAM. Save the following configuration as quota.yaml:
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: engineering
spec:
hard:
pods: "2"
requests.cpu: "1"
requests.memory: 2Gi
limits.cpu: "2"
limits.memory: 4Gi
Apply the quota:
$ kubectl apply -f quota.yaml
resourcequota/team-quota created
Inspect the quota status inside the namespace:
$ kubectl get resourcequota -n engineering
NAME AGE REQUEST LIMIT
team-quota 10s pods: 0/2, ...
If you attempt to launch a third pod in the engineering namespace, the admission controller will block the request and return a quota exceeded error.
To configure default resource limits for containers in this namespace, save the following as limitrange.yaml:
apiVersion: v1
kind: LimitRange
metadata:
name: container-limits
namespace: engineering
spec:
limits:
- default:
memory: 512Mi
cpu: 500m
defaultRequest:
memory: 256Mi
cpu: 250m
type: Container
Apply the LimitRange:
$ kubectl apply -f limitrange.yaml
limitrange/container-limits created
To avoid typing the -n engineering flag with every command, you can change your active namespace context:
$ CONTEXT=$(kubectl config current-context)
$ kubectl config set-context $CONTEXT --namespace=engineering
Context "minikube" modified.
Now, running commands like kubectl get pods will automatically target the engineering namespace. To switch back to the default namespace context, run:
$ kubectl config set-context $CONTEXT --namespace=default

