etcd Compaction and Defragmentation in Kubernetes

etcd Compaction and Defragmentation in Kubernetes

Why the database behind your cluster keeps growing even when you delete things, how compaction forgets old history, and why only defragmentation gives the disk space back.

Imagine a diary in which you are never allowed to erase anything. When a fact changes, you do not scratch out the old line. You turn to a fresh page, write the new fact, and keep the old page exactly as it was. After a year, the diary is thick with pages that nobody will ever read again, yet every one of them still takes up room on the shelf.

Kubernetes keeps its entire state in a database called etcd, and etcd behaves much like that diary. Every change to every Pod, Node, Secret and ConfigMap is written as a new version. Old versions stay behind. Left alone, the database swells until one day it hits a size limit and the whole cluster stops accepting changes. Two housekeeping jobs prevent this: compaction, which forgets old versions, and defragmentation, which hands the freed space back to the disk. They sound alike but do very different things, and mixing them up is one of the most common causes of etcd trouble.

In this guide you will learn how etcd stores history, what exactly each job does, why compaction alone never shrinks the file, how to run both safely in a live cluster, and how to watch for the warning signs. Every new word is explained the first time it appears, and nothing is assumed.

1What Are Compaction and Defragmentation?

Two jobs, one goal: keep the database small, fast and healthy.

etcd (pronounced “et-see-dee”) is a small, reliable database that stores key-value pairs. A key is a name, such as the address of a Pod, and a value is the data saved under that name. Kubernetes uses etcd as its single source of truth. If etcd were lost, the cluster would forget every Deployment, Service, Secret and Node it ever knew about.

Because etcd never overwrites data in place, it needs two clean-up operations.

Job 1

Compaction

A logical clean-up. It tells etcd to forget every old version of every key older than a chosen point in time, keeping only the latest value of each key. It frees space inside the database file but does not make the file smaller.

Job 2

Defragmentation

A physical clean-up. It rewrites the database file without the empty gaps that compaction left behind, and returns that room to the operating system. This is the step that actually shrinks the file on disk.

Everyday analogy

Think of a thick ring binder where every update to a form is a new sheet. Compaction is pulling out all the old, superseded sheets and throwing them away. The binder now has loose gaps between the sheets that remain, but it is still the same fat binder. Defragmentation is taking the remaining sheets, putting them into a fresh slim binder with no gaps, and returning the big one to the shelf. You need the first step to create the free space and the second to make it count.

2
separate clean-up jobs with different effects
2 GiB
default size limit before etcd stops accepting writes
5 min
default interval at which the API server asks etcd to compact

The one-sentence difference

Compaction decides what history to forget. Defragmentation decides how much disk space to give back. Forgetting never gives anything back by itself.

2Why etcd Needs Both Jobs

etcd keeps history on purpose

Most databases overwrite a value when it changes. etcd does not. It uses a design called multi-version concurrency control, usually shortened to MVCC. Each change creates a new revision, a number that always goes up. The old value stays readable under its old revision. This is not a flaw. It is what makes two of etcd’s most important abilities possible.

  • Watching. A client can say “tell me everything that changed since revision 5000”. etcd can answer only because it still remembers what happened after that point. Kubernetes controllers rely on this all day long.
  • Consistent reads. A client can read the state of many keys as they were at one exact revision, so it never sees a half-updated picture.

But history is not free

If nobody ever removes old revisions, the database grows forever. A busy Kubernetes cluster writes constantly: nodes report their health every few seconds, controllers update the status of thousands of objects, and Pods start and stop all day. Each of those writes adds another revision. Even if the number of live objects stays the same, the stored history keeps piling up.

!
Why deleting objects does not help

When you delete a Pod, etcd records the delete as one more revision. The earlier versions of that Pod remain in history until compaction removes them. So “I deleted lots of things, why is etcd still huge?” is a very common and very reasonable question.

The size limit makes this urgent

etcd has a built-in ceiling on the size of its database file, called the backend quota. The default is two gibibytes (GiB), and the project suggests staying well below eight. When the file reaches the quota, etcd raises an alarm and refuses every write except deletes. For a Kubernetes cluster, refusing writes is a disaster. No new Pods can be created, no status can be updated, and controllers cannot do their jobs. The cluster is effectively frozen in place, although workloads already running keep running.

Without compaction history never ends. Without defragmentation the disk never gets the space back.

Why two jobs and not one

Separating the jobs is a deliberate engineering choice. Compaction is cheap and safe to run often, because it only marks data as removable. Defragmentation is heavy: it rewrites the whole file and briefly pauses the member that is doing it. So the first is run constantly and automatically, and the second is run occasionally and with care. Understanding that difference is the heart of this topic.

3Core Concepts You Must Know First

A short vocabulary makes everything after this much easier.

Key, value and revision

A key is a name and a value is the data stored under it. In Kubernetes, the keys live under a prefix called /registry, for example a key for one Pod in one namespace. A revision is a cluster-wide counter that increases by one with every successful change anywhere in the database. Every version of every key is tagged with the revision at which it was written.

Tombstone

When a key is deleted, etcd does not erase it. It writes a small marker called a tombstone at a new revision. The tombstone says “this key stopped existing here”. Compaction later removes both the tombstone and the old versions behind it.

Backend and bbolt

etcd keeps the actual data in a single file on disk, called the backend. The storage engine that manages the file is a library named bbolt. It organises data in fixed-size blocks called pages and uses a copy-on-write approach: when something changes, it writes new pages and abandons the old ones rather than editing them. This is where fragmentation originates.

Free pages and the freelist

When compaction deletes old revisions, the pages that held them are no longer needed. bbolt records these pages in a list called the freelist and reuses them for future writes. The pages stay inside the file, so the file does not shrink. This is the central fact of the whole article.

Raft, members and leader

A production etcd runs as a group of members, usually three or five. They agree on every change using the Raft consensus protocol, which means a change counts only when a majority of members have recorded it. One member is the leader and handles the ordering of writes. Each member keeps its own copy of the database file, and so each has its own fragmentation. That is why defragmentation is done member by member.

Quota and alarm

The quota is the maximum size of the backend file. The alarm is a flag, named NOSPACE, that etcd raises when the quota is reached. While it is on, the cluster accepts reads and deletes only.

TermPlain-words meaningWhy it matters here
RevisionA number that goes up with every changeThe “point in time” used to decide what to forget
MVCCKeeping many versions of each keyCause of growth and the reason compaction exists
CompactionForgetting versions older than a revisionCreates reusable free space inside the file
FragmentationFree gaps scattered inside the fileMakes the file larger than the data it holds
DefragmentationRewriting the file without the gapsReturns space to the operating system
QuotaMaximum allowed file sizeHitting it stops all writes
SnapshotA point-in-time backup of the databaseTaken before risky maintenance
WatchA stream of changes from a given revisionAffected when old revisions are compacted
i
Tip

When you read about etcd size, always ask two questions: how big is the file, and how much of it is actually in use? The gap between the two is the fragmentation, and it is the number that tells you whether defragmentation will help.

4Architecture: Where etcd Sits in Kubernetes

Only one component talks to etcd directly. Seeing this makes it clear who triggers what.

In Kubernetes the kube-apiserver is the only component that reads and writes etcd. The scheduler, the controllers and the kubelets all go through the API server. The API server sends requests to etcd over a secure connection, and etcd replicates each write across its members before confirming.

flowchart TB
  KUBECTL["kubectl, controllers, kubelets"] --> API["kube-apiserver replicas"]
  API -->|"gRPC with TLS"| E1["etcd member 1: leader"]
  API --> E2["etcd member 2"]
  API --> E3["etcd member 3"]
  E1 |"Raft replication"| E2
  E1 |"Raft replication"| E3
  E2 |"Raft replication"| E3
  E1 --> W1["WAL log and bbolt database file"]
  E2 --> W2["WAL log and bbolt database file"]
  E3 --> W3["WAL log and bbolt database file"]
  API -.->|"compact request about every 5 minutes"| E1
  OPS["Operator or automation"] -.->|"defragment one member at a time"| E2
    
Figure 1. etcd inside a Kubernetes control plane, and who triggers each clean-up

Reading the picture

1

The API server is the only client

Every object you create or change passes through it. It translates your request into etcd writes and reads.

2

