# GKE Node Pool Not Using COS Image

> Flags GKE node pools not on Container-Optimized OS, Google's recommended and security-focused node image.

Source: https://zop.dev/integrations/gcp/recommendations/gke-node-pool-not-using-cos-image

---

## Why Google steers node pools to Container-Optimized OS

GKE Standard lets you choose the node operating system per pool. Google's
[node image guide](https://cloud.google.com/kubernetes-engine/docs/concepts/node-images) is clear
about its preference: Container-Optimized OS with containerd (`cos_containerd`) is the
recommended node OS, and Autopilot clusters always use it. The same page describes the images as
optimised to enhance node security and backed by a Google team that can quickly patch them, and
states they provide better support, security and stability than the other images.

Ubuntu is supported and validated, and Google names the cases for it: nodes that need XFS,
CephFS or Debian packages. Outside those cases, a general-purpose distribution on nodes is more
software to patch without a reason to have it.

## Listing image types per pool

```bash
gcloud container node-pools list --cluster=CLUSTER_NAME --location=LOCATION \
  --format="table(name,config.imageType)"
```

## Which pools ZopNight flags

ZopNight reads each node pool's image type from inventory. A value of `COS` or `COS_CONTAINERD`
is compliant; any other value, including Ubuntu and Windows images, raises a finding that names
the image in use. A pool with no recorded image type is skipped.

## Cases that deserve an exception

Windows containers need Windows Server nodes, so a Windows Server LTSC (`windows_ltsc_containerd`) pool is flagged
even though it cannot move to Container-Optimized OS. Treat those findings as documented
exceptions. The same applies to Ubuntu pools that exist for one of Google's named reasons, or for
a DaemonSet that installs kernel modules or host packages.

## Security posture only

There is no saving attached to this finding. The concern is attack surface and how quickly the
node OS receives fixes.

## Moving a pool to Container-Optimized OS

1. Check workloads for host dependencies: privileged DaemonSets that install packages, hostPath
   mounts of distribution-specific paths, or kernel modules.
2. Test on a new small pool first:
   `gcloud container node-pools create cos-test --cluster=CLUSTER_NAME --location=LOCATION --image-type=COS_CONTAINERD --num-nodes=1`.
3. Switch the pool: `gcloud container clusters upgrade CLUSTER_NAME --location=LOCATION --image-type=COS_CONTAINERD --node-pool=POOL_NAME`.
4. Watch Pods reschedule onto the new nodes.

**Warning**
Changing the image recreates every node in the pool using its upgrade strategy, and Google notes it starts immediately regardless of maintenance windows. Disabling auto-upgrade does not prevent it.
