Learning Kubernetes - Episode 8 - Introduction and Explanation of Namespace Object

Learning Kubernetes - Episode 8 - Introduction and Explanation of Namespace Object

In this episode, we'll discuss an important concept in Kubernetes called Namespaces. We'll learn how to use Namespaces to divide cluster resources between multiple users or teams.

Arman Dwi Pangestu
Arman Dwi PangestuMarch 11, 2026
0 views
10 min read

Introduction

Note

If you want to read the previous episode, you can click the Episode 7 thumbnail below

Episode 7Episode 7

In the previous episode, we learned deeply about the Annotation object in Kubernetes. In episode 8, we'll discuss another fundamental concept in Kubernetes: Namespaces.

Note: Here I'll be using a Kubernetes Cluster installed through K3s.

Namespaces are a way to divide cluster resources between multiple users, teams, or projects. They provide a scope for names and allow you to organize and isolate resources within a single cluster. Understanding Namespaces is crucial for managing multi-tenant clusters and organizing resources effectively.

What Are Namespaces?

A Namespace is a virtual cluster within a physical Kubernetes cluster. It provides a way to divide cluster resources between multiple users or teams. Namespaces are intended for use in environments with many users spread across multiple teams or projects.

Think of Namespaces like folders on your computer. Just as folders help you organize files into logical groups, Namespaces help you organize Kubernetes resources into logical groups. For example, you might have separate Namespaces for development, staging, and production environments, or separate Namespaces for different teams or projects.

Namespaces provide:

  • Resource isolation - Resources in one Namespace are isolated from resources in other Namespaces
  • Name scoping - Resource names need to be unique within a Namespace, but not across Namespaces
  • Resource quotas - You can set resource limits per Namespace
  • Access control - You can apply different RBAC policies to different Namespaces
  • Organization - Logical grouping of resources for better management

Namespace Characteristics

Key characteristics of Namespaces:

  • Names must be unique - Each Namespace must have a unique name within the cluster
  • Not all objects are namespaced - Some resources like Nodes, PersistentVolumes, and Namespaces themselves are cluster-scoped
  • Cannot be nested - You cannot create a Namespace inside another Namespace
  • Deletion cascades - Deleting a Namespace deletes all resources within it
  • DNS integration - Services get DNS names that include the Namespace

Why Do We Need Namespaces?

You might wonder why we need Namespaces when we already have Labels for organizing resources. The key differences are:

  • Labels are for grouping and selecting resources - they don't provide isolation
  • Namespaces provide actual isolation and separate scopes for resources

Consider this scenario: You have a development team and a production team both deploying applications to the same cluster. Without Namespaces, they might accidentally overwrite each other's resources if they use the same names. With Namespaces, each team can have their own isolated environment within the same cluster.

Another important use case is resource quotas. You can set limits on how much CPU, memory, and storage each Namespace can use. This prevents one team or project from consuming all cluster resources.

Default Namespaces

When you create a Kubernetes cluster, it comes with several default Namespaces:

default Namespace

The default Namespace is where resources are created if you don't specify a Namespace. When you run kubectl get pods without specifying a Namespace, you're querying the default Namespace.

Kubernetesbash
# This queries the default Namespace
sudo kubectl get pods

kube-system Namespace

The kube-system Namespace contains resources created by the Kubernetes system itself. This includes system components like the DNS server, metrics server, and other control plane components.

Kubernetesbash
# View system components
sudo kubectl get pods -n kube-system

Warning

Be careful when working with resources in the kube-system Namespace. Deleting or modifying these resources can break your cluster.

kube-public Namespace

The kube-public Namespace is readable by all users (including unauthenticated users). It's typically used for resources that should be publicly accessible across the cluster.

Kubernetesbash
# View public resources
sudo kubectl get all -n kube-public

kube-node-lease Namespace

The kube-node-lease Namespace holds lease objects associated with each node. Node leases allow the kubelet to send heartbeats so the control plane can detect node failures.

Kubernetesbash
# View node leases
sudo kubectl get leases -n kube-node-lease

Viewing Namespaces