The leader orders writes, all members store them

A write is accepted once a majority have it. Each member then applies it to its own database file.

3

Compaction is a cluster-wide, replicated action

The compact request goes through Raft like any write, so every member forgets the same revisions at the same logical moment.

4

Defragmentation is local to one member

It is not replicated. Each member rewrites only its own file, and it must be repeated for every member that needs it.

Two different kinds of “log”

Newcomers often confuse compaction with the clean-up of etcd’s write-ahead log. The write-ahead log, or WAL, is a sequential diary of changes used for crash recovery, and etcd trims it automatically by taking periodic snapshots. That is a separate mechanism. The compaction in this article concerns the versions of keys inside the database, not the recovery log.

i
Good to know

On managed services such as GKE, EKS and AKS, the provider runs etcd for you and performs this maintenance. You cannot log in to etcd there. This guide matters most when you run your own control plane, for example with kubeadm, on virtual machines or on bare metal, and it also explains the symptoms you may hear about from a provider.

5How etcd Stores History: A Small Worked Picture

Follow one key through five changes and watch the revisions pile up.

Suppose the cluster starts empty and the revision counter is at 100. A Deployment’s replica count is stored in a key. Here is what happens over a few minutes.

RevisionWhat happenedWhat etcd stores for this key
101Deployment created with 3 replicasVersion 1: three replicas
102Another unrelated object changedNothing new for this key
103Scaled up to 5 replicasVersion 2: five replicas
104Status updated by a controllerVersion 3: five replicas, new status
105Scaled to 4 replicasVersion 4: four replicas
106Deployment deletedTombstone marker

At revision 106 the Deployment is gone from the point of view of Kubernetes. Yet etcd still holds four versions plus a tombstone for that key. Nothing was lost, and nothing was freed.

What compaction does to this history

Say someone asks etcd to compact at revision 105. etcd then removes every version that is older than revision 105 and is not the newest version at or before it. The rule keeps the latest value as of revision 105, because that is what a reader at revision 105 would see. Older versions are dropped. The result: versions 1, 2 and 3 vanish, version 4 is kept for now, and the tombstone at 106 is newer than the compaction point so it stays. After the next compaction at a later revision, version 4 and the tombstone disappear too, and the key has fully left the database.

!
Important consequence

Once compacted, a revision cannot be read again. A client that asks for history older than the compaction point receives an error saying the required revision has been compacted. Well-written clients, including Kubernetes components, handle this by starting afresh. Chapter 12 explains how.

Why Kubernetes makes this pile up fast

Every Kubernetes update rewrites the whole object, not just the changed field. A Pod object might be a few kilobytes. Each status change stores another full copy. A cluster with ten thousand Pods, each updated a handful of times during its life, quickly generates millions of stored versions. The next chapters show how compaction removes the ones nobody needs.

Production example: the cost of frequent heartbeats

Every node in a cluster keeps a small lease object fresh as a heartbeat. In a five thousand node cluster, those heartbeats alone produce hundreds of etcd writes per second, each creating a new revision. Large operators have learned to watch these write rates closely, because heartbeats are a large share of total revision growth even though they carry almost no information.

6Compaction in Depth

Compaction is the everyday, low-risk job. Let us see who starts it, what it removes and what it leaves.

What a compaction request contains

A compaction request carries a single number: a revision. It means “forget all history older than this revision, except the newest version of each key as of that revision”. The request goes through the Raft process like any write, so every member applies it identically. Because it is replicated, you only need to send it once to any member.

Who triggers compaction in a Kubernetes cluster

Trigger 1

The kube-apiserver

By default, the API server asks etcd to compact about every five minutes. The interval is controlled by an API server setting. When several API server replicas run, they coordinate through a small shared record so that only one of them performs each compaction. Each pass keeps roughly the most recent interval of history.

Trigger 2

etcd’s own auto-compaction

etcd can compact on its own, in a periodic mode that keeps a time window such as one hour, or in a revision mode that keeps the last N revisions. It is off unless you enable it.

Trigger 3

A person or script

An operator can compact manually to a chosen revision, which is the standard first step when recovering from a full database.

Trigger 4

The cloud provider

Managed services run their own schedules and hide the details from you.

i
Tip

In a normal Kubernetes cluster you do not need to turn on etcd’s own auto-compaction as well. Two compactors working on the same data add no benefit. Pick one owner of this job, and the API server is already doing it by default.

How it runs without freezing the cluster

Compaction is designed to be gentle. etcd does the physical deletion in small batches with short pauses between them, so that reads and writes keep flowing while the clean-up proceeds in the background. For a database of several gibibytes, a compaction pass often completes in seconds, though a very large backlog can take longer and slightly raise latency while it runs. This is why compaction can safely happen every few minutes, while defragmentation cannot.

What compaction removes and what it keeps

Removed by compaction

  • Every old version of a key that has a newer version before the compaction point.
  • Tombstones and the history of keys that were deleted before the compaction point.
  • The ability to read or watch from revisions older than the compaction point.

Not changed by compaction

  • The current value of every live key.
  • The size of the database file on disk.
  • History newer than the compaction point.

Running a compaction by hand

Sometimes you want to compact yourself, for example during recovery from a full database. The procedure is simple in idea. First, ask any member for its current revision, a number shown in the status output of the command line client. Second, send a compaction request using that number. Because the request is replicated, one request to one healthy member is enough for all of them. Third, check the status again: the in-use size should drop sharply while the file size stays the same. That last observation is a useful lesson in itself, because it proves with your own eyes that compaction alone does not shrink the file.

!
Careful with the number

Compacting to the very latest revision removes all history, which can make live watches fail and cause a wave of relists. In a healthy cluster prefer a revision from a few minutes ago. In an emergency with a full database, the latest revision is acceptable because getting writes back matters more than preserving a short window of history.

How much history should be kept?

Keeping very little history keeps the database small, but if a controller restarts and needs to catch up on changes it missed a few minutes ago, there must still be enough history for it to do so. Kubernetes picks a short window because its components keep their own in-memory copies of state, as chapter 12 explains. A window of a few minutes is the default, and very long windows are rarely needed. Longer windows cost disk space in direct proportion to how many writes you make.

7Why Compaction Alone Does Not Shrink the File

This is the idea people struggle with most, so we will take it slowly with pictures.

The page picture

The database file is divided into equal pages, like the pages of a notebook. As revisions are written they fill pages. Compaction removes old data, which empties some pages, but those pages are scattered all over the file between pages that are still in use. bbolt cannot hand back a page from the middle of a file to the operating system. A file is a single continuous object. You can only cut the end off a file, and the end is full of live data.

flowchart LR
  subgraph B["Before compaction: 10 pages, file is 10 pages long"]
    P1["live"] --- P2["old"] --- P3["old"] --- P4["live"] --- P5["old"] --- P6["live"] --- P7["old"] --- P8["old"] --- P9["old"] --- P10["live"]
  end
  subgraph C["After compaction: still 10 pages long"]
    Q1["live"] --- Q2["free"] --- Q3["free"] --- Q4["live"] --- Q5["free"] --- Q6["live"] --- Q7["free"] --- Q8["free"] --- Q9["free"] --- Q10["live"]
  end
  subgraph D["After defragmentation: 4 pages long"]
    R1["live"] --- R2["live"] --- R3["live"] --- R4["live"]
  end
  B --> C --> D
    
Figure 2. The same data across compaction and defragmentation

What the free pages are good for

The free pages are not wasted. bbolt remembers them in its freelist and uses them for new writes before it grows the file. In a steady cluster that compacts regularly, the file therefore settles at a size that is a little above the live data plus the recent history, and then stops growing. The file size reflects the high-water mark, the largest it ever needed to be, not the amount of live data today.

The life of a page

stateDiagram-v2
  [*] --> LiveData : write creates a new revision
  LiveData --> OldRevision : a newer revision of the key is written
  OldRevision --> FreeInFile : compaction removes it
  FreeInFile --> LiveData : reused by a later write
  FreeInFile --> ReleasedToDisk : defragmentation rewrites the file
  ReleasedToDisk --> [*]
    
Figure 3. Where compaction and defragmentation act on a page

So why ever defragment?

