$ wwblog


Investigating a hot CPU on my laptop when running Kubernetes

Something has been bugging me for a while now: why does my laptop sound like a jet engine whenever I start Kubernetes, even if nothing is running on the cluster? CPU utilization and temperature go high, and the fans kick on and stay that way.

High CPU utilization when idling my k8s app
Figure 1. High CPU utilization when idling my k8s app

I finally became annoyed enough to investigate.

My setup

First, let me say a bit about my setup, as it matters for this story:

  • Hardware: I have an older (2019) MacBook Pro running a 2.4 GHz Intel processor with 8 physical CPU cores, but 16 logical cores due to hyper-threading. GPU-wise, the laptop has both an integrated GPU (Intel) and a discrete GPU (Radeon).

  • Software: I’m running my app on minikube, using the Docker driver. I was running Docker Desktop for the Linux VM, but ended up switching to Colima as a result of this investigation. I’ll explain that at the end.

Initial hypothesis: app not really idle?

My first thought was that maybe my app wasn’t quite as idle as I had imagined. Maybe some third-party pod was kicking off a background job, or maybe Prometheus was scraping too fast. So I logged into the minikube VM to take a look:

$ minikube ssh
$ top
top - 08:18:23 up 15 min,  0 users,  load average: 5.00, 3.17, 2.05
Tasks: 118 total,   1 running, 117 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.4 us,  0.2 sy,  0.0 ni, 99.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   7835.3 total,   1843.8 free,   3307.3 used,   2684.1 buff/cache
MiB Swap:   1024.0 total,   1024.0 free,      0.0 used.   4247.4 avail Mem

Notice that CPU idle is 99.4%. I watched this for a while and it stayed over 99% idle. So the app was in fact idle.

This was the first major pivot in the investigation. The guest VM believed it was idle, while the host was clearly busy. That meant the problem had to live in the virtualization boundary rather than in the application.

I confirmed that by running top from the host:

The VM is responsible for the high CPU utilization
Figure 2. The VM is responsible for the high CPU utilization

That com.apple.Vi is a truncation of VirtualMachine — the macOS hypervisor process that runs the Linux VM. You can see from the screenshot that this is running pretty hot. But I didn’t know why.

New hypothesis: default virtual file shares in Docker Desktop

I asked ChatGPT for ideas, and it helpfully suggested that I might check file sharing in Docker Desktop. Apparently, the Docker Desktop defaults are too broad and result in constant metadata churn. So I cleaned that up. And that really helped:

Low CPU utilization
Figure 3. Low CPU utilization, but high CPU temperature

You can see that the Docker process itself went from ~32% utilization of a logical core to 3%. So that was a big improvement.

(The observant reader will note that 31.9% × 16 = 5.1 doesn’t account for all 16 logical cores being loaded up. iStat hides some of the other processes involved, like the VM. top gives better visibility, and I should have used it here, but I used iStat.)

But there’s something that seemed off. The CPU temperature was still 78.33° C (173° F), which was higher than expected and roughly unchanged. The fan was still running. Based on comparable systems and prior experience, I expected:

ModeTemp

No Docker

~45–55°C (~113–131°F)

Docker only

~55–65°C (~131–149°F)

Docker + K8s

~70–80°C (~158–176°F)

I shut down Docker, and the CPU temperature dropped to 67° C (152.6° F). Better, and not extreme, but still meaningfully higher than expected. So I wasn’t quite done yet.

Tip

There’s a superb book called Understanding Software Dynamics, by Richard L. Sites (Addison -Wesley). Sites points out that when troubleshooting, it’s important to have a defensible expectation as to what the measurement should be. Otherwise you can’t rule out the possibility that there’s nothing wrong.

In this case, however, I did have an expectation, and the actual temperature was high enough to require an explanation.

Additional hypothesis: external monitors are the problem

There is a clue in the Figure 3 screenshot above. Take a look at the temperature for the Radeon Pro 560X GPU. That’s driving two external monitors that I’ve attached to my laptop. I thought that might be related and ChatGPT agreed. I won’t reproduce its entire response here, but the long and short of it was as follows:

  • Yes, this likely explains the issue.

  • The external monitors force the discrete GPU (Radeon) to activate, as the integrated GPU (Intel) can’t drive the monitors. This adds ~10-20W of constant heat.

  • In the Intel-based MacBooks, the CPU and dGPU share heat pipes, cooling system, and chassis. So the GPU heats up the CPU. (The newer Apple Silicon machines have a different design that avoids this issue.)

The experiment was easy to run. Just unplug the monitors, wait five minutes, and observe the new temperature:

Low CPU utilization and temperature
Figure 4. Low CPU utilization and temperature (temp in C this time)

The temperature (I switched the display to Celsius) dropped to 51°C, lining up beautifully with the expected temperature.

Conclusion and takeaways

So wrapping up, my hot CPU and noisy fan were not caused by k8s or my k8s app at all. Instead, there were a couple of contributing factors:

  • overly broad Docker Desktop file share defaults, leading to CPU-intensive watcher activity; and

  • having two external monitors attached to my laptop, driving up the GPU heat and spilling over to the CPU.

I reached these conclusions by stating explicit hypotheses and running experiments to test them. That scientific method thing I learned in the seventh grade really works!

More generally, this investigation revealed some common patterns:

  • Resource saturation often lives outside the layer you are inspecting.

  • Virtualization and indirection hide costs.

  • Progress comes from investigating deviations from expectations, not from collecting more metrics.

Finally, LLMs are a powerful tool for generating hypotheses, expectations, and explanations. In this case, the LLM didn’t quite solve the problem, but it did help generate hypotheses and calibrate expectations.

Note regarding Docker Desktop vs Colima

I promised earlier to explain why I switched from Docker Desktop to Colima. Docker Desktop kept forgetting my file share settings on restart. Colima doesn’t have that issue.