skip to content

What are the Kubernetes built-in namespaces default, kube-system, kube-public and kube-node-lease for, and which namespace does kubectl use without -n?

level: juniorimportance: should knowfreq 50%

answer

  1. four namespaces a cluster makes itself
  2. one is a fallback, one is public
  3. heartbeat Leases per node
  4. flag, then context, then fallback
  5. NamespaceLifecycle guards deletion

basics

~10 s

Kubernetes creates default for objects with no namespace, kube-system for control-plane and add-on components, kube-public for world-readable data, and kube-node-lease for node heartbeat Leases. Without -n, kubectl uses the kubeconfig context's namespace, else default.

solid answer

~40 s

A fresh cluster has four system namespaces. `default` is where objects land when nothing names a namespace, and it holds the `kubernetes` Service that fronts the API server. `kube-system` holds components the cluster itself runs: CoreDNS, kube-proxy and, on kubeadm clusters, the control-plane static pods. `kube-public` is meant to be readable by everyone; kubeadm keeps the `cluster-info` ConfigMap there and lets anonymous clients read it for node bootstrap. `kube-node-lease` holds one `Lease` per node, which the kubelet renews every 10 seconds by default as a cheap heartbeat. kubectl picks a namespace in this order: the `-n`/`--namespace` flag, then the current kubeconfig context's `namespace`, then `default`. The API server recreates these namespaces if they go missing, and refuses to delete `default`, `kube-system` and `kube-public`.

code

bash · 4 lines
bash
kubectl get namespaces
kubectl get leases -n kube-node-lease
kubectl config set-context --current --namespace=records-dev
kubectl get pods

go deeper

for a junior

Recall the four system namespaces and one thing each holds, and the order kubectl uses to choose a namespace when -n is missing.

for a middle

Explain why node heartbeats are Leases, how kubeadm uses kube-public for discovery, and how a manifest's own namespace interacts with the -n flag.

for a senior

Show the operational habits: no workloads in default or kube-system, context namespaces set per environment, and watching for objects that land in default by accident.

for a principal

Treat the system namespaces as the platform's reserved space and decide which of them tenants may read, and how an accidental default deployment is caught.

## The four system namespaces When a Kubernetes API server starts, it makes sure a small set of **system namespaces** exists and recreates any that are missing. On a current cluster there are four. | Namespace | What lives there | Who should put things there | |---|---|---| | `default` | Objects created without a namespace; the `kubernetes` Service for the API server | Nobody on purpose in a shared cluster | | `kube-system` | CoreDNS, kube-proxy, network-plugin agents, control-plane static pods on kubeadm clusters | Cluster operators only | | `kube-public` | Data meant to be readable by every client, such as kubeadm's `cluster-info` ConfigMap | Cluster tooling | | `kube-node-lease` | One `Lease` object per node, used as a heartbeat | The kubelet | ### default `default` is the fallback. A manifest without `metadata.namespace`, applied from a kubeconfig context with no namespace set, ends up here. It also contains the `kubernetes` Service, the in-cluster address of the API server. In a team cluster, workloads in `default` are usually a sign that someone forgot `-n`, and platform teams often block or watch it. ### kube-system `kube-system` is for the cluster's own components. On a kubeadm cluster, and on most laptop clusters built the same way, you find: - the control-plane static pods (`kube-apiserver`, `kube-controller-manager`, `kube-scheduler`, `etcd`), whose manifests the kubelet reads from disk; - the DNS add-on (CoreDNS) and `kube-proxy`; - the network plugin's agents and other add-ons. Leader-election Leases for kube-controller-manager and kube-scheduler also live here. Application workloads do not belong in `kube-system`: its ServiceAccounts often hold broad permissions, and mixing app pods in makes those permissions easier to misuse. ### kube-public `kube-public` is a convention: a place for information any client may read. kubeadm creates the `cluster-info` ConfigMap there, holding the cluster CA certificate and API server address, and binds the anonymous user to a Role that can read that one ConfigMap. A joining node can then discover the cluster before it has credentials. Nothing secret belongs in this namespace. ### kube-node-lease Each node has a `Lease` object here, named after the node. The kubelet renews it every 10 seconds by default, a quarter of its 40-second lease duration. A Lease update is far smaller than rewriting the whole `Node` status, so the node lifecycle controller uses Lease renewals as the main "this node is alive" signal on large clusters. ## Deletion protection The **NamespaceLifecycle** admission plugin in kube-apiserver rejects a delete of `default`, `kube-system` or `kube-public` with the message `this namespace may not be deleted`. `kube-node-lease` is not on that list, but the API server runs its own check every minute and recreates any missing system namespace, so a deleted `kube-node-lease` comes back once its deletion completes. The lifecycle of ordinary namespaces, including a namespace stuck in `Terminating`, is a separate subject. ## How kubectl picks a namespace For namespaced resources, kubectl resolves the namespace in a fixed order: 1. The `-n` / `--namespace` flag on the command line. 2. The `namespace` field of the current context in the kubeconfig. 3. The literal `default`. Two details trip people up: - A manifest that sets `metadata.namespace` **wins over the context** when you pass no `-n`. If you pass `-n` with a different value, kubectl refuses with an error saying the namespace in the object does not match the namespace given. - `-A` (`--all-namespaces`) lists across every namespace and ignores both the flag and the context. To stop typing `-n` on a laptop cluster, set the context namespace once: ```bash kubectl config set-context --current --namespace=records-dev kubectl config view --minify -o jsonpath='{..namespace}' ``` The second command prints the namespace the current context now uses. ## Practical habits - Create a namespace per application or environment (`records-dev`, `records-review`) instead of using `default`. - Treat `kube-system` as off-limits for application pods. - Never store anything sensitive in `kube-public`. - Leave `kube-node-lease` alone; its objects are the node heartbeat. - On a laptop cluster, make the context namespace part of your prompt or shell setup, so it is always visible which namespace a bare `kubectl` command will touch. Most "my pod disappeared" moments on a single-node dev cluster are a command that ran against `default` or against the wrong context namespace.

  • Why does Kubernetes keep node heartbeats as Lease objects in kube-node-lease rather than only in Node status?
    A `Lease` is a tiny object, so renewing it every 10 seconds costs far less in API server and etcd traffic than rewriting a large `Node` status. The kubelet still updates Node status, but less often. The node lifecycle controller treats Lease renewals as the main liveness signal, which scales much better on clusters with many nodes.
  • Is it acceptable to deploy application workloads into the Kubernetes kube-system namespace?
    No. `kube-system` holds cluster components whose ServiceAccounts often carry broad permissions. Application pods there are easier to escalate from, harder to audit, and get caught by policies meant for system add-ons. Put applications in their own namespaces, so quotas, RBAC and network rules can be applied to them separately.

saying these in an interview costs you the question

  • kube-public is a safe place for shared credentials
  • kubectl always uses default unless you pass -n
  • Application pods can go in kube-system if they are important
  • kube-node-lease stores the kubelet's TLS certificates
  • Deleting default is a quick way to clean up a dev cluster