If free pages get reused, why not leave the file alone? There are three reasons.

  • The quota counts the file, not the live data. A file that grew to its high-water mark during a bad hour still counts that size against the quota forever, even when most pages are free. The cluster can hit the quota with mostly empty pages.
  • The file is memory-mapped. etcd maps the database file into memory for fast reads. A bloated file wastes address space and, when it exceeds the available memory, forces the operating system to read from disk more often, which slows reads.
  • Backups and restores get bigger. A snapshot copies the file as it is, so a bloated file makes every backup, copy and recovery slower and larger.
Everyday analogy

A suitcase that you packed for a long trip stays the same size when you take clothes out at home. The empty space inside is available for your next trip, but the suitcase still takes up the same shelf in the cupboard and still counts against your airline’s baggage limit. Only if you swap it for a smaller suitcase do you get the shelf back.

8Defragmentation in Depth

Defragmentation is the heavy job. It is safe when done with care, and painful when done carelessly.

What happens during a defragmentation

sequenceDiagram
  autonumber
  participant OP as Operator or tool
  participant M as etcd member
  participant OLD as Old database file
  participant NEW as New temporary file
  participant OS as Operating system
  OP->>M: Request defragmentation of this member only
  M->>M: Pause serving reads and writes
  M->>NEW: Create a new empty database file
  M->>OLD: Read every live key and value
  M->>NEW: Write them out in compact order
  M->>NEW: Flush to disk
  M->>OS: Replace the old file with the new one
  OS-->>M: Old space returned to the filesystem
  M->>M: Resume serving requests
  M-->>OP: Done
    
Figure 4. The steps inside a single defragmentation

Reading the steps

1

The member stops serving requests

While it rewrites its file, that one member cannot answer reads or writes. Other members keep working, so a healthy cluster stays available if the defragmentation is done one member at a time.

2

A new file is created beside the old one

This means you need spare disk room during the operation, in the worst case about the size of the live data. Running out of disk space in the middle is a real risk on a nearly full volume.

3

Only live data is copied across

Free pages are simply not copied, which is what removes the gaps.

4

The new file replaces the old one

The swap is done in a way that is safe against a crash. If the machine fails halfway, the old file is still intact.

5

The member resumes and catches up

If it fell behind during the pause, it quickly receives the missing changes from the leader.

How long does it take?

The time depends on the amount of live data and the speed of the disk. On fast solid-state storage it is typically a few seconds for databases of around a gibibyte, and it can grow to a minute or more for large ones. Slow or shared disks stretch the pause much longer. Measure it in a test cluster before running it in production.

Practical tips that save trouble

Tip

Measure first

Record the file size and in-use size on each member before and after. If the numbers barely move, you did not need to do it.

Tip

Mind the client timeout

A long defragmentation may exceed the default command timeout of the client. Use a generous timeout so the command does not give up while the member is still working.

Tip

Let things settle

Wait a short while between members. This lets the resumed member catch up and lets clients finish any relists before the next pause.

Tip

Avoid busy moments

Do not defragment during a large rollout, a node pool upgrade or a known traffic peak, when the control plane is already under extra load.

The leader needs special care

The leader sends regular heartbeats to the followers to prove it is alive. If the leader is paused for defragmentation for longer than the election timeout, the followers may think it has died and start an election. A new leader will be chosen quickly and the cluster will recover, but writes will stall briefly in the meantime. The safe habit is to defragment followers first and the leader last. Some teams move leadership to another member before defragmenting the original leader.

!
Never do this

Do not defragment all members at the same moment. Each one stops serving while it works, and if a majority is paused together, the cluster loses quorum and cannot accept writes at all until some of them return. Always one at a time, and wait until the member is healthy before moving to the next.

9Compaction vs Defragmentation: Side-by-Side

Place the two jobs next to each other and the differences are easy to remember.

QuestionCompactionDefragmentation
What does it change?Which revisions exist in the databaseThe physical layout and size of the file
NatureLogical, about dataPhysical, about storage
Frees file space?Inside the file onlyYes, returns it to the filesystem
Changes data visible to clients?Removes the ability to read old revisionsNo, all live data stays exactly the same
Replicated across members?Yes, one request affects all membersNo, run separately on each member
Blocks the member?No, runs in small background batchesYes, the member pauses while it runs
Typical frequencyEvery few minutes, automaticOccasional, when fragmentation is high
Needs extra disk space?NoYes, room for a temporary new file
Risk levelLowModerate, needs planning
Who normally runs itThe API server or etcd itselfAn operator, a scheduled job or a tool
Skipping it leads toEndless growth of historyA bloated file that can hit the quota

Why keeping them separate is good

  • The frequent job is cheap and non-blocking.
  • The costly job can be scheduled in quiet hours.
  • Each member can be maintained without taking the cluster down.
  • Operators can decide history length and disk policy independently.

What it costs

  • People must remember to do both.
  • The second job is easy to forget until an alarm fires.
  • Misunderstanding leads to the belief that compaction alone is enough.
  • Defragmentation needs care around leaders and disk room.
Compaction creates the empty room. Defragmentation gives the room back.

10The Quota and the NOSPACE Alarm

What actually happens on the bad day, and how to get out of it.

What the quota does

The quota is a safety brake. etcd is not designed for very large databases, and a runaway database could exhaust the disk and corrupt everything. So when the file grows to the quota, etcd raises the NOSPACE alarm and rejects all writes with an error message that says the database space is exceeded. Deletes still work, because deleting is how you recover.

What the cluster looks like when the alarm is on

Symptom

Writes fail

Creating, updating or scaling anything returns an error mentioning that the database space is exceeded.

Symptom

Controllers stall

Status updates, leases and events cannot be written. Lease renewals fail, and leader election for controllers can start to flap.

Symptom

Running Pods keep running

Containers already started are not stopped. But nothing can be changed, healed or replaced.

Symptom

Reads still work

You can still inspect the cluster, which helps with diagnosis.

The recovery path

flowchart TD
  A["Writes fail: database space exceeded"] --> B["Confirm the NOSPACE alarm is active"]
  B --> C["Find the current revision"]
  C --> D["Compact up to that revision"]
  D --> E["Defragment each member, one at a time"]
  E --> F["Disarm the alarm"]
  F --> G["Verify that writes succeed again"]
  G --> H["Find the root cause of the growth"]
  H --> I["Raise the quota only if the need is real"]
    
Figure 5. Recovering from a full etcd database

Why Kubernetes feels so broken when this happens

The NOSPACE alarm is dramatic because so much of Kubernetes’ normal operation is writing. Node heartbeats stop being recorded, so after a while the control plane may start marking nodes as unreachable. Controllers that use leader election cannot renew their leases, so they may give up leadership and stop working. The scheduler cannot record where it placed Pods. The kubelets cannot report status. The API server itself keeps answering reads, which is a trap for the unwary, because a quick look at the cluster can seem fine. Only attempts to change anything reveal the problem.

This is also why the alarm is better treated as a rehearsed emergency than as a surprise. Teams that have written the recovery steps in their runbook, and have tried them once in a test cluster, usually restore writes in minutes. Teams that discover the steps during the outage often spend hours.

A test worth running

In a disposable test cluster, set a very small quota, generate writes until the alarm trips, and then follow the recovery path from this chapter. Doing it once turns an abstract diagram into muscle memory, and teaches you exactly what the error messages look like.

Why every step matters

  • Compact first so that old history becomes free pages. Without this, defragmentation has nothing to reclaim.
  • Defragment second so that the file really shrinks below the quota. If you skip this, the file is still at the quota and the alarm will return immediately.
  • Disarm third. The alarm does not clear itself, even when space is available. Until you disarm it, etcd keeps refusing writes.
  • Investigate last. Something wrote far more than usual. Finding it is what stops a repeat.
i
Tip

Take a snapshot backup before you start recovery if etcd will accept the command. A backup costs a few minutes and removes the fear from every step that follows.

11Data Flow and Lifecycle: From a Write to Reclaimed Space

Follow one update from the moment you press Enter until the disk space it used is finally given back.

1

You change an object

For example you scale a Deployment. The API server validates the change and sends the complete new object to etcd.

2

The leader orders it and the majority records it

The change is appended to the write-ahead log on a majority of members. Only then is it confirmed.

3

A new revision is created in the database

Each member applies the change to its bbolt file. The old version of the key is kept and the new one is stored under the next revision number. The file may grow.

