This guide covers machine-controller configuration for Google Cloud Platform.
The Service Account needs the following roles:
roles/compute.instanceAdmin.v1roles/iam.serviceAccountUserOr a custom role with these permissions:
compute.instances.*compute.disks.*compute.networks.usecompute.subnetworks.usecompute.zones.listiam.serviceAccounts.actAs# Create service account
gcloud iam service-accounts create machine-controller-sa \
--display-name="Machine Controller Service Account"
# Grant permissions
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:machine-controller-sa@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/compute.instanceAdmin.v1"
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:machine-controller-sa@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountUser"
# Create and download key
gcloud iam service-accounts keys create key.json \
--iam-account=machine-controller-sa@PROJECT_ID.iam.gserviceaccount.com
# Base64 encode the key
cat key.json | base64 -w0 # Linux
cat key.json | base64 # macOS
cloudProviderSpec:
# Service account (base64-encoded JSON key)
serviceAccount: "<< BASE64_ENCODED_SERVICE_ACCOUNT_JSON >>"
# Zone
zone: "us-central1-a"
# Machine configuration
machineType: "n1-standard-2"
diskSize: 50
diskType: "pd-standard"
# Network
network: "default"
subnetwork: "default"
# Public IP
assignPublicIPAddress: true
# Labels
labels:
kubernetesCluster: "my-cluster"
Create a secret:
# Encode service account
SA_BASE64=$(cat key.json | base64 -w0)
# Create secret
kubectl create secret generic gcp-credentials \
-n kube-system \
--from-literal=serviceAccount=$SA_BASE64
Reference in MachineDeployment:
cloudProviderSpec:
serviceAccount:
secretKeyRef:
name: gcp-credentials
key: serviceAccount
cloudProviderSpec:
# Service account (base64-encoded JSON)
serviceAccount: "<< BASE64_ENCODED_SA >>"
# Can also be set via GOOGLE_SERVICE_ACCOUNT env var
# Zone (required)
zone: "us-central1-a"
# Machine type
machineType: "n1-standard-2"
# Preemptible instances (spot VMs)
preemptible: false
# Disk configuration
diskSize: 50 # GB
diskType: "pd-standard" # pd-standard, pd-ssd, or pd-balanced
# Custom image (optional)
customImage: ""
# e.g., "projects/PROJECT_ID/global/images/IMAGE_NAME"
# or "projects/ubuntu-os-cloud/global/images/family/ubuntu-2404-lts"
# Network configuration
network: "default"
subnetwork: "default"
# Can use name or full path:
# network: "projects/PROJECT_ID/global/networks/NETWORK"
# subnetwork: "projects/PROJECT_ID/regions/REGION/subnetworks/SUBNET"
# Public IP
assignPublicIPAddress: true
# Service account for the instance (optional)
# If true, no service account is assigned to the instance
disableMachineServiceAccount: false
# Or specify a custom service account email
# email: "instance-sa@PROJECT_ID.iam.gserviceaccount.com"
# Regional persistent disk (optional)
regionalPersistentDisk: false
# Labels (for resource organization)
labels:
kubernetesCluster: "my-cluster"
environment: "production"
# Tags (for firewall rules)
tags:
- "worker-node"
- "kubernetes"
apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
name: gcp-ubuntu-workers
namespace: kube-system
spec:
replicas: 3
selector:
matchLabels:
name: gcp-ubuntu-workers
template:
metadata:
labels:
name: gcp-ubuntu-workers
spec:
providerSpec:
value:
cloudProvider: "gce"
cloudProviderSpec:
zone: "us-central1-a"
machineType: "n1-standard-2"
diskSize: 50
diskType: "pd-balanced"
network: "default"
subnetwork: "default"
assignPublicIPAddress: true
serviceAccount:
secretKeyRef:
name: gcp-credentials
key: serviceAccount
labels:
kubernetesCluster: "my-cluster"
tags:
- "worker-node"
operatingSystem: "ubuntu"
operatingSystemSpec:
distUpgradeOnBoot: false
versions:
kubelet: "<YOUR-KUBERNETES-VERSION>"
apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
name: gcp-preemptible-workers
namespace: kube-system
spec:
replicas: 5
selector:
matchLabels:
name: gcp-preemptible-workers
template:
metadata:
labels:
name: gcp-preemptible-workers
spec:
providerSpec:
value:
cloudProvider: "gce"
cloudProviderSpec:
zone: "us-central1-a"
machineType: "n1-standard-4"
preemptible: true
diskSize: 100
diskType: "pd-standard"
network: "default"
subnetwork: "default"
assignPublicIPAddress: true
labels:
kubernetesCluster: "my-cluster"
workload: "batch"
operatingSystem: "ubuntu"
versions:
kubelet: "<YOUR-KUBERNETES-VERSION>"
apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
name: gcp-ssd-workers
namespace: kube-system
spec:
replicas: 2
selector:
matchLabels:
name: gcp-ssd-workers
template:
metadata:
labels:
name: gcp-ssd-workers
spec:
providerSpec:
value:
cloudProvider: "gce"
cloudProviderSpec:
zone: "us-central1-a"
machineType: "n1-highmem-4"
diskSize: 200
diskType: "pd-ssd"
network: "default"
subnetwork: "default"
assignPublicIPAddress: true
labels:
kubernetesCluster: "my-cluster"
workload: "database"
operatingSystem: "ubuntu"
versions:
kubelet: "<YOUR-KUBERNETES-VERSION>"
apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
name: gcp-flatcar-workers
namespace: kube-system
spec:
replicas: 3
selector:
matchLabels:
name: gcp-flatcar-workers
template:
metadata:
labels:
name: gcp-flatcar-workers
spec:
providerSpec:
value:
cloudProvider: "gce"
cloudProviderSpec:
zone: "us-central1-a"
machineType: "n1-standard-2"
customImage: "projects/kinvolk-public/global/images/family/flatcar-stable"
diskSize: 50
diskType: "pd-balanced"
network: "default"
subnetwork: "default"
assignPublicIPAddress: true
labels:
kubernetesCluster: "my-cluster"
operatingSystem: "flatcar"
versions:
kubelet: "<YOUR-KUBERNETES-VERSION>"
| Type | vCPUs | RAM | Use Case |
|---|---|---|---|
| e2-medium | 2 | 4 GB | Cost-effective |
| n1-standard-2 | 2 | 7.5 GB | General purpose |
| n1-standard-4 | 4 | 15 GB | General purpose |
| n1-highmem-4 | 4 | 26 GB | Memory-intensive |
| n1-highcpu-4 | 4 | 3.6 GB | Compute-intensive |
| c2-standard-4 | 4 | 16 GB | Compute-optimized |
List available machine types:
gcloud compute machine-types list \
--zones=us-central1-a \
--filter="guestCpus<8" \
--format="table(name,guestCpus,memoryMb)"
Workers should be in a subnet with:
Required firewall rules:
# Allow kubelet API
gcloud compute firewall-rules create allow-kubelet \
--network=default \
--allow=tcp:10250 \
--source-ranges=CONTROL_PLANE_CIDR \
--target-tags=worker-node
# Allow NodePort services
gcloud compute firewall-rules create allow-nodeport \
--network=default \
--allow=tcp:30000-32767 \
--source-ranges=0.0.0.0/0 \
--target-tags=worker-node
# Allow internal communication
gcloud compute firewall-rules create allow-internal \
--network=default \
--allow=tcp,udp,icmp \
--source-ranges=10.0.0.0/8 \
--target-tags=worker-node
For private workers without public IPs:
# Enable Private Google Access on subnet
gcloud compute networks subnets update SUBNET_NAME \
--region=REGION \
--enable-private-ip-google-access
# List Ubuntu images
gcloud compute images list \
--project=ubuntu-os-cloud \
--filter="family:ubuntu-2404-lts" \
--format="table(name,family,creationTimestamp)"
# Use in MachineDeployment
customImage: "projects/ubuntu-os-cloud/global/images/family/ubuntu-2404-lts"
# List Flatcar images
gcloud compute images list \
--project=kinvolk-public \
--filter="family:flatcar-stable" \
--format="table(name,family,creationTimestamp)"
cloudProviderSpec:
preemptible: true
machineType: "n1-standard-4"
By default, instances use the Compute Engine default service account. To disable:
cloudProviderSpec:
disableMachineServiceAccount: true
To use a custom service account:
cloudProviderSpec:
email: "worker-sa@PROJECT_ID.iam.gserviceaccount.com"
For high availability:
cloudProviderSpec:
regionalPersistentDisk: true
zone: "us-central1-a" # Primary zone
# Disk replicated to another zone in the region
# Check machine events
kubectl describe machine <machine-name> -n kube-system
# Common issues:
# - Invalid service account permissions
# - Quota exceeded
# - Machine type not available in zone
# - Network/subnet not found
# List recent operations
gcloud compute operations list \
--filter="zone:us-central1-a" \
--limit=10
# Describe specific operation
gcloud compute operations describe OPERATION_NAME \
--zone=us-central1-a
# View instance serial console
gcloud compute instances get-serial-port-output INSTANCE_NAME \
--zone=us-central1-a
Deploy across multiple zones:
---
apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
name: workers-us-central1-a
namespace: kube-system
spec:
replicas: 2
template:
spec:
providerSpec:
value:
cloudProviderSpec:
zone: "us-central1-a"
---
apiVersion: cluster.k8s.io/v1alpha1
kind: MachineDeployment
metadata:
name: workers-us-central1-b
namespace: kube-system
spec:
replicas: 2
template:
spec:
providerSpec:
value:
cloudProviderSpec:
zone: "us-central1-b"