HTTP Chunked Transfer Encoding in Kubernetes Watch Streams

Kubernetes controllers, schedulers, and kubelets stay in-sync by streaming resource changes from the API server. The underlying transport is nothing exotic—just plain HTTP/1.1 kept alive with Transfer-Encoding: chunked. This article strips the problem down to the wire format and shows how the chunking mechanism is used to deliver watch events.

Chunked encoding refrseher

When a handler does not know the final body size it can send the response as a sequence of chunks. Each chunk is prefixed by its length in hexadecimal, terminated by \r\n, and followed by the payload and another \r\n. The stream ends with a zero-length chunk.

The following toy server demonstrates the idea:

func streamHandler(w http.ResponseWriter, r *http.Request) {
    flusher, ok := w.(http.Flusher)
    if !ok {
        http.Error(w, "streaming unsupported", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Transfer-Encoding", "chunked")
    w.Header().Set("Content-Type", "text/plain")

    for i := 0; i < 3; i++ {
        fmt.Fprintf(w, "tick %d\n", i)
        flusher.Flush()
        time.Sleep(time.Second)
    }
}

A curl trace shows the raw bytes:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: text/plain

7\r\ntick 0\n\r\n
7\r\ntick 1\n\r\n
7\r\ntick 2\n\r\n
0\r\n

The client simply reads until io.EOF; the HTTP library re-assembles the chunks transparently.

Watch endopint in action

Expose the API server locally:

$ kubectl proxy
Starting to serve on 127.0.0.1:8001

Open a watch on any object:

$ curl -N http://localhost:8001/api/v1/watch/namespaces/default/configmaps/sample

The first event arrives immediately:

{"type":"ADDED","object":{...}}

Now edit the ConfigMap; a second event appears:

{"type":"MODIFIED","object":{...}}

Both JSON documents are delivered as separate chunks. A packet capture confirms the framing:

Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
    Transfer-Encoding: chunked\r\n
    Content-Type: application/json\r\n
    \r\n
    000003a8\r\n{"type":"ADDED",...}\r\n
    000003ab\r\n{"type":"MODIFIED",...}\r\n

The hexadecimal numbers 3a8 and 3ab are the byte lengths of the two JSON payloads. The connection remains open; further changes will be emitted as additional chunks until the client closes the stream or the server times it out.

Thus, Kubernetes watch streams are ordinary HTTP chunked responses where each chunk is a complete watch event. No custom framing protocol is required—just the standard mechanism already built into every HTTP/1.1 stack.

Tags: kubernetes HTTP/1.1 Transfer-Encoding Watch API Chunked Transfer

Posted on Sun, 30 Aug 2026 16:23:27 +0000 by plazz2000