4

Watchers are notified

Controllers watching that key receive the change right away. This is the main reason history exists.

5

Time passes and the old version becomes unnecessary

Nobody can still be watching from before that revision. It is now just weight.

6

Compaction removes the old version

Its pages become free inside the file. Future writes reuse them. The file size does not change.

7

Defragmentation rewrites the file if the gaps grow too large

The file shrinks to roughly the size of the live data and the operating system gets the space back.

Where the time goes

StageTypical timescaleWho controls it
Write confirmedMillisecondsDisk speed and network between members
Old version becomes unneededSeconds to minutesHow long watchers might still need it
Compaction removes itUp to the next compaction pass, minutes by defaultAPI server compaction interval
Space returned to the operating systemHours to weeks, until the next defragmentationYour maintenance schedule
i
Good to know

This is why file size alone is a misleading health signal. A file that is large but has mostly free pages is healthy for writes. A file that is large and nearly full of live data is a real capacity problem. You need both numbers to tell the difference.

12Impact on Kubernetes: Watches, Revisions and “Too Old” Errors

Compaction is invisible most of the time. Here is where it can touch the rest of the cluster.

Resource versions are revisions in disguise

Every Kubernetes object carries a field called resourceVersion. It is derived from the etcd revision at which the object last changed. When a controller says “watch Pods starting from this resource version”, the API server turns that into “watch from this etcd revision”.

The watch cache shields most clients

To avoid hitting etcd for every request, the API server keeps a watch cache, an in-memory copy of recent changes for each resource type. Almost all controller and kubelet watches are served from this cache and never reach etcd directly. The cache keeps a window of recent events, so a client that disconnects briefly can resume without any help from etcd history.

When a client falls too far behind

If a client asks to resume from a resource version that is older than both the watch cache window and the compaction point, the API server cannot supply the missing changes. It answers with an HTTP 410 response meaning the resource version is too old. Well-behaved clients, such as the informers used by controllers, react by doing a fresh full list of the resource and then starting a new watch from there. This is called a relist. It is a normal, designed-for event and not a bug.

sequenceDiagram
  autonumber
  participant C as Controller informer
  participant A as kube-apiserver
  participant E as etcd
  C->>A: Watch from resource version 5000
  A->>E: Watch from revision 5000
  E-->>A: Error: revision has been compacted
  A-->>C: 410 Gone: resource version too old
  C->>A: List all objects of this type
  A->>E: Read current state
  E-->>A: Current objects and latest revision
  A-->>C: Full list with new resource version
  C->>A: Start a new watch from the new version
    
Figure 6. How a client recovers when its history has been compacted

When this becomes a problem

  • Many clients relist at once. After a long etcd pause, such as a slow defragmentation or a leader election, hundreds of controllers and thousands of kubelets may fall behind together and relist simultaneously. The resulting burst of large list calls can load the API server heavily, a pattern sometimes called a thundering herd.
  • Very aggressive compaction. Keeping almost no history leaves little room for slow clients to catch up.
  • Overloaded or slow components. A controller that is starved of CPU may fall behind the window repeatedly and relist over and over.

Why Kubernetes can compact so often

Because clients are built to recover from “too old” by relisting, the cluster can safely compact on a short timer. History in etcd is a convenience for catching up, not the only memory in the system. The API server’s cache and each client’s own in-memory copy do most of the work.

!
Common trap

Custom tools and scripts that hold a watch open for a long time and do not handle the “too old” response will break after the next compaction. If you write clients, always handle this case by relisting and rewatching.

13What Makes the Database Grow in Real Clusters

Finding the biggest source of writes is usually more valuable than any amount of tuning.

Source

Events

Every Pod start, failure, image pull and scheduling decision creates an Event object. Busy clusters generate vast numbers of them. They expire after about an hour by default, but they still cause writes and deletes at a high rate.

Source

Node and controller leases

Small heartbeat objects renewed every few seconds by every node and by leader-elected controllers. Tiny objects, but extremely frequent.

Source

Status churn

Controllers that rewrite status fields on every reconcile loop, even when nothing meaningful has changed, create endless revisions.

Source

Endpoint and EndpointSlice updates

Every Pod becoming ready or not ready updates the matching endpoint objects. Large Services with frequent Pod changes can be heavy writers.

Source

Large objects

Big ConfigMaps, Secrets and custom resources store a full copy on every update. A one-megabyte object updated every minute adds over a gigabyte of history per day before compaction.

Source

Package manager release records

Tools such as Helm store each release revision as a Secret. Many releases with large charts and frequent upgrades keep many sizeable objects alive in etcd.

How to find the biggest writers

Count objects by type under the Kubernetes prefix, and look at the API server’s request metrics broken down by resource and verb. The resource types at the top of the write counts are your suspects. Another useful approach is to list the largest keys. A handful of runaway objects is a very common cause of surprising growth.

Production example: a controller that never stops updating

A team once found their etcd file growing by hundreds of megabytes a day in a quiet cluster. The cause was a custom controller that wrote a “last checked” timestamp into the status of thousands of objects every few seconds. Nothing important changed, but every write produced a full new copy of each object. Removing the unnecessary timestamp updates cut the growth rate dramatically, and no tuning of compaction or defragmentation could have matched that fix.

A quick habit: ask “what changed?”

When growth suddenly speeds up, the most useful question is not “how do I clean this up?” but “what changed recently?”. Think through the likely suspects in order. Was a new controller or operator installed? Did a deployment tool start recording more history? Did a workload begin crash-looping and flooding Events? Was a very large ConfigMap or custom resource added and updated often? Did the cluster grow in node count, multiplying heartbeats? Teams that make a habit of asking this question, and of keeping a short log of significant changes to the cluster, find the answer in minutes instead of hours.

i
Tip

The API server’s own request metrics, broken down by resource and verb, usually reveal the culprit within a minute. Look for a resource type whose write rate does not match the number of objects you expect to be changing.

Separating the noisy tenants

Kubernetes allows certain resource types to be stored in a different etcd cluster from the rest. The official documentation for large clusters recommends storing Events in a separate, dedicated etcd instance, using an API server setting that overrides the etcd servers for a given resource. The very high write rate of Events then cannot slow down or bloat the main store that holds the objects your cluster truly depends on. Several large operators have described using this approach to keep their primary etcd healthy at scale.

14Planning and Sizing: Quota, Memory and Disk

Choose the quota on purpose

The default quota of two gibibytes is comfortable for small clusters and tight for large ones. Many production clusters raise it, with eight gibibytes being the figure the etcd project suggests as a practical upper limit. Beyond that, performance and recovery times degrade, and it is a sign that the cluster should be split or its noisy resource types separated. Set the quota high enough that normal growth plus a bad day does not hit it, and low enough that a runaway process is stopped before it harms the disk.

The memory-mapped file

etcd maps its database file into memory. For best read performance, the machine should have enough free memory to hold the whole file, in addition to what etcd itself needs. If the file is larger than the available memory, the operating system must fetch pages from disk during reads, and latency rises. This is a practical reason to keep the file compact and an argument for regular defragmentation even when the quota is far away.

Disk matters more than CPU

etcd waits for the disk on every write, because it must flush the write-ahead log before confirming. Slow disks cause slow writes, missed heartbeats and leader changes. Use dedicated solid-state storage with low and steady latency, and avoid sharing the disk with other busy workloads. Leave generous free space: the data file, the logs and the temporary file created during defragmentation all live on the volume.

Planning questionRule of thumbReason
How big should the quota be?Several times the live data size, within the suggested upper limitRoom for history and for fragmentation between maintenance runs
How much disk space should be free?At least the size of the database file, plus space for logs and snapshotsDefragmentation writes a temporary new file
How much memory?Enough for etcd plus the whole database fileKeeps reads fast through the memory mapping
How many members?Three for most clusters, five for higher resilienceMore members add safety but also replication cost
Where should Events go?A separate etcd for large, busy clustersIsolates the heaviest write load
i
Tip

Treat the quota like a fuse box. You want it to trip before the wiring melts, but not so often that you cannot run the kettle. Record the reasoning behind the number you choose so that the next engineer does not raise it blindly during an incident.

15Operating It: A Safe Defragmentation Runbook