Let's learn how to view Namespaces in your cluster:

List All Namespaces

To view all Namespaces in your cluster:

Kubernetesbash
sudo kubectl get namespaces

Or use the shorthand:

Kubernetesbash
sudo kubectl get ns

The output will look like this:

Kubernetesbash
NAME              STATUS   AGE
default           Active   45d
kube-node-lease   Active   45d
kube-public       Active   45d
kube-system       Active   45d

View Namespace Details

To see detailed information about a specific Namespace:

Kubernetesbash
sudo kubectl describe namespace default

The output will show:

Kubernetesbash
Name:         default
Labels:       kubernetes.io/metadata.name=default
Annotations:  <none>
Status:       Active
 
No resource quota.
 
No LimitRange resource.

View Resources in a Namespace

To view resources in a specific Namespace, use the -n or --namespace flag:

Kubernetesbash
# View Pods in kube-system Namespace
sudo kubectl get pods -n kube-system
 
# View all resources in a Namespace
sudo kubectl get all -n kube-system

To view resources across all Namespaces, use the --all-namespaces or -A flag:

Kubernetesbash
# View all Pods in all Namespaces
sudo kubectl get pods --all-namespaces
 
# Or use the shorthand
sudo kubectl get pods -A

Creating Namespaces

There are two main ways to create Namespaces:

Method 1: Using kubectl Command

The quickest way to create a Namespace is using the kubectl create namespace command:

Kubernetesbash
sudo kubectl create namespace development

Or use the shorthand:

Kubernetesbash
sudo kubectl create ns staging

Method 2: Using YAML Configuration

You can also create a Namespace using a YAML configuration file:

Kubernetesnamespace.yml
apiVersion: v1
kind: Namespace
metadata:
    name: production
    labels:
        environment: production
        team: platform

Apply the configuration:

Kubernetesbash
sudo kubectl apply -f namespace.yml

Creating Namespace with Labels and Annotations

You can add Labels and Annotations to Namespaces for better organization:

Kubernetesnamespace-with-metadata.yml
apiVersion: v1
kind: Namespace
metadata:
    name: backend-team
    labels:
        team: backend
        environment: production
        cost-center: engineering
    annotations:
        description: "Namespace for backend team production workloads"
        contact: "backend-team@company.com"
        created-by: "platform-team"

Working with Namespaces

Creating Resources in a Namespace

When creating resources, you can specify the Namespace in two ways:

Method 1: In the YAML configuration

Kubernetespod-in-namespace.yml
apiVersion: v1
kind: Pod
metadata:
    name: nginx-pod
    namespace: development
spec:
    containers:
        - name: nginx
          image: nginx
          ports:
              - containerPort: 80

Method 2: Using kubectl flag

Kubernetesbash
sudo kubectl apply -f pod.yml -n development

Setting Default Namespace

Instead of specifying the Namespace every time, you can set a default Namespace for your kubectl context:

Kubernetesbash
# Set default Namespace to development
sudo kubectl config set-context --current --namespace=development

Now all kubectl commands will use the development Namespace by default:

Kubernetesbash
# This will query the development Namespace
sudo kubectl get pods

To switch back to the default Namespace:

Kubernetesbash
sudo kubectl config set-context --current --namespace=default

Viewing Current Namespace

To see which Namespace is currently set as default:

Kubernetesbash
sudo kubectl config view --minify | grep namespace:

Practical Example: Multi-Environment Setup

Let's create a practical example where we set up multiple Namespaces for different environments:

Step 1: Create Namespaces for Different Environments

Create a file named environments.yml:

Kubernetesenvironments.yml
apiVersion: v1
kind: Namespace
metadata:
    name: development
    labels:
        environment: development
    annotations:
        description: "Development environment"
---
apiVersion: v1
kind: Namespace
metadata:
    name: staging
    labels:
        environment: staging
    annotations:
        description: "Staging environment"
---
apiVersion: v1
kind: Namespace
metadata:
    name: production
    labels:
        environment: production
    annotations:
        description: "Production environment"

Apply the configuration:

