Kubernetes for the Solo Developer: A Practical GKE Guide Without the Overhead

Photo by Unsplash

Photo by Unsplash
Kubernetes has a reputation for being overkill for solo developers and small teams. In most cases, that reputation is deserved — maintaining your own cluster control plane, managing node pools, and debugging obscure CRD conflicts takes time that is better spent building product. But GKE Autopilot changes the calculus. It eliminates node management entirely, charges only for actual Pod resource requests (not idle node capacity), and provides a production-grade Kubernetes experience at a cost that is competitive with managed VPS setups once you factor in operational time. This guide shares what I learned deploying GKE Autopilot for client projects at Commsult Indonesia — what works well, what to watch out for, and a CI/CD setup that a single developer can operate without burning out.
There are three ways to run Kubernetes on Google Cloud: Standard GKE (you manage nodes, GKE manages the control plane), Autopilot GKE (Google manages both nodes and control plane, you only manage Pods), and self-managed Kubernetes on Compute Engine VMs (you manage everything). For solo developers, Autopilot is almost always the right choice. Standard GKE's node pool management — right-sizing, auto-scaling, upgrade windows, node taints — is a significant operational burden. Autopilot removes all of it. You define your Pod resource requests and limits, and Google provisions the underlying compute transparently. If a node fails, your Pods are rescheduled automatically without your involvement.
Autopilot charges per Pod-second of CPU, memory, and ephemeral storage requested. A Pod requesting 250m CPU and 256Mi memory costs approximately $0.016/hour — about $11.50/month for a continuously running Pod. Two replicas of that Pod costs $23/month. Compare this to a standard $12/month DigitalOcean Droplet with 2 vCPU and 2GB RAM running two Docker containers — DigitalOcean is clearly cheaper for simple always-on workloads. GKE Autopilot becomes competitive when you need features like HPA (Horizontal Pod Autoscaler), rolling updates with readiness gates, multi-namespace isolation, or CronJobs with resource guarantees. The break-even point versus a managed VPS is roughly at 3-5 services running continuously.
Create a GKE Autopilot cluster in the region closest to your users — for Indonesian-market projects, asia-southeast1 (Singapore) or asia-southeast2 (Jakarta). Enable private nodes to keep worker node IP addresses off the public internet, and use Cloud NAT for outbound traffic from private nodes. Enable Workload Identity to allow Pods to access GCP services (Cloud SQL, Cloud Storage) using IAM service accounts without storing credentials as Kubernetes secrets. The initial cluster creation takes 5-10 minutes and requires only a project ID and region — no node pool configuration needed.
┌────────────────────────────────────────────────────────────────────┐
│ Solo Developer Kubernetes Stack (GKE Autopilot) │
│ │
│ GitHub Actions CI/CD │
│ │ │
│ │ docker build + push to Artifact Registry │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ GKE Autopilot Cluster │ │
│ │ │ │
│ │ Namespace: production │ │
│ │ ┌────────────────┐ ┌────────────────┐ ┌──────────────┐ │ │
│ │ │ Deployment │ │ Deployment │ │ CronJob │ │ │
│ │ │ app (3 pods) │ │ worker (2p) │ │ scheduler │ │ │
│ │ └───────┬────────┘ └───────┬────────┘ └──────────────┘ │ │
│ │ │ │ │ │
│ │ ┌───────▼───────────────────▼──────────────────────────┐ │ │
│ │ │ Service (ClusterIP) + Ingress (NGINX) + TLS cert │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Namespace: monitoring │ │
│ │ Prometheus + Grafana (Helm charts) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ Cloud SQL (PostgreSQL) │
│ Cloud Storage (backups) │
└────────────────────────────────────────────────────────────────────┘Use GKE's Binary Authorization policy to ensure only images from your Artifact Registry that have been verified by your CI pipeline can be deployed to the cluster. This prevents accidental or malicious deployment of unvetted images. Set up a Cloud Build attestor that signs successful CI builds, then configure Binary Authorization to require that attestation before allowing deployment. For a solo developer setup, this adds 10 minutes of setup time but eliminates an entire class of supply-chain risk.
The deployment workflow for a GKE Autopilot project uses GitHub Actions to build a Docker image, push it to Artifact Registry in the same GCP region as the cluster (for fastest pull times), and then apply updated Kubernetes manifests using `kubectl set image` or by updating the image tag in a manifest file and running `kubectl apply`. Use Workload Identity Federation to authenticate GitHub Actions to GCP — this replaces long-lived service account keys with short-lived tokens, eliminating the need to store GCP credentials in GitHub secrets.
Even as a solo developer, use namespaces to separate concerns. A minimal namespace structure: `production` for your live application, `staging` for pre-production testing, and `monitoring` for Prometheus and Grafana. This separation allows you to apply ResourceQuotas per namespace (preventing the staging namespace from consuming all cluster resources during a runaway load test) and makes it easier to add team members later with namespace-scoped RBAC roles. Install the NGINX Ingress Controller in the `ingress-nginx` namespace and use a single Cloud Load Balancer IP with name-based virtual hosting to route traffic to multiple services.
# Create GKE Autopilot cluster (one-time)
gcloud container clusters create-auto myapp-cluster --region asia-southeast1 --project my-project-id
# deployment.yaml — minimal production manifest
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: production
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: asia-southeast1-docker.pkg.dev/my-project/myapp:latest
ports:
- containerPort: 3000
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
---
apiVersion: v1
kind: Service
metadata:
name: myapp-service
namespace: production
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 3000
type: ClusterIP
# Apply and rollout
kubectl apply -f deployment.yaml
kubectl rollout status deployment/myapp -n production
# Rolling update with image change
kubectl set image deployment/myapp myapp=asia-southeast1-docker.pkg.dev/my-project/myapp:v2.0.0 -n productionKubernetes Secrets are base64-encoded, not encrypted — anyone with kubectl access to the namespace can decode them. For production, use External Secrets Operator with GCP Secret Manager as the backend. External Secrets syncs GCP Secret Manager values into Kubernetes Secrets automatically, meaning your actual secret values never live in your Git repository or unencrypted in etcd. In GCP Secret Manager, enable automatic rotation for database passwords and API keys, and configure Secret Manager to notify your application via Pub/Sub when a secret rotates so it can reload without restarting.
GKE Autopilot has Pod resource limits that differ from Standard GKE. The minimum Pod resource request is 250m CPU and 512Mi memory — you cannot run Pods with smaller resource requests. If you deploy a lightweight container (e.g., a small cron job) without specifying resource requests, GKE Autopilot automatically bumps them to the minimum, which may cost more than you expect. Always explicitly set resource requests and limits in your manifests. Also, some DaemonSet configurations (like running Node Exporter for Prometheus) are not supported in Autopilot — use GKE's built-in Cloud Monitoring instead, or run Node Exporter as a regular Deployment.
Several tactics reduce GKE Autopilot costs significantly. First, set accurate resource requests and limits — over-requesting CPU and memory wastes money since Autopilot charges for what you request. Use Vertical Pod Autoscaler (VPA) in recommendation mode for one week to get data-driven resource suggestions. Second, use CronJobs instead of always-running Pods for batch workloads — a Pod that runs for 30 minutes daily costs 48x less than one running continuously. Third, configure HPA to scale down to 1 replica during off-peak hours for non-critical services. Fourth, use `preemptible: true` in your Pod spec for fault-tolerant batch jobs — Autopilot discounts preemptible Pods by approximately 60%.
Kubernetes is not always the answer. If your project is a single Docker container serving HTTP traffic, a DigitalOcean Droplet or GCP Compute Engine instance with Docker and NGINX is the simpler and cheaper choice. Add blue-green deployments via bash script (as described in another post) and you get zero-downtime deployments without any Kubernetes complexity. Reach for GKE Autopilot when you genuinely need: automatic scaling based on load (HPA), multi-service orchestration with health-check-based rolling updates, namespace-level resource isolation, or scheduled jobs with resource guarantees. The operational investment in Kubernetes starts to pay off at 4-6 services or 3+ team members.