A repeatable routine turns a frightening operation into a boring one.

When to defragment

Do not defragment on a fixed calendar alone. Base the decision on two numbers: the size of the file and the amount of it that is actually in use. A common rule of thumb is to act when the file is large in absolute terms, for example above a few hundred megabytes, and a large share of it, such as half or more, is free. The standard monitoring rules published with etcd raise a warning on very similar conditions, which makes them a good starting point.

The routine, step by step

1

Check cluster health

All members should be healthy, with a leader, and no active alarm. Never start maintenance on a cluster that is already struggling.

2

Take a snapshot backup

Save it somewhere off the machine. This is your safety net for every later step.

3

Compare file size and in-use size on each member

Record the numbers before you start so that you can show the effect afterwards.

4

Check free disk space

Confirm the volume has room for a temporary copy of the live data.

5

Defragment one follower

Talk only to that member’s own address, not to a load balancer in front of the cluster. Wait for it to finish.

6

Verify before moving on

Confirm the member rejoined, is in sync, and the file is smaller. Pause for a short while so the cluster settles.

7

Repeat for the other followers, then the leader last

Optionally move leadership first so the final step affects a follower.

8

Record the results

Note sizes, durations and any alarms. These notes make the next run faster and safer.

Tools and automation

Tool

The etcdctl command line

The official client. It supports compaction, defragmentation, status checks, alarms and snapshots, and is the basis for every other approach.

Tool

etcd-defrag

A purpose-built tool maintained under the etcd project. It can check each member’s fragmentation, skip members that do not need it, and process them one at a time with the leader last.

Tool

Scheduled jobs

A Kubernetes CronJob or an operating system timer that runs the routine in a quiet window, with alerts on failure.

Tool

Platform operators

Some distributions automate this for you. For example, OpenShift’s etcd operator defragments members automatically when fragmentation passes a threshold.

!
Common trap

Pointing the defragmentation command at a load balancer or at all endpoints at once. It may hit several members together or the wrong member. Always target one specific member address at a time, unless you are using a tool that is built to sequence them safely.

16High Availability, Reliability and Failure Scenarios

Quorum is the number to protect

A three-member cluster needs two members to agree on any write. While you defragment one member, two remain, which is exactly enough. If another member fails or is slow at the same time, the cluster loses its majority and stops accepting writes. For this reason a three-member cluster has no room for a second problem during maintenance. Five members tolerate one planned pause plus one unexpected failure, which is one reason larger or more critical clusters use five.

What can go wrong, and what to do

ScenarioWhat you seeRecovery
Defragmentation takes much longer than expectedTimeouts from the API server, slow kubectl, brief errorsWait if the member is healthy. Schedule future runs in quiet windows and test durations first.
Leader defragmented and election occursA short stall in writes, a leader change eventThe cluster recovers on its own. Defragment followers first next time.
Disk fills during defragmentationThe operation fails, possibly with a leftover temporary fileFree space, remove the temporary file after confirming the member state, and retry.
NOSPACE alarm raisedAll writes rejectedCompact, defragment all members, disarm the alarm.
Member crashes during defragmentationMember restarts with the old file intactCheck health, let it catch up, then retry.
Mass relist after a long pauseAPI server CPU and memory spike, slow responsesWait for the herd to settle. Avoid back-to-back pauses.
Members differ widely in sizeOne member close to quota while others are fineDefragment the large one. Differences are normal because each file is independent.

Backups and restores

A snapshot backup is a copy of the database at one moment. It is also a handy way to understand fragmentation, because restoring a snapshot creates a fresh file that contains only live data, in effect a defragmented database. Test restoring from your backups regularly, in a separate environment, so that you know it works and how long it takes. A backup that has never been restored is only a hope.

i
Good to know

The three members of a healthy cluster usually have slightly different file sizes. This is normal because the physical layout depends on each member’s own history of writes and restarts. Do not treat a small difference as an error.

17Performance and Scalability Effects

How a healthy or neglected database changes the speed of everything built on it.

How fragmentation hurts

A fragmented file is slower in several quiet ways. It spreads live data over more pages, so reads touch more of the disk and more of memory. It enlarges snapshots, which slows the process of bringing a new or recovering member up to date, because the leader has to send a bigger file. And it pushes the file towards the memory limit of the machine, after which the operating system starts to swap pages in and out.

How the maintenance jobs themselves cost performance

Cost

Compaction

Adds light disk activity while it runs. Usually invisible, but a very large backlog after a long gap can raise latency for a short time.

Cost

Defragmentation

Blocks one member for the duration. Overall cluster latency can rise a little because requests must use the other members only.

Cost

Relist storms

If the pause is long, clients reconnect and relist together, adding load on the API server.

Cost

Cache warm-up

After the new file is in place, the operating system must load it into memory again, so the first reads may be slower.

Reading the effect in your own graphs

After a defragmentation, three graphs should tell a clear story. The file size line drops sharply to close to the in-use line. The request latency line shows a small bump at the moment the member paused and then returns to its usual level. The leader change counter stays flat unless you defragmented the leader. If instead the latency stays high, or leader changes keep happening, something else is wrong, most likely a slow disk or a network problem between members, and the maintenance simply made it visible.

Scaling guidance

  • Keep compaction frequent and automatic so that each pass is small and quick.
  • Defragment only when the numbers say it will help, and run it in a quiet window.
  • Reduce the cause of growth first, since every avoided write is cheaper than any clean-up.
  • Split noisy resource types, especially Events, into their own etcd when the main one becomes crowded.
  • At very large scale, consider several smaller clusters rather than one enormous one with a huge database.

A fair expectation

A well-run cluster with sensible write patterns reaches a steady state. The file size rises to a plateau, compaction keeps in-use data small, and defragmentation is needed only rarely, perhaps after unusual events such as a mass deployment, a bug in a controller or an event storm. If you must defragment every few days, treat it as a sign of excessive write activity somewhere and look for the cause.

18Security Considerations

etcd holds the keys to the kingdom, so every maintenance action must respect that.

Why access to etcd is access to everything

Everything in the cluster, including every Secret, lives in etcd. Anyone who can read etcd directly can read all of it and bypass the API server’s login and permission checks entirely. Anyone who can write to it can change the cluster without leaving a trace in the API audit logs. For this reason etcd must be reachable only from the control plane, with mutual certificate authentication between the API server and etcd, and between etcd members.

Security points specific to maintenance

Point

Authenticated maintenance

Compaction and defragmentation need a valid client certificate. When etcd’s own role system is enabled, maintenance operations typically require a highly privileged role. Keep those credentials tightly controlled.

Point

Snapshot protection

A backup contains the entire cluster state, including all Secrets. Store backups encrypted, restrict who can read them, and set a retention period.

Point

Secrets at rest

By default Secrets are stored without encryption in etcd. The API server can encrypt them before storage through an encryption configuration. This protects the file, the backups and the snapshots.

Point

Old data lingers

Compaction and defragmentation remove old versions logically and physically, but they do not securely wipe the underlying disk blocks. Use disk-level encryption so that discarded blocks are not readable later.

Least privilege for automation

A scheduled defragmentation job needs a client certificate that can reach etcd. Give that job its own certificate, narrow in purpose and short in lifetime where possible. Run it from a control plane node or a locked-down pod, never from a developer laptop. Log every run, so that any maintenance action on the cluster’s most sensitive data store is traceable.

!
Never do this

Do not open the etcd client port to a wider network “just so the maintenance script can reach it”. The port gives full control over the cluster. Run maintenance from where etcd is already reachable.

19Monitoring, Logging, Metrics and Troubleshooting

The signals that matter

etcd exposes metrics in a format that monitoring systems such as Prometheus can collect. The exact metric names can differ a little between versions, but the ideas are stable.

SignalWhat it tells youTypical alert idea
Database file sizeHow big the file is on diskWarn when it passes a large share of the quota
Database size in useHow much of the file holds live data and recent historyCompare with the file size to compute fragmentation
Quota sizeThe configured limitUse as the denominator for usage percentage
Fragmentation ratioShare of the file that is free pagesWarn when the file is large and more than about half is free
Backend commit durationHow long it takes to commit changes to the database fileWarn when high percentiles rise
WAL sync durationHow long the disk takes to flush the write-ahead logWarn when the high percentile goes above about ten milliseconds
Leader changesHow often leadership movedWarn on repeated changes in a short period
Has leaderWhether a member can see a leaderPage when it is false
Compaction durationHow long each compaction tookWatch for steady growth
API server request latency by resourceUser-visible effect of etcd slownessWarn on sustained rises
i
Tip