Kubernetesbash
sudo kubectl apply -f environments.yml

Step 2: Deploy Applications to Different Namespaces

Create a file named app-deployments.yml:

Kubernetesapp-deployments.yml
# Development deployment
apiVersion: v1
kind: Pod
metadata:
    name: web-app
    namespace: development
    labels:
        app: web
        environment: development
spec:
    containers:
        - name: nginx
          image: nginx:1.25
          ports:
              - containerPort: 80
---
# Staging deployment
apiVersion: v1
kind: Pod
metadata:
    name: web-app
    namespace: staging
    labels:
        app: web
        environment: staging
spec:
    containers:
        - name: nginx
          image: nginx:1.25
          ports:
              - containerPort: 80
---
# Production deployment
apiVersion: v1
kind: Pod
metadata:
    name: web-app
    namespace: production
    labels:
        app: web
        environment: production
spec:
    containers:
        - name: nginx
          image: nginx:1.25
          ports:
              - containerPort: 80

Apply the configuration:

Kubernetesbash
sudo kubectl apply -f app-deployments.yml

Step 3: Verify Deployments

Now we have the same Pod name (web-app) in three different Namespaces:

Kubernetesbash
# View Pods in development
sudo kubectl get pods -n development
 
# View Pods in staging
sudo kubectl get pods -n staging
 
# View Pods in production
sudo kubectl get pods -n production
 
# View all Pods across all Namespaces
sudo kubectl get pods -A | grep web-app

The output will show:

Kubernetesbash
NAMESPACE     NAME      READY   STATUS    RESTARTS   AGE
development   web-app   1/1     Running   0          2m
staging       web-app   1/1     Running   0          2m
production    web-app   1/1     Running   0          2m

Tip

Notice how we can have resources with the same name in different Namespaces. This is one of the key benefits of using Namespaces.

DNS and Namespaces

Kubernetes DNS automatically creates DNS records for Services. The DNS name includes the Namespace, allowing Services to communicate across Namespaces.

DNS Name Format

Services get DNS names in this format:

plaintext
<service-name>.<namespace>.svc.cluster.local

For example:

  • web-service.development.svc.cluster.local
  • web-service.production.svc.cluster.local

Accessing Services Across Namespaces

Within the same Namespace, you can use the short name:

Tip

To try to access the domain, you can enter the pod/container shell by running the following command:

bash
sudo kubectl exec -it web-app -n development -- bash

After that, you can install network tools such as dnsutils, iputils-ping, and curl

bash
apt update
apt install dnsutils iputils-ping curl -y

So the result when an http request uses curl is to return the HTML content from the nginx page.

bash
# Method 1
curl http://web-service
# Method 2
curl http://web-service.production
# Method 3
curl http://web-service.production.svc.cluster.local
bash
curl http://web-service

Across Namespaces, you need to use the full DNS name:

bash
curl http://web-service.production.svc.cluster.local

Example: Cross-Namespace Communication

Create Services in different Namespaces:

Kubernetesservices.yml
apiVersion: v1
kind: Service
metadata:
    name: web-service
    namespace: development
spec:
    selector:
        app: web
    ports:
        - protocol: TCP
          port: 80
          targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
    name: web-service
    namespace: production
spec:
    selector:
        app: web
    ports:
        - protocol: TCP
          port: 80
          targetPort: 80

Now a Pod in the development Namespace can access the Service in the production Namespace:

Kubernetesbash
# From a Pod in development Namespace
curl http://web-service.production.svc.cluster.local

Resource Quotas and Namespaces

One of the most powerful features of Namespaces is the ability to set resource quotas. This prevents any single Namespace from consuming all cluster resources.

Creating a ResourceQuota

Create a file named resource-quota.yml:

Kubernetesresource-quota.yml
apiVersion: v1
kind: ResourceQuota
metadata:
    name: compute-quota
    namespace: development
spec:
    hard:
        requests.cpu: "4"
        requests.memory: 8Gi
        limits.cpu: "8"
        limits.memory: 16Gi
        pods: "10"

