# Using C4A and C4D with Compute Class I’ve been following Arm for a while, so was glad that the [C4A VM](https://cloud.google.com/blog/products/compute/try-c4a-the-first-google-axion-processor) was [GA’d](https://cloud.google.com/blog/products/compute/first-google-axion-processor-c4a-now-ga-with-titanium-ssd) earlier this year. These machines run Google silicon [Axion](https://cloud.google.com/products/axion) chip. It’s also great to see [broad geographical availability](https://cloud.google.com/compute/docs/regions-zones) including regions like Tokyo. Feels like Arm is finally ready for prime time. C4D running 5th Gen AMD EPYC processors (Turin) was even more [recently released](https://cloud.google.com/blog/products/compute/c4d-vms-unparalleled-performance-for-business-workloads). Let’s try them both out! ## Arm on GKE Here’s how to deploy an Arm workload on GKE using Compute Class. I’ll be using Autopilot mode. First, define the Compute Class. Why Compute Class? Among other reasons, it’s a convenient place to deploy our compute priorities and other configurations giving the workload a single name to reference. If in the future a new Arm VM was added, we can replace it in the Compute Class without updating every workload. It’s also possible to request the machine-family directly. Here’s a simple Compute Class requesting C4A. I included “minCores: 4” out of habit since GKE adds a bit of overhead on the node, anything less than 4 cores is not a great overhead-to-allocatable ratio. ```yaml {hl_lines=[7]} apiVersion: cloud.google.com/v1 kind: ComputeClass metadata: name: c4a spec: priorities: - machineFamily: c4a minCores: 4 ``` [c4a-cc.yaml](https://github.com/WilliamDenniss/autopilot-examples/blob/master/custom-compute-class/c4a/c4a-cc.yaml) To request this in an Arm workload, we actually need to do two things. First reference the compute class, and second request an Arm node. This may seem redundant since this compute class only offers Arm nodes (and you might see a warning like “Key ‘kubernetes.io/arch’ is not recommended with node selector; Consider using Custom Compute Classes mechanisms, simultaneous use of both may lead to unexpected behavior, use with caution.”), but **GKE requires Arm workloads to have this selector** or the workload won’t be scheduled. ```yaml {hl_lines=[16, 17]} apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 1 selector: matchLabels: pod: nginx-pod template: metadata: labels: pod: nginx-pod spec: nodeSelector: kubernetes.io/arch: arm64 cloud.google.com/compute-class: c4a containers: - name: nginx-container image: nginx resources: requests: cpu: 40m memory: 40Mi ephemeral-storage: 100Mi ``` [deploy.yaml](https://github.com/WilliamDenniss/autopilot-examples/blob/master/custom-compute-class/c4a/deploy.yaml) That’s it! Create both objects and you should now have a workload running on GKE Autopilot using Arm C4A. ```bash kubectl create -f https://raw.githubusercontent.com/WilliamDenniss/autopilot-examples/refs/heads/master/custom-compute-class/c4a/c4a-cc.yaml kubectl create -f https://raw.githubusercontent.com/WilliamDenniss/autopilot-examples/refs/heads/master/custom-compute-class/c4a/deploy.yaml ``` Remember, you can ignore the warning in this instance. ``` computeclass.cloud.google.com/c4a created Warning: Key 'kubernetes.io/arch' is not recommended with node selector; Consider using Custom Compute Classes mechanisms, simultaneous use of both may lead to unexpected behavior, use with caution. deployment.apps/nginx created ``` Another thing to notice is that when you run using node-based compute classes (instead of the Pod-based container-optimized compute platform), you have the full VM at your disposal and there are no Pod minimums. Just make sure you fill the VM for efficiency, as you’re paying for the whole thing regardless. Taking a look at the created, we can see an Arm C4A machine in this abridged output: ```bash {hl_lines=[4, 5]} $ kubectl describe node gk3-autopilot-tokyo-nap-1j2padwp-97ecb77b-rp6h Name: gk3-autopilot-tokyo-nap-1j2padwp-97ecb77b-rp6h Roles: Labels: addon.gke.io/node-local-dns-ds-ready=true cloud.google.com/compute-class=c4a kubernetes.io/arch=arm64 topology.kubernetes.io/region=asia-northeast1 topology.kubernetes.io/zone=asia-northeast1-b ``` And the Pod we can see is running as a Burstable QoS with 40mCPU requested (allowing it to burst outside this when resources are available). ```bash {hl_lines=[17, 21, 22]} $ kubectl describe pod Name: nginx-574cbc959d-79w2m Namespace: default Controlled By: ReplicaSet/nginx-574cbc959d Containers: nginx-container: Container ID: containerd://3a8b8ad97a828f589068f3aa7e59167a8e71af3a0fdbd634ac492e6b0208a7cd Image: nginx Image ID: docker.io/library/nginx@sha256:33e0bbc7ca9ecf108140af6288c7c9d1ecc77548cbfd3952fd8466a75edefe57 Port: Host Port: State: Running Started: Sun, 17 Aug 2025 19:31:02 +0000 Ready: True Restart Count: 0 Requests: cpu: 40m ephemeral-storage: 100Mi memory: 40Mi QoS Class: Burstable Node-Selectors: cloud.google.com/compute-class=c4a kubernetes.io/arch=arm64 Tolerations: cloud.google.com/compute-class=c4a:NoSchedule kubernetes.io/arch=arm64:NoSchedule node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s ``` ## C4D on GKE Here’s the same setup for the very capable C4D machine. Again, I’ll use Compute Class as a convenient way to declare my machine configuration in a single place, and request a min-4 core machine (C4D goes as low as 2 cores, but there’s a bit of system overhead that makes them less useful). Here’s the compute class: ```yaml {hl_lines=[7]} apiVersion: cloud.google.com/v1 kind: ComputeClass metadata: name: c4d spec: priorities: - machineFamily: c4d minCores: 4 ``` [c4d-cc.yaml](https://github.com/WilliamDenniss/autopilot-examples/blob/master/custom-compute-class/c4d/c4d-cc.yaml) And the workload: ```yaml {hl_lines=[16]} apiVersion: apps/v1 kind: Deployment metadata: name: nginx-x86 spec: replicas: 1 selector: matchLabels: pod: nginx-x86-pod template: metadata: labels: pod: nginx-x86-pod spec: nodeSelector: cloud.google.com/compute-class: c4d containers: - name: nginx-container image: nginx resources: requests: cpu: 40m memory: 40Mi ephemeral-storage: 100Mi ``` [deploy.yaml](https://github.com/WilliamDenniss/autopilot-examples/blob/master/custom-compute-class/c4d/deploy.yaml) Create both: ```bash kubectl create -f https://raw.githubusercontent.com/WilliamDenniss/autopilot-examples/refs/heads/master/custom-compute-class/c4d/c4d-cc.yaml kubectl create -f https://raw.githubusercontent.com/WilliamDenniss/autopilot-examples/refs/heads/master/custom-compute-class/c4d/deploy.yaml ``` As with the earlier example, no minimums apply when using node-based compute classes, our workload is using 40mCPU of the allocatable space, so it’s our responsibility to fully utilize this node. ```bash {hl_lines=[16]} $ kubectl describe pod nginx-x86-688f977fbc-77v69 Name: nginx-x86-688f977fbc-77v69 Namespace: default Containers: nginx-container: Container ID: containerd://e2d87da8bf2b540ba367627a27a15a9b4a24748b6ba0c31ec8a2b70137058b83 Image: nginx Image ID: docker.io/library/nginx@sha256:33e0bbc7ca9ecf108140af6288c7c9d1ecc77548cbfd3952fd8466a75edefe57 Port: Host Port: State: Running Started: Sun, 17 Aug 2025 19:57:08 +0000 Ready: True Restart Count: 0 Requests: cpu: 40m ephemeral-storage: 100Mi memory: 40Mi Environment: Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-pt8zc (ro) QoS Class: Burstable Node-Selectors: cloud.google.com/compute-class=c4d Tolerations: cloud.google.com/compute-class=c4d:NoSchedule node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s ``` ## Comparing the Compute Class option to machine-family For completeness, the alternative option is to use `machine-family` instead of Compute Class ```yaml {hl_lines=[16]} apiVersion: apps/v1 kind: Deployment metadata: name: nginx-x86-m spec: replicas: 1 selector: matchLabels: pod: nginx-x86-m-pod template: metadata: labels: pod: nginx-x86-m-pod spec: nodeSelector: cloud.google.com/machine-family: c4d containers: - name: nginx-container image: nginx resources: requests: cpu: 40m memory: 40Mi ephemeral-storage: 100Mi ``` [deploy_machine-family.yaml](https://github.com/WilliamDenniss/autopilot-examples/blob/master/custom-compute-class/c4d/deploy_machine-family.yaml) To deploy ```bash kubectl create -f https://raw.githubusercontent.com/WilliamDenniss/autopilot-examples/refs/heads/master/custom-compute-class/c4d/deploy_machine-family.yaml ``` The result for this example is similar, except that a smaller machine was allocated since no minimum was specified. The pod: ```bash {hl_lines=[15]} $ kubectl describe pod Name: nginx-x86-m-85f976f84d-5rqcs Containers: nginx-container: Container ID: containerd://006ed9473ff7923eba20132ee481316e7706656e6a204405e1f8de929a3e66cc Image: nginx Image ID: docker.io/library/nginx@sha256:33e0bbc7ca9ecf108140af6288c7c9d1ecc77548cbfd3952fd8466a75edefe57 Port: Host Port: State: Running Started: Mon, 18 Aug 2025 16:55:05 +0000 Ready: True Restart Count: 0 Requests: cpu: 40m ephemeral-storage: 100Mi memory: 40Mi Environment: Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-t8r4p (ro) QoS Class: Burstable Node-Selectors: cloud.google.com/machine-family=c4d cloud.google.com/pods-per-node=any Tolerations: cloud.google.com/machine-family=c4d:NoSchedule cloud.google.com/pods-per-node=any:NoSchedule kubernetes.io/arch=amd64:NoSchedule node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s ``` The node that was provisioned: ```bash {hl_lines=[26, 43]} $ kubectl describe node gk3-autopilot-tokyo-nap-15v5fvfh-e8d2d0a6-djw2 Name: gk3-autopilot-tokyo-nap-15v5fvfh-e8d2d0a6-djw2 Roles: Labels: addon.gke.io/node-local-dns-ds-ready=true cloud.google.com/gke-boot-disk=hyperdisk-balanced cloud.google.com/gke-container-runtime=containerd cloud.google.com/gke-cpu-scaling-level=2 cloud.google.com/gke-gcfs=true cloud.google.com/gke-image-streaming=true cloud.google.com/gke-logging-variant=DEFAULT cloud.google.com/gke-max-pods-per-node=64 cloud.google.com/gke-memory-gb-scaling-level=7 cloud.google.com/gke-netd-ready=true cloud.google.com/gke-nodepool=nap-15v5fvfh cloud.google.com/gke-os-distribution=cos cloud.google.com/gke-provisioning=standard cloud.google.com/gke-stack-type=IPV4 cloud.google.com/machine-family=c4d cloud.google.com/pods-per-node=any cloud.google.com/private-node=false cloud.google.com/slice-of-hardware=true iam.gke.io/gke-metadata-server-enabled=true kubernetes.io/arch=amd64 kubernetes.io/hostname=gk3-autopilot-tokyo-nap-15v5fvfh-e8d2d0a6-djw2 kubernetes.io/os=linux node.kubernetes.io/instance-type=c4d-standard-2 node.kubernetes.io/masq-agent-ds-ready=true topology.gke.io/zone=asia-northeast1-b topology.kubernetes.io/region=asia-northeast1 topology.kubernetes.io/zone=asia-northeast1-b Annotations: container.googleapis.com/instance_id: 7900722399951119444 csi.volume.kubernetes.io/nodeid: {"filestore.csi.storage.gke.io":"gk3-autopilot-tokyo-nap-15v5fvfh-e8d2d0a6-djw2","gcsfuse.csi.storage.gke.io":"gk3-autopilot-tokyo-nap-15v... node.alpha.kubernetes.io/ttl: 0 node.gke.io/last-applied-node-labels: addon.gke.io/node-local-dns-ds-ready=true,cloud.google.com/gke-boot-disk=hyperdisk-balanced,cloud.google.com/gke-container-runtime=contain... node.gke.io/last-applied-node-taints: cloud.google.com/machine-family=c4d:NoSchedule,cloud.google.com/pods-per-node=any:NoSchedule volumes.kubernetes.io/controller-managed-attach-detach: true CreationTimestamp: Mon, 18 Aug 2025 16:54:48 +0000 Taints: cloud.google.com/machine-family=c4d:NoSchedule cloud.google.com/pods-per-node=any:NoSchedule Capacity: cpu: 2 ephemeral-storage: 98831908Ki hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 7106096Ki pods: 64 Allocatable: cpu: 1930m ephemeral-storage: 47060071478 hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 5264944Ki pods: 64 Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) Resource Requests Limits -------- -------- ------ cpu 589m (30%) 7 (362%) memory 1237668096 (22%) 3134394880 (58%) ephemeral-storage 100Mi (0%) 0 (0%) hugepages-1Gi 0 (0%) 0 (0%) hugepages-2Mi 0 (0%) 0 (0%) ```