The monitoring rules that ship with the etcd project already contain alerts for low quota space, high fragmentation ratio, slow disk syncs and frequent leader changes. Adopt them first and tune them later, rather than writing everything from scratch.

A calm path from symptom to cause

flowchart TD
  A["Symptom: slow API or failing writes"] --> B{"Do writes fail with space exceeded?"}
  B -->|"Yes"| C["Follow the NOSPACE recovery path"]
  B -->|"No"| D{"Is the file far larger than the in-use size?"}
  D -->|"Yes"| E["Plan defragmentation, one member at a time"]
  D -->|"No"| F{"Is the in-use size itself growing fast?"}
  F -->|"Yes"| G["Find the heaviest writers: events, leases, status churn, large objects"]
  F -->|"No"| H{"Are disk sync or commit times high?"}
  H -->|"Yes"| I["Fix the slow or shared disk"]
  H -->|"No"| J["Check leader changes, network and API server load"]
    
Figure 7. Deciding between compaction, defragmentation and other fixes

Reading common messages

“database space exceeded”

The quota has been reached and the NOSPACE alarm is on. Follow the recovery path in chapter 10. Remember to disarm the alarm at the end.

“required revision has been compacted”

A client asked for history that no longer exists. Usually harmless: the client should relist. If it repeats constantly for one component, investigate why that component keeps falling behind.

“too old resource version” from the API server

The same situation as seen from the Kubernetes side, with an HTTP 410 response. Look for custom clients that do not handle it.

“request timed out” from etcd

The member could not respond in time. Check for a defragmentation in progress, slow disk, heavy compaction or a network problem between members.

Logging advice

etcd logs compaction and defragmentation events with timings. Keep these logs, because they are the best record of how long maintenance really took and of whether a slow period matches a maintenance window. Send them to a central place that survives the loss of the machine itself.

20Design Patterns and Anti-patterns

Patterns that work

Pattern

One owner for compaction

Let the API server do it, or etcd, but not both. Clarity avoids surprises.

Pattern

Threshold-driven defragmentation

Act on measured fragmentation and size, not only on the calendar.

Pattern

Followers first, leader last

Keep the member that coordinates writes available for as long as possible.

Pattern

Back up, act, verify, record

Every maintenance run follows the same four steps.

Pattern

Isolate noisy data

Put Events, and any other heavy writer, in a separate etcd.

Pattern

Fix the writers

Treat high growth as a bug in some component and repair it at the source.

Anti-patterns to avoid

ANTI-PATTERN 01 Avoid
What it looks like

Running compaction and believing the file size will fall.

Why it hurts

The file does not shrink, the quota still fills, and the team is confused when the alarm appears.

Better approach

Pair compaction with defragmentation and monitor both file size and in-use size.

ANTI-PATTERN 02 Avoid
What it looks like

Defragmenting every member at once to “finish quickly”.

Why it hurts

A majority of members is paused together, quorum is lost and the whole cluster stops accepting writes.

Better approach

One member at a time, with a health check between each.

ANTI-PATTERN 03 Avoid
What it looks like

Raising the quota every time the alarm appears.

Why it hurts

The underlying cause stays, the file grows larger and slower, and recovery and backup times balloon.

Better approach

Find the heavy writers and reduce them. Raise the quota only for a proven need and within the supported range.

ANTI-PATTERN 04 Avoid
What it looks like

Forgetting to disarm the alarm after recovery.

Why it hurts

etcd keeps refusing writes even though space is available, and the outage drags on.

Better approach

Make “disarm and verify a write” an explicit final step of the runbook.

21Best Practices and Common Mistakes

Best practices

1

Know who compacts

Check the API server setting for the compaction interval and confirm that etcd’s own auto-compaction is either off or deliberately chosen.

2

Alert before the fuse blows

Warn at a comfortable share of the quota, so you have hours or days, not minutes, to react.

3

Automate defragmentation with safeguards

Use a tool or job that checks health first, works one member at a time, does the leader last and stops on any error.

4

Keep dedicated fast disks

Storage quality prevents more trouble than any tuning flag.

5

Back up regularly and test restores

Maintenance is calm only when recovery is proven.

6

Review the biggest writers every quarter

New controllers and new tools change the write pattern. Catch bad ones early.

7

Document the runbook

At two in the morning, nobody wants to remember the order of the steps.

Common mistakes

  • Treating compaction and defragmentation as the same thing. They are not. One forgets, the other reclaims.
  • Judging health by file size only. Compare it with in-use size.
  • Running defragmentation through a load balancer. It may hit the wrong member or several at once.
  • Starting without enough free disk. The temporary file needs room.
  • Ignoring slow disks. Many “etcd problems” are disk problems.
  • Letting Events share the main etcd in a very busy cluster. They are the loudest writer in most clusters.
  • Skipping the backup because the operation is “routine”. Routine operations are where rare failures hurt most.

22A Worked Example With Real Numbers

Let us walk through a realistic story from calm, to trouble, to repair. The cluster here is an illustration, not a specific company.

The cluster

A three-member etcd cluster serves a mid-sized Kubernetes cluster. The quota is set to 8 GiB. The API server compacts every five minutes. Nobody has defragmented for a year.

MomentFile sizeIn useFree pagesFragmentation
Calm, a year ago1.6 GiB1.2 GiB0.4 GiB25 percent
After a night of runaway Events6.2 GiB5.9 GiB0.3 GiB5 percent
Next morning, after compaction6.2 GiB1.4 GiB4.8 GiB77 percent
After defragmenting one member1.5 GiB1.4 GiB0.1 GiB7 percent

What the numbers mean

1

The storm

A misbehaving workload restarted thousands of times overnight, producing a flood of Events. The live data briefly reached 5.9 GiB. The file grew to hold it.

2

The false comfort

Once the Events expired and compaction ran, the in-use data fell back to 1.4 GiB. The monitoring dashboard that only showed “in use” looked healthy. The file, however, remained at 6.2 GiB.

3

The danger

The file sat at 78 percent of the 8 GiB quota. A second, smaller storm of just 2 GiB of new activity could have pushed the file to the limit and triggered the NOSPACE alarm, even though the real data was small.

4

The fix

The team defragmented the two followers one after the other, then the leader last. Each took under a minute on solid-state disks. The files dropped to about 1.5 GiB each, restoring more than 6 GiB of headroom under the quota.

5

The prevention

They added an alert on fragmentation ratio and file size, moved Events into a separate etcd, and fixed the workload that caused the storm.

i
What the example teaches

The dangerous moment was not during the storm. It was the quiet morning after, when everything looked fine on a dashboard that watched the wrong number. Always chart file size and in-use size together.

23Real-World and Industry Examples

The same two jobs appear across the industry, from managed services to the largest self-run clusters.

Managed Kubernetes on the major clouds

Google Kubernetes Engine, Amazon EKS and Azure AKS operate etcd on your behalf. You never run these commands yourself, but the providers do the same maintenance in the background. When a provider mentions limits on object counts or sizes, it is protecting exactly this database.

Self-managed clusters with kubeadm

A cluster built with kubeadm runs etcd as a static Pod on each control plane node. The API server compacts by default, but nothing defragments automatically. Teams commonly add a scheduled job or a tool such as etcd-defrag, together with the alert rules that ship with etcd.

OpenShift

Red Hat’s OpenShift includes an etcd operator that watches member health and automatically defragments members when fragmentation passes a threshold. It is a good example of turning the manual runbook of this guide into a controller.

Large-scale operators

Organisations running thousands of nodes have publicly described isolating Kubernetes Events in their own etcd cluster, placing etcd on fast local solid-state disks, and watching write rates closely. OpenAI’s write-up about scaling Kubernetes to thousands of nodes is a widely read example of these practices.

Heritage and governance

etcd was created at CoreOS and is now a graduated project of the Cloud Native Computing Foundation. Its maintainers publish operational guidance on maintenance, including compaction, defragmentation and the space quota, which is the basis for the practices in this guide.

i
Pattern to notice