This quota limits the development Namespace to:

  • Maximum 4 CPU cores requested
  • Maximum 8Gi memory requested
  • Maximum 8 CPU cores limit
  • Maximum 16Gi memory limit
  • Maximum 10 Pods

Apply the quota:

Kubernetesbash
sudo kubectl apply -f resource-quota.yml

Viewing Resource Quotas

To view resource quotas in a Namespace:

Kubernetesbash
sudo kubectl get resourcequota -n development

For detailed information:

Kubernetesbash
sudo kubectl describe resourcequota compute-quota -n development

The output will show:

Kubernetesbash
Name:            compute-quota
Namespace:       development
Resource         Used  Hard
--------         ----  ----
limits.cpu       0     8
limits.memory    0     16Gi
pods             1     10
requests.cpu     0     4
requests.memory  0     8Gi

Example: ResourceQuota in Action

When you try to create a Pod that exceeds the quota, it will be rejected:

Kuberneteslarge-pod.yml
apiVersion: v1
kind: Pod
metadata:
    name: large-pod
    namespace: development
spec:
    containers:
        - name: app
          image: nginx
          resources:
              requests:
                  cpu: "5"
                  memory: 10Gi
              limits:
                  cpu: "10"
                  memory: 20Gi

Applying this will fail:

Kubernetesbash
sudo kubectl apply -f large-pod.yml

Error message:

Kubernetesbash
Error from server (Forbidden): error when creating "large-pod.yml": pods "large-pod" is forbidden: exceeded quota: compute-quota, requested: requests.cpu=5,requests.memory=10Gi, used: requests.cpu=0,requests.memory=0, limited: requests.cpu=4,requests.memory=8Gi

LimitRange and Namespaces

LimitRange allows you to set default resource limits for containers in a Namespace. This is useful when developers forget to specify resource limits.

Creating a LimitRange

Create a file named limit-range.yml:

Kuberneteslimit-range.yml
apiVersion: v1
kind: LimitRange
metadata:
    name: resource-limits
    namespace: development
spec:
    limits:
        - default:
              cpu: "500m"
              memory: 512Mi
          defaultRequest:
              cpu: "250m"
              memory: 256Mi
          max:
              cpu: "2"
              memory: 2Gi
          min:
              cpu: "100m"
              memory: 128Mi
          type: Container

This LimitRange sets:

  • Default limits: 500m CPU, 512Mi memory
  • Default requests: 250m CPU, 256Mi memory
  • Maximum: 2 CPU, 2Gi memory
  • Minimum: 100m CPU, 128Mi memory

Apply the LimitRange:

Kubernetesbash
sudo kubectl apply -f limit-range.yml

Now any Pod created in the development Namespace without resource specifications will automatically get these defaults.

Deleting Namespaces

To delete a Namespace:

Kubernetesbash
sudo kubectl delete namespace development

Warning

Deleting a Namespace will delete ALL resources within it. This action cannot be undone. Always double-check before deleting a Namespace.

You can also delete using a YAML file:

Kubernetesbash
sudo kubectl delete -f namespace.yml

Namespace Deletion Process

When you delete a Namespace:

  1. The Namespace enters a Terminating state
  2. Kubernetes deletes all resources within the Namespace
  3. Once all resources are deleted, the Namespace itself is removed

You can check the status:

Kubernetesbash
sudo kubectl get namespace development

Output during deletion:

Kubernetesbash
NAME          STATUS        AGE
development   Terminating   5m

Common Mistakes and Pitfalls

Mistake 1: Not Specifying Namespace

Forgetting to specify the Namespace when working with resources can lead to confusion.

Problem: You create a resource but can't find it because it's in a different Namespace.

Solution: Always specify the Namespace explicitly or set a default Namespace for your context.

Mistake 2: Using Namespaces for Network Isolation

Namespaces provide logical isolation, not network isolation. Pods in different Namespaces can still communicate by default.

Solution: Use NetworkPolicies for actual network isolation between Namespaces.

Mistake 3: Creating Too Many Namespaces

Creating too many Namespaces can make cluster management complex.

