Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Resource Requests and Limits: QoS, OOMKilled, CPU Throttling and the .NET GC in Containers
A request tells the scheduler how much room to reserve and a limit tells the kernel a ceiling that can't be crossed; exceeding memory means OOMKilled, hitting the CPU limit means throttling. With real output we see a 500m limit drop .NET's ProcessorCount to 1 and turn Server GC off, the heap limit at 75 percent of the limit, managed OutOfMemoryException versus native OOMKilled, the GCHeapHardLimitPercent hex trap, throttling and quotas.
Kubernetes Health Probes: Startup, Liveness, Readiness and ASP.NET Core Health Checks
A startup probe waits for startup, liveness restarts a stuck process and readiness pulls a pod out of traffic; in ASP.NET Core tagged health checks give each probe its own endpoint. With real output we watch a 40-second warm-up fall into an endless restart loop under liveness, reach zero restarts with a startupProbe, see a database check in liveness cause four restarts per pod in two minutes, and do the math on probe timings.
.NET Configuration with ConfigMaps and Secrets: Environment Variables, Volumes and Picking Up Changes
ConfigMaps and Secrets enter .NET configuration as environment variables (ConnectionStrings__Default) or as files in a volume; env and subPath mounts never update, directory mounts update in 10 to 80 seconds. Measured on kind, .NET 10's default watcher missed the ConfigMap change while the polling watcher caught it. We also cover the provider order trap, triggering rollouts, immutable ConfigMaps, base64 not being encryption and Angular's config.json.
External Traffic in Kubernetes: Ingress, the ingress-nginx Retirement and Gateway API with HTTPRoute
The Ingress API is frozen and ingress-nginx retired in March 2026; the way forward is the Gateway API, split into GatewayClass, Gateway and HTTPRoute. We install Envoy Gateway on kind, route /api to .NET and everything else to Angular, and look at why PathPrefix doesn't catch /apifoo, route status conditions, TLS and forwarded header notes, and the warnings of an ingress2gateway migration, all with real output.
Kubernetes Services: ClusterIP, NodePort, LoadBalancer, DNS and EndpointSlices
A Service puts a stable virtual IP and a DNS name such as api.bookstore.svc.cluster.local in front of changing pod IPs, taking addresses from EndpointSlices and routing from kube-proxy rules. With real output we look at named targetPorts, per-connection load balancing and HttpClient, readiness pulling every pod out of traffic, NodePort vs LoadBalancer vs headless, the 1.36 externalIPs deprecation and empty-endpoint traps.
Kubernetes Deployments and ReplicaSets: Labels, Rolling Updates, Rollout History and Undo
A Deployment finds its pods through a label selector, creates a ReplicaSet per pod template and drives rolling updates with maxSurge, maxUnavailable and minReadySeconds. We watch a four-replica rollout second by second, then see a missing tag hit progressDeadlineSeconds, the gap rollout undo opens with Git, bundling changes with pause, the change-cause trap and immutable image tags, all with real output.
Kubernetes Pods: Running a .NET Container, Lifecycle, Init Containers and Native Sidecars
A pod is the unit of execution for containers sharing one network; .NET 8+ images listen on 8080, chiseled images come non-root and shell-less, while the full aspnet image trips runAsNonRoot. With real output we look at pod phases, CrashLoopBackOff's doubling backoff, the limits of a wait-for-db init container, native sidecars (stable in 1.33) and why a sidecar that ignores SIGTERM stretches pod deletion by 30 seconds.
A Local Kubernetes Cluster and kubectl: kind, k3d, minikube, Contexts and Namespaces
We use kind in this series: a three-node cluster comes up from one YAML file in 20 seconds and local images reach the nodes with kind load. We compare kind, k3d, minikube and Docker Desktop, then look at kubeconfig, contexts and namespaces, commands that silently run in the wrong context, the :latest ErrImagePull trap, server dry runs, drift seen through kubectl diff and kubectl version skew, all with real output.
What Is Kubernetes and When Don't You Need It? Control Plane, Nodes and Desired State
Kubernetes is a container orchestration platform where you declare what you want and it keeps pulling the actual state towards it. We watch a deleted pod come back, map the control plane and node components, measure how long a dead node really takes to recover, look at the three-releases-a-year support calendar and ask when Kubernetes is an unnecessary cost.
Reading and Migrating Old Jenkins Setups: Freestyle to Pipeline, Blue Ocean to Pipeline Graph View, Java 17 to 21
You read an old Jenkins with an inventory first, then migrate step by step: Java 21 first, then the Jenkins version, then jobs. The real message 2.580.2 prints when refusing to start on Java 17, the Java timeline for controllers and agents, the Jenkinsfile equivalent of a Freestyle config.xml, Pipeline Graph View instead of the deprecated Blue Ocean, JNLP to WebSocket, and a quick look at GitHub Actions Importer.
Managing Jenkins as Code: Configuration as Code (JCasC), plugins.txt and Backups
You manage Jenkins as code with a Dockerfile, a pinned plugins.txt and JCasC YAML in Git, and back up only the state in JENKINS_HOME. The YAML's structure, the export's encrypted-secret trap, a manual change undone on reload, --available-updates, no bundled plugins in the war since 2.580.1, a 1.7 MB backup, a real restore test and the LTS upgrade flow.
Jenkins Shared Libraries: Sharing Pipeline Code with vars/ and src/
A Shared Library keeps repeated pipeline code in a separate repository as vars/ steps and src/ classes; pipelines load it pinned to a tag with @Library('lib@v1.2.0'). The dotnetCi and angularCi steps, a global library via JCasC, the risk of an unpinned main, real output of the difference between a trusted global library and a sandboxed folder library, a JenkinsPipelineUnit test, and when not to write a library.