Every mature team ends up with the same trio: automatic compaction, threshold-driven defragmentation and alerts on both size numbers. The details differ, the shape does not.

24Advanced Topic: Inside the bbolt Storage Engine

To truly understand why files do not shrink, it helps to look one level below etcd at the storage library it relies on.

A tree of pages in one file

bbolt stores data as a B+tree, a tree-shaped structure that keeps keys in sorted order so that lookups and range reads are fast. The tree is built out of fixed-size pages, usually the same size as a page of the operating system, commonly four kibibytes. Small pages near the top of the tree point to pages further down, and the actual data sits in the leaf pages at the bottom. Everything lives inside one single file.

Copy-on-write: never edit, always replace

When a value changes, bbolt does not edit the page in place. It writes a new copy of the changed page, and of every page above it in the tree that needs to point to the new copy, and then switches the root to the new version. The old pages are not erased. They are marked as free once no reader can still be using them. This is called copy-on-write, and it has a great benefit: a crash in the middle of a write cannot damage the existing tree, because the old version is still intact until the switch is complete. That safety is the reason etcd uses it.

Everyday analogy

Imagine a town directory printed as a book. When an address changes, a careful editor never scribbles over the page. They reprint that page and every index page that refers to it, then swap the new set into the binder in one move. If the power fails mid-reprint, the old binder is still complete and correct. The cost is that a stack of discarded pages builds up beside the binder.

One writer, many readers

bbolt allows a single writer at a time and any number of readers. Readers see a consistent picture of the tree as it was when they began, and are never blocked by the writer. The pages that a long-running reader might still be looking at cannot be reused yet. In practice this means a very long read can delay the reuse of free pages, which is one more reason to avoid holding enormous reads open in etcd.

How etcd lays its data on top

etcd does not use the user’s key directly as the tree key. Inside the main bucket, the tree key is the revision, and the value holds the user key together with the data. Separately, etcd keeps an in-memory index that maps each user key to the list of revisions at which it has existed. This design explains several behaviours.

  • Writing is fast, because new revisions are always larger and are appended at the right-hand end of the tree.
  • Reading the latest value of a key means looking up the key in the in-memory index, finding its newest revision, and fetching that revision from the tree.
  • Compaction has two parts: pruning the in-memory index, and deleting the old revision entries from the tree. Only the second part creates free pages.
  • A key’s life from creation to deletion is called a generation, and compaction can drop whole generations of keys that have been deleted.

Batching writes to disk

To avoid flushing to the disk after every single change, etcd groups writes and commits them to the file in batches, roughly ten times a second or whenever a batch limit is reached. The durability of an individual write is already guaranteed by the write-ahead log. The batch commit is what turns many small changes into one disk operation. The time this commit takes appears in the backend commit duration metric and is a good indicator of storage health.

Why the file cannot give pages back

The file is also memory-mapped, which means a region of the process’s address space mirrors the file. Free pages sit scattered through that region. Returning a middle page to the operating system would punch a hole in a structure that the engine assumes is contiguous. The designers chose simplicity and safety: the file only grows, free pages are tracked in a list, and the only way to compact the physical layout is to build a fresh file. That is precisely what defragmentation does.

i
Tip

When you think “why is my file still big?”, picture the town directory binder with the stack of discarded pages beside it. Compaction removes the pages from the binder. Defragmentation prints a new, thin binder.

25Advanced Topic: Raft, Revisions and Why Compaction Is Replicated

Compaction looks simple, but it must give the same answer on every member. Raft is how that is guaranteed.

One log, applied in the same order everywhere

Raft keeps an ordered log of operations. A write is proposed to the leader, copied to a majority of members, and then applied to each member’s database in exactly the same order. Because every member applies the same operations in the same order, they all arrive at the same revision numbers. Revision 5000 means the same change on every member. That determinism is what makes revisions a safe thing for clients to rely on, even when they switch between members.

Compaction travels through the same log

A compaction request is also an operation in the log. When it reaches a member’s turn to be applied, the member removes the old revisions up to the chosen point. Since every member does it at the same logical position in the log, every member forgets exactly the same history. If compaction were applied independently on each member at different times, a client could be told “your revision is fine” by one member and “your revision is gone” by another. Replication avoids that confusion.

Defragmentation stays outside the log

Defragmentation changes only the physical layout of one member’s file. The logical contents are identical before and after, so there is nothing for the other members to agree about. It is therefore performed locally and is not part of the log. This is why you must repeat it on every member, and why a successful defragmentation of one member says nothing about the others.

flowchart LR
  REQ["Compact request for revision N"] --> L["Leader appends to Raft log"]
  L --> F1["Follower 1 receives entry"]
  L --> F2["Follower 2 receives entry"]
  F1 -->|"acknowledge"| L
  F2 -->|"acknowledge"| L
  L -->|"majority reached"| A0["Leader applies compaction"]
  F1 --> A1["Follower 1 applies compaction"]
  F2 --> A2["Follower 2 applies compaction"]
  DF["Defragmentation request"] -.->|"local only, not in the log"| A1
    
Figure 8. Compaction is replicated through Raft, defragmentation is local to a member

What happens to a member that falls behind

A member that is paused, for example during defragmentation, falls behind on applying new log entries. When it resumes, the leader either sends the missing entries or, if the member is too far behind for the leader to still hold them, sends a full snapshot. A snapshot transfer is slower and larger when the database file is bloated. A neat side effect is that a member rebuilt from a snapshot ends up with a compact file, because it starts fresh from live data.

Why keeping members similar helps

If one member has a much bigger file than the others, it also takes longer to defragment, longer to restore and longer to ship in a snapshot. It is wise to treat all members the same way in your maintenance plan, even though only one at a time is paused.

Consistency checks

Because every member applies the same operations, members can compare a hash of their data at a given revision to prove they are identical. Recent etcd versions can check this after compaction and raise an alarm if a member has diverged. It is a strong safety net against rare storage corruption, and it works only because compaction is applied at a precisely agreed point.

26Settings Explained: Where Each Knob Lives

Several settings influence this topic. Knowing which component owns each one prevents contradictory choices.

SettingOwned byWhat it controlsNotes
Compaction intervalkube-apiserverHow often the API server asks etcd to compactDefault is about five minutes. Setting it to zero turns the API server’s compaction off.
Auto-compaction modeetcdWhether etcd compacts by time window or by revision countOff by default. Choose either time-based or revision-based, never rely on both and the API server together.
Auto-compaction retentionetcdHow much history to keep: a duration in time mode or a count in revision modeWorks together with the mode above.
Backend quotaetcdThe maximum size of the database fileDefault is two gibibytes, suggested ceiling is eight.
Maximum request sizeetcdThe largest single request acceptedDefault is around one and a half mebibytes, which also limits object sizes.
Heartbeat interval and election timeoutetcdHow fast failures are detected and how long a leader may be silentDefaults are 100 milliseconds and 1000 milliseconds. Long pauses can exceed them.
Event time to livekube-apiserverHow long Events are keptDefault is about one hour. Shorter values reduce stored volume.
Server overrides for resourceskube-apiserverSends chosen resource types to a different etcdStandard way to isolate Events.
Data directoryetcdWhere the file, logs and snapshots livePlace on a dedicated fast disk.

Two auto-compaction modes of etcd

Mode

Periodic

Keeps a fixed window of time, for example the last hour. Predictable in terms of recovery windows, but the amount of history depends on write rate.

Mode

Revision

Keeps a fixed number of revisions, for example the last thousand. Predictable in terms of disk size, but the time window shrinks when writes are busy.

Choosing between them

In a Kubernetes cluster the API server already provides periodic-style compaction by default, so the simplest choice is to leave etcd’s own auto-compaction off and let the API server own the job. In an etcd cluster used by other applications as well, or where the API server’s compaction has been turned off, etcd’s own setting is the right place. Whichever you pick, write it down in your runbook so that the next engineer does not enable a second compactor and wonder about the extra activity.

!
Common trap

Turning off every compactor by accident. A migration to a new installer, or an attempt to “reduce load”, can leave neither the API server nor etcd compacting. The database then grows silently until the alarm appears. Verify the end state, not just the intention.

27Special Situations: Offline Maintenance, Restores and Upgrades

Offline defragmentation