Solution: Use Namespaces for major divisions (teams, environments) and use Labels for finer-grained organization.

Mistake 4: Not Setting Resource Quotas

Without resource quotas, one Namespace can consume all cluster resources.

Solution: Always set ResourceQuotas for production Namespaces.

Mistake 5: Hardcoding Namespace Names

Hardcoding Namespace names in application code makes it difficult to deploy to different environments.

Solution: Use environment variables or configuration files to specify Namespace names.

Best Practices for Using Namespaces

Use Namespaces for Environment Separation

Create separate Namespaces for different environments:

Kubernetesbash
sudo kubectl create namespace dev
sudo kubectl create namespace staging
sudo kubectl create namespace prod

Use Namespaces for Team Separation

Create separate Namespaces for different teams:

Kubernetesbash
sudo kubectl create namespace team-backend
sudo kubectl create namespace team-frontend
sudo kubectl create namespace team-data

Always Set Resource Quotas

Set resource quotas for every Namespace to prevent resource exhaustion:

Kubernetesquota-template.yml
apiVersion: v1
kind: ResourceQuota
metadata:
    name: namespace-quota
    namespace: <namespace-name>
spec:
    hard:
        requests.cpu: "10"
        requests.memory: 20Gi
        limits.cpu: "20"
        limits.memory: 40Gi
        pods: "50"
        services: "20"
        persistentvolumeclaims: "10"

Use Labels for Namespace Organization

Add Labels to Namespaces for better organization:

Kubernetesyml
apiVersion: v1
kind: Namespace
metadata:
    name: production
    labels:
        environment: production
        team: platform
        cost-center: engineering
        compliance: pci-dss

Document Namespace Purpose

Use Annotations to document the purpose of each Namespace:

Kubernetesyml
apiVersion: v1
kind: Namespace
metadata:
    name: production
    annotations:
        description: "Production environment for customer-facing applications"
        contact: "platform-team@company.com"
        oncall: "https://oncall.company.com/platform"
        runbook: "https://runbook.company.com/production"

Use Naming Conventions

Establish consistent naming conventions for Namespaces:

  • <team>-<environment> (e.g., backend-prod, frontend-dev)
  • <project>-<environment> (e.g., web-app-staging, api-prod)
  • <environment> (e.g., development, staging, production)

Implement RBAC per Namespace

Use Role-Based Access Control (RBAC) to control who can access each Namespace:

Kubernetesnamespace-rbac.yml
apiVersion: v1
kind: Namespace
metadata:
    name: team-backend
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
    name: developer
    namespace: team-backend
rules:
    - apiGroups: ["", "apps"]
      resources: ["pods", "deployments", "services"]
      verbs: ["get", "list", "create", "update", "delete"]

When NOT to Use Namespaces

While Namespaces are useful, there are cases where you shouldn't use them:

  • Small clusters - If you have a small cluster with few resources, Namespaces might add unnecessary complexity
  • Single team - If only one team uses the cluster, Namespaces might not be necessary
  • Network isolation - Don't rely on Namespaces for network security. Use NetworkPolicies instead
  • Fine-grained organization - For organizing resources within a team or project, use Labels instead

Conclusion

In episode 8, we've explored the Namespace concept in Kubernetes in depth. We've learned what Namespaces are, why they're important, how to create and manage them, and best practices for using them effectively.

Namespaces are a fundamental feature for organizing and isolating resources in Kubernetes clusters. They enable multi-tenancy, resource quotas, and logical separation of environments. By understanding Namespaces, you can manage complex clusters with multiple teams, projects, and environments more effectively.

Key takeaways:

  • Namespaces provide logical isolation and name scoping
  • Use Namespaces for environment and team separation
  • Always set ResourceQuotas to prevent resource exhaustion
  • Combine Namespaces with Labels and RBAC for complete resource management
  • DNS names include Namespace for cross-Namespace communication

Are you getting a clearer understanding of Namespaces in Kubernetes? In the next episode 9, we'll discuss Pod Deletion.

Note

If you want to continue reading, you can click the Episode 9 thumbnail below

Episode 9Episode 9

Related Posts