Kubernetes (K8s) & AKS
In short: Kubernetes is an open-source container orchestrator (from Google, now CNCF).
- It automates deploying, scaling and operating containers across a cluster: scheduling pods onto nodes, self-healing (restarting/rescheduling failed containers), service discovery and load balancing, rolling updates and rollbacks, horizontal autoscaling, configuration and secret management, and storage orchestration — all driven by declarative desired state.
In short: Control plane: kube-apiserver (API front end), etcd (cluster state store), kube-scheduler (places pods on nodes), kube-controller-manager (reconciliation loops), cloud-controller-manager (cloud integration).
- Worker nodes: kubelet (runs and monitors pods), kube-proxy (service networking rules), and a container runtime (containerd/CRI-O).
- In AKS, Azure manages the control plane; you manage node pools and workloads.
In short: A Pod is the smallest deployable unit: one or more tightly coupled containers sharing an IP address, port space and volumes, scheduled together on one node (e.g. app + sidecar).
- Pods are ephemeral and replaceable, so you manage them through higher-level controllers (Deployments, StatefulSets, Jobs) that recreate and scale them, instead of running bare containers or bare pods.
In short: A ReplicaSet keeps a set number of identical pod replicas running.
- A Deployment manages ReplicaSets to provide declarative updates, rolling updates, rollbacks and revision history for stateless apps — you normally use Deployments, not ReplicaSets directly.
- A StatefulSet is for stateful apps: pods get stable names (
app-0,app-1), stable network identities via a headless Service, ordered start/stop, and their own persistent volumes.
In short: ClusterIP (default;
- stable internal IP/DNS for pod-to-pod traffic), NodePort (exposes a port on each node), LoadBalancer (provisions a cloud load balancer with an external IP), ExternalName (DNS alias to an external name).
- A headless Service (
clusterIP: None) returns pod IPs directly. - Services select pods by labels and load-balance to ready endpoints.
In short: A virtual partition inside a cluster that scopes names and lets you apply RBAC, resource quotas, limit ranges and network policies per team or environment.
- Default namespaces:
default,kube-system,kube-public,kube-node-lease. - DNS for services includes the namespace (
svc.namespace.svc.cluster.local). - Nodes and PersistentVolumes are cluster-scoped.
In short: Both inject configuration into pods as environment variables or mounted files.
- ConfigMaps hold non-sensitive data.
- Secrets hold sensitive data (passwords, keys, certificates);
- they're base64-encoded (not encrypted by default), can be encrypted at rest in etcd, have tighter RBAC, and are mounted on tmpfs.
- In production, source secrets from Azure Key Vault (Secrets Store CSI driver / External Secrets) with Workload Identity.
In short: Liveness checks whether the container is alive; failing it causes a restart (use for deadlocks/hangs; don't include dependency checks).
- Readiness checks whether it can serve traffic; failing removes the pod from Service endpoints without restarting (use for warm-up and dependency availability).
- Startup probes protect slow-starting apps — liveness and readiness don't run until the startup probe succeeds.
In short: Requests are the guaranteed amount used by the scheduler to place pods.
- Limits are the maximum a container may use.
- Exceeding the CPU limit causes throttling (slower, not killed); exceeding the memory limit gets the container OOMKilled.
- Requests/limits determine QoS (Guaranteed, Burstable, BestEffort), which affects eviction order under node pressure.
- Set requests based on observed usage; many teams set memory limits but avoid CPU limits to prevent throttling.
In short: When the pod template changes (e.g. new image), the Deployment creates a new ReplicaSet and gradually scales it up while scaling the old one down, respecting maxSurge (extra pods allowed) and maxUnavailable, and waiting for readiness.
- If the new version is bad:
kubectl rollout undo deployment/name(or--to-revision), orhelm rollback. - Check with
kubectl rollout status/history.
In short: A LoadBalancer Service exposes one service with its own cloud load balancer at layer 4.
- An Ingress is a layer-7 (HTTP/HTTPS) routing rule set — host and path based routing, TLS termination — handled by an ingress controller behind a single load balancer for many services.
- The Gateway API is the newer, more powerful successor.
In short: The package manager for Kubernetes.
- A chart bundles templated manifests plus default
values.yaml; you install it as a release with environment-specific values, upgrade, view history and roll back. - It removes copy-paste YAML across environments and lets you share apps (e.g. installing ingress-nginx, cert-manager, Prometheus from public charts).
In short: HPA adjusts the number of pod replicas based on metrics (CPU/memory via metrics-server, or custom/external metrics).
- VPA adjusts pod resource requests.
- Cluster Autoscaler (or Node Auto Provisioning/Karpenter) adds or removes nodes when pods are unschedulable or nodes are underused.
- KEDA scales on event sources like queue length, including to zero.
- Requests must be set for CPU-based HPA to work.
In short: Entra ID integration and least-privilege RBAC;
- separate namespaces;
- NetworkPolicies (default deny);
- Pod Security Standards (non-root, read-only FS, no privilege escalation);
- private registry with image scanning and admission policies (Azure Policy/Gatekeeper/Kyverno);
- secrets in Key Vault via CSI + Workload Identity;
- etcd encryption;
- private cluster/API server authorised IP ranges;
- keep Kubernetes and node images patched;
- Defender for Containers;
- audit logs;
- limit
cluster-admin.
In short: A helper container in the same pod as the main app, sharing its network and volumes, that adds functionality without changing the app: service mesh proxies (Envoy/Istio), log shippers, config reloaders, Dapr sidecar, auth proxies.
- Kubernetes 1.29+ supports native sidecars (init containers with
restartPolicy: Always) that start before and stop after the main container.
kubectl apply -f deployment.yaml?kubectl sends the manifest to the API server → authentication, authorisation (RBAC) and admission controllers (validation/mutation) → object stored in etcd → the Deployment controller sees it and creates/updates a ReplicaSet → the ReplicaSet controller creates Pod objects → the scheduler assigns each pod to a node → the kubelet on that node pulls images via the container runtime and starts containers → probes report health → endpoints controller adds ready pods to Services.
In short: kubectl describe pod (events, last state, exit code, probe failures); kubectl logs <pod> --previous to see why the last run died.
- Common causes: unhandled exception at startup (bad connection string, missing env var/secret key), wrong command/entrypoint, liveness probe failing too early (add a startup probe/initialDelay), permission errors (non-root), OOMKilled (exit 137).
- Reproduce locally with the same image and env; fix config and redeploy.
In short: Ensure readiness probes reflect real readiness so traffic only reaches ready pods;
- set
maxUnavailable: 0andmaxSurge: 1+; - handle SIGTERM gracefully (ASP.NET Core does — finish in-flight requests) and add a short
preStopsleep so endpoints are removed from load balancers before shutdown; - set an adequate
terminationGracePeriodSeconds; - run ≥ 2–3 replicas with a PodDisruptionBudget;
- keep API and DB changes backward compatible (expand-contract) because old and new versions overlap.
In short: Pod requests exceed free allocatable memory on all nodes.
- Options: check whether requests are oversized (right-size them using actual usage), scale the node pool or enable the cluster autoscaler/node auto-provisioning, add a node pool with larger VMs, remove unused workloads, check ResourceQuotas and taints/node selectors preventing placement.
- Verify with
kubectl describe nodes(Allocated resources) andkubectl top nodes.
In short: Enable the OIDC issuer and Workload Identity on AKS;
- create a user-assigned managed identity with Key Vault access (RBAC role "Key Vault Secrets User");
- create a federated credential linking the identity to the Kubernetes ServiceAccount;
- annotate the ServiceAccount and label pods to use it.
- Then either use the Secrets Store CSI Driver (mount secrets as files/sync to K8s Secrets) or call Key Vault from code with
DefaultAzureCredential. - No passwords stored anywhere.
In short: Usually no.
- Stateful databases need careful handling of storage, backups, HA, failover and upgrades;
- a managed service (Azure SQL Database/Managed Instance) gives backups, HA, patching and SLAs out of the box.
- Running databases in Kubernetes (StatefulSets, operators) is viable for teams with strong expertise or specific needs (portability, edge, dev/test).
- Keep the cluster for stateless services and connect to managed data stores.