Besides the online command, newer etcd releases include a separate utility meant for operations on files while the member is stopped. It can defragment a data directory offline. This is useful when a member is so full that it cannot start or cannot serve the online command, or when you prefer to perform a long rewrite while the member is out of the cluster. Stop the member cleanly, run the offline step against its data directory, and then start it again so that it catches up from its peers.

Restoring from a snapshot

A snapshot restore builds a new data directory from the saved file. The result is a fresh, compact database. It also starts a new cluster identity, so restoring a whole control plane means restoring every member from the same snapshot, then restarting the API servers so that they reconnect. Two consequences are worth knowing.

  • Revisions can go backwards. The restored database continues from the revision at the time of the snapshot, which may be lower than revisions that clients saw before the failure. Some clients then hold resource versions from the “future”. Newer etcd tools can raise the revision after a restore so that this does not confuse clients, and following current guidance for your version is wise.
  • Caches must be refreshed. The API server and its clients should relist after a restore. Restarting the control plane components achieves this.

Upgrades

Upgrading etcd is done one member at a time, like defragmentation, and for the same reason: quorum must stay. Do not combine an upgrade with a defragmentation of the same member in the same window. Separate changes make a problem easy to attribute. After a successful upgrade, there is normally no need to defragment unless the numbers call for it.

Disaster recovery planning

1

Decide the recovery goals

How much data loss, measured in time, can you accept, and how long can the cluster be without writes?

2

Schedule backups to match

If you can lose at most fifteen minutes of changes, back up at least that often.

3

Store copies off the machine and off the site

A backup on the same disk as the data does not survive the disk.

4

Rehearse a full restore

Measure the time and write down every command. The first time should not be during an outage.

5

Keep the file compact

A defragmented file means faster backups, faster copies and faster restores.

Many clusters, one routine

Organisations with dozens of clusters cannot maintain each one by hand. They package the runbook as automation that reads health and fragmentation, acts only when thresholds are met, staggers work so that not all clusters pause on the same minute, and reports results to a central place. The principles in this guide are the same at any scale. Only the amount of repetition changes.

28Cost and Capacity Economics

Keeping etcd lean is not only about safety. It also saves money and time.

What a bloated file really costs

ItemEffect of a bloated fileEffect of a lean file
Disk provisionedMore capacity needed on every control plane nodeSmaller volumes suffice
Memory needed for the mapped fileLarger machines, or slower readsSmaller machines with fast reads
Backup size and storageEach snapshot is as large as the fileSnapshots only as large as live data
Backup and copy timeLonger, so recovery points drift apartShort, so frequent backups are practical
Restore timeLonger outage during a disasterShorter outage
Member recovery after failureSlow snapshot transfer from the leaderFast catch-up
Risk of hitting the quotaHigh, even with small live dataLow, large headroom

A simple calculation

Suppose a cluster keeps its snapshots for thirty days, taking one every hour. That is about seven hundred and twenty snapshots. With a bloated file of six gibibytes, the archive holds more than four terabytes. With a lean file of one and a half gibibytes, the same archive is about a terabyte. Even before counting transfer costs between sites, the saving is substantial. Compression helps both cases, but it cannot hide a four-to-one difference in the raw size.

The price of the maintenance itself

Defragmentation costs a few minutes of an engineer’s attention, or nothing at all once automated, and a few seconds of one member’s availability. Compared with the costs above, and with the cost of even a short outage caused by the quota, it is among the cheapest forms of reliability work available to a platform team.

What not to optimise

  • Do not shorten the compaction interval to extremes to save a few megabytes. Clients need a little history to catch up.
  • Do not run defragmentation on a small, healthy file just to see the numbers fall. It adds risk for no benefit.
  • Do not spend weeks tuning flags when a single misbehaving controller is the real source of the growth.
i
Tip

Put three numbers on one dashboard that leadership can read at a glance: file size as a share of the quota, fragmentation ratio and time since the last successful backup. They tell the whole health story of the cluster’s memory in one place.

29Glossary of Terms

TermMeaning in plain words
etcdThe reliable key-value database where Kubernetes stores all cluster state
Key and valueA name and the data saved under that name
RevisionA number that increases with every change in the database
MVCCStoring many versions of each key rather than overwriting
TombstoneA marker recording that a key was deleted
CompactionForgetting old versions older than a chosen revision
DefragmentationRewriting the database file to remove free gaps and return space to the disk
FragmentationFree space scattered inside the file
bboltThe storage library that manages etcd’s database file
PageA fixed-size block of the database file
FreelistThe list of free pages that can be reused
Backend quotaThe maximum allowed size of the database file
NOSPACE alarmThe flag raised when the quota is reached, after which only reads and deletes work
RaftThe agreement protocol used by etcd members
MemberOne etcd server in the group
LeaderThe member that orders writes
QuorumThe majority of members needed to accept a write
Write-ahead log (WAL)A sequential log used for crash recovery
SnapshotA point-in-time backup copy of the database
WatchA live stream of changes from a given revision
Watch cacheThe API server’s in-memory copy of recent changes
resourceVersionThe Kubernetes field derived from the etcd revision
RelistA client fetching the full current state again after its history is lost
EventsShort-lived Kubernetes objects describing what happened to other objects
LeaseA small heartbeat object renewed on a timer

30Frequently Asked Questions

Q1If Kubernetes compacts etcd automatically, why would I ever need to defragment?

Because compaction frees space only inside the file. The file keeps its high-water mark size. Defragmentation is the only normal way to return that space to the disk and bring the file back under the quota margin.

Q2Does compaction lose any current data?

No. It removes only old versions and deleted history. The latest value of every live key is always kept.

Q3Does defragmentation lose any data?

No. It copies all live data into a new file and swaps it in. Take a backup first anyway, as with any maintenance.

Q4Will defragmenting cause downtime for my applications?

Running workloads are not affected. The control plane may see brief slowness while one member is paused. Done one member at a time on a healthy cluster, applications normally notice nothing.

Q5How often should I defragment?

As often as the measurements say. When the file is large and a big share of it is free, defragment. In a well-behaved cluster that may be rarely.

Q6Why do my three members have different file sizes?

Each member keeps its own file, shaped by its own history of writes, restarts and defragmentations. Differences are normal.

Q7What is the difference between etcd’s write-ahead log trimming and compaction?

The write-ahead log is the recovery diary, trimmed by snapshots. Compaction removes old key versions inside the database. They are separate mechanisms with separate purposes.

Q8Can I just increase the quota instead of defragmenting?

You can, within the supported range, but it hides the symptom rather than fixing it. Larger files are slower to back up, restore and map into memory.

Q9The alarm is still on after I freed space. Why?

The NOSPACE alarm does not clear itself. You must disarm it explicitly after compaction and defragmentation, then confirm that a write succeeds.

Q10Does deleting objects in Kubernetes shrink etcd?

Not by itself. A delete adds a new revision. The space is only freed inside the file after compaction and returned to the disk after defragmentation.

Q11Do I need to do anything on a managed Kubernetes service?

Usually no, since the provider operates etcd. Your best contribution is to avoid runaway writes and very large objects, which reduces load on the shared design limits.

Q12Is it safe to run these jobs during business hours?

Compaction is. Defragmentation is usually safe on a healthy cluster with proper sequencing, but a quiet window is wiser, particularly for the leader.

31Summary and Key Takeaways

What to remember

  • etcd keeps history. Every change creates a new revision, and deletes only add tombstones. That is why the database grows even when you remove objects.
  • Compaction forgets, it does not shrink. It removes old revisions and turns their pages into free space inside the file, but the file stays the same size.
  • Defragmentation gives space back. It rewrites the file with only live data and returns the rest to the operating system. It runs per member and briefly pauses that member.
  • The quota counts the file. A bloated file can hit the limit and freeze writes cluster-wide even when real data is small. Recovery is compact, defragment every member, then disarm the alarm.
  • Kubernetes is built for compaction. Clients relist when their history is gone, so frequent compaction is safe, but long pauses can cause a burst of relists.
  • Operate with discipline. Back up first, one member at a time, followers before the leader, verify between steps, and automate with safeguards.
  • Watch two numbers, fix the writers. Chart file size and in-use size together, alert on fragmentation, and reduce the heavy writers such as Events, leases and noisy controllers.