Managed K8s Basics
This page is a hands-on intro to running workloads on a managed cluster, covering the commands and manifests you touch on day one across EKS, GKE, and AKS.
Prerequisites
- kubectl matching your cluster minor (target Kubernetes 1.36; the client may skew one minor).
- Helm 3 for chart-based installs.
- A managed cluster on one of EKS, GKE, or AKS, plus the matching cloud CLI (
aws,gcloud, oraz). - Docker Engine 29.6.1 locally only for building images; nodes run containerd via CRI.
Quick install of kubectl and Helm on Debian or Ubuntu:
curl -LO "https://dl.k8s.io/release/v1.36.2/bin/linux/amd64/kubectl"
sudo install -m 0755 kubectl /usr/local/bin/kubectl
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bashBasic Examples
1. Get cluster credentials
Each cloud writes a kubeconfig entry with its own CLI so kubectl can reach the managed API server.
aws eks update-kubeconfig --name prod --region us-east-1
gcloud container clusters get-credentials prod --region us-central1
az aks get-credentials --resource-group rg-prod --name prod- Only one of these applies to your cluster; they all merge into
~/.kube/config. - The token is short-lived and refreshed by the cloud CLI on each call.
- Switch clusters with
kubectl config use-context <name>. - Cloud IAM authenticates you; Kubernetes RBAC still authorizes actions.
2. Inspect the control plane and nodes
Confirm the managed control-plane version and see your worker nodes.
kubectl version --output=yaml
kubectl get nodes -o wide- The server version is the managed control plane you selected.
-o wideshows the container runtime column, which readscontainerd://....- Node
AGEandVERSIONreveal node-pool upgrade drift. - Nodes stay on their pool version until you upgrade them.
3. Create a namespace
Namespaces are your first isolation boundary for teams and environments.
kubectl create namespace payments
kubectl label namespace payments team=payments- Namespaces scope names, quotas, RBAC, and NetworkPolicy.
- Labels drive selectors and policy targeting later.
- Delete a namespace to garbage-collect everything inside it.
4. Deploy a workload
A minimal Deployment runs your image with a pinned, non-root container.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: payments
spec:
replicas: 3
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: ghcr.io/acme/web@sha256:abc123
ports:
- containerPort: 8080replicas: 3spreads pods for availability.- Pinning by digest (
@sha256:...) makes rollouts reproducible. - The selector must match the pod template labels.
- Apply it with
kubectl apply -f web.yaml.
5. Expose the workload
A Service gives pods a stable virtual IP and DNS name inside the cluster.
apiVersion: v1
kind: Service
metadata:
name: web
namespace: payments
spec:
selector: { app: web }
ports:
- port: 80
targetPort: 8080- The Service load-balances across all matching pod IPs.
- In-cluster DNS resolves
web.payments.svc.cluster.local. - Use
type: LoadBalancerto provision a cloud load balancer. - kube-proxy or the CNI programs the routing on each node.
6. Add health probes
Probes let Kubernetes restart hung pods and hold traffic until ready.
readinessProbe:
httpGet: { path: /healthz, port: 8080 }
periodSeconds: 5
livenessProbe:
httpGet: { path: /livez, port: 8080 }
periodSeconds: 10- Readiness gates whether the pod receives Service traffic.
- Liveness restarts a pod that is alive but stuck.
- Keep probe endpoints cheap and dependency-free.
- Missing readiness probes cause traffic to 503 during rollouts.
7. Set requests and limits
Requests drive scheduling and autoscaling; limits cap runaway pods.
resources:
requests: { cpu: "100m", memory: "128Mi" }
limits: { cpu: "500m", memory: "256Mi" }- The scheduler places pods using requests, not limits.
- Exceeding a memory limit gets the container OOMKilled.
- Node autoscalers size nodes from summed requests.
- Serverless modes (Fargate, Autopilot) bill on requests directly.
Intermediate Examples
8. Wire cloud identity to a ServiceAccount
Each cloud federates pod identity so you avoid long-lived secrets.
apiVersion: v1
kind: ServiceAccount
metadata:
name: web
namespace: payments
annotations:
# EKS IRSA (or use EKS Pod Identity associations instead)
eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/web
# GKE Workload Identity
iam.gke.io/gcp-service-account: web@project.iam.gserviceaccount.com- Annotate the ServiceAccount, then reference it in the pod spec.
- AKS uses Microsoft Entra Workload ID with a federated credential.
- The pod receives a projected token exchanged for cloud credentials.
- Scope the mapped IAM role to least privilege.
9. Enforce a default-deny NetworkPolicy
Pod traffic is open by default; lock it down per namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: payments
spec:
podSelector: {}
policyTypes: [Ingress, Egress]- An empty
podSelectorselects every pod in the namespace. - With no rules, all ingress and egress are denied.
- Add explicit allow policies for the traffic you need.
- The CNI must support NetworkPolicy for this to take effect.
10. Autoscale on CPU
The HorizontalPodAutoscaler scales replicas from live metrics.
kubectl autoscale deployment web -n payments \
--cpu-percent=70 --min=3 --max=20- Requires metrics-server (managed as an add-on on most clouds).
- The HPA scales pods; a node autoscaler then adds nodes.
- Target utilization is a percentage of the CPU request.
- Pair with a PodDisruptionBudget to protect availability.
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).