<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ajinkya Singh</title>
    <description>The latest articles on DEV Community by Ajinkya Singh (@ajinkya_singh_2c02bd40423).</description>
    <link>https://dev.to/ajinkya_singh_2c02bd40423</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3547083%2F9137aefe-15a5-47fe-a3b8-5daaab2a99a5.jpg</url>
      <title>DEV Community: Ajinkya Singh</title>
      <link>https://dev.to/ajinkya_singh_2c02bd40423</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ajinkya_singh_2c02bd40423"/>
    <language>en</language>
    <item>
      <title>Kubernetes Core Workloads: Everything You Need to Know</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Fri, 03 Apr 2026 07:52:31 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/kubernetes-core-workloads-everything-you-need-to-know-4e4m</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/kubernetes-core-workloads-everything-you-need-to-know-4e4m</guid>
      <description>&lt;p&gt;If you've made it past the basics of Kubernetes — you know what a cluster is, you've spun up a local environment with &lt;code&gt;kind&lt;/code&gt; or &lt;code&gt;minikube&lt;/code&gt; — the next wall you hit is understanding the &lt;strong&gt;workload objects&lt;/strong&gt;. There are nine of them. They look similar in YAML. They all involve containers. But they each exist for a very different reason.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Quick Reference: Which Workload Do You Need?
&lt;/h2&gt;

&lt;p&gt;Before diving in, here's the decision tree you'll use every day:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload&lt;/th&gt;
&lt;th&gt;Use When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Running stateless apps, APIs, web servers, workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;StatefulSet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Databases, message brokers, anything needing stable identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DaemonSet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Log agents, monitoring — one pod per node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Job&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One-off batch tasks: migrations, reports, cleanup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CronJob&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Scheduled recurring tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Pod&lt;/strong&gt; (bare)&lt;/td&gt;
&lt;td&gt;Almost never in production — use one of the above&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now let's understand &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pods: The Atomic Unit
&lt;/h2&gt;

&lt;p&gt;Everything in Kubernetes ultimately runs as a &lt;strong&gt;Pod&lt;/strong&gt; — the smallest deployable unit. You don't run containers directly; you run Pods that contain containers.&lt;/p&gt;

&lt;p&gt;Think of a Pod as a tiny apartment that one or more containers share:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They share a &lt;strong&gt;single IP address&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Containers within a Pod talk to each other via &lt;code&gt;localhost&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;They can share &lt;strong&gt;volumes&lt;/strong&gt; (disk storage)&lt;/li&gt;
&lt;li&gt;They always land on the &lt;strong&gt;same node&lt;/strong&gt; — never split
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-server-pod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mycompany/api:2.1.0&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;256Mi"&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;250m"&lt;/span&gt;
        &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000m"&lt;/span&gt;
      &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/health&lt;/span&gt;
          &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
        &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
        &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
      &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/ready&lt;/span&gt;
          &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
        &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
        &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Most Important Thing About Pods
&lt;/h3&gt;

&lt;p&gt;Pods are &lt;strong&gt;ephemeral&lt;/strong&gt;. When a Pod dies, a new one is created with a completely new name and a completely new IP. Any code that hardcoded the old IP breaks. This is why Services exist (Phase 3) — but it's the mental model you need to carry through everything else.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two Probes You Can't Skip
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Liveness probe&lt;/strong&gt; — "Is this container still alive?" If it fails, Kubernetes &lt;strong&gt;restarts&lt;/strong&gt; the container. Use for crash detection and deadlocks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Readiness probe&lt;/strong&gt; — "Is this container ready for traffic?" If it fails, the pod is &lt;strong&gt;removed from the Service's endpoints&lt;/strong&gt; — stops receiving traffic — but is &lt;em&gt;not&lt;/em&gt; restarted. Use for startup warmup and temporary overload.&lt;/p&gt;

&lt;p&gt;These two probes are doing different jobs. Never confuse them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pod Status Lifecycle
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pending → Running → Succeeded
              ↓
         Failed / CrashLoopBackOff / OOMKilled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you see &lt;code&gt;CrashLoopBackOff&lt;/code&gt;, run &lt;code&gt;kubectl logs my-pod --previous&lt;/code&gt; — that's where your crash output lives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Debugging Playbook
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Pod stuck in Pending?&lt;/span&gt;
kubectl describe pod my-pod   &lt;span class="c"&gt;# read the Events section&lt;/span&gt;
&lt;span class="c"&gt;# "Insufficient CPU" → reduce requests or add nodes&lt;/span&gt;

&lt;span class="c"&gt;# ImagePullBackOff?&lt;/span&gt;
kubectl describe pod my-pod   &lt;span class="c"&gt;# wrong image name? typo? private registry?&lt;/span&gt;

&lt;span class="c"&gt;# CrashLoopBackOff?&lt;/span&gt;
kubectl logs my-pod &lt;span class="nt"&gt;--previous&lt;/span&gt;   &lt;span class="c"&gt;# read the crash&lt;/span&gt;

&lt;span class="c"&gt;# OOMKilled?&lt;/span&gt;
kubectl describe pod my-pod   &lt;span class="c"&gt;# see Last State → increase memory limit&lt;/span&gt;

&lt;span class="c"&gt;# Running but not working?&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; my-pod &lt;span class="nt"&gt;--&lt;/span&gt; /bin/bash   &lt;span class="c"&gt;# investigate from inside&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🧪 Practice — Pods
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab 1: Your first pod&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: hello-nginx
  labels:
    app: hello
spec:
  containers:
    - name: nginx
      image: nginx:1.25
      ports:
        - containerPort: 80
      resources:
        requests:
          memory: "64Mi"
          cpu: "50m"
        limits:
          memory: "128Mi"
          cpu: "200m"
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;--watch&lt;/span&gt;
kubectl describe pod hello-nginx    &lt;span class="c"&gt;# read the Events section top to bottom&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; hello-nginx &lt;span class="nt"&gt;--&lt;/span&gt; /bin/bash
&lt;span class="c"&gt;# inside: curl localhost&lt;/span&gt;
kubectl port-forward pod/hello-nginx 8080:80 &amp;amp;
curl http://localhost:8080
&lt;span class="nb"&gt;kill&lt;/span&gt; %1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lab 2: Multi-container pod — shared localhost&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: multi-pod
spec:
  containers:
    - name: app
      image: nginx:1.25
    - name: sidecar
      image: busybox
      command: ['sh', '-c', 'while true; do echo sidecar running; sleep 5; done']
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;kubectl logs multi-pod &lt;span class="nt"&gt;-c&lt;/span&gt; app
kubectl logs multi-pod &lt;span class="nt"&gt;-c&lt;/span&gt; sidecar
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; multi-pod &lt;span class="nt"&gt;-c&lt;/span&gt; sidecar &lt;span class="nt"&gt;--&lt;/span&gt; /bin/sh
&lt;span class="c"&gt;# inside: wget -q -O- localhost   ← hits the nginx container via shared IP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lab 3: Trigger and observe CrashLoopBackOff&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: crasher
spec:
  containers:
    - name: app
      image: busybox
      command: ['sh', '-c', 'echo crashing; exit 1']
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;--watch&lt;/span&gt;    &lt;span class="c"&gt;# watch it go into CrashLoopBackOff&lt;/span&gt;
kubectl logs crasher &lt;span class="nt"&gt;--previous&lt;/span&gt;   &lt;span class="c"&gt;# see the crash output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod hello-nginx multi-pod crasher
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Namespaces: Logical Isolation
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Namespace&lt;/strong&gt; is a virtual cluster inside your real cluster. It's how you divide one Kubernetes cluster into isolated sections — by team, environment, or application.&lt;/p&gt;

&lt;p&gt;Four namespaces exist by default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;default&lt;/code&gt; — where objects land if you don't specify&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kube-system&lt;/code&gt; — Kubernetes system components (etcd, apiserver, coredns)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kube-public&lt;/code&gt; — publicly readable data (rarely used)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kube-node-lease&lt;/code&gt; — node heartbeat objects (internal, ignore)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What Namespaces Give You
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Name reuse&lt;/strong&gt; — you can have a &lt;code&gt;webapp&lt;/code&gt; Deployment in both &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; with no conflict.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RBAC scoping&lt;/strong&gt; — give team A access only to their namespace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource quotas&lt;/strong&gt; — cap a namespace to 4 CPUs and 8Gi memory total.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ResourceQuota&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production-quota&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50"&lt;/span&gt;
    &lt;span class="na"&gt;requests.cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
    &lt;span class="na"&gt;requests.memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;20Gi&lt;/span&gt;
    &lt;span class="na"&gt;limits.cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;20"&lt;/span&gt;
    &lt;span class="na"&gt;limits.memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;40Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  One Critical Misconception
&lt;/h3&gt;

&lt;p&gt;Namespaces do &lt;strong&gt;not&lt;/strong&gt; provide network isolation by default. A pod in &lt;code&gt;dev&lt;/code&gt; can still reach a pod in &lt;code&gt;prod&lt;/code&gt; if it knows the IP or DNS name. For actual network isolation, you need NetworkPolicies.&lt;/p&gt;

&lt;p&gt;Cross-namespace DNS format: &lt;code&gt;&amp;lt;service&amp;gt;.&amp;lt;namespace&amp;gt;.svc.cluster.local&lt;/code&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🧪 Practice — Namespaces
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab: Isolation, quotas, and the -n flag&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create two environments&lt;/span&gt;
kubectl create namespace dev
kubectl create namespace prod

&lt;span class="c"&gt;# Deploy the same app name in both — no conflict&lt;/span&gt;
kubectl create deployment webapp &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.25 &lt;span class="nt"&gt;-n&lt;/span&gt; dev
kubectl create deployment webapp &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.25 &lt;span class="nt"&gt;-n&lt;/span&gt; prod

kubectl get deployments &lt;span class="nt"&gt;-A&lt;/span&gt;    &lt;span class="c"&gt;# see both side-by-side&lt;/span&gt;

&lt;span class="c"&gt;# Apply a quota to prod&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: v1
kind: ResourceQuota
metadata:
  name: prod-quota
  namespace: prod
spec:
  hard:
    pods: "5"
    requests.cpu: "2"
    requests.memory: 4Gi
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Try to exceed it&lt;/span&gt;
kubectl scale deployment webapp &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10 &lt;span class="nt"&gt;-n&lt;/span&gt; prod
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; prod              &lt;span class="c"&gt;# stops at quota limit&lt;/span&gt;
kubectl describe resourcequota prod-quota &lt;span class="nt"&gt;-n&lt;/span&gt; prod   &lt;span class="c"&gt;# usage vs hard&lt;/span&gt;

&lt;span class="c"&gt;# Set dev as your default namespace&lt;/span&gt;
kubectl config set-context &lt;span class="nt"&gt;--current&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
kubectl get pods    &lt;span class="c"&gt;# now implicitly reads from dev&lt;/span&gt;

&lt;span class="c"&gt;# Switch back&lt;/span&gt;
kubectl config set-context &lt;span class="nt"&gt;--current&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete namespace dev prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Labels, Selectors &amp;amp; Annotations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Labels&lt;/strong&gt; are key-value pairs on any Kubernetes object. They're the connective tissue — how Services find Pods, how Deployments track their ReplicaSets, how you filter resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Annotations&lt;/strong&gt; are also key-value pairs but for &lt;em&gt;non-identifying&lt;/em&gt; metadata: descriptions, tool config, URLs. They cannot be used in selectors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.1.0"&lt;/span&gt;   &lt;span class="c1"&gt;# always quote values that look like numbers&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Payments&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;API&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;server"&lt;/span&gt;
    &lt;span class="na"&gt;prometheus.io/scrape&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How a Service Uses Labels
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;           &lt;span class="c1"&gt;# matches pods with app=api&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;    &lt;span class="c1"&gt;# AND env=production&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Service routes traffic to any pod with &lt;em&gt;both&lt;/em&gt; labels. Remove a label from a pod and it's immediately removed from the Service's endpoints. Add it back and it rejoins. This is live — no restart required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set-Based Selectors
&lt;/h3&gt;

&lt;p&gt;Beyond simple equality, you can use expressions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matchExpressions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env&lt;/span&gt;
      &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;In&lt;/span&gt;
      &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;staging&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tier&lt;/span&gt;
      &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NotIn&lt;/span&gt;
      &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
      &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Exists&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One gotcha: always quote version numbers in YAML. &lt;code&gt;version: 2.0&lt;/code&gt; is parsed as a float, stored as &lt;code&gt;"2"&lt;/code&gt; — breaking your selectors silently.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧪 Practice — Labels &amp;amp; Selectors
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab: Live label manipulation and Service routing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create three pods with different label combos&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: frontend-v1
  labels:
    app: frontend
    env: prod
    version: "1.0"
spec:
  containers:
    - name: nginx
      image: nginx:1.25
---
apiVersion: v1
kind: Pod
metadata:
  name: backend-v1
  labels:
    app: backend
    env: prod
    version: "1.0"
spec:
  containers:
    - name: nginx
      image: nginx:1.24
---
apiVersion: v1
kind: Pod
metadata:
  name: backend-staging
  labels:
    app: backend
    env: staging
    version: "2.0"
spec:
  containers:
    - name: nginx
      image: nginx:1.26
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Filter practice&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;--show-labels&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend,env&lt;span class="o"&gt;=&lt;/span&gt;prod
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s1"&gt;'env in (prod,staging)'&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s1"&gt;'version notin (1.0)'&lt;/span&gt;

&lt;span class="c"&gt;# Create a Service that selects app=backend + env=prod&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: backend-svc
spec:
  selector:
    app: backend
    env: prod
  ports:
    - port: 80
      targetPort: 80
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;kubectl describe service backend-svc   &lt;span class="c"&gt;# check Endpoints section&lt;/span&gt;

&lt;span class="c"&gt;# Live label surgery — remove env from backend-v1&lt;/span&gt;
kubectl label pod backend-v1 env-
kubectl describe service backend-svc   &lt;span class="c"&gt;# endpoint disappears immediately&lt;/span&gt;

&lt;span class="c"&gt;# Add it back&lt;/span&gt;
kubectl label pod backend-v1 &lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prod
kubectl describe service backend-svc   &lt;span class="c"&gt;# endpoint returns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod frontend-v1 backend-v1 backend-staging
kubectl delete service backend-svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ReplicaSets: Self-Healing
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;ReplicaSet&lt;/strong&gt; ensures a specified number of identical Pods are always running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec.replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;

&lt;span class="s"&gt;Pod-2 crashes → ReplicaSet creates Pod-4 → back to &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="s"&gt;Rogue pod added → ReplicaSet deletes one → back to &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The RS continuously counts pods matching its selector. Actual count ≠ desired → create or delete.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why You Almost Never Create ReplicaSets Directly
&lt;/h3&gt;

&lt;p&gt;ReplicaSets don't support rolling updates or rollbacks. That's exactly what Deployments add. In practice, you create a Deployment and it creates/manages a ReplicaSet for you.&lt;/p&gt;

&lt;p&gt;You need to understand ReplicaSets because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployments own them under the hood&lt;/li&gt;
&lt;li&gt;Debugging often means inspecting the RS&lt;/li&gt;
&lt;li&gt;It explains the self-healing behavior you see&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The RS name format when created by a Deployment: &lt;code&gt;&amp;lt;deployment-name&amp;gt;-&amp;lt;pod-template-hash&amp;gt;&lt;/code&gt;. That hash changes every time the pod template changes — which is exactly how rolling updates work.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧪 Practice — ReplicaSets
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab: Self-healing in action&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: demo-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;demo

&lt;span class="c"&gt;# Open a watch in a second terminal: kubectl get pods --watch&lt;/span&gt;

&lt;span class="c"&gt;# Kill one pod — RS heals immediately&lt;/span&gt;
kubectl delete pod &lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;demo &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;demo    &lt;span class="c"&gt;# new pod already created&lt;/span&gt;

&lt;span class="c"&gt;# Scale up&lt;/span&gt;
kubectl scale rs demo-rs &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;demo

&lt;span class="c"&gt;# Try creating a stray pod with the same label&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: stray-pod
  labels:
    app: demo        # matches RS selector!
spec:
  containers:
    - name: nginx
      image: nginx:1.25
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;demo    &lt;span class="c"&gt;# RS sees 6, wants 5 → deletes one&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete rs demo-rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deployments: The Standard Way to Run Apps
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Deployment&lt;/strong&gt; is what you use 90% of the time. It wraps a ReplicaSet and adds rolling updates, rollbacks, and version history.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You → Deployment → manages → ReplicaSets → manages → Pods
                      │
                      ├── RS v1 (old image)  → 0 pods
                      └── RS v2 (new image)  → 3 pods ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How a Rolling Update Actually Works
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;maxSurge: 1, maxUnavailable: 0&lt;/code&gt; and 3 replicas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[v1][v1][v1]               # start

[v1][v1][v1][v2]           # spin up 1 new pod (surge)
[v1][v1][v2]               # v2 passes readiness → kill 1 v1

[v1][v1][v2][v2]           # spin up another v2
[v1][v2][v2]               # v2 passes → kill v1

[v1][v2][v2][v2]           # final new pod
[v2][v2][v2]               # all updated, zero downtime ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The readiness probe gates each step. Without it, Kubernetes can't tell when a new pod is actually ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production Deployment YAML
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orders-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orders-api&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
    &lt;span class="na"&gt;rollingUpdate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;maxSurge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;maxUnavailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;   &lt;span class="c1"&gt;# never go below desired count&lt;/span&gt;
  &lt;span class="na"&gt;minReadySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;revisionHistoryLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orders-api&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mycompany/orders-api:3.0.1&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/ready&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
            &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Commands You'll Use Daily
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Update image → triggers rolling update&lt;/span&gt;
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deployment/my-app &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.26

&lt;span class="c"&gt;# Watch it happen&lt;/span&gt;
kubectl rollout status deployment/my-app

&lt;span class="c"&gt;# Something went wrong?&lt;/span&gt;
kubectl rollout undo deployment/my-app

&lt;span class="c"&gt;# Check history&lt;/span&gt;
kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deployment/my-app

&lt;span class="c"&gt;# Restart all pods (rolling, with zero downtime)&lt;/span&gt;
kubectl rollout restart deployment/my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;kubectl rollout undo&lt;/code&gt; is your emergency brake. Run it first, debug second.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧪 Practice — Deployments
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab: Full deployment lifecycle — deploy, update, break, rollback&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Deploy v1&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  annotations:
    kubernetes.io/change-cause: "initial deployment nginx 1.24"
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webapp
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
        - name: nginx
          image: nginx:1.24
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 3
            periodSeconds: 5
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;--watch&lt;/span&gt;    &lt;span class="c"&gt;# Ctrl+C when all 3 Running&lt;/span&gt;
kubectl get rs              &lt;span class="c"&gt;# see the RS created by the Deployment&lt;/span&gt;

&lt;span class="c"&gt;# Rolling update to 1.25&lt;/span&gt;
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deployment/webapp &lt;span class="nv"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.25
kubectl annotate deployment/webapp kubernetes.io/change-cause&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"upgrade to nginx 1.25"&lt;/span&gt; &lt;span class="nt"&gt;--overwrite&lt;/span&gt;
kubectl rollout status deployment/webapp
kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deployment/webapp   &lt;span class="c"&gt;# see 2 revisions&lt;/span&gt;
kubectl get rs    &lt;span class="c"&gt;# old RS now has 0 pods but still exists for rollback&lt;/span&gt;

&lt;span class="c"&gt;# Simulate a bad update — nonexistent image&lt;/span&gt;
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deployment/webapp &lt;span class="nv"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:NONEXISTENT
kubectl rollout status deployment/webapp    &lt;span class="c"&gt;# hangs — new pods can't start&lt;/span&gt;
kubectl get pods    &lt;span class="c"&gt;# old pods still serving! new pods in ErrImagePull&lt;/span&gt;

&lt;span class="c"&gt;# Emergency rollback&lt;/span&gt;
kubectl rollout undo deployment/webapp
kubectl rollout status deployment/webapp    &lt;span class="c"&gt;# watch recovery&lt;/span&gt;
kubectl get pods    &lt;span class="c"&gt;# all healthy again&lt;/span&gt;

&lt;span class="c"&gt;# Scale&lt;/span&gt;
kubectl scale deployment webapp &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6
kubectl scale deployment webapp &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete deployment webapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Imperative vs Declarative: The Mental Model
&lt;/h2&gt;

&lt;p&gt;There are two ways to work with Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imperative&lt;/strong&gt; — tell Kubernetes what to do step by step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create deployment web &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.25
kubectl scale deployment web &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deployment/web &lt;span class="nv"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.26
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Declarative&lt;/strong&gt; — tell Kubernetes what you want, let it figure out how:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; web.yaml
&lt;span class="c"&gt;# edit the file&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; web.yaml   &lt;span class="c"&gt;# kubernetes computes the diff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key advantage of declarative: &lt;strong&gt;idempotency&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Imperative — fails on second run&lt;/span&gt;
kubectl create deployment web &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx
&lt;span class="c"&gt;# Error: deployments.apps "web" already exists&lt;/span&gt;

&lt;span class="c"&gt;# Declarative — safe to run forever&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; web.yaml
&lt;span class="c"&gt;# deployment.apps/web created      (first run)&lt;/span&gt;
&lt;span class="c"&gt;# deployment.apps/web unchanged    (no changes)&lt;/span&gt;
&lt;span class="c"&gt;# deployment.apps/web configured   (file changed)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;In production: always declarative.&lt;/strong&gt; Store YAML in Git. CI/CD runs &lt;code&gt;kubectl apply&lt;/code&gt;. This is GitOps — Git is the source of truth, the cluster always mirrors it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate YAML Fast
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create deployment web &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.25 &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--dry-run=client -o yaml&lt;/code&gt; generates the YAML locally without sending anything to the API server. Edit it, then apply. This is extremely useful in CKA/CKAD exams.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧪 Practice — Imperative vs Declarative
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab: Generate, edit, and apply&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate Deployment YAML without applying&lt;/span&gt;
kubectl create deployment web &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.25 &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; deployment.yaml

&lt;span class="nb"&gt;cat &lt;/span&gt;deployment.yaml    &lt;span class="c"&gt;# inspect what was generated&lt;/span&gt;

&lt;span class="c"&gt;# Add resources block manually, then apply&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml    &lt;span class="c"&gt;# safe to run again — "unchanged"&lt;/span&gt;

&lt;span class="c"&gt;# Edit the file — change replicas to 5&lt;/span&gt;
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/replicas: 3/replicas: 5/'&lt;/span&gt; deployment.yaml
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml    &lt;span class="c"&gt;# "configured" — only diff applied&lt;/span&gt;
kubectl get deployment web

&lt;span class="c"&gt;# Generate Pod and Service YAML for practice&lt;/span&gt;
kubectl run my-pod &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pod.yaml
kubectl expose deployment web &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80 &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ClusterIP &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete deployment web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  DaemonSets: One Pod per Node
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;DaemonSet&lt;/strong&gt; ensures exactly one Pod runs on every node in the cluster. New node joins → pod auto-created. Node removed → pod garbage collected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node 1      Node 2      Node 3      Node 4 (new)
[log]       [log]       [log]       [log] ← auto-created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When to Use DaemonSets
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Log collection&lt;/td&gt;
&lt;td&gt;Fluentd, Filebeat, Promtail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring agents&lt;/td&gt;
&lt;td&gt;Prometheus node-exporter, Datadog agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network plugins&lt;/td&gt;
&lt;td&gt;Calico, Cilium, kube-proxy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security agents&lt;/td&gt;
&lt;td&gt;Falco, Sysdig&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;kube-proxy&lt;/code&gt; itself is a DaemonSet. Verify: &lt;code&gt;kubectl get ds -n kube-system&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Running on Control-Plane Nodes
&lt;/h3&gt;

&lt;p&gt;By default, DaemonSet pods won't run on control-plane nodes because of a taint: &lt;code&gt;node-role.kubernetes.io/control-plane:NoSchedule&lt;/code&gt;. If you need them there, add a toleration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;tolerations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-role.kubernetes.io/control-plane&lt;/span&gt;
      &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Exists&lt;/span&gt;
      &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NoSchedule&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update Strategies
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RollingUpdate&lt;/strong&gt; (default): automatically updates pods one node at a time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OnDelete&lt;/strong&gt;: only updates pods when you manually delete them — useful for per-node maintenance windows&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧪 Practice — DaemonSets
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab: Per-node coverage and system DaemonSets&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# See existing DaemonSets in the cluster&lt;/span&gt;
kubectl get ds &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;span class="c"&gt;# kube-proxy is a DaemonSet — one pod per node&lt;/span&gt;

&lt;span class="c"&gt;# Create a simple node-monitoring DaemonSet&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-monitor
spec:
  selector:
    matchLabels:
      app: node-monitor
  template:
    metadata:
      labels:
        app: node-monitor
    spec:
      containers:
        - name: monitor
          image: busybox
          command:
            - sh
            - -c
            - while true; do echo "Node &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;NODE_NAME&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt; alive at &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"; sleep 10; done
          env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          resources:
            requests:
              memory: "20Mi"
              cpu: "10m"
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Verify one pod per worker node&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node-monitor &lt;span class="nt"&gt;-o&lt;/span&gt; wide

&lt;span class="c"&gt;# Check logs from one&lt;/span&gt;
&lt;span class="nv"&gt;POD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node-monitor &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
kubectl logs &lt;span class="nv"&gt;$POD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete ds node-monitor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Jobs &amp;amp; CronJobs: Batch and Scheduled Work
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Job&lt;/strong&gt; — runs pods to completion. Once finished successfully, stops. For one-off batch tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CronJob&lt;/strong&gt; — runs a Job on a schedule (cron syntax). For recurring tasks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployment:  "Run this forever"
Job:         "Run this ONCE until it succeeds"
CronJob:     "Run this Job every day at 2am"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Job YAML
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Job&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db-migration&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backoffLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;              &lt;span class="c1"&gt;# retry up to 3 times&lt;/span&gt;
  &lt;span class="na"&gt;activeDeadlineSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;   &lt;span class="c1"&gt;# kill after 5 minutes regardless&lt;/span&gt;
  &lt;span class="na"&gt;ttlSecondsAfterFinished&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;  &lt;span class="c1"&gt;# auto-delete 60s after completion&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;  &lt;span class="c1"&gt;# REQUIRED — Always is invalid for Jobs&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;migration&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mycompany/api:3.0.1&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scripts/migrate.js"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;restartPolicy: OnFailure&lt;/code&gt; (or &lt;code&gt;Never&lt;/code&gt;) is mandatory — Jobs cannot use &lt;code&gt;Always&lt;/code&gt; because they'd never complete.&lt;/p&gt;

&lt;p&gt;Set &lt;code&gt;ttlSecondsAfterFinished&lt;/code&gt; or finished Jobs pile up in your cluster forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  CronJob YAML
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CronJob&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nightly-report&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;        &lt;span class="c1"&gt;# every day at 2:00 AM&lt;/span&gt;
  &lt;span class="na"&gt;concurrencyPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Forbid&lt;/span&gt;    &lt;span class="c1"&gt;# skip if previous run still running&lt;/span&gt;
  &lt;span class="na"&gt;successfulJobsHistoryLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;failedJobsHistoryLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;jobTemplate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;backoffLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
      &lt;span class="na"&gt;ttlSecondsAfterFinished&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
          &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reporter&lt;/span&gt;
              &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mycompany/reporter:1.0&lt;/span&gt;
              &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_report.py"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cron Schedule Quick Reference
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 2 * * *       Every day at 2:00 AM
*/5 * * * *     Every 5 minutes
0 9 * * 1       Every Monday at 9:00 AM
0 0 1 * *       1st of every month at midnight
@daily          Shortcut for 0 0 * * *
@hourly         Shortcut for 0 * * * *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Trigger a CronJob Manually
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create job &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cronjob/nightly-report manual-run-01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a Job immediately using the CronJob's template, without affecting scheduled runs.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧪 Practice — Jobs &amp;amp; CronJobs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab 1: Simple one-off Job&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
  name: hello-job
spec:
  backoffLimit: 2
  ttlSecondsAfterFinished: 60
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: hello
          image: busybox
          command: ['sh', '-c', 'echo "Job running at &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"; sleep 5; echo Done!']
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;--watch&lt;/span&gt;    &lt;span class="c"&gt;# watch pod go: Pending → Running → Completed&lt;/span&gt;
kubectl logs &lt;span class="nt"&gt;-l&lt;/span&gt; job-name&lt;span class="o"&gt;=&lt;/span&gt;hello-job
kubectl get job hello-job   &lt;span class="c"&gt;# COMPLETIONS should show 1/1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lab 2: CronJob that runs every minute&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: batch/v1
kind: CronJob
metadata:
  name: minute-job
spec:
  schedule: "* * * * *"
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      ttlSecondsAfterFinished: 60
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: echo
              image: busybox
              command: ['sh', '-c', 'echo "Scheduled run at &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"']
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Wait 1-2 minutes&lt;/span&gt;
kubectl get &lt;span class="nb"&gt;jobs
&lt;/span&gt;kubectl get cronjob minute-job

&lt;span class="c"&gt;# Trigger it manually right now&lt;/span&gt;
kubectl create job &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cronjob/minute-job manual-run-01
kubectl logs &lt;span class="nt"&gt;-l&lt;/span&gt; job-name&lt;span class="o"&gt;=&lt;/span&gt;manual-run-01

&lt;span class="c"&gt;# Suspend future runs without deleting&lt;/span&gt;
kubectl patch cronjob minute-job &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"suspend":true}}'&lt;/span&gt;
kubectl get cronjob minute-job    &lt;span class="c"&gt;# SUSPEND should show True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete cronjob minute-job
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  StatefulSets: Stateful Applications
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;StatefulSet&lt;/strong&gt; is like a Deployment, but for applications that need three guarantees:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stable, predictable names&lt;/strong&gt; — pods are always &lt;code&gt;pod-0&lt;/code&gt;, &lt;code&gt;pod-1&lt;/code&gt;, &lt;code&gt;pod-2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stable storage&lt;/strong&gt; — each pod gets its own PVC that sticks with it across restarts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordered startup/shutdown&lt;/strong&gt; — pods start in order (0→1→2) and stop in reverse
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEPLOYMENT:              STATEFULSET:
my-app-abc12 (random)    mysql-0  (always 0)
my-app-def34 (random)    mysql-1  (always 1)
my-app-ghi56 (random)    mysql-2  (always 2)

Pod dies → new name      Pod dies → comes back as mysql-1
Pod dies → new IP        Pod dies → same storage re-attached
Starts in any order      Starts 0 first, then 1, then 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Headless Service Requirement
&lt;/h3&gt;

&lt;p&gt;StatefulSets require a &lt;strong&gt;headless Service&lt;/strong&gt; (&lt;code&gt;clusterIP: None&lt;/code&gt;) to provide stable DNS names per pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql-0.mysql-svc.default.svc.cluster.local → 10.244.1.5
mysql-1.mysql-svc.default.svc.cluster.local → 10.244.2.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A normal Service load-balances across pods. A headless Service returns individual DNS records for each pod — so applications can say "connect to the primary at &lt;code&gt;mysql-0.mysql-svc&lt;/code&gt;" and mean it.&lt;/p&gt;

&lt;h3&gt;
  
  
  StatefulSet YAML
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Headless Service — create this FIRST&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql-svc&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;    &lt;span class="c1"&gt;# ← this makes it headless&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3306&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;StatefulSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;serviceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql-svc&lt;/span&gt;    &lt;span class="c1"&gt;# links to headless service above&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:8.0&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;data&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/mysql&lt;/span&gt;
  &lt;span class="na"&gt;volumeClaimTemplates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;     &lt;span class="c1"&gt;# ← key difference from Deployment&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;data&lt;/span&gt;
      &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ReadWriteOnce"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;volumeClaimTemplates&lt;/code&gt; creates individual PVCs per pod: &lt;code&gt;data-mysql-0&lt;/code&gt;, &lt;code&gt;data-mysql-1&lt;/code&gt;, &lt;code&gt;data-mysql-2&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The PVC Retention Gotcha
&lt;/h3&gt;

&lt;p&gt;When you delete a StatefulSet, the PVCs are &lt;strong&gt;not deleted&lt;/strong&gt;. This is intentional — data is precious. But it means they stay around until you clean them up manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete sts mysql
kubectl delete pvc &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mysql   &lt;span class="c"&gt;# must do this separately&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Canary Updates with partition
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;partition&lt;/code&gt; field in &lt;code&gt;rollingUpdate&lt;/code&gt; is powerful for staged rollouts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;updateStrategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
  &lt;span class="na"&gt;rollingUpdate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;partition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;    &lt;span class="c1"&gt;# only update pods with ordinal &amp;gt;= 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set &lt;code&gt;partition: 2&lt;/code&gt; to update only &lt;code&gt;mysql-2&lt;/code&gt; first. Test it. Lower to &lt;code&gt;1&lt;/code&gt;. Lower to &lt;code&gt;0&lt;/code&gt; to complete. This is native canary deployment for StatefulSets.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧪 Practice — StatefulSets
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab: Stable identity, persistent storage, and ordered startup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create headless service + StatefulSet&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  clusterIP: None
  selector:
    app: web
  ports:
    - port: 80
      name: http
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: web-svc
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
          volumeMounts:
            - name: www
              mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
    - metadata:
        name: www
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 1Gi
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Watch ordered startup — web-0 first, then web-1, then web-2&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;--watch&lt;/span&gt;

&lt;span class="c"&gt;# Confirm stable names&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web   &lt;span class="c"&gt;# always web-0, web-1, web-2&lt;/span&gt;

&lt;span class="c"&gt;# See the per-pod PVCs created&lt;/span&gt;
kubectl get pvc   &lt;span class="c"&gt;# www-web-0, www-web-1, www-web-2&lt;/span&gt;

&lt;span class="c"&gt;# Write data to web-0's volume&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;web-0 &lt;span class="nt"&gt;--&lt;/span&gt; sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'echo "pod-0 data" &amp;gt; /usr/share/nginx/html/index.html'&lt;/span&gt;

&lt;span class="c"&gt;# Delete web-0 — watch it come back with the SAME name&lt;/span&gt;
kubectl delete pod web-0
kubectl get pods &lt;span class="nt"&gt;--watch&lt;/span&gt;    &lt;span class="c"&gt;# web-0 comes back, not a random name&lt;/span&gt;

&lt;span class="c"&gt;# Data persists — PVC was reattached&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;web-0 &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /usr/share/nginx/html/index.html   &lt;span class="c"&gt;# still "pod-0 data"&lt;/span&gt;

&lt;span class="c"&gt;# Reach a specific pod by stable DNS from another pod&lt;/span&gt;
kubectl run tmp &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  wget &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-O-&lt;/span&gt; web-0.web-svc.default.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt; — note PVCs must be deleted separately&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete sts web
kubectl delete svc web-svc
kubectl delete pvc &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web    &lt;span class="c"&gt;# PVCs are NOT auto-deleted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Master Cheat Sheet
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# LIST&lt;/span&gt;
kubectl get pods / deploy / rs / ds / sts / &lt;span class="nb"&gt;jobs&lt;/span&gt; / cronjobs

&lt;span class="c"&gt;# USEFUL FLAGS&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; wide              &lt;span class="c"&gt;# +IP +NODE&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;--show-labels&lt;/span&gt;        &lt;span class="c"&gt;# show label columns&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-app        &lt;span class="c"&gt;# filter by label&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;                   &lt;span class="c"&gt;# all namespaces&lt;/span&gt;

&lt;span class="c"&gt;# INSPECT (always read the Events section)&lt;/span&gt;
kubectl describe pod/deploy/sts &amp;lt;n&amp;gt;

&lt;span class="c"&gt;# LOGS&lt;/span&gt;
kubectl logs &amp;lt;pod&amp;gt;
kubectl logs &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;--previous&lt;/span&gt;         &lt;span class="c"&gt;# after a crash&lt;/span&gt;
kubectl logs &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &amp;lt;container&amp;gt;     &lt;span class="c"&gt;# multi-container pod&lt;/span&gt;

&lt;span class="c"&gt;# SHELL&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; /bin/bash

&lt;span class="c"&gt;# DEPLOYMENTS&lt;/span&gt;
kubectl scale deploy &amp;lt;n&amp;gt; &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deploy/&amp;lt;n&amp;gt; &amp;lt;container&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;image&amp;gt;:tag
kubectl rollout status deploy/&amp;lt;n&amp;gt;
kubectl rollout undo deploy/&amp;lt;n&amp;gt;
kubectl rollout restart deploy/&amp;lt;n&amp;gt;

&lt;span class="c"&gt;# JOBS&lt;/span&gt;
kubectl create job &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cronjob/&amp;lt;n&amp;gt;   &lt;span class="c"&gt;# manual trigger&lt;/span&gt;
kubectl patch cronjob &amp;lt;n&amp;gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"suspend":true}}'&lt;/span&gt;

&lt;span class="c"&gt;# GENERATE YAML BOILERPLATE&lt;/span&gt;
kubectl create deployment web &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.25 &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API Versions Quick Reference
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload&lt;/th&gt;
&lt;th&gt;apiVersion&lt;/th&gt;
&lt;th&gt;kind&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pod&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pod&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Namespace&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Namespace&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ReplicaSet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apps/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ReplicaSet&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apps/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Deployment&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DaemonSet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apps/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DaemonSet&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;StatefulSet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apps/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;StatefulSet&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;&lt;code&gt;batch/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Job&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CronJob&lt;/td&gt;
&lt;td&gt;&lt;code&gt;batch/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CronJob&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Restart Policy Rules
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Policy&lt;/th&gt;
&lt;th&gt;Use In&lt;/th&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Always&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deployments, DaemonSets&lt;/td&gt;
&lt;td&gt;Restart on any exit — default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OnFailure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Jobs&lt;/td&gt;
&lt;td&gt;Restart only on non-zero exit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Never&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Jobs&lt;/td&gt;
&lt;td&gt;Never restart — new pod on each retry&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧪 Final Practice — End-to-End Scenario
&lt;/h2&gt;

&lt;p&gt;This lab ties everything together. You'll deploy a full application stack using every concept from this article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Deploy a web application with a background worker, a nightly cleanup job, and per-node logging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Step 1: Create a dedicated namespace&lt;/span&gt;
kubectl create namespace myapp

&lt;span class="c"&gt;# Step 2: Deploy the web app (Deployment)&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: myapp
  labels:
    app: web
    tier: frontend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
        tier: frontend
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
          resources:
            requests: { memory: "64Mi", cpu: "50m" }
            limits:   { memory: "128Mi", cpu: "200m" }
          readinessProbe:
            httpGet: { path: /, port: 80 }
            initialDelaySeconds: 3
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Step 3: Deploy a background worker (Deployment, different labels)&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: worker
  namespace: myapp
  labels:
    app: worker
    tier: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: worker
  template:
    metadata:
      labels:
        app: worker
        tier: backend
    spec:
      containers:
        - name: worker
          image: busybox
          command: ['sh', '-c', 'while true; do echo "worker processing..."; sleep 10; done']
          resources:
            requests: { memory: "32Mi", cpu: "25m" }
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Step 4: Per-node log collector (DaemonSet)&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-collector
  namespace: myapp
spec:
  selector:
    matchLabels:
      app: log-collector
  template:
    metadata:
      labels:
        app: log-collector
    spec:
      containers:
        - name: collector
          image: busybox
          command: ['sh', '-c', 'while true; do echo "collecting logs from &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;NODE_NAME&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"; sleep 15; done']
          env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          resources:
            requests: { memory: "20Mi", cpu: "10m" }
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Step 5: Nightly cleanup Job (CronJob)&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cleanup
  namespace: myapp
spec:
  schedule: "0 3 * * *"
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 2
  jobTemplate:
    spec:
      ttlSecondsAfterFinished: 120
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: cleanup
              image: busybox
              command: ['sh', '-c', 'echo "cleaning up old data..."; sleep 3; echo done']
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Inspect the whole namespace&lt;/span&gt;
kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; myapp

&lt;span class="c"&gt;# Check labels&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; myapp &lt;span class="nt"&gt;--show-labels&lt;/span&gt;

&lt;span class="c"&gt;# Filter by tier&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; myapp &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;tier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;frontend
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; myapp &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;tier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend

&lt;span class="c"&gt;# Trigger cleanup job manually&lt;/span&gt;
kubectl create job &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cronjob/cleanup manual-cleanup-01 &lt;span class="nt"&gt;-n&lt;/span&gt; myapp
kubectl logs &lt;span class="nt"&gt;-l&lt;/span&gt; job-name&lt;span class="o"&gt;=&lt;/span&gt;manual-cleanup-01 &lt;span class="nt"&gt;-n&lt;/span&gt; myapp

&lt;span class="c"&gt;# Simulate rolling update on web&lt;/span&gt;
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deployment/web &lt;span class="nv"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.26 &lt;span class="nt"&gt;-n&lt;/span&gt; myapp
kubectl rollout status deployment/web &lt;span class="nt"&gt;-n&lt;/span&gt; myapp

&lt;span class="c"&gt;# Scale worker up&lt;/span&gt;
kubectl scale deployment worker &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nt"&gt;-n&lt;/span&gt; myapp
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete namespace myapp    &lt;span class="c"&gt;# deletes everything inside it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>docker</category>
      <category>devops</category>
      <category>linux</category>
    </item>
    <item>
      <title>Kubernetes Foundations — Architecture, Components &amp; kubectl</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Sun, 22 Mar 2026 19:05:21 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/kubernetes-foundations-architecture-components-kubectl-n20</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/kubernetes-foundations-architecture-components-kubectl-n20</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why Kubernetes Exists&lt;/li&gt;
&lt;li&gt;Cluster Architecture&lt;/li&gt;
&lt;li&gt;Control Plane&lt;/li&gt;
&lt;li&gt;Worker Node Components&lt;/li&gt;
&lt;li&gt;kubectl&lt;/li&gt;
&lt;li&gt;Local Cluster Setup&lt;/li&gt;
&lt;li&gt;Cheat Sheet&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Kubernetes Exists
&lt;/h2&gt;

&lt;p&gt;Before Kubernetes, running containers in production meant: SSH into servers, start and stop containers by hand, write fragile shell scripts for restarts, and scale by spinning up machines one by one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes is a container orchestration system.&lt;/strong&gt; It solves five problems that every team hits at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔴 Problem 1 — Single Point of Failure&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without Kubernetes:
  [App] ──► [Server A] ──✕──► App is DOWN until someone manually fixes it

With Kubernetes:
             ┌──► [Node A] ──✕── dies
  [App] ─────┤──► [Node B]  ✓  still running
             └──► [Node C]  ✓  still running
                            K8s auto-reschedules pod from A → B or C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Kubernetes detects the dead node and automatically reschedules all pods to healthy ones. No pager. No SSH.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📈 Problem 2 — Manual Scaling&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without Kubernetes:
  Traffic spike → someone notices → SSH → docker run ×10 → 20 minutes wasted

With Kubernetes:
  Traffic spike → HPA detects high CPU → pods spin up automatically → seconds, no human
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The Horizontal Pod Autoscaler watches metrics and adds or removes pods automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚀 Problem 3 — Deployment Downtime&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without Kubernetes:
  Deploy v2:   stop v1 ──► [gap — users see errors] ──► start v2

With Kubernetes (rolling update):
  [v1][v1][v1]
       ↓
  [v2][v1][v1]   ← v2 started and health-checked first
       ↓
  [v2][v2][v1]
       ↓
  [v2][v2][v2]   ← v1 fully gone. Zero downtime.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;New pods are health-checked before old ones are removed. Users never see an error page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔑 Problem 4 — Config &amp;amp; Secrets Chaos&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without Kubernetes:
  DB_PASSWORD="hunter2"  ← hardcoded in source code
  Different .env files per environment ← drift guaranteed

With Kubernetes:
  ConfigMaps + Secrets   ← config lives outside the image
  Same binary            ← works in dev / staging / prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Config is decoupled from the container image entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🌐 Problem 5 — Service Discovery Breakage&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without Kubernetes:
  Service A ──hardcoded──► IP 10.0.0.45 (Service B)
  Service B restarts → new IP → Service A breaks

With Kubernetes:
  Service A ──DNS──► "payment-service"
  Kubernetes routes to the right pods — IPs are irrelevant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Pods are ephemeral and get new IPs on restart. Kubernetes Services provide stable DNS names that always resolve correctly.&lt;/p&gt;




&lt;h3&gt;
  
  
  Common Misconceptions
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Misconception&lt;/th&gt;
&lt;th&gt;Reality&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes replaces Docker&lt;/td&gt;
&lt;td&gt;No — K8s orchestrates containers; Docker/containerd runs them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Only for large companies&lt;/td&gt;
&lt;td&gt;Works equally well for a 2-person startup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud-only&lt;/td&gt;
&lt;td&gt;Runs on laptops, on-prem hardware, and cloud equally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replaces CI/CD pipelines&lt;/td&gt;
&lt;td&gt;K8s is the deployment &lt;em&gt;target&lt;/em&gt;, not the pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Cluster Architecture
&lt;/h2&gt;

&lt;p&gt;A Kubernetes &lt;strong&gt;cluster&lt;/strong&gt; has two types of machines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Control Plane&lt;/strong&gt; — the brain. Makes all scheduling and reconciliation decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker Nodes&lt;/strong&gt; — the muscle. Runs your actual application containers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All communication goes through the control plane. You never interact with worker nodes directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────────┐
│                        KUBERNETES CLUSTER                            │
│                                                                      │
│   You (kubectl)                                                      │
│        │  HTTPS                                                      │
│        ▼                                                             │
│   ┌──────────────────────────────────────────────────────────────┐  │
│   │                     CONTROL PLANE                            │  │
│   │                                                              │  │
│   │   kube-apiserver  ◄──────────────►  etcd                    │  │
│   │   (front door · port 6443)          (cluster database)      │  │
│   │                                                              │  │
│   │   kube-scheduler                  controller-manager        │  │
│   │   (pod placement)                 (reconciliation loops)    │  │
│   └───────────────┬──────────────────────────┬────────────────  ┘  │
│                   │                          │                      │
│      ┌────────────▼──────┐  ┌────────────────▼──┐  ┌────────────┐  │
│      │   Worker Node 1   │  │   Worker Node 2   │  │  Worker 3  │  │
│      │  Pod  Pod         │  │   Pod             │  │  Pod  Pod  │  │
│      │  kubelet          │  │   kubelet         │  │  kubelet   │  │
│      │  kube-proxy       │  │   kube-proxy      │  │  kube-proxy│  │
│      │  containerd       │  │   containerd      │  │  containerd│  │
│      └───────────────────┘  └───────────────────┘  └────────────┘  │
└──────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;▶ Full flow: &lt;code&gt;kubectl create deployment&lt;/code&gt; → running container&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1.   kubectl          reads ~/.kube/config → finds API server URL
2.   kube-apiserver   authenticates, RBAC check, validates request
3.   kube-apiserver   writes Deployment object to etcd
4.   controller-mgr   detects new Deployment → creates ReplicaSet → unscheduled Pod
5.   kube-scheduler   filters + scores nodes → binds pod to best node
6.   kubelet          sees assignment → calls containerd via CRI
7.   containerd       pulls image → calls runc → starts container
8.   kubelet          reports "Running" to API server
9.   etcd             pod status updated
10.  kubectl get pods → my-app  1/1  Running ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Control Plane
&lt;/h2&gt;

&lt;h3&gt;
  
  
  kube-apiserver
&lt;/h3&gt;

&lt;p&gt;The single entry point for everything — &lt;code&gt;kubectl&lt;/code&gt;, CI/CD pipelines, dashboards, and internal components. Validates requests, enforces RBAC, persists state to etcd. Port &lt;strong&gt;6443&lt;/strong&gt; over HTTPS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;▶ The 4-gate request pipeline&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Incoming request
       │
       ▼
┌─ GATE 1: AUTHENTICATION ─────────────────────────────────────────┐
│  "Who are you?"                                                  │
│  TLS client certificates · Bearer tokens · OIDC                 │
│  Failure → 401 Unauthorized                                      │
└──────────────────────────────────────┬───────────────────────────┘
                                       │
                                       ▼
┌─ GATE 2: AUTHORIZATION (RBAC) ───────────────────────────────────┐
│  "Are you allowed to do this?"                                   │
│  Checks Roles and ClusterRoles bound to the user                 │
│  Failure → 403 Forbidden                                         │
└──────────────────────────────────────┬───────────────────────────┘
                                       │
                                       ▼
┌─ GATE 3: ADMISSION CONTROL ──────────────────────────────────────┐
│  Mutating webhooks   → can modify the request                    │
│  Validating webhooks → can reject the request                    │
│  Failure → 400 / 422                                             │
└──────────────────────────────────────┬───────────────────────────┘
                                       │
                                       ▼
┌─ GATE 4: PERSIST TO etcd ────────────────────────────────────────┐
│  Object written → 201 Created returned ✓                         │
└──────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Controllers and &lt;code&gt;kubectl --watch&lt;/code&gt; use long-lived HTTP &lt;strong&gt;watch streams&lt;/strong&gt;, not polling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# GET /api/v1/namespaces/default/pods?watch=true&lt;/span&gt;
&lt;span class="c"&gt;# Server streams:&lt;/span&gt;
&lt;span class="c"&gt;# ADDED    my-pod   Pending&lt;/span&gt;
&lt;span class="c"&gt;# MODIFIED my-pod   Running&lt;/span&gt;
&lt;span class="c"&gt;# DELETED  my-pod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  etcd
&lt;/h3&gt;

&lt;p&gt;Distributed key-value store. The &lt;strong&gt;single source of truth&lt;/strong&gt; for all cluster state. Losing etcd without a backup = losing all cluster configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/registry/pods/default/my-pod         →  { pod spec }
/registry/deployments/default/my-app  →  { deployment spec }
/registry/services/default/my-svc     →  { service config }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;etcd uses &lt;strong&gt;Raft consensus&lt;/strong&gt; — a write commits only when a majority quorum agrees.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;▶ Raft quorum explained&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3-node etcd cluster:

  Leader ──heartbeat──► Follower 1
         ──heartbeat──► Follower 2

Write committed when majority (2 of 3) agree ✓
Leader + one Follower offline → 1 of 3 → no majority → writes halt ✗
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cluster Size&lt;/th&gt;
&lt;th&gt;Quorum&lt;/th&gt;
&lt;th&gt;Failures Tolerated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;1&lt;/strong&gt; ← production minimum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;2&lt;/strong&gt; ← recommended&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Always use an &lt;strong&gt;odd number&lt;/strong&gt;. Even numbers risk a 50/50 split → no quorum → all writes halt.&lt;/p&gt;




&lt;h3&gt;
  
  
  kube-scheduler
&lt;/h3&gt;

&lt;p&gt;Decides which node a new pod runs on. Does &lt;strong&gt;not&lt;/strong&gt; start the pod — only decides placement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;▶ How the scheduler picks a node&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;New pod (unscheduled)
       │
       ▼
PHASE 1 — FILTER: "Which nodes can run this pod?"
  Node 1: 90% CPU → skip
  Node 2: 20% CPU → feasible ✓
  Node 3: 55% CPU → feasible ✓

PHASE 2 — SCORE: "Which is the best node?"
  Node 2: score 85  (less loaded, image already cached)
  Node 3: score 62

PHASE 3 — BIND:
  Pod assigned to Node 2 → kubelet starts the container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Diagnosing a pod stuck in &lt;code&gt;Pending&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pod my-pod
&lt;span class="c"&gt;# Events:&lt;/span&gt;
&lt;span class="c"&gt;# Warning  FailedScheduling  0/3 nodes are available:&lt;/span&gt;
&lt;span class="c"&gt;#   3 Insufficient memory.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  controller-manager
&lt;/h3&gt;

&lt;p&gt;Runs all built-in controllers in a single binary. Each one watches for drift between desired and actual state and corrects it — forever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;desired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_desired_state&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;actual&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_actual_state&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;desired&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;take_corrective_action&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# create / delete / update
&lt;/span&gt;    &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brief_interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;▶ Built-in controllers&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Controller&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Deployment Controller&lt;/td&gt;
&lt;td&gt;Manages ReplicaSets to maintain desired replicas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ReplicaSet Controller&lt;/td&gt;
&lt;td&gt;Ensures the correct number of Pods exist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node Controller&lt;/td&gt;
&lt;td&gt;Detects node failures, evicts pods from dead nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job Controller&lt;/td&gt;
&lt;td&gt;Runs pods to completion for batch workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CronJob Controller&lt;/td&gt;
&lt;td&gt;Creates Jobs on a cron schedule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Endpoint Controller&lt;/td&gt;
&lt;td&gt;Updates Service endpoints when backing pods change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Namespace Controller&lt;/td&gt;
&lt;td&gt;Cleans up resources when a namespace is deleted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Production note:&lt;/strong&gt; Run 3 or 5 control plane nodes for HA. Back up etcd on a schedule. Never run user workloads on control plane nodes.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Worker Node Components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  kubelet
&lt;/h3&gt;

&lt;p&gt;Runs on every worker node as a &lt;code&gt;systemd&lt;/code&gt; service — &lt;strong&gt;not&lt;/strong&gt; a Kubernetes pod. If it crashes, &lt;code&gt;systemd&lt;/code&gt; restarts it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;▶ What kubelet manages&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PodSpecs&lt;/td&gt;
&lt;td&gt;Downloads pod definitions from the API server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Container lifecycle&lt;/td&gt;
&lt;td&gt;Start, stop, restart via the container runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health checks&lt;/td&gt;
&lt;td&gt;Runs liveness, readiness, and startup probes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource reporting&lt;/td&gt;
&lt;td&gt;Reports CPU/memory usage to the API server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volume mounting&lt;/td&gt;
&lt;td&gt;Mounts ConfigMaps, Secrets, and PVCs into containers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static pods&lt;/td&gt;
&lt;td&gt;Reads YAML from &lt;code&gt;/etc/kubernetes/manifests/&lt;/code&gt; directly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;▶ Static pods — how the control plane bootstraps itself&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Static pods allow kubelet to start containers without a running API server, by reading YAML files from disk. This is how K8s starts itself from scratch:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/etc/kubernetes/manifests/
  etcd.yaml
  kube-apiserver.yaml
  kube-controller-manager.yaml
  kube-scheduler.yaml

Bootstrap order:
  systemd starts kubelet
    → kubelet reads manifests → starts etcd
    → starts kube-apiserver
    → everything else connects normally
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Inspect in a kind cluster:&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;kind-control-plane &lt;span class="nb"&gt;ls&lt;/span&gt; /etc/kubernetes/manifests/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  kube-proxy
&lt;/h3&gt;

&lt;p&gt;Programs &lt;code&gt;iptables&lt;/code&gt; or IPVS rules into the Linux kernel for Service routing. &lt;strong&gt;Not&lt;/strong&gt; in the packet data path at runtime — it writes the rules and steps aside.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → GET http://my-service:80
       ↓
Linux kernel intercepts (rules written by kube-proxy)
       ├── 33% ──► Pod 10.244.1.5 (Node 1)
       ├── 33% ──► Pod 10.244.2.8 (Node 2)
       └── 34% ──► Pod 10.244.3.2 (Node 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;▶ Proxy modes comparison&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Lookup&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;iptables&lt;/code&gt; (default)&lt;/td&gt;
&lt;td&gt;Linux iptables chains&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;&amp;lt; ~1,000 Services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ipvs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kernel hash table&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;Large clusters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;eBPF (Cilium)&lt;/td&gt;
&lt;td&gt;Bypasses iptables entirely&lt;/td&gt;
&lt;td&gt;Best-in-class&lt;/td&gt;
&lt;td&gt;Performance-critical&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  containerd
&lt;/h3&gt;

&lt;p&gt;The default container runtime. kubelet calls it via the &lt;strong&gt;CRI (Container Runtime Interface)&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubelet → (gRPC / CRI) → containerd → (OCI) → runc → container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;▶ The "Docker was removed" myth — clarified&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What was removed in K8s 1.24: &lt;strong&gt;dockershim&lt;/strong&gt; (an adapter between kubelet and Docker's API).&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What was NOT removed:
  ✓  Docker images and Dockerfiles → still work perfectly
  ✓  docker build                  → still valid locally

Before K8s 1.24:  kubelet → dockershim → Docker → containerd → runc
After  K8s 1.24:  kubelet → containerd → runc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Docker was a middleman. containerd — which Docker itself uses internally — always did the actual work.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Used By&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;containerd&lt;/td&gt;
&lt;td&gt;GKE, EKS, AKS, kind&lt;/td&gt;
&lt;td&gt;Default — lightweight, fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CRI-O&lt;/td&gt;
&lt;td&gt;OpenShift, bare-metal&lt;/td&gt;
&lt;td&gt;Built specifically for Kubernetes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  kubectl
&lt;/h2&gt;

&lt;p&gt;kubectl reads &lt;code&gt;~/.kube/config&lt;/code&gt; to find your cluster's API server URL and credentials, then talks to kube-apiserver over HTTPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing Multiple Clusters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl config view
kubectl config get-contexts
kubectl config use-context kind-k8s-lab
kubectl config current-context
kubectl config set-context &lt;span class="nt"&gt;--current&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-team
kubectl get pods &lt;span class="nt"&gt;--context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production-cluster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Command Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl  [verb]    [resource]   [name]      [flags]
         get       pods         my-pod      -n production
         describe  deployment   my-dep
         delete    service      my-svc
         apply                  -f app.yaml
         exec      -it my-pod   --          /bin/bash
         logs      my-pod                   -f --previous
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;▶ Getting information&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system        &lt;span class="c"&gt;# specific namespace&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;                    &lt;span class="c"&gt;# all namespaces&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; wide               &lt;span class="c"&gt;# with IP and NODE columns&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; yaml               &lt;span class="c"&gt;# full YAML spec&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;--watch&lt;/span&gt;               &lt;span class="c"&gt;# live stream&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-app         &lt;span class="c"&gt;# filter by label&lt;/span&gt;
kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; my-namespace

kubectl describe pod my-pod            &lt;span class="c"&gt;# full details + Events ← debug here&lt;/span&gt;
kubectl describe node my-node
kubectl describe deployment my-dep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&amp;gt; Always read the &lt;strong&gt;Events&lt;/strong&gt; section in &lt;code&gt;kubectl describe&lt;/code&gt; — it is the primary debugging signal in Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;▶ Creating and updating resources&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; app.yaml              &lt;span class="c"&gt;# create or update (idempotent) ← always prefer this&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; ./manifests/
kubectl create deployment my-app &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx
kubectl create namespace my-team
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;kubectl apply&lt;/code&gt; is idempotent — creates if absent, updates if present. &lt;code&gt;kubectl create&lt;/code&gt; fails if the resource already exists. Use &lt;code&gt;apply&lt;/code&gt; in all scripts and pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;▶ Deleting resources&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod my-pod
kubectl delete &lt;span class="nt"&gt;-f&lt;/span&gt; app.yaml
kubectl delete deployment my-app                        &lt;span class="c"&gt;# removes ReplicaSet and pods too&lt;/span&gt;
kubectl delete pod my-pod &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--grace-period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0      &lt;span class="c"&gt;# immediate (stuck pods)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;▶ Logs&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs my-pod
kubectl logs my-pod &lt;span class="nt"&gt;-f&lt;/span&gt;                      &lt;span class="c"&gt;# stream live&lt;/span&gt;
kubectl logs my-pod &lt;span class="nt"&gt;--previous&lt;/span&gt;              &lt;span class="c"&gt;# logs before last restart ← use after crashes&lt;/span&gt;
kubectl logs my-pod &lt;span class="nt"&gt;-c&lt;/span&gt; my-container         &lt;span class="c"&gt;# specific container&lt;/span&gt;
kubectl logs my-pod &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100
kubectl logs my-pod &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1h
kubectl logs &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-app                  &lt;span class="c"&gt;# all matching pods&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;▶ Exec into a pod&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; my-pod &lt;span class="nt"&gt;--&lt;/span&gt; /bin/bash
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; my-pod &lt;span class="nt"&gt;--&lt;/span&gt; /bin/sh          &lt;span class="c"&gt;# if bash is unavailable&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;my-pod &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; /app
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; my-pod &lt;span class="nt"&gt;-c&lt;/span&gt; sidecar &lt;span class="nt"&gt;--&lt;/span&gt; /bin/sh

&lt;span class="c"&gt;# Ephemeral debug pod — auto-deleted on exit&lt;/span&gt;
kubectl run debug &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="nt"&gt;--&lt;/span&gt; /bin/sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;▶ Port forwarding&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward pod/my-pod 8080:80
kubectl port-forward service/my-svc 8080:80
kubectl port-forward deployment/my-app 8080:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;▶ Scaling and rollouts&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl scale deployment my-app &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deployment/my-app &lt;span class="nv"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.25
kubectl rollout status deployment/my-app
kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deployment/my-app
kubectl rollout undo deployment/my-app
kubectl rollout undo deployment/my-app &lt;span class="nt"&gt;--to-revision&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;▶ JSONPath — extract specific fields&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pod my-pod &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.podIP}'&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[*].metadata.name}'&lt;/span&gt;

&lt;span class="c"&gt;# All pods: namespace, name, IP&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.status.podIP}{"\n"}{end}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Common Mistakes
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mistake&lt;/th&gt;
&lt;th&gt;Correct Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Using &lt;code&gt;kubectl create&lt;/code&gt; in scripts&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;kubectl apply&lt;/code&gt; — idempotent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forgetting &lt;code&gt;-n &amp;lt;namespace&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;-A&lt;/code&gt; or set a default namespace in the context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deleting a pod and expecting it to stay gone&lt;/td&gt;
&lt;td&gt;Delete the Deployment — the ReplicaSet recreates pods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skipping the Events section in &lt;code&gt;describe&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Events are the primary debugging signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not using &lt;code&gt;--previous&lt;/code&gt; after a crash&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;kubectl logs my-pod --previous&lt;/code&gt; shows pre-crash logs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Local Cluster Setup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;▶ Tool comparison&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Nodes&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;kind&lt;/strong&gt; &lt;em&gt;(recommended)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;Multi-node&lt;/td&gt;
&lt;td&gt;CI/CD, multi-node testing, closest to production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;minikube&lt;/td&gt;
&lt;td&gt;Single-node&lt;/td&gt;
&lt;td&gt;Quick experiments, rich addons&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;kubectl kind

&lt;span class="c"&gt;# Linux — kubectl&lt;/span&gt;
curl &lt;span class="nt"&gt;-LO&lt;/span&gt; &lt;span class="s2"&gt;"https://dl.k8s.io/release/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://dl.k8s.io/release/stable.txt&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/bin/linux/amd64/kubectl"&lt;/span&gt;
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x kubectl &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo mv &lt;/span&gt;kubectl /usr/local/bin/

&lt;span class="c"&gt;# Linux — kind&lt;/span&gt;
curl &lt;span class="nt"&gt;-Lo&lt;/span&gt; ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x kind &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo mv &lt;/span&gt;kind /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a Multi-Node Cluster
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# kind-config.yaml&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cluster&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8s-lab&lt;/span&gt;
&lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;control-plane&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;worker&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;worker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kind create cluster &lt;span class="nt"&gt;--config&lt;/span&gt; kind-config.yaml

kubectl get nodes
&lt;span class="c"&gt;# k8s-lab-control-plane  Ready  control-plane&lt;/span&gt;
&lt;span class="c"&gt;# k8s-lab-worker         Ready  &amp;lt;none&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;# k8s-lab-worker2        Ready  &amp;lt;none&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify Health
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes                   &lt;span class="c"&gt;# all nodes → Ready&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system     &lt;span class="c"&gt;# all system pods → Running&lt;/span&gt;
kubectl cluster-info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;▶ First application lab&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Deploy&lt;/span&gt;
kubectl create deployment my-nginx &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.25 &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2
kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; wide

&lt;span class="c"&gt;# Expose&lt;/span&gt;
kubectl expose deployment my-nginx &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80 &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-nginx-service
kubectl describe service my-nginx-service

&lt;span class="c"&gt;# Access&lt;/span&gt;
kubectl port-forward service/my-nginx-service 8080:80 &amp;amp;amp&lt;span class="p"&gt;;&lt;/span&gt;
curl http://localhost:8080

&lt;span class="c"&gt;# Scale&lt;/span&gt;
kubectl scale deployment my-nginx &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4

&lt;span class="c"&gt;# Rolling update&lt;/span&gt;
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deployment/my-nginx &lt;span class="nv"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.26
kubectl rollout status deployment/my-nginx

&lt;span class="c"&gt;# Rollback&lt;/span&gt;
kubectl rollout undo deployment/my-nginx

&lt;span class="c"&gt;# Clean up&lt;/span&gt;
&lt;span class="nb"&gt;kill&lt;/span&gt; %1
kubectl delete deployment my-nginx
kubectl delete service my-nginx-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  kind Management
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kind get clusters
kind create cluster &lt;span class="nt"&gt;--config&lt;/span&gt; kind-config.yaml
kind delete cluster &lt;span class="nt"&gt;--name&lt;/span&gt; k8s-lab
kind load docker-image my-app:latest &lt;span class="nt"&gt;--name&lt;/span&gt; k8s-lab
kubectl config use-context kind-k8s-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cheat Sheet
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;▶ Architecture &amp;amp; key concepts&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Control Plane:   kube-apiserver · etcd · kube-scheduler · controller-manager
Worker Nodes:    kubelet · kube-proxy · containerd
Full flow:       kubectl → apiserver → etcd/scheduler → kubelet → container

Reconciliation:  desired ≠ actual → controller fixes it → repeat forever
Static pods:     /etc/kubernetes/manifests/ → kubelet reads directly
kubeconfig:      ~/.kube/config → cluster URLs + credentials
etcd quorum:     always odd — 3 or 5 in production
Scheduler:       filter → score → bind to winner
kubelet:         systemd service (not a pod); bootstraps the control plane
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;▶ kubectl quick reference&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get&lt;/span&gt;
kubectl get pods / svc / deploy / nodes
kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;                      &lt;span class="c"&gt;# all namespaces&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-o&lt;/span&gt; wide                 &lt;span class="c"&gt;# +IP +NODE&lt;/span&gt;
kubectl get pod  &lt;span class="nt"&gt;-o&lt;/span&gt; yaml             &lt;span class="c"&gt;# full spec&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;--watch&lt;/span&gt;                 &lt;span class="c"&gt;# live stream&lt;/span&gt;
kubectl describe pod                &lt;span class="c"&gt;# details + Events ← debug here&lt;/span&gt;
kubectl explain pod.spec.containers      &lt;span class="c"&gt;# built-in docs&lt;/span&gt;

&lt;span class="c"&gt;# Apply / Delete&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; file.yaml
kubectl delete &lt;span class="nt"&gt;-f&lt;/span&gt; file.yaml
kubectl delete pod  &lt;span class="nt"&gt;--force&lt;/span&gt;

&lt;span class="c"&gt;# Logs&lt;/span&gt;
kubectl logs  &lt;span class="nt"&gt;-f&lt;/span&gt;
kubectl logs  &lt;span class="nt"&gt;--previous&lt;/span&gt;            &lt;span class="c"&gt;# after crash ← important&lt;/span&gt;
kubectl logs  &lt;span class="nt"&gt;-c&lt;/span&gt; 
kubectl logs &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-app

&lt;span class="c"&gt;# Exec / Port-forward&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt;  &lt;span class="nt"&gt;--&lt;/span&gt; /bin/bash
kubectl port-forward svc/ 8080:80

&lt;span class="c"&gt;# Scale / Rollout&lt;/span&gt;
kubectl scale deployment  &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5
kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deployment/ &lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;img&amp;gt;:tag
kubectl rollout status deployment/
kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deployment/
kubectl rollout undo deployment/

&lt;span class="c"&gt;# Context&lt;/span&gt;
kubectl config get-contexts
kubectl config use-context 
kubectl config set-context &lt;span class="nt"&gt;--current&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;▶ kind quick reference&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kind create cluster &lt;span class="nt"&gt;--config&lt;/span&gt; kind-config.yaml
kind get clusters
kind load docker-image  &lt;span class="nt"&gt;--name&lt;/span&gt; 
kind delete cluster &lt;span class="nt"&gt;--name&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;🤖 AI-generated · Personal reference only · Not original content"&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>docker</category>
      <category>beginners</category>
    </item>
    <item>
      <title>📚 Complete Java Microservices Guide: Dropwizard &amp; Ecosystem</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Thu, 26 Feb 2026 17:39:46 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/complete-java-microservices-guide-dropwizard-ecosystem-4llj</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/complete-java-microservices-guide-dropwizard-ecosystem-4llj</guid>
      <description>&lt;h3&gt;
  
  
  A Step-by-Step Beginner-to-Intermediate Learning Path
&lt;/h3&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How to use this guide:&lt;/strong&gt; Read chapter by chapter. Every concept builds on the previous one. Code examples are practical and runnable. Chapters marked 🔲 are &lt;strong&gt;TODO&lt;/strong&gt; — topics to study next.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📋 Table of Contents
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Chapter&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;What is Dropwizard &amp;amp; Why Use It?&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Project Setup &amp;amp; Fat JAR&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Configuration with YAML&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Building REST Resources (JAX-RS)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Bean Validation (Hibernate Validator)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Jackson – JSON Serialization&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Database Access with Hibernate/JDBI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Liquibase – Database Migrations&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Authentication (Basic Auth &amp;amp; OAuth2)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Health Checks &amp;amp; Metrics&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Testing in Dropwizard&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Lombok – Boilerplate Killer&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;MapStruct – Object Mapping&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;Google Guice – Dependency Injection&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;OkHttp – HTTP Client&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;Hystrix – Circuit Breaker&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;TODO: Advanced Topics&lt;/td&gt;
&lt;td&gt;🔲&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 1: What is Dropwizard &amp;amp; Why Use It?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🤔 The Problem It Solves
&lt;/h3&gt;

&lt;p&gt;Imagine you want to build a Java REST API. You'd need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick a web server (Jetty, Tomcat?)&lt;/li&gt;
&lt;li&gt;Pick a JSON library (Jackson, Gson?)&lt;/li&gt;
&lt;li&gt;Pick a validation library&lt;/li&gt;
&lt;li&gt;Pick a database library&lt;/li&gt;
&lt;li&gt;Pick a metrics/monitoring library&lt;/li&gt;
&lt;li&gt;Make sure they all work together (version conflicts are a nightmare!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This research alone can take weeks and paralyze a developer.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Dropwizard's Solution
&lt;/h3&gt;

&lt;p&gt;Dropwizard is a &lt;strong&gt;curated collection of best-of-breed libraries&lt;/strong&gt; glued together so they work out of the box.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Library Used&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Web Server&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Jetty&lt;/strong&gt; (embedded)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;REST Framework&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Jersey&lt;/strong&gt; (JAX-RS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Jackson&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validation&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Hibernate Validator&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database Migrations&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Liquibase&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metrics &amp;amp; Health&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Metrics&lt;/strong&gt; library&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logging&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Logback + SLF4J&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;YAML + Jackson&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  🫙 The Fat JAR Concept
&lt;/h3&gt;

&lt;p&gt;Traditional Java apps rely on an app server (Tomcat, GlassFish) being installed on the machine. The problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"It works on my computer" 😤
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dropwizard packages &lt;strong&gt;everything&lt;/strong&gt; — your code + all dependencies + the web server — into a &lt;strong&gt;single JAR file&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myapp.jar  ← Contains Jetty, Jersey, Jackson, your code... everything!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-jar&lt;/span&gt; myapp.jar server config.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No app server needed. No "works on my machine" problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏗️ Microservices Context
&lt;/h3&gt;

&lt;p&gt;Microservices = breaking a big monolithic app into small, independent services. Each service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does one thing well&lt;/li&gt;
&lt;li&gt;Has its own database&lt;/li&gt;
&lt;li&gt;Communicates via REST/HTTP&lt;/li&gt;
&lt;li&gt;Can be deployed independently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dropwizard is &lt;strong&gt;perfect&lt;/strong&gt; for microservices because each service is a single JAR that starts up fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  🆚 Dropwizard vs Spring Boot
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Dropwizard&lt;/th&gt;
&lt;th&gt;Spring Boot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Philosophy&lt;/td&gt;
&lt;td&gt;Opinionated, curated&lt;/td&gt;
&lt;td&gt;Flexible, extensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning curve&lt;/td&gt;
&lt;td&gt;Easier if you know JAX-RS&lt;/td&gt;
&lt;td&gt;Easier if you know Spring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup speed&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ecosystem size&lt;/td&gt;
&lt;td&gt;Smaller&lt;/td&gt;
&lt;td&gt;Huge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;REST APIs, microservices&lt;/td&gt;
&lt;td&gt;Anything Java&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Which to choose?&lt;/strong&gt; If you're building a focused REST microservice, Dropwizard is excellent. For complex enterprise apps, Spring Boot has more features.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 2: Project Setup &amp;amp; Fat JAR
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🛠️ Prerequisites
&lt;/h3&gt;

&lt;p&gt;Make sure you have installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Java 8+&lt;/strong&gt; (Dropwizard 1.x requires Java 8)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maven 3.x&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;An IDE (IntelliJ IDEA recommended)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📁 Creating a Project with Maven Archetype
&lt;/h3&gt;

&lt;p&gt;The fastest way to start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn archetype:generate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DarchetypeGroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;io.dropwizard.archetypes &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DarchetypeArtifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;java-simple &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DarchetypeVersion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.3.29 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DgroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.example &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DartifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-Dversion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.0-SNAPSHOT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-Dname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;MyApi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important:&lt;/strong&gt; The &lt;code&gt;-Dname=MyApi&lt;/code&gt; parameter is used in generated file names. Always provide it!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  📂 Generated Project Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-api/
├── pom.xml
└── src/
    └── main/
        ├── java/
        │   └── com/example/
        │       ├── MyApiApplication.java   ← Main class (entry point)
        │       └── MyApiConfiguration.java ← Config class
        └── resources/
            └── config.yml                  ← Configuration file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📄 The &lt;code&gt;pom.xml&lt;/code&gt; — Your Project's Heart
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;project&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.example&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;my-api&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dropwizard.version&amp;gt;&lt;/span&gt;1.3.29&lt;span class="nt"&gt;&amp;lt;/dropwizard.version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Core Dropwizard --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.dropwizard&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;dropwizard-core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${dropwizard.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- This plugin creates the Fat JAR --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-shade-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;createDependencyReducedPom&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/createDependencyReducedPom&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;filters&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;filter&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;artifact&amp;gt;&lt;/span&gt;*:*&lt;span class="nt"&gt;&amp;lt;/artifact&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;excludes&amp;gt;&lt;/span&gt;
                                &lt;span class="nt"&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;META-INF/*.SF&lt;span class="nt"&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;
                                &lt;span class="nt"&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;META-INF/*.DSA&lt;span class="nt"&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;
                                &lt;span class="nt"&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;META-INF/*.RSA&lt;span class="nt"&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;/excludes&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/filters&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;package&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&amp;lt;goal&amp;gt;&lt;/span&gt;shade&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;transformers&amp;gt;&lt;/span&gt;
                                &lt;span class="nt"&gt;&amp;lt;transformer&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;
                                  &lt;span class="s"&gt;"org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                                &lt;span class="nt"&gt;&amp;lt;transformer&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;
                                  &lt;span class="s"&gt;"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                                    &lt;span class="c"&gt;&amp;lt;!-- This tells Java which class has main() --&amp;gt;&lt;/span&gt;
                                    &lt;span class="nt"&gt;&amp;lt;mainClass&amp;gt;&lt;/span&gt;com.example.MyApiApplication&lt;span class="nt"&gt;&amp;lt;/mainClass&amp;gt;&lt;/span&gt;
                                &lt;span class="nt"&gt;&amp;lt;/transformer&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;/transformers&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 The Application Class
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.Application&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.setup.Bootstrap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.setup.Environment&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApiApplication&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Java's main method — this starts everything&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MyApiApplication&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"my-api"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Name of your app&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bootstrap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Register bundles (plugins) here&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Register your resources (REST endpoints) here&lt;/span&gt;
        &lt;span class="c1"&gt;// This is where the app "comes alive"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🏗️ Building &amp;amp; Running
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build the Fat JAR&lt;/span&gt;
mvn clean package

&lt;span class="c"&gt;# Run with server command&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; target/my-api-1.0-SNAPSHOT.jar server config.yml

&lt;span class="c"&gt;# Check if it's alive (admin port 8081)&lt;/span&gt;
curl http://localhost:8081/ping

&lt;span class="c"&gt;# Your API is on port 8080 by default&lt;/span&gt;
curl http://localhost:8080/hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📋 Built-in Commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Validate your config file (catches errors before running!)&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar check config.yml

&lt;span class="c"&gt;# Run the server&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar server config.yml

&lt;span class="c"&gt;# Database commands (when Liquibase is added)&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar db migrate config.yml
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar db status config.yml
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar db drop-all &lt;span class="nt"&gt;--confirm-delete-everything&lt;/span&gt; config.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Pro tip:&lt;/strong&gt; Run &lt;code&gt;check&lt;/code&gt; before &lt;code&gt;server&lt;/code&gt; in deployment scripts to catch config errors early!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 3: Configuration with YAML
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🤷 Why Configuration Matters
&lt;/h3&gt;

&lt;p&gt;Hard-coding things like database URLs, passwords, and ports in code is bad practice. Configuration files let you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have different settings for dev/test/production&lt;/li&gt;
&lt;li&gt;Change settings without recompiling&lt;/li&gt;
&lt;li&gt;Keep secrets out of code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📄 The &lt;code&gt;config.yml&lt;/code&gt; File
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Server ports&lt;/span&gt;
&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;applicationConnectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;adminConnectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8081&lt;/span&gt;

&lt;span class="c1"&gt;# Logging&lt;/span&gt;
&lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INFO&lt;/span&gt;
  &lt;span class="na"&gt;loggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;com.example&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DEBUG&lt;/span&gt;  &lt;span class="c1"&gt;# More verbose logging for your package&lt;/span&gt;

&lt;span class="c1"&gt;# Custom config (your own properties)&lt;/span&gt;
&lt;span class="na"&gt;login&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret123&lt;/span&gt;

&lt;span class="c1"&gt;# Database (added later with Hibernate bundle)&lt;/span&gt;
&lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;driverClass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.mysql.jdbc.Driver&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:mysql://localhost:3306/mydb&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dbuser&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dbpassword&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ☕ The Configuration Class
&lt;/h3&gt;

&lt;p&gt;Every key in &lt;code&gt;config.yml&lt;/code&gt; maps to a field in your Configuration class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.Configuration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.fasterxml.jackson.annotation.JsonProperty&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.hibernate.validator.constraints.NotEmpty&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Configuration&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// @NotEmpty = Hibernate Validator annotation&lt;/span&gt;
    &lt;span class="c1"&gt;// If this field is empty/missing, app won't start!&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// @JsonProperty tells Jackson the YAML key name&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getLogin&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setLogin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🌍 Multiple Config Files (Best Practice)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Development&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar server config-dev.yml

&lt;span class="c"&gt;# Production  &lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar server config-prod.yml

&lt;span class="c"&gt;# Testing (uses H2 in-memory database)&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar server config-test.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each config file can point to different databases, use different ports, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔐 Accessing Config in Your App
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Access config values&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogin&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Pass them to classes that need them&lt;/span&gt;
    &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jersey&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 4: Building REST Resources (JAX-RS)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🌐 What is JAX-RS?
&lt;/h3&gt;

&lt;p&gt;JAX-RS is a &lt;strong&gt;Java standard&lt;/strong&gt; (specification) for building REST APIs using annotations. Dropwizard uses &lt;strong&gt;Jersey&lt;/strong&gt; as the JAX-RS implementation.&lt;/p&gt;

&lt;p&gt;The key idea: annotate a regular Java class with special annotations, and Jersey turns it into a REST endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Core Annotations
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Annotation&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Path("/users")&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL path this class/method handles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Responds to HTTP GET requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Responds to HTTP POST requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@PUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Responds to HTTP PUT requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@DELETE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Responds to HTTP DELETE requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Produces(MediaType.APPLICATION_JSON)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Consumes(MediaType.APPLICATION_JSON)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Accepts JSON input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@PathParam("id")&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gets value from URL: &lt;code&gt;/users/42&lt;/code&gt; → id=42&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@QueryParam("name")&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gets value from query string: &lt;code&gt;?name=John&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  ☕ Your First Resource Class
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.resources&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.core.MediaType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.core.Response&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bookmarks"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;// All methods in this class handle /bookmarks&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// All responses are JSON&lt;/span&gt;
&lt;span class="nd"&gt;@Consumes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// All requests accept JSON&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bookmarks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// GET /bookmarks → returns all bookmarks&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllBookmarks&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bookmarks&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// GET /bookmarks/42 → returns one bookmark by ID&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{id}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="nf"&gt;getBookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bookmarks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NotFoundException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bookmark not found: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// POST /bookmarks → create a new bookmark&lt;/span&gt;
    &lt;span class="nd"&gt;@POST&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="nf"&gt;createBookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;bookmarks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CREATED&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// DELETE /bookmarks/42 → delete a bookmark&lt;/span&gt;
    &lt;span class="nd"&gt;@DELETE&lt;/span&gt;
    &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{id}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="nf"&gt;deleteBookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;bookmarks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeIf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;noContent&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// 204 No Content&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// GET /bookmarks/search?tag=java → filter by query param&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;searchByTag&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@QueryParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tag"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// filter logic here&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bookmarks&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📦 The Domain Model (Bookmark.java)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.core&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Default constructor (required for JSON deserialization)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Getters and setters&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getTitle&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setTitle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getTag&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setTag&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📝 Register the Resource in Application
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Without this line, Dropwizard doesn't know about your resource!&lt;/span&gt;
    &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jersey&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔧 HTTP Status Codes Quick Reference
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;OK&lt;/td&gt;
&lt;td&gt;Successful GET, PUT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;201&lt;/td&gt;
&lt;td&gt;Created&lt;/td&gt;
&lt;td&gt;Successful POST (new resource created)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;204&lt;/td&gt;
&lt;td&gt;No Content&lt;/td&gt;
&lt;td&gt;Successful DELETE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;Bad Request&lt;/td&gt;
&lt;td&gt;Invalid input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;Unauthorized&lt;/td&gt;
&lt;td&gt;Not authenticated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;403&lt;/td&gt;
&lt;td&gt;Forbidden&lt;/td&gt;
&lt;td&gt;Authenticated but no permission&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;404&lt;/td&gt;
&lt;td&gt;Not Found&lt;/td&gt;
&lt;td&gt;Resource doesn't exist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;Server Error&lt;/td&gt;
&lt;td&gt;Something blew up&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  🧑‍💻 Recommended Folder Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/main/java/com/example/
├── MyApiApplication.java       ← Entry point
├── MyApiConfiguration.java     ← Config class
├── core/                       ← Domain models / entities
│   └── Bookmark.java
├── db/                         ← Database access (DAOs)
│   └── BookmarkDAO.java
├── resources/                  ← REST endpoints
│   └── BookmarkResource.java
└── auth/                       ← Authentication
    └── MyAuthenticator.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 5: Bean Validation (Hibernate Validator)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❓ Why Validate?
&lt;/h3&gt;

&lt;p&gt;Users send bad data. Always. Never trust input. Validation catches bad data &lt;strong&gt;before&lt;/strong&gt; it hits your database.&lt;/p&gt;

&lt;p&gt;Without validation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would save garbage data to your database!&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Dependency (already included in dropwizard-core)
&lt;/h3&gt;

&lt;p&gt;Dropwizard includes Hibernate Validator automatically. No extra dependency needed!&lt;/p&gt;

&lt;h3&gt;
  
  
  🏷️ Common Validation Annotations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.validation.constraints.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.hibernate.validator.constraints.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"URL cannot be empty"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@URL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Must be a valid URL"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Title must be 1-200 characters"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Min&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Views cannot be negative"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Must be a valid email"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;authorEmail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Pattern&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regexp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"^[A-Z].*"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Must start with uppercase"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ Using &lt;code&gt;@Valid&lt;/code&gt; in Resources
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;@Valid&lt;/code&gt; before the parameter — Dropwizard validates automatically!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@POST&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="nf"&gt;createBookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If bookmark fails validation, Dropwizard returns 422 Unprocessable Entity&lt;/span&gt;
    &lt;span class="c1"&gt;// with details about what's wrong — automatically!&lt;/span&gt;
    &lt;span class="n"&gt;bookmarks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If validation fails, the client gets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"errors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"bookmark.url may not be empty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"bookmark.title size must be between 1 and 200"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🛡️ Validating Config Too!
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Configuration&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;  &lt;span class="c1"&gt;// App won't start if login is missing in config.yml!&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✍️ Custom Validator
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Create the annotation&lt;/span&gt;
&lt;span class="nd"&gt;@Documented&lt;/span&gt;
&lt;span class="nd"&gt;@Constraint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validatedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NoSpacesValidator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Target&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="nc"&gt;ElementType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FIELD&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nd"&gt;@Retention&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetentionPolicy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RUNTIME&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nd"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;NoSpaces&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="s"&gt;"Must not contain spaces"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;{};&lt;/span&gt;
    &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Payload&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[]&lt;/span&gt; &lt;span class="nf"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;{};&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Create the validator logic&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NoSpacesValidator&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ConstraintValidator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;NoSpaces&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ConstraintValidatorContext&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Use it&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NoSpaces&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;slug&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 6: Jackson – JSON Serialization
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔄 What is Jackson?
&lt;/h3&gt;

&lt;p&gt;Jackson converts between &lt;strong&gt;Java objects ↔ JSON&lt;/strong&gt;. This is called &lt;strong&gt;serialization&lt;/strong&gt; (Java → JSON) and &lt;strong&gt;deserialization&lt;/strong&gt; (JSON → Java).&lt;/p&gt;

&lt;p&gt;Dropwizard uses Jackson automatically for all REST responses. When your method returns a &lt;code&gt;Bookmark&lt;/code&gt; object, Jackson converts it to JSON for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Dependency
&lt;/h3&gt;

&lt;p&gt;Already included in &lt;code&gt;dropwizard-core&lt;/code&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  🏷️ Key Jackson Annotations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.fasterxml.jackson.annotation.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Changes the JSON key name&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bookmark_id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Java field "id" → JSON key "bookmark_id"&lt;/span&gt;

    &lt;span class="c1"&gt;// Include in JSON even if null&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonInclude&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JsonInclude&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Include&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALWAYS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Exclude from JSON output&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonIgnore&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;internalNotes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Exclude null values from JSON&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonInclude&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JsonInclude&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Include&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NON_NULL&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;optionalField&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Custom date format&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonFormat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonFormat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;STRING&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"yyyy-MM-dd HH:mm:ss"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt; &lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Map JSON → object (deserialization constructor)&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonCreator&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bookmark_id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🗺️ Working with Unknown Fields
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ignore any extra JSON fields you don't have a field for&lt;/span&gt;
&lt;span class="nd"&gt;@JsonIgnoreProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ignoreUnknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// JSON might have "extra_field" — this annotation ignores it instead of throwing an error&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⚙️ Customizing Jackson in Dropwizard
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bootstrap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Customize the ObjectMapper&lt;/span&gt;
    &lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getObjectMapper&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SerializationFeature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WRITE_DATES_AS_TIMESTAMPS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DeserializationFeature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FAIL_ON_UNKNOWN_PROPERTIES&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSerializationInclusion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JsonInclude&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Include&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NON_NULL&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🌐 Polymorphic Types (Advanced)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Base class&lt;/span&gt;
&lt;span class="nd"&gt;@JsonTypeInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonTypeInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;property&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@JsonSubTypes&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonSubTypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WebBookmark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"web"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="nd"&gt;@JsonSubTypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BookBookmark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"book"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebBookmark&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookBookmark&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;isbn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// JSON will look like:&lt;/span&gt;
&lt;span class="c1"&gt;// { "type": "web", "url": "https://..." }&lt;/span&gt;
&lt;span class="c1"&gt;// { "type": "book", "isbn": "978-..." }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 7: Database Access with Hibernate/JDBI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🗃️ Your Two Options in Dropwizard
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hibernate (JPA)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ORM — maps Java objects to DB tables&lt;/td&gt;
&lt;td&gt;Complex domain models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JDBI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Thin wrapper over JDBC — write SQL directly&lt;/td&gt;
&lt;td&gt;Simple, fast queries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  📦 Dependencies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- For Hibernate --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.dropwizard&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;dropwizard-hibernate&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${dropwizard.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- MySQL Driver (use 5.x to avoid Liquibase conflicts!) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;mysql&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mysql-connector-java&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.1.49&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🗄️ Part A: Hibernate
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1 — The Entity (maps to a DB table)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.core&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.persistence.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;                         &lt;span class="c1"&gt;// This Java class = a database table&lt;/span&gt;
&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"bookmarks"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;// Table name in the database&lt;/span&gt;
&lt;span class="nd"&gt;@NamedQueries&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// Pre-defined queries attached to this class&lt;/span&gt;
    &lt;span class="nd"&gt;@NamedQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.example.core.Bookmark.findAll"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT b FROM Bookmark b"&lt;/span&gt;     &lt;span class="c1"&gt;// JPQL (not SQL!)&lt;/span&gt;
    &lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="nd"&gt;@NamedQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.example.core.Bookmark.findByTag"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT b FROM Bookmark b WHERE b.tag = :tag"&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Auto-increment&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"tag"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Getters, setters, default constructor...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2 — The DAO (Data Access Object)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.db&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.hibernate.AbstractDAO&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.example.core.Bookmark&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.hibernate.SessionFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.hibernate.query.Query&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Optional&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractDAO&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SessionFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// AbstractDAO handles Hibernate session management&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Get all bookmarks&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namedQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.example.core.Bookmark.findAll"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Get by ID — returns Optional (empty if not found)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofNullable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Get by tag — using named query parameter&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findByTag&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Query&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;namedQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.example.core.Bookmark.findByTag"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tag"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Create or update&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// AbstractDAO's persist = INSERT or UPDATE&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Delete&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3 — Register Hibernate Bundle in Application
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApiApplication&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Create the Hibernate bundle — tell it about all your entities!&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;HibernateBundle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hibernate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HibernateBundle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;// list ALL entities here&lt;/span&gt;
            &lt;span class="nd"&gt;@Override&lt;/span&gt;
            &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DataSourceFactory&lt;/span&gt; &lt;span class="nf"&gt;getDataSourceFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDataSourceFactory&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;};&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bootstrap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addBundle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hibernate&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Register the bundle!&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create DAO with Hibernate session factory&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hibernate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSessionFactory&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;// Pass DAO to resource&lt;/span&gt;
        &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jersey&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4 — Config file addition
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config.yml&lt;/span&gt;
&lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;driverClass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.mysql.jdbc.Driver&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:mysql://localhost:3306/bookmarks_db&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret&lt;/span&gt;
  &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;charSet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UTF-8&lt;/span&gt;
    &lt;span class="na"&gt;hibernate.dialect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.hibernate.dialect.MySQL5InnoDBDialect&lt;/span&gt;
  &lt;span class="na"&gt;maxWaitForConnection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1s&lt;/span&gt;
  &lt;span class="na"&gt;validationQuery&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;MyService&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Health&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Check&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*/&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SELECT&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
  &lt;span class="na"&gt;minSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;
  &lt;span class="na"&gt;checkConnectionWhileIdle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 5 — Add DataSourceFactory to Config class
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Configuration&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Valid&lt;/span&gt;
    &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;DataSourceFactory&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DataSourceFactory&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"database"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DataSourceFactory&lt;/span&gt; &lt;span class="nf"&gt;getDataSourceFactory&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@JsonProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"database"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setDataSourceFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DataSourceFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 6 — Use &lt;code&gt;@UnitOfWork&lt;/code&gt; in Resource
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;BookmarkResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="c1"&gt;// @UnitOfWork manages the Hibernate session + transaction for you!&lt;/span&gt;
    &lt;span class="c1"&gt;// Without it, you'd have to open/close sessions manually.&lt;/span&gt;
    &lt;span class="nd"&gt;@UnitOfWork&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllBookmarks&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// ⚠️ WARNING: Lazy-loaded fields must be accessed INSIDE this method!&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@POST&lt;/span&gt;
    &lt;span class="nd"&gt;@UnitOfWork&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="nf"&gt;createBookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmark&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 8: Liquibase – Database Migrations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🤔 The Problem Without Migrations
&lt;/h3&gt;

&lt;p&gt;Imagine two developers both changing the database schema. Developer A adds a &lt;code&gt;tag&lt;/code&gt; column, Developer B renames &lt;code&gt;url&lt;/code&gt; to &lt;code&gt;link&lt;/code&gt;. Who goes first? How do you track DB changes? How do you roll back?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Liquibase is like Git, but for your database schema.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.dropwizard&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;dropwizard-migrations&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${dropwizard.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⚙️ Register the Bundle
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bootstrap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addBundle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MigrationsBundle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DataSourceFactory&lt;/span&gt; &lt;span class="nf"&gt;getDataSourceFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDataSourceFactory&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📄 The Migration File (&lt;code&gt;migrations.xml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Place at &lt;code&gt;src/main/resources/migrations.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;databaseChangeLog&lt;/span&gt;
    &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.liquibase.org/xml/ns/dbchangelog"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
    &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;"http://www.liquibase.org/xml/ns/dbchangelog
    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Each changeSet = one atomic database change --&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- id + author combination must be globally unique! --&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;changeSet&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;author=&lt;/span&gt;&lt;span class="s"&gt;"mitri"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;createTable&lt;/span&gt; &lt;span class="na"&gt;tableName=&lt;/span&gt;&lt;span class="s"&gt;"bookmarks"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;column&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"BIGINT"&lt;/span&gt; &lt;span class="na"&gt;autoIncrement=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;constraints&lt;/span&gt; &lt;span class="na"&gt;primaryKey=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;nullable=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;column&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"VARCHAR(500)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;constraints&lt;/span&gt; &lt;span class="na"&gt;nullable=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;column&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"VARCHAR(255)"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;column&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tag"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"VARCHAR(100)"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/createTable&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Liquibase can auto-generate rollback for createTable (just DROP TABLE) --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/changeSet&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;changeSet&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="na"&gt;author=&lt;/span&gt;&lt;span class="s"&gt;"mitri"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;addColumn&lt;/span&gt; &lt;span class="na"&gt;tableName=&lt;/span&gt;&lt;span class="s"&gt;"bookmarks"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;column&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"created_at"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"TIMESTAMP"&lt;/span&gt; &lt;span class="na"&gt;defaultValueDate=&lt;/span&gt;&lt;span class="s"&gt;"CURRENT_TIMESTAMP"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/addColumn&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/changeSet&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;changeSet&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt; &lt;span class="na"&gt;author=&lt;/span&gt;&lt;span class="s"&gt;"mitri"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Insert test data — must specify manual rollback! --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;insert&lt;/span&gt; &lt;span class="na"&gt;tableName=&lt;/span&gt;&lt;span class="s"&gt;"bookmarks"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;column&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"https://dropwizard.io"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;column&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Dropwizard Official Site"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;column&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"tag"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"java"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/insert&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;rollback&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- Tell Liquibase how to undo this changeSet --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;delete&lt;/span&gt; &lt;span class="na"&gt;tableName=&lt;/span&gt;&lt;span class="s"&gt;"bookmarks"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;where&amp;gt;&lt;/span&gt;url = 'https://dropwizard.io'&lt;span class="nt"&gt;&amp;lt;/where&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/delete&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/rollback&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/changeSet&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/databaseChangeLog&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 Running Migrations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check current state of your database&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar db status config.yml

&lt;span class="c"&gt;# Apply all pending migrations&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar db migrate config.yml

&lt;span class="c"&gt;# Apply migrations up to a specific tag&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar db migrate &lt;span class="nt"&gt;--include-tag&lt;/span&gt; mytag config.yml

&lt;span class="c"&gt;# Roll back last 1 change&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar db rollback &lt;span class="nt"&gt;--count&lt;/span&gt; 1 config.yml

&lt;span class="c"&gt;# Danger zone! Drops everything. Only for dev!&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; my-api.jar db drop-all &lt;span class="nt"&gt;--confirm-delete-everything&lt;/span&gt; config.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🆚 Liquibase vs Flyway
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Liquibase&lt;/th&gt;
&lt;th&gt;Flyway&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Migration format&lt;/td&gt;
&lt;td&gt;XML, YAML, SQL, JSON&lt;/td&gt;
&lt;td&gt;SQL (primarily)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollbacks&lt;/td&gt;
&lt;td&gt;Built-in support&lt;/td&gt;
&lt;td&gt;Manual in Flyway Pro&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Author tracking&lt;/td&gt;
&lt;td&gt;Yes (prevents conflicts)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB independence&lt;/td&gt;
&lt;td&gt;Yes (XML format)&lt;/td&gt;
&lt;td&gt;SQL-only = DB specific&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dropwizard default&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;Via third-party bundle&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why Liquibase wins for teams:&lt;/strong&gt; The author field prevents naming collisions. Two developers can't accidentally create conflicting migrations.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 9: Authentication
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔐 Dropwizard's Two Built-in Auth Methods
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Basic Auth&lt;/strong&gt; — Username + Password sent with every request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OAuth 2.0&lt;/strong&gt; — Token-based auth (used by most modern APIs)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  📦 Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.dropwizard&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;dropwizard-auth&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${dropwizard.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  👤 Step 1 — The User Class
&lt;/h3&gt;

&lt;p&gt;Must extend &lt;code&gt;java.security.Principal&lt;/code&gt; in Dropwizard 1.x:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.auth&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.security.Principal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Principal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔑 Step 2 — The Authenticator
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.auth&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.auth.AuthenticationException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.auth.Authenticator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.auth.basic.BasicCredentials&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Optional&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAuthenticator&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Authenticator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BasicCredentials&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;validLogin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;validPassword&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyAuthenticator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validLogin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BasicCredentials&lt;/span&gt; &lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;AuthenticationException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Check if credentials match&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validLogin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="n"&gt;validPassword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Return empty Optional = authentication failed&lt;/span&gt;
        &lt;span class="c1"&gt;// Dropwizard will return 401 Unauthorized automatically&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🏭 Step 3 — Register in Application
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Create the authenticator with credentials from config&lt;/span&gt;
    &lt;span class="nc"&gt;MyAuthenticator&lt;/span&gt; &lt;span class="n"&gt;authenticator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyAuthenticator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogin&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Register Basic Auth with the authenticator&lt;/span&gt;
    &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jersey&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AuthDynamicFeature&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BasicCredentialAuthFilter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAuthenticator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authenticator&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRealm&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"My Secure API"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Shown in browser login dialog&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buildAuthFilter&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Enable @Auth annotation injection in resources&lt;/span&gt;
    &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jersey&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AuthValueFactoryProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Binder&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔒 Step 4 — Protect Your Endpoints
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GET&lt;/span&gt;
&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{id}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@UnitOfWork&lt;/span&gt;
&lt;span class="c1"&gt;// @Auth injects the authenticated user AND protects the endpoint&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="nf"&gt;getBookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Auth&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// user = logged in user&lt;/span&gt;
                             &lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Only authenticated users reach here&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NotFoundException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not found: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📡 Making a Request with Basic Auth
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Using curl — -u "username:password"&lt;/span&gt;
curl &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"admin:secret123"&lt;/span&gt; http://localhost:8080/bookmarks/1

&lt;span class="c"&gt;# With HTTPS (ignore self-signed cert for dev)&lt;/span&gt;
curl &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"admin:secret123"&lt;/span&gt; https://localhost:8443/bookmarks

&lt;span class="c"&gt;# Or manually with header&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Basic YWRtaW46c2VjcmV0MTIz"&lt;/span&gt; http://localhost:8080/bookmarks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 10: Health Checks &amp;amp; Metrics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  💓 Health Checks
&lt;/h3&gt;

&lt;p&gt;Health checks answer: &lt;strong&gt;"Is my app healthy right now?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The admin port (8081) exposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/ping&lt;/code&gt; → returns "pong" if app is up&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/healthcheck&lt;/code&gt; → runs all registered health checks&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Built-in Health Checks
&lt;/h4&gt;

&lt;p&gt;Dropwizard provides one by default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DeadlockHealthCheck&lt;/strong&gt; — checks if JVM has thread deadlocks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you add the Hibernate bundle, you get a free extra:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database connectivity check&lt;/strong&gt; — tries to ping the database&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Writing a Custom Health Check
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.health&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.codahale.metrics.health.HealthCheck&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExternalServiceHealthCheck&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HealthCheck&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;serviceUrl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ExternalServiceHealthCheck&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;serviceUrl&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;serviceUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serviceUrl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Try to call the external service&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// ... make HTTP call to serviceUrl ...&lt;/span&gt;
            &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;isReachable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pingService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serviceUrl&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isReachable&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;healthy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"External service is UP"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unhealthy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"External service is DOWN at: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;serviceUrl&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unhealthy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Exception connecting: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;pingService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Simplified — use OkHttp (Chapter 15) in real code&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Registering a Health Check
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Register your custom health check&lt;/span&gt;
    &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;healthChecks&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"external-service"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExternalServiceHealthCheck&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.thirdparty.com/ping"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Response When Healthy
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8081/healthcheck
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deadlocks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hibernate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"external-service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"External service is UP"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Response When Unhealthy (returns 500)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"external-service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"External service is DOWN at: https://api.thirdparty.com/ping"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📊 Metrics
&lt;/h3&gt;

&lt;p&gt;Dropwizard's Metrics library lets you measure things in your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.codahale.metrics.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Meter&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// How many requests per second&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Timer&lt;/span&gt; &lt;span class="n"&gt;latency&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// How long requests take&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="n"&gt;activeUsers&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Count something&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Histogram&lt;/span&gt; &lt;span class="n"&gt;payloadSize&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Distribution of values&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;BookmarkResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MetricRegistry&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;meter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bookmark.requests"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;timer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bookmark.latency"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;activeUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bookmark.active-users"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllBookmarks&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mark&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Record a request happened&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;latency&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;// Measure how long this takes&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📈 Sending Metrics to Graphite
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config.yml&lt;/span&gt;
&lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;reporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;graphite&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;graphite.example.com&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2003&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
      &lt;span class="na"&gt;frequency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 minute&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 11: Testing in Dropwizard
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🧪 Testing Philosophy
&lt;/h3&gt;

&lt;p&gt;Dropwizard takes testing seriously and provides special tools that make it easy to test REST APIs without running a full server.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.dropwizard&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;dropwizard-testing&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${dropwizard.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Note: JUnit is included automatically! No need to add it separately. --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧩 Level 1: Unit Testing a Resource (ResourceTestRule)
&lt;/h3&gt;

&lt;p&gt;Tests just your resource class + Jersey, without a real database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.resources&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.testing.junit.ResourceTestRule&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mockito&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Mockito&lt;/span&gt;&lt;span class="o"&gt;.*;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.*;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.core.Response&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResourceTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Mock the DAO — no real database needed!&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Spins up an in-memory Jersey server for testing&lt;/span&gt;
    &lt;span class="nd"&gt;@ClassRule&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ResourceTestRule&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ResourceTestRule&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Define what the mock returns&lt;/span&gt;
        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Example"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@After&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Reset mock between tests&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testGetAllBookmarks&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Make a GET request using the test client&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bookmarks"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GenericType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;(){});&lt;/span&gt;

        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;hasSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getUrl&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isEqualTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Verify DAO was called&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testCreateBookmark_returns201&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="n"&gt;newBookmark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://new.com"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"New Site"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newBookmark&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bookmarks"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newBookmark&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isEqualTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testGetBookmark_notFound_returns404&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;99L&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bookmarks/99"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isEqualTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔗 Level 2: Integration Testing (DropwizardAppRule)
&lt;/h3&gt;

&lt;p&gt;Starts the entire application — tests everything together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.dropwizard.testing.junit.DropwizardAppRule&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.client.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.core.Response&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkIntegrationTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Starts the ENTIRE app (real server, real database)&lt;/span&gt;
    &lt;span class="nd"&gt;@ClassRule&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DropwizardAppRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;RULE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DropwizardAppRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;MyApiApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"config-test.yml"&lt;/span&gt;  &lt;span class="c1"&gt;// Use test config (H2 in-memory DB)&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClientBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testServerIsRunning&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:%d/bookmarks"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="no"&gt;RULE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLocalPort&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isEqualTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testAuthenticatedEndpoint&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://localhost:%d/bookmarks"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="no"&gt;RULE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLocalPort&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="c1"&gt;// Add Basic Auth header&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Basic "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Base64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"admin:secret"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isEqualTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🗃️ Testing Database Queries (DAOTest)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAOTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Spins up real Hibernate with H2 in-memory database&lt;/span&gt;
    &lt;span class="nd"&gt;@ClassRule&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DAOTestRule&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DAOTestRule&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEntityClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSessionFactory&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testSaveAndFind&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="n"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inTransaction&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://test.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTitle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;

        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saved&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isGreaterThan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saved&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;())).&lt;/span&gt;&lt;span class="na"&gt;isPresent&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 12: Lombok – Boilerplate Killer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  😤 The Problem
&lt;/h3&gt;

&lt;p&gt;Java is verbose. For every field in a class, you write:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A getter&lt;/li&gt;
&lt;li&gt;A setter&lt;/li&gt;
&lt;li&gt;Constructor(s)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;equals()&lt;/code&gt; and &lt;code&gt;hashCode()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toString()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's 30+ lines of boring code for a simple 5-field class.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✨ Lombok's Solution
&lt;/h3&gt;

&lt;p&gt;Annotations that &lt;strong&gt;generate&lt;/strong&gt; all that code at compile time. You write the fields. Lombok writes the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;lombok&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.18.30&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;provided&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- Only needed at compile time --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also install the &lt;strong&gt;Lombok plugin&lt;/strong&gt; in IntelliJ IDEA (Settings → Plugins → search "Lombok").&lt;/p&gt;

&lt;h3&gt;
  
  
  🏷️ Core Lombok Annotations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.extern.slf4j.Slf4j&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// @Data = @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Lombok generates: getters, setters, toString(), equals(), hashCode(), constructor&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Breakdown of each annotation:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Getter&lt;/span&gt;              &lt;span class="c1"&gt;// Generates getters for all fields&lt;/span&gt;
&lt;span class="nd"&gt;@Setter&lt;/span&gt;              &lt;span class="c1"&gt;// Generates setters for all fields&lt;/span&gt;
&lt;span class="nd"&gt;@ToString&lt;/span&gt;            &lt;span class="c1"&gt;// Generates toString() like: Bookmark(id=1, url=https://...)&lt;/span&gt;
&lt;span class="nd"&gt;@EqualsAndHashCode&lt;/span&gt;   &lt;span class="c1"&gt;// Generates equals() and hashCode() based on fields&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;   &lt;span class="c1"&gt;// Generates: public Bookmark() {}&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;  &lt;span class="c1"&gt;// Generates: public Bookmark(long id, String url, String title) {}&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;  &lt;span class="c1"&gt;// Constructor for @NonNull and final fields only&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🏗️ &lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt; Pattern
&lt;/h3&gt;

&lt;p&gt;Immutable objects with a fluent builder API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Builder&lt;/span&gt;
&lt;span class="nd"&gt;@Getter&lt;/span&gt;  &lt;span class="c1"&gt;// @Builder doesn't auto-generate getters&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkRequest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage:&lt;/span&gt;
&lt;span class="nc"&gt;BookmarkRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BookmarkRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Example"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔒 Immutable Objects with @Value
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @Value = immutable version of @Data&lt;/span&gt;
&lt;span class="c1"&gt;// All fields are private final, only getters generated (no setters!)&lt;/span&gt;
&lt;span class="nd"&gt;@Value&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserId&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📝 Logging with @Slf4j
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;  &lt;span class="c1"&gt;// Generates: private static final Logger log = LoggerFactory.getLogger(BookmarkResource.class);&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fetching all bookmarks"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Use log directly!&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Debug details here"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Something went wrong"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⚠️ Lombok + Jackson Integration
&lt;/h3&gt;

&lt;p&gt;Jackson needs a default constructor for deserialization. Use both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;          &lt;span class="c1"&gt;// Jackson needs this&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;         &lt;span class="c1"&gt;// Useful for your code&lt;/span&gt;
&lt;span class="nd"&gt;@JsonIgnoreProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ignoreUnknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use &lt;code&gt;@Builder&lt;/code&gt; with &lt;code&gt;@Jacksonized&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Builder&lt;/span&gt;
&lt;span class="nd"&gt;@Jacksonized&lt;/span&gt;  &lt;span class="c1"&gt;// Tells Jackson to use the builder for deserialization&lt;/span&gt;
&lt;span class="nd"&gt;@Value&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 13: MapStruct – Object Mapping
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🗺️ The Mapping Problem
&lt;/h3&gt;

&lt;p&gt;In real applications, you have different object types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entity&lt;/strong&gt; — maps to database (has Hibernate annotations)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DTO&lt;/strong&gt; (Data Transfer Object) — what you send/receive in API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain Model&lt;/strong&gt; — internal business logic object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You need to convert between them constantly. Manually writing conversion code is error-prone and tedious.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Manual mapping — boring, error-prone&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="nf"&gt;toDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUrl&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTitle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTitle&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="c1"&gt;// Forget one field and you have a bug!&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✨ MapStruct Solution
&lt;/h3&gt;

&lt;p&gt;MapStruct &lt;strong&gt;generates&lt;/strong&gt; these conversion methods at compile time using annotations.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mapstruct&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mapstruct&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.5.5.Final&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mapstruct&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mapstruct-processor&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.5.5.Final&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;provided&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔧 Maven Plugin (required with Lombok)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-compiler-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;annotationProcessorPaths&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;path&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;lombok&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.18.30&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;path&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mapstruct&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mapstruct-processor&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.5.5.Final&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/annotationProcessorPaths&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📦 Define Your Objects
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Database Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkEntity&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt; &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt; &lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;internalNotes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Should NOT be in API response!&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// API DTO (Data Transfer Object)&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Notice: no internalNotes — we don't expose this!&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;createdDate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Different format than entity!&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🗺️ The Mapper Interface
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.mapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.mapstruct.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Mapper&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;componentModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Use "cdi" for CDI, "spring" for Spring&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Simple mapping — same field names map automatically!&lt;/span&gt;
    &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="nf"&gt;toDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkEntity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Map from DTO back to entity&lt;/span&gt;
    &lt;span class="nc"&gt;BookmarkEntity&lt;/span&gt; &lt;span class="nf"&gt;toEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Custom field mapping&lt;/span&gt;
    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"createdAt"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"createdDate"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;dateFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"yyyy-MM-dd"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Convert Date to formatted String&lt;/span&gt;
    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"internalNotes"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ignore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Don't map this field&lt;/span&gt;
    &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="nf"&gt;toDTOCustom&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkEntity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Map a list automatically!&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toDTOList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BookmarkEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🏭 Getting the Mapper Instance
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Approach 1: Factory method (no DI)&lt;/span&gt;
&lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mappers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMapper&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Approach 2: With Guice (Chapter 14)&lt;/span&gt;
&lt;span class="c1"&gt;// Bind in your module, inject where needed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ Using the Mapper in Resource
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bookmarks"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mappers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMapper&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="nd"&gt;@UnitOfWork&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllBookmarks&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BookmarkEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toDTOList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Entity → DTO, one line!&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@POST&lt;/span&gt;
    &lt;span class="nd"&gt;@UnitOfWork&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="nf"&gt;createBookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;BookmarkEntity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toEntity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// DTO → Entity&lt;/span&gt;
        &lt;span class="nc"&gt;BookmarkEntity&lt;/span&gt; &lt;span class="n"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saved&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Entity → DTO for response&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 14: Google Guice – Dependency Injection
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🤔 The Problem
&lt;/h3&gt;

&lt;p&gt;As your app grows, you end up with this mess in your &lt;code&gt;run()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Config&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;HibernateBundle&lt;/span&gt; &lt;span class="n"&gt;hib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hibernate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSessionFactory&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mappers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMapper&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;MyAuthenticator&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyAuthenticator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogin&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jersey&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// What if BookmarkResource needs 5 more dependencies?!&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every class manually creates its dependencies. Change one thing → change everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✨ Guice Solution
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Inversion of Control&lt;/strong&gt;: Instead of classes creating their dependencies, Guice creates them and &lt;em&gt;injects&lt;/em&gt; them where needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.google.inject&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;guice&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.1.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Dropwizard + Guice integration --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;ru.vyarus&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;dropwizard-guicey&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.7.1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📝 Step 1 — Mark Dependencies with @Inject
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BookmarkDAO depends on SessionFactory&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractDAO&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BookmarkEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;  &lt;span class="c1"&gt;// Guice will provide SessionFactory&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SessionFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// BookmarkResource depends on DAO and Mapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookmarkResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;  &lt;span class="c1"&gt;// Guice will inject both!&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;BookmarkResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📋 Step 2 — The Guice Module (Wiring Configuration)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.google.inject.AbstractModule&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.google.inject.Provides&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.google.inject.Singleton&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModule&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractModule&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Bind interface → implementation&lt;/span&gt;
        &lt;span class="c1"&gt;// "Whenever someone asks for UserService, give them UserServiceImpl"&lt;/span&gt;
        &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Bind a class directly&lt;/span&gt;
        &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Bind mapper&lt;/span&gt;
        &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Mappers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMapper&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// @Provides methods create instances that need configuration&lt;/span&gt;
    &lt;span class="nd"&gt;@Provides&lt;/span&gt;
    &lt;span class="nd"&gt;@Singleton&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt; &lt;span class="nf"&gt;provideBookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SessionFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🏭 Step 3 — Register with Dropwizard
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;dropwizard-guicey&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApiApplication&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;GuiceApplication&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bootstrap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addBundle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hibernate&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Resources are auto-discovered and injected!&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;Injector&lt;/span&gt; &lt;span class="nf"&gt;createInjector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyApiConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Guice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createInjector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyModule&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🏷️ Key Guice Annotations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Inject&lt;/span&gt;     &lt;span class="c1"&gt;// Mark constructor/field/method for injection&lt;/span&gt;
&lt;span class="nd"&gt;@Singleton&lt;/span&gt;  &lt;span class="c1"&gt;// One instance for entire app lifetime&lt;/span&gt;
&lt;span class="nd"&gt;@Named&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dbUrl"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Disambiguate when multiple bindings of same type exist&lt;/span&gt;

&lt;span class="c1"&gt;// Usage:&lt;/span&gt;
&lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="nd"&gt;@Named&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dbUrl"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;databaseUrl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔄 Guice Scopes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;// One instance per app&lt;/span&gt;
&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RequestScoped&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// New instance per HTTP request&lt;/span&gt;
&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDAO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;                         &lt;span class="c1"&gt;// Default: new instance every time&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 15: OkHttp – HTTP Client
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🌐 Why OkHttp?
&lt;/h3&gt;

&lt;p&gt;Microservices talk to each other over HTTP. You need an HTTP client to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call third-party APIs (payment, email, maps)&lt;/li&gt;
&lt;li&gt;Call other microservices in your system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OkHttp is the most popular Java HTTP client — fast, simple, feature-rich.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.squareup.okhttp3&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;okhttp&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.11.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 Basic GET Request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;okhttp3.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExternalApiClient&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// IMPORTANT: Reuse the same OkHttpClient — it manages connection pooling!&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Build the request&lt;/span&gt;
        &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Accept"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer my-token"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Execute synchronously&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCall&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSuccessful&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unexpected response: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📤 POST Request with JSON Body
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;MediaType&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json; charset=utf-8"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt; &lt;span class="nf"&gt;createRemoteBookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeValueAsString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.other-service.com/bookmarks"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RequestBody&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;// POST with JSON body&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCall&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;responseBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseBody&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Bookmark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⏱️ Timeouts &amp;amp; Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;connectTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// How long to wait to connect&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;// How long to wait for data&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;// How long to wait for upload&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;retryOnConnectionFailure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;// Retry on network errors&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔄 Async Requests
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fetchDataAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Callback&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Non-blocking — callback is called when done&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCall&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;enqueue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Callback&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onFailure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Call&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request failed"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Call&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="c1"&gt;// Process response&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔌 OkHttp Interceptors (Middleware)
&lt;/h3&gt;

&lt;p&gt;Interceptors run for every request — perfect for logging, auth headers, etc.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Logging interceptor&lt;/span&gt;
&lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addInterceptor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chain&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"→ {} {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;proceed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"← {} {} ({}ms)"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;})&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addInterceptor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chain&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Auth interceptor — add token to every request&lt;/span&gt;
        &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;authenticated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;getToken&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;proceed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authenticated&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;})&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 16: Hystrix – Circuit Breaker
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⚡ The Cascading Failure Problem
&lt;/h3&gt;

&lt;p&gt;Service A calls Service B. Service B calls Service C. Service C goes down.&lt;/p&gt;

&lt;p&gt;Without circuit breakers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Service C times out after 30 seconds&lt;/li&gt;
&lt;li&gt;Service B waits 30s, then times out&lt;/li&gt;
&lt;li&gt;Service A waits 30s too = everything hangs for 30+ seconds!&lt;/li&gt;
&lt;li&gt;Threads pile up, memory fills up, your whole system crashes&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  🔌 The Circuit Breaker Pattern
&lt;/h3&gt;

&lt;p&gt;Like an electrical circuit breaker — when failures exceed a threshold, it "trips" and subsequent calls &lt;strong&gt;fail immediately&lt;/strong&gt; instead of waiting.&lt;/p&gt;

&lt;p&gt;States:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CLOSED&lt;/strong&gt; — Normal operation, calls pass through&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OPEN&lt;/strong&gt; — Too many failures, all calls fail immediately&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HALF-OPEN&lt;/strong&gt; — Testing if service recovered; allows one call through&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📦 Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.netflix.hystrix&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;hystrix-core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.5.18&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ☕ Wrapping Calls with HystrixCommand
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.hystrix&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.netflix.hystrix.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FetchBookmarkCommand&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HystrixCommand&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;bookmarkId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ExternalApiClient&lt;/span&gt; &lt;span class="n"&gt;apiClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FetchBookmarkCommand&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;bookmarkId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExternalApiClient&lt;/span&gt; &lt;span class="n"&gt;apiClient&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HystrixCommandGroupKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BookmarkService"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bookmarkId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bookmarkId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apiClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// The actual (potentially failing) call&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;apiClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.service.com/bookmarks/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bookmarkId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getFallback&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// This runs when:&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. run() throws an exception&lt;/span&gt;
        &lt;span class="c1"&gt;// 2. Circuit is OPEN (previous failures)&lt;/span&gt;
        &lt;span class="c1"&gt;// 3. Timeout occurs&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"{\"id\":\""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bookmarkId&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\",\"status\":\"unavailable\"}"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🎯 Using the Command
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Synchronous execution&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FetchBookmarkCommand&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmarkId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Asynchronous (returns Future)&lt;/span&gt;
&lt;span class="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FetchBookmarkCommand&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmarkId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Reactive (returns Observable)&lt;/span&gt;
&lt;span class="nc"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;observable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FetchBookmarkCommand&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookmarkId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;observe&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⚙️ Configuring Hystrix
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;HystrixCommand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Setter&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HystrixCommand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Setter&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withGroupKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HystrixCommandGroupKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BookmarkService"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andCommandKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HystrixCommandKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FetchBookmark"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andCommandPropertiesDefaults&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;HystrixCommandProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Setter&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withExecutionTimeoutInMilliseconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// 3 second timeout&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withCircuitBreakerRequestVolumeThreshold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Min requests before circuit can trip&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withCircuitBreakerErrorThresholdPercentage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Trip if 50% fail&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withCircuitBreakerSleepWindowInMilliseconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Wait 5s before trying again&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Use in command:&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FetchBookmarkCommand&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExternalApiClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Pass config to super&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bookmarkId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apiClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🏎️ HystrixCommand + OkHttp (Combined Example)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExternalServiceClient&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ExternalServiceClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;httpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;objectMapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="nf"&gt;getBookmark&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Wrap the OkHttp call in Hystrix&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HystrixCommand&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;HystrixCommandGroupKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ExternalBookmarks"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="nd"&gt;@Override&lt;/span&gt;
            &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://external.api.com/bookmarks/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

                &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCall&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

            &lt;span class="nd"&gt;@Override&lt;/span&gt;
            &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="nf"&gt;getFallback&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;warn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fallback triggered for bookmark: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt; &lt;span class="n"&gt;fallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookmarkDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="n"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTitle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unavailable"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 17: 🔲 TODO — Advanced Topics to Study Next
&lt;/h2&gt;

&lt;p&gt;These topics weren't covered in this guide but are important for production-ready applications:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔐 Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;OAuth 2.0&lt;/strong&gt; — Token-based authentication (JWT tokens)&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;HTTPS/TLS&lt;/strong&gt; — Configure SSL in Dropwizard config.yml&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;LDAP Authentication&lt;/strong&gt; — Enterprise authentication via directory services&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;CORS&lt;/strong&gt; — Cross-Origin Resource Sharing configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📊 Observability
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Distributed Tracing&lt;/strong&gt; — Zipkin/Jaeger for tracing requests across microservices&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Prometheus&lt;/strong&gt; — Modern metrics collection (alternative to Graphite)&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Grafana Dashboards&lt;/strong&gt; — Visualizing your metrics&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Structured Logging&lt;/strong&gt; — JSON logs for log aggregation (ELK Stack)&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;OpenTelemetry&lt;/strong&gt; — Unified observability standard&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🏗️ Architecture
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Authorization&lt;/strong&gt; — &lt;code&gt;@RolesAllowed&lt;/code&gt;, &lt;code&gt;@PermitAll&lt;/code&gt; annotations&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Rate Limiting&lt;/strong&gt; — Prevent API abuse&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;API Versioning&lt;/strong&gt; — Strategies for versioning your REST API&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;HATEOAS&lt;/strong&gt; — Hypermedia-driven REST (links in responses)&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;GraphQL&lt;/strong&gt; — Alternative to REST for flexible queries&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;OpenAPI/Swagger&lt;/strong&gt; — Auto-generate API documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🗄️ Database
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;JDBI&lt;/strong&gt; — Lighter-weight alternative to Hibernate&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Connection Pooling&lt;/strong&gt; — HikariCP configuration&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Read Replicas&lt;/strong&gt; — Routing reads vs writes&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Database Sharding&lt;/strong&gt; — Horizontal scaling&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🐳 Deployment
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Docker&lt;/strong&gt; — Containerizing your Fat JAR&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Kubernetes&lt;/strong&gt; — Orchestrating containers&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;CI/CD&lt;/strong&gt; — GitHub Actions / Jenkins pipelines&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Blue/Green Deployment&lt;/strong&gt; — Zero-downtime deployments&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Service Discovery&lt;/strong&gt; — Consul, Eureka&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚡ Performance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Async Resources&lt;/strong&gt; — &lt;code&gt;@Suspended&lt;/code&gt; and &lt;code&gt;AsyncResponse&lt;/code&gt; in JAX-RS&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Caching&lt;/strong&gt; — Redis/Memcached with Dropwizard&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Connection Timeout Tuning&lt;/strong&gt; — Jetty thread pool settings&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;GraalVM Native Image&lt;/strong&gt; — Compile to native binary for faster startup&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧪 Advanced Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Consumer-Driven Contract Testing&lt;/strong&gt; — Pact framework&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;WireMock&lt;/strong&gt; — Mock external HTTP services in tests&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;TestContainers&lt;/strong&gt; — Real databases in Docker for integration tests&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Chaos Engineering&lt;/strong&gt; — Testing failure scenarios (Chaos Monkey)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📨 Messaging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Apache Kafka&lt;/strong&gt; — Event streaming&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;RabbitMQ&lt;/strong&gt; — Message queuing&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Dropwizard Kafka Bundle&lt;/strong&gt; — Integration&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>beginners</category>
      <category>java</category>
      <category>microservices</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Understanding Apache Kafka: Topics, Partitions, Delivery Guarantees &amp; Replication 🔥</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Tue, 25 Nov 2025 19:09:21 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/mastering-apache-kafka-topics-partitions-delivery-guarantees-replication-2937</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/mastering-apache-kafka-topics-partitions-delivery-guarantees-replication-2937</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Topic Architecture: Building Your Data Highway&lt;/li&gt;
&lt;li&gt;Delivery Guarantees: Never Lose, Never Duplicate&lt;/li&gt;
&lt;li&gt;Replication &amp;amp; ISR: Zero Downtime Architecture&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Topic Architecture: Building Your Data Highway
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🎯 The Foundation: Understanding Topics
&lt;/h3&gt;

&lt;p&gt;Think of a Kafka &lt;strong&gt;topic&lt;/strong&gt; as a &lt;strong&gt;multi-lane highway&lt;/strong&gt; where your data travels. Just like how more lanes allow more cars to drive simultaneously, more &lt;strong&gt;partitions&lt;/strong&gt; allow more messages to be processed in parallel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Your First Topic
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/kafka/bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; order-events &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--partitions&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9092
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What just happened?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Created a topic called &lt;code&gt;order-events&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ Split it into &lt;strong&gt;4 parallel lanes&lt;/strong&gt; (partitions)&lt;/li&gt;
&lt;li&gt;✅ Made &lt;strong&gt;3 copies&lt;/strong&gt; of each partition (for safety)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🛣️ Partitions: Your Performance Dial
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Scenario: E-commerce Order Processing
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;You run an online store with these requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5,000 orders per second during peak hours&lt;/li&gt;
&lt;li&gt;Each processing server handles 1,250 orders/second&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Calculate partitions needed:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partitions = Target Throughput ÷ Consumer Throughput
Partitions = 5,000 ÷ 1,250 = 4 partitions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The Highway Analogy Visualized
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1 Partition Topic (Bottleneck):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[═══════════════════════] Single lane - all traffic stuck
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4 Partition Topic (Optimal):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[═══════════════════════] Partition 0 → Consumer A
[═══════════════════════] Partition 1 → Consumer B
[═══════════════════════] Partition 2 → Consumer C
[═══════════════════════] Partition 3 → Consumer D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔑 Message Keys: The Secret to Ordering
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Problem
&lt;/h4&gt;

&lt;p&gt;Without keys, messages for the same customer could process out of order, causing chaos!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;❌ Without Keys (Random Distribution):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer #42 creates account    → Partition 1
Customer #42 updates email      → Partition 0  ← Different partition!
Customer #42 adds phone         → Partition 2  ← Processed out of order!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;✅ With Keys (Guaranteed Order):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Key: "customer-42" → hash → Partition 2

Customer #42 creates account    → Partition 2
Customer #42 updates email      → Partition 2  ← Same partition!
Customer #42 adds phone         → Partition 2  ← Perfect order!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Real-World Example: Social Media Feed
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Building an Instagram-like feed processor&lt;/p&gt;

&lt;p&gt;When users create posts, you need to ensure each user's posts are processed in order, but different users can be processed in parallel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Strategy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User ID as Key → All posts from same user → Same partition → Guaranteed order
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; All of Sarah's posts stay in order, but different users' posts can be processed in parallel across partitions!&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Strategy Decision Tree
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do you need message ordering?
├─ NO  → Use NO KEY (round-robin for max throughput)
│         Perfect for: Metrics, logs, sensor data
│
└─ YES → Use MESSAGE KEY
    ├─ User activity?     → key = user_id
    ├─ Order processing?  → key = order_id
    ├─ IoT devices?       → key = device_id
    └─ Multi-tenant app?  → key = tenant_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🛡️ Replication: Your Safety Net
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Scenario: Banking Application
&lt;/h4&gt;

&lt;p&gt;You're building a payment processor. &lt;strong&gt;One question matters most:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If a server crashes at 2 AM, do we lose transaction records?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Answer depends on replication factor:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replication Factor = 1 (❌ NEVER IN PRODUCTION)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition 0:
└── Broker 1 (Leader) ← Single point of failure
    If Broker 1 crashes → DATA PERMANENTLY LOST
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Replication Factor = 3 (✅ Production Standard)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition 0:
├── Broker 1 (Leader)    ← Handles all reads/writes
├── Broker 2 (Follower)  ← Backup copy
└── Broker 3 (Follower)  ← Another backup

Broker 1 crashes? → Broker 2 becomes leader → NO DATA LOSS ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Real Failure Scenario: Diwali Sale
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Timeline of a broker failure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;11:59 PM - Diwali sale starts, 10,000 orders/second
12:03 AM - Broker 2 crashes (hardware failure)
12:03 AM - Controller detects failure (3 seconds)
12:03 AM - Broker 3 promoted to leader
12:03 AM - Orders continue processing
         - Zero orders lost ✓
         - 3-second interruption only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ⚙️ Advanced Configuration: Retention &amp;amp; Durability
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Configuration Example: Multi-Tier Data Strategy
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Real-time Analytics Topic (High Volume, Short Retention)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/kafka/bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; clickstream-events &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--partitions&lt;/span&gt; 16 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; retention.ms&lt;span class="o"&gt;=&lt;/span&gt;86400000 &lt;span class="se"&gt;\ &lt;/span&gt; &lt;span class="c"&gt;# 1 day&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; min.insync.replicas&lt;span class="o"&gt;=&lt;/span&gt;1    &lt;span class="c"&gt;# Lower durability for speed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Financial Transactions Topic (Critical, Long Retention)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/kafka/bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; payment-transactions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--partitions&lt;/span&gt; 6 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; retention.ms&lt;span class="o"&gt;=&lt;/span&gt;7776000000 &lt;span class="se"&gt;\ &lt;/span&gt; &lt;span class="c"&gt;# 90 days&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; min.insync.replicas&lt;span class="o"&gt;=&lt;/span&gt;2      &lt;span class="c"&gt;# High durability&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Event Sourcing Topic (Forever, Maximum Safety)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/kafka/bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; account-events &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--partitions&lt;/span&gt; 8 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; retention.ms&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;         &lt;span class="c"&gt;# Forever&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; min.insync.replicas&lt;span class="o"&gt;=&lt;/span&gt;3      &lt;span class="c"&gt;# Maximum durability&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Delivery Guarantees: Never Lose, Never Duplicate
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🎭 The Central Dilemma
&lt;/h3&gt;

&lt;p&gt;In distributed systems, failures are &lt;strong&gt;inevitable&lt;/strong&gt;. The question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When your consumer crashes mid-processing, what happens to that message?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;You have two choices, each with trade-offs:&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  📊 At Most Once: "Fire and Forget"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; Process each message &lt;strong&gt;0 or 1 times&lt;/strong&gt; (never more than once)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Prevent duplicates at all costs, even if it means losing messages&lt;/p&gt;

&lt;h4&gt;
  
  
  The Coffee Shop Analogy
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You order coffee:
1. Barista writes order ✓
2. ✅ MARKS YOUR ORDER COMPLETE (commits offset)
3. 💥 Power outage before making coffee!
4. Power returns
5. Order marked complete → You never get your coffee

Result: Order processed ZERO times (at most once)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  How It Works: Automatic Offset Commit
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Consumer Configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;enable.auto.commit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;auto.commit.interval.ms&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5000  # Commits every 5 seconds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Processing Flow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Fetch message from Kafka
2. ✅ Auto-commit saves offset (marks as done)
3. Start processing message
4. If crash here → Message LOST
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Timeline of Message Loss
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:00:00 - Fetch message "user_clicked_buy_button"
10:00:01 - Auto-commit saves offset 1001 ✓
10:00:02 - Start processing...
10:00:03 - 💥 APPLICATION CRASHES
10:00:04 - Restart
10:00:05 - Ask Kafka: "Where was I?"
10:00:05 - Kafka: "You were at offset 1001"
10:00:06 - Skip to offset 1001
          - Message 1000 NEVER PROCESSED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🎯 At Least Once: "Never Lose Anything"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; Process each message &lt;strong&gt;1 or more times&lt;/strong&gt; (never zero times)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Ensure every message is processed, even if it means processing some twice&lt;/p&gt;

&lt;h4&gt;
  
  
  The Coffee Shop Analogy (Revised)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You order coffee:
1. Barista makes your coffee ✓
2. Serves it to you ✓
3. 💥 Power outage before marking order complete!
4. Power returns
5. Order NOT marked complete → Makes coffee AGAIN
6. You get TWO coffees (one extra)

Result: Order processed TWICE (at least once)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  How It Works: Manual Offset Commit
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Consumer Configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;enable.auto.commit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;false  # Manual control&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Processing Flow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Fetch message from Kafka
2. Process message successfully ✓
3. Write to database ✓
4. Commit offset manually ✓
5. If crash before step 4 → Message REPROCESSED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Timeline of Duplicate Processing
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:00:00 - Fetch message "order_12345: charge $100"
10:00:01 - Process order successfully ✓
10:00:02 - Charge customer $100 ✓
10:00:03 - Write to database ✓
10:00:04 - 💥 APPLICATION CRASHES (before committing offset)
10:00:05 - Restart
10:00:06 - Ask Kafka: "Where was I?"
10:00:06 - Kafka: "You were at offset 1000"
10:00:07 - Fetch message 1000 AGAIN
10:00:08 - Process order AGAIN
10:00:09 - Charge customer $100 AGAIN ⚠️ (DUPLICATE!)
10:00:10 - Write to database AGAIN
10:00:11 - Commit offset successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🎓 Decision Matrix: Which Guarantee to Use?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    START HERE
                        ↓
            Can you afford to lose messages?
                    ↙       ↘
                  YES        NO
                   ↓          ↓
           AT MOST ONCE   AT LEAST ONCE
                   ↓          ↓
            Use cases:   Can you handle duplicates?
            • Sensors       ↙            ↘
            • Metrics     YES            NO
            • Logs         ↓              ↓
                    Implement      Add deduplication
                    idempotency    • Transaction IDs
                    • Txn IDs      • DB constraints
                    • DB keys      • Processing log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Use Case Decision Table
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Guarantee&lt;/th&gt;
&lt;th&gt;Reasoning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Banking transactions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At Least Once&lt;/td&gt;
&lt;td&gt;Cannot lose money transfers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User registrations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At Least Once&lt;/td&gt;
&lt;td&gt;Cannot lose new users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;E-commerce orders&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At Least Once&lt;/td&gt;
&lt;td&gt;Cannot lose customer orders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stock trades&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At Least Once&lt;/td&gt;
&lt;td&gt;Cannot lose trade records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IoT sensor readings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At Most Once&lt;/td&gt;
&lt;td&gt;Losing one reading is acceptable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Application logs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At Most Once&lt;/td&gt;
&lt;td&gt;Missing one log entry is okay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Click analytics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At Most Once&lt;/td&gt;
&lt;td&gt;Approximate counts are fine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System metrics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At Most Once&lt;/td&gt;
&lt;td&gt;Slightly off counts acceptable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  ⚙️ Configuration Comparison
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;At Most Once Configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# Consumer config
&lt;/span&gt;&lt;span class="py"&gt;enable.auto.commit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;auto.commit.interval.ms&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;At Least Once Configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# Consumer config
&lt;/span&gt;&lt;span class="py"&gt;enable.auto.commit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;false  # Manual control&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Replication And ISR: Zero Downtime Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🏗️ The Architecture: No Single Point of Failure
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Problem Visualized
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Without Replication:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: customer-orders
Partition 0 → Broker 1 ← Single copy
              💥 Crashes
              ↓
          🚨 DATA LOST FOREVER
          🚨 Service DOWN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;With Replication:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: customer-orders
Partition 0:
├── Broker 1 (Leader)    ← Primary copy
├── Broker 2 (Follower)  ← Backup copy
└── Broker 3 (Follower)  ← Another backup

Broker 1 💥 Crashes
         ↓
Broker 2 becomes Leader (3 seconds)
         ↓
✅ NO DATA LOST
✅ Service continues
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🎭 Leaders and Followers
&lt;/h3&gt;

&lt;h4&gt;
  
  
  How Replication Works
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Every partition has ONE leader and multiple followers:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition 0 (Replication Factor = 3):

                    Producers write here
                           ↓
        ┌──────────────────────────────┐
        │  Broker 1 (LEADER)           │
        │  [msg1][msg2][msg3][msg4]    │
        └──────────────────────────────┘
                 ↓           ↓
    ┌────────────┘           └────────────┐
    ↓                                     ↓
┌──────────────────┐           ┌──────────────────┐
│ Broker 2         │           │ Broker 3         │
│ (FOLLOWER)       │           │ (FOLLOWER)       │
│ [msg1][msg2]     │           │ [msg1][msg2]     │
│ [msg3][msg4]     │           │ [msg3][msg4]     │
└──────────────────┘           └──────────────────┘
    Actively                        Actively
    replicating                     replicating
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Rules:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;All writes&lt;/strong&gt; go through the leader&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All reads&lt;/strong&gt; go through the leader&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Followers continuously pull&lt;/strong&gt; new data from leader&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Followers do NOT serve&lt;/strong&gt; client requests&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🎯 In-Sync Replicas (ISR): The Safety Net
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ISR = A follower that is fully caught up and healthy&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  What Makes a Replica "In-Sync"?
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ IN-SYNC REPLICA:
   • Has all committed messages
   • Actively fetching from leader
   • Not fallen behind (&amp;lt; replica.lag.time.max.milliseconds)
   • Ready to become leader at any moment

❌ OUT-OF-SYNC REPLICA:
   • Missing recent messages
   • Stopped fetching (network issue, crashed)
   • Fallen too far behind
   • CANNOT become leader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Real-World Analogy: Emergency Contact List
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You have 3 emergency contacts:

Contact 1 (Leader): Mom
  • Always answers immediately
  • Has all current information

Contact 2 (ISR): Dad
  • Answers within seconds
  • Fully updated on family matters
  • Can step in if Mom unavailable ✓

Contact 3 (Out-of-Sync): Cousin
  • Takes hours to respond
  • Out of the loop
  • Can't be relied on in emergency ✗
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔒 Message Commitment: The Two-Phase Process
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Phase 1: Leader Writes
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer sends: "Transfer $500 from Alice to Bob"
        ↓
Leader writes to local log
        ↓
Message is "uncommitted" (not safe yet)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Phase 2: ISRs Acknowledge
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Leader notifies followers:
        ↓
Follower 1 (ISR) replicates ✓
        ↓
Follower 2 (ISR) replicates ✓
        ↓
Message now "committed" (safe!)
        ↓
Producer receives ACK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Producer Configuration Impact
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;acks=1&lt;/code&gt; (Fast but Risky):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer → Leader writes → ACK immediately
           (Followers not yet replicated)

Leader crashes before replication?
→ Message LOST 💥
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;acks=all&lt;/code&gt; (Slow but Safe):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer → Leader writes → Wait for ALL ISRs → ACK

Takes longer, but:
→ Message GUARANTEED safe ✅
→ Zero data loss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🚨 Failure Scenario: Leader Election
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Real-World Example: Diwali Sale at 2 AM
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Initial State:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: flash-sale-orders
Partition 0:
├── Broker 1 (Leader)    ← 50,000 orders/sec
│   ISR: [1, 2, 3]
├── Broker 2 (Follower)  ← In-Sync
└── Broker 3 (Follower)  ← In-Sync
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Failure Timeline:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;02:00:00 - Broker 1 crashes (power supply failure)
02:00:01 - Producer attempts write → Connection refused
02:00:02 - Zookeeper detects missing heartbeat
02:00:03 - Controller initiates leader election
           Candidates: Broker 2, Broker 3 (both ISR)
02:00:03 - Broker 2 elected as new leader
02:00:04 - Controller notifies all brokers
02:00:04 - Producer auto-discovers new leader
02:00:05 - Orders resume processing ✅

Total downtime: 5 seconds
Orders lost: ZERO (because acks=all)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why Was Broker 2 Chosen?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Was in ISR (fully caught up)&lt;/li&gt;
&lt;li&gt;✅ Had all committed messages&lt;/li&gt;
&lt;li&gt;✅ First in preferred replica list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What If Broker 2 Was Out-of-Sync?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;02:00:03 - Controller checks ISR: [1, 3]
02:00:03 - Broker 2 NOT in ISR → SKIPPED
02:00:03 - Broker 3 elected instead
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ⚙️ Configuration Deep Dive
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Replication Factor (Topic Level)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Development: Fast, no safety&lt;/span&gt;
/opt/kafka/bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; dev-logs &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 1  &lt;span class="c"&gt;# ❌ Never in production!&lt;/span&gt;

&lt;span class="c"&gt;# Staging: Moderate safety&lt;/span&gt;
/opt/kafka/bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; staging-events &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 2

&lt;span class="c"&gt;# Production: Standard safety&lt;/span&gt;
/opt/kafka/bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; production-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 3  &lt;span class="c"&gt;# ✅ Industry standard&lt;/span&gt;

&lt;span class="c"&gt;# Mission-Critical: Maximum safety&lt;/span&gt;
/opt/kafka/bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; financial-transactions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Min In-Sync Replicas (Topic Level)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Works with &lt;code&gt;acks=all&lt;/code&gt; on producer side:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Weak durability (fast but risky)&lt;/span&gt;
&lt;span class="nt"&gt;--config&lt;/span&gt; min.insync.replicas&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="c"&gt;# Leader only needs to write&lt;/span&gt;
&lt;span class="c"&gt;# If leader crashes before followers replicate → DATA LOST&lt;/span&gt;

&lt;span class="c"&gt;# Strong durability (recommended)&lt;/span&gt;
&lt;span class="nt"&gt;--config&lt;/span&gt; min.insync.replicas&lt;span class="o"&gt;=&lt;/span&gt;2
&lt;span class="c"&gt;# Leader + at least 1 follower must acknowledge&lt;/span&gt;
&lt;span class="c"&gt;# Can survive 1 broker failure&lt;/span&gt;

&lt;span class="c"&gt;# Maximum durability (mission-critical)&lt;/span&gt;
&lt;span class="nt"&gt;--config&lt;/span&gt; min.insync.replicas&lt;span class="o"&gt;=&lt;/span&gt;3
&lt;span class="c"&gt;# Leader + at least 2 followers must acknowledge&lt;/span&gt;
&lt;span class="c"&gt;# Can survive 2 broker failures&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Replica Lag Time (Broker Level)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# In server.properties
&lt;/span&gt;&lt;span class="py"&gt;replica.lag.time.max.milliseconds&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10000  # 10 seconds&lt;/span&gt;

&lt;span class="c"&gt;# If follower doesn't fetch within 10 seconds:
# → Removed from ISR
# → Cannot become leader
# → Logs warning
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>messaging</category>
      <category>apachekafka</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Understanding Kafka Storage Architecture: How It Handles Billions of Messages⚡</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Mon, 24 Nov 2025 19:56:31 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/how-kafka-stores-billions-of-messages-the-storage-architecture-nobody-explains-51c6</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/how-kafka-stores-billions-of-messages-the-storage-architecture-nobody-explains-51c6</guid>
      <description>&lt;h2&gt;
  
  
  🎯 Introduction: Beyond the Message Queue
&lt;/h2&gt;

&lt;p&gt;Imagine you're running a global streaming platform processing millions of viewer events every second—play, pause, skip, like, and watch history. How do you store this tsunami of data efficiently while keeping it instantly accessible? This is where Kafka's storage architecture becomes a masterpiece of engineering.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ The Three Core Responsibilities
&lt;/h2&gt;

&lt;p&gt;Every Kafka broker juggles three critical tasks simultaneously:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. 📥 &lt;strong&gt;Producer Gateway&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Accepts incoming streams of events from applications across your network&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 💾 &lt;strong&gt;Storage Engine&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Writes messages to disk durably and efficiently—this is where the magic happens&lt;/p&gt;

&lt;h3&gt;
  
  
  3. 📤 &lt;strong&gt;Consumer Server&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Rapidly locates and delivers data to consumers while replicating to other brokers&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 The Storage Hierarchy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: "viewer-activity"
│
├── Partition 0 (folder: /data/viewer-activity-0/)
│   ├── 00000000000000000000.log
│   ├── 00000000000000000000.index
│   ├── 00000000000000000000.timeindex
│   ├── 00000000000000850000.log
│   ├── 00000000000000850000.index
│   ├── 00000000000000850000.timeindex
│   └── 00000000000001700000.log (active segment)
│
├── Partition 1 (folder: /data/viewer-activity-1/)
│   └── [similar segment files...]
│
└── Partition 2 (folder: /data/viewer-activity-2/)
    └── [similar segment files...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Why Segments? The Problem with Giant Files
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Imagine storing all viewer events in one massive file:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;❌ A 15TB file is impossible to manage&lt;br&gt;&lt;br&gt;
❌ Deleting old watch history requires rewriting everything&lt;br&gt;&lt;br&gt;
❌ Finding "what did user watch at 3 PM yesterday" means scanning terabytes&lt;br&gt;&lt;br&gt;
❌ File corruption destroys all your data  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Segment Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kafka divides each partition's log into &lt;strong&gt;segments&lt;/strong&gt;—smaller, manageable chunks (typically 1GB each).&lt;/p&gt;


&lt;h2&gt;
  
  
  🔄 When Does Kafka Create a New Segment?
&lt;/h2&gt;

&lt;p&gt;A new segment rolls when either condition is met:&lt;/p&gt;
&lt;h3&gt;
  
  
  Condition 1: Size Threshold
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current segment reaches 1GB (default)
→ Close it, start fresh segment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Condition 2: Time Threshold
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;7 days have passed (default)
→ Roll to new segment regardless of size
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  📅 Real-World Timeline Example:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Monday 9:00 AM  → Users start watching shows
                → Messages written to segment 0

Monday 2:30 PM  → Segment 0 hits 1GB
                → Kafka creates segment 1
                → New events go to segment 1

Tuesday 3:00 PM → Segment 1 hits 1GB
                → Kafka creates segment 2 (now active)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🗂️ Segment File Anatomy
&lt;/h2&gt;

&lt;p&gt;For each segment, Kafka maintains &lt;strong&gt;three files&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition Folder: viewer-activity-0/
│
├── 00000000000000850000.log        (1GB - actual messages)
├── 00000000000000850000.index      (10MB - offset lookup map)
└── 00000000000000850000.timeindex  (10MB - timestamp lookup map)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  File Naming Convention
&lt;/h3&gt;

&lt;p&gt;The number &lt;code&gt;00000000000000850000&lt;/code&gt; is the &lt;strong&gt;base offset&lt;/strong&gt;—the first message's offset in this segment.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ Index Files: Kafka's Speed Secret
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🎯 &lt;strong&gt;The Two-Step Lookup Process&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When Kafka needs to find a message, it uses &lt;strong&gt;TWO files in sequence&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First:&lt;/strong&gt; Check the segment file name (base offset) to find the RIGHT segment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Second:&lt;/strong&gt; Use the &lt;code&gt;.index&lt;/code&gt; file to find the EXACT location within that segment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's see this in action!&lt;/p&gt;




&lt;h3&gt;
  
  
  🔍 &lt;strong&gt;1. Offset Index (.index)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Maps message offset → byte position in the log file&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumer Request: "Give me messages starting from offset 850,125"

Step 1: FIND THE RIGHT SEGMENT (using base offsets)
        Available segments:
        • 00000000000000000000.log (base: 0)
        • 00000000000000850000.log (base: 850,000) ← THIS ONE!
        • 00000000000001700000.log (base: 1,700,000)

        Offset 850,125 falls between 850,000 and 1,700,000
        → Select segment: 00000000000000850000.log

Step 2: FIND EXACT POSITION (using .index file)
        Broker loads 00000000000000850000.index into memory
        Binary search finds:
        • offset 850,100 → byte 3072
        • offset 850,150 → byte 6144

        Message 850,125 must be between bytes 3072-6144

Step 3: READ THE MESSAGE
        Read from byte 3072 in 00000000000000850000.log
        Scan forward until offset 850,125 is found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Index Structure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────┬─────────────┐
│  Offset  │  Byte Pos   │
├──────────┼─────────────┤
│  850000  │      0      │
│  850100  │   3072      │
│  850150  │   6144      │
│  850200  │   9216      │
│   ...    │    ...      │
└──────────┴─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; ✨ No scanning millions of messages—instant lookup!&lt;/p&gt;




&lt;h3&gt;
  
  
  📋 &lt;strong&gt;Visual: The Two-File Lookup System&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🎯 FINDING MESSAGE BY OFFSET (850,125)

File System View:
├── 00000000000000000000.log      (offsets: 0 - 849,999)
├── 00000000000000000000.index
├── 00000000000000850000.log      (offsets: 850,000 - 1,699,999) ⭐
├── 00000000000000850000.index    ⭐ USE THIS!
├── 00000000000001700000.log      (offsets: 1,700,000+)
└── 00000000000001700000.index

Step 1: Match offset to segment name (base offset)
        850,125 is &amp;gt;= 850,000 and &amp;lt; 1,700,000
        → Open segment: 00000000000000850000

Step 2: Use that segment's .index file
        → Open: 00000000000000850000.index
        → Find byte position: 3072
        → Read from .log file at byte 3072
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔑 &lt;strong&gt;Key Insight: Why Two Files?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Without segment files (base offset in filename):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Would need to check EVERY index file&lt;/li&gt;
&lt;li&gt;❌ Open thousands of files to find the right one&lt;/li&gt;
&lt;li&gt;❌ Very slow!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;With segment files (base offset in filename):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Filename tells you the offset range instantly&lt;/li&gt;
&lt;li&gt;✅ Only open ONE .index file&lt;/li&gt;
&lt;li&gt;✅ Lightning fast!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Two-Step Magic:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Segment filename&lt;/strong&gt; (base offset) = Coarse filter (which file?)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index file&lt;/strong&gt; (.index) = Fine filter (which byte position?)&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  ⏰ &lt;strong&gt;2. Time Index (.timeindex)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Maps timestamp → corresponding offset (also uses two-step lookup!)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumer Request: "Show me all viewer activity from the last hour"
                  (timestamp: 2025-11-25 13:00:00)

Step 1: FIND THE RIGHT SEGMENT (using .timeindex files)
        Check all segments' time ranges:
        • Segment 0: timestamps 10:00 - 11:59
        • Segment 850000: timestamps 12:00 - 13:59 ← THIS ONE!
        • Segment 1700000: timestamps 14:00 onwards

        Timestamp 13:00:00 falls in segment 850000

Step 2: FIND THE OFFSET (using .timeindex)
        Broker checks 00000000000000850000.timeindex
        Binary search finds:
        2025-11-25 13:00:00 → offset 850,750

Step 3: USE OFFSET INDEX (now it's a regular offset lookup!)
        Uses 00000000000000850000.index
        Finds: offset 850,750 → byte position 225,280

Step 4: READ THE MESSAGES
        Reads from byte 225,280 in .log file
        Returns all messages from that point forward
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Time Index Structure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────┬──────────┐
│     Timestamp        │  Offset  │
├──────────────────────┼──────────┤
│ 2025-11-25 10:00:00  │  850000  │
│ 2025-11-25 11:30:00  │  850300  │
│ 2025-11-25 13:00:00  │  850750  │
│ 2025-11-25 14:15:00  │  851000  │
│        ...           │   ...    │
└──────────────────────┴──────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 The Memory Advantage
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why are index lookups so blazing fast?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Disk Storage (Slow):
├── segment.log (1GB - rarely loaded fully)
├── segment.index (10MB - loaded into RAM!)
└── segment.timeindex (10MB - loaded into RAM!)

Memory (Lightning Fast):
└── Index files cached → Microsecond lookups
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because index files are tiny (10-20MB), they fit entirely in memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ No disk reads for lookups&lt;/li&gt;
&lt;li&gt;✅ Binary search through in-memory structures&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Microseconds instead of seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🗑️ Retention Policies: Managing Disk Space
&lt;/h2&gt;

&lt;p&gt;Without cleanup, your disks would eventually overflow. Kafka automatically deletes old segments based on policies.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Time-Based Retention&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Configuration:
log.retention.hours = 168  (7 days)

Timeline:
Day 1  → Segment 0 created (Nov 18 viewer data)
Day 2  → Segment 1 created (Nov 19 viewer data)
...
Day 8  → Segment 0 is now 7 days old
       → Kafka deletes:
         - segment-0.log
         - segment-0.index
         - segment-0.timeindex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Visual:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before Cleanup (Day 8):
[Seg0: Nov 18] [Seg1: Nov 19] [Seg2: Nov 20] ... [Seg7: Nov 25]
      ↓ 7 days old - DELETE

After Cleanup:
[Seg1: Nov 19] [Seg2: Nov 20] ... [Seg7: Nov 25]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;2. Size-Based Retention&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Configuration:
log.retention.bytes = 107374182400  (100GB per partition)

Current State:
Partition total size = 98GB ✓ OK

New Segment Added:
Partition total size = 103GB ✗ EXCEEDS LIMIT

Action:
→ Kafka deletes oldest segment
→ New total = 102GB ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;3. Combined Policies&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can use both simultaneously—Kafka deletes when &lt;strong&gt;either&lt;/strong&gt; condition is met:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;log.retention.hours = 168     (7 days)
log.retention.bytes = 100GB

Segment deleted if:
✓ Age &amp;gt; 7 days  OR
✓ Total size &amp;gt; 100GB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💨 Why Deletion is Lightning Fast
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Segment-Level Operations
&lt;/h3&gt;

&lt;p&gt;Kafka &lt;strong&gt;never deletes individual messages&lt;/strong&gt;. It operates on entire segment files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ Inefficient (What Kafka DOESN'T do):
Read file → Skip old messages → Write remaining → Rebuild indexes
(Hours of processing)

✅ Efficient (What Kafka DOES):
Delete segment-000.log
Delete segment-000.index  
Delete segment-000.timeindex
(Milliseconds)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 One filesystem operation&lt;/li&gt;
&lt;li&gt;🚀 No data rewriting&lt;/li&gt;
&lt;li&gt;🚀 No index rebuilding&lt;/li&gt;
&lt;li&gt;🚀 Extremely low CPU usage&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎬 Real-World Message Journey
&lt;/h2&gt;

&lt;p&gt;Let's trace a viewer event through the entire system:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Producer Sends Event&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer → Kafka Broker

Message: {
  user_id: "viewer-789",
  action: "started_watching",
  show_id: "breaking-code-s1e3",
  timestamp: 2025-11-25 14:45:00
}

Destination:
Topic: viewer-activity
Partition: 2 (based on user_id hash)
Offset: 1,700,082 (next available)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Write to Active Segment&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Active Segment: 00000000000001700000.log
Position: Append at byte 245,760
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Update Indexes&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Offset Index:
1,700,082 → byte 245,760

Time Index:
2025-11-25 14:45:00 → offset 1,700,082
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4: Acknowledge Producer&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Broker → Producer:
"✓ Message written at offset 1,700,082"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5: Consumer Reads Message&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumer Request: "Give me messages from offset 1,700,082"

Kafka Process:
1. Which segment? → 00000000000001700000.log
2. Load offset index into memory
3. Find: offset 1,700,082 → byte 245,760
4. Read from disk starting at byte 245,760
5. Return message to consumer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧹 Log Compaction: Latest State Only
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Use Case
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Storing user profile updates&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User ID: viewer-789

Messages Over Time:
1. viewer-789 → {email: "old@email.com", plan: "basic"}
2. viewer-789 → {email: "new@email.com", plan: "basic"}
3. viewer-789 → {email: "new@email.com", plan: "premium"}

Question: Do we need messages 1 and 2?
Answer: NO! Only the latest state matters.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  How Compaction Works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Configuration:
log.cleanup.policy = compact

Result:
Kafka guarantees: For each key, retain at least the last known value

Background Process:
1. Log cleaner reads old segments
2. Identifies duplicate keys
3. Keeps only latest message per key
4. Creates cleaned segments
5. Replaces old segments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  💀 Tombstones: Deleting Keys
&lt;/h3&gt;

&lt;p&gt;To &lt;strong&gt;remove&lt;/strong&gt; a key entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Send message: {key: "viewer-789", value: null}

Effect:
→ Log cleaner removes the key
→ Includes its last valid value
→ After configurable grace period
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Compaction vs. Retention Comparison&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Retention (Delete)&lt;/th&gt;
&lt;th&gt;Compaction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What's Kept&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Time/size window of all messages&lt;/td&gt;
&lt;td&gt;Latest value per key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What's Deleted&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Old segments entirely&lt;/td&gt;
&lt;td&gt;Old values for same key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use Case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Time-series events, logs&lt;/td&gt;
&lt;td&gt;User profiles, state management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;log.cleanup.policy=delete&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;log.cleanup.policy=compact&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;History&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited time/size window&lt;/td&gt;
&lt;td&gt;No history, only latest&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 Performance Benefits Summary
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Kafka is Blazing Fast
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sequential Writes&lt;/strong&gt; → Always append to end (disk-friendly)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory-Mapped Indexes&lt;/strong&gt; → Entire index files in RAM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Copy Transfer&lt;/strong&gt; → Direct disk → network socket&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch Processing&lt;/strong&gt; → Multiple messages written together&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segment-Level Operations&lt;/strong&gt; → No expensive per-message work&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  📊 Real-World Numbers
&lt;/h3&gt;

&lt;p&gt;A single Kafka broker can handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Millions of messages per second&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Hundreds of MB/s throughput&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Sub-millisecond latencies&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;All while maintaining durability&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backend</category>
      <category>kafka</category>
      <category>webdev</category>
      <category>go</category>
    </item>
    <item>
      <title>Learn Kafka by Doing: Build a 3-Broker Kafka Cluster with Docker Compose</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Sun, 23 Nov 2025 11:00:00 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/learn-kafka-by-doing-build-a-3-broker-kafka-cluster-with-docker-compose-ank</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/learn-kafka-by-doing-build-a-3-broker-kafka-cluster-with-docker-compose-ank</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;This configuration deploys a 3-broker Kafka cluster with automatic failover, data replication, and a management UI.&lt;/p&gt;




&lt;h2&gt;
  
  
  Docker Compose Configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kafka1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apache/kafka:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka1&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9093:9093"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;29092:29092"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./kafka-data/kafka1:/var/lib/kafka/data&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka-bridge&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_BROKER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;CLUSTER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t7jxO1XIQwWtRhIzV5PE4w&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_PROCESS_ROLES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;broker,controller&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTROLLER:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL://kafka1:29092,EXTERNAL://localhost:9093&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTROLLER://:9092,EXTERNAL://0.0.0.0:9093,INTERNAL://:29092&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_INTER_BROKER_LISTENER_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CONTROLLER_LISTENER_NAMES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTROLLER&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CONTROLLER_QUORUM_VOTERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1@kafka1:9092&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_TRANSACTION_STATE_LOG_MIN_ISR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LOG_DIRS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/kafka/data&lt;/span&gt;

  &lt;span class="na"&gt;kafka2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apache/kafka:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka2&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9094:9093"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./kafka-data/kafka2:/var/lib/kafka/data&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka-bridge&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_BROKER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
      &lt;span class="na"&gt;CLUSTER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t7jxO1XIQwWtRhIzV5PE4w&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_PROCESS_ROLES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;broker&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTROLLER:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL://kafka2:29092,EXTERNAL://localhost:9094&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EXTERNAL://0.0.0.0:9093,INTERNAL://:29092&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_INTER_BROKER_LISTENER_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CONTROLLER_LISTENER_NAMES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTROLLER&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CONTROLLER_QUORUM_VOTERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1@kafka1:9092&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_TRANSACTION_STATE_LOG_MIN_ISR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LOG_DIRS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/kafka/data&lt;/span&gt;

  &lt;span class="na"&gt;kafka3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apache/kafka:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka3&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9095:9093"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./kafka-data/kafka3:/var/lib/kafka/data&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka-bridge&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_BROKER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;CLUSTER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t7jxO1XIQwWtRhIzV5PE4w&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_PROCESS_ROLES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;broker&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTROLLER:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL://kafka3:29092,EXTERNAL://localhost:9095&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EXTERNAL://0.0.0.0:9093,INTERNAL://:29092&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_INTER_BROKER_LISTENER_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CONTROLLER_LISTENER_NAMES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTROLLER&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CONTROLLER_QUORUM_VOTERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1@kafka1:9092&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_TRANSACTION_STATE_LOG_MIN_ISR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LOG_DIRS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/kafka/data&lt;/span&gt;

  &lt;span class="na"&gt;kafka-ui&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;provectuslabs/kafka-ui:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka-ui&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8000:8080"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka-bridge&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CLUSTERS_0_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafkamultinodecluster&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kafka1:29092,kafka2:29092,kafka3:29092"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka3&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kafka-bridge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Configuration Breakdown
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Port Strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;9093-9095&lt;/strong&gt;: External access (your apps connect here)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;29092&lt;/strong&gt;: Internal broker communication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;9092&lt;/strong&gt;: Controller coordination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;8000&lt;/strong&gt;: Kafka UI web interface&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Listeners Explained
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONTROLLER (9092) - Controllers coordinate cluster operations
INTERNAL (29092)  - Brokers communicate with each other
EXTERNAL (9093+)  - External clients connect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Critical Environment Variables
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CLUSTER_ID&lt;/strong&gt;: Must be identical across all brokers (forms the cluster)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BROKER_ID&lt;/strong&gt;: Unique identifier per broker (1, 2, 3)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PROCESS_ROLES&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kafka1: &lt;code&gt;broker,controller&lt;/code&gt; (both roles)&lt;/li&gt;
&lt;li&gt;kafka2/3: &lt;code&gt;broker&lt;/code&gt; (worker only)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CONTROLLER_QUORUM_VOTERS&lt;/strong&gt;: &lt;code&gt;1@kafka1:9092&lt;/code&gt; (only kafka1 can be controller)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ADVERTISED_LISTENERS&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;INTERNAL://kafka1:29092&lt;/code&gt; - Used by other brokers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EXTERNAL://localhost:9093&lt;/code&gt; - Used by external clients&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Replication Factors&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3&lt;/code&gt; - Consumer offsets replicated 3x&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 3&lt;/code&gt; - Transaction logs replicated 3x&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1&lt;/code&gt; - Minimum in-sync replicas (trade-off between availability and durability)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data Persistence
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./kafka-data/kafka1 → /var/lib/kafka/data (in container)
./kafka-data/kafka2 → /var/lib/kafka/data
./kafka-data/kafka3 → /var/lib/kafka/data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data survives container restarts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Producer Script
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;producer-read.sh&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;BOOTSTRAP_SERVERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"kafka2:29092"&lt;/span&gt;
&lt;span class="nv"&gt;TOPIC_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;CONTAINER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"kafka1"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOPIC_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;topic-name&amp;gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;1..10&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;MESSAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Message &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt; from producer"&lt;/span&gt;
  docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$MESSAGE&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; | /opt/kafka/bin/kafka-console-producer.sh --bootstrap-server &lt;/span&gt;&lt;span class="nv"&gt;$BOOTSTRAP_SERVERS&lt;/span&gt;&lt;span class="s2"&gt; --topic &lt;/span&gt;&lt;span class="nv"&gt;$TOPIC_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Sent: &lt;/span&gt;&lt;span class="nv"&gt;$MESSAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;: &lt;code&gt;./producer-read.sh customer-orders&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Sends 10 messages to the specified topic through kafka2, running from kafka1 container.&lt;/p&gt;




&lt;h2&gt;
  
  
  Consumer Script
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;consumer-read.sh&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;BOOTSTRAP_SERVERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"kafka1:29092"&lt;/span&gt;
&lt;span class="nv"&gt;TOPIC_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;CONTAINER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"kafka2"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOPIC_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;topic-name&amp;gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"/opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server &lt;/span&gt;&lt;span class="nv"&gt;$BOOTSTRAP_SERVERS&lt;/span&gt;&lt;span class="s2"&gt; --topic &lt;/span&gt;&lt;span class="nv"&gt;$TOPIC_NAME&lt;/span&gt;&lt;span class="s2"&gt; --from-beginning"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;: &lt;code&gt;./consumer-read.sh customer-orders&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Reads all messages from the beginning, running from kafka2 container, connecting to kafka1.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start cluster&lt;/strong&gt;: &lt;code&gt;docker-compose up -d&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access UI&lt;/strong&gt;: &lt;a href="http://localhost:8000" rel="noopener noreferrer"&gt;http://localhost:8000&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send messages&lt;/strong&gt;: &lt;code&gt;./producer-read.sh my-topic&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read messages&lt;/strong&gt;: &lt;code&gt;./consumer-read.sh my-topic&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop cluster&lt;/strong&gt;: &lt;code&gt;docker-compose down&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Architecture Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────┐
│  kafka1 (broker + controller)               │
│  Ports: 9093 (external), 29092 (internal)   │
└─────────────────────────────────────────────┘
                    ↕
┌─────────────────────────────────────────────┐
│  kafka2 (broker)                            │
│  Ports: 9094 (external), 29092 (internal)   │
└─────────────────────────────────────────────┘
                    ↕
┌─────────────────────────────────────────────┐
│  kafka3 (broker)                            │
│  Ports: 9095 (external), 29092 (internal)   │
└─────────────────────────────────────────────┘
                    ↕
┌─────────────────────────────────────────────┐
│  kafka-ui (management interface)            │
│  Port: 8000                                 │
└─────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All brokers share the same CLUSTER_ID and communicate on the &lt;code&gt;kafka-bridge&lt;/code&gt; network.&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>tutorial</category>
      <category>docker</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>🎯 Apache Kafka Single-Node Practice Guide</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Fri, 21 Nov 2025 20:30:38 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/apache-kafka-single-node-practice-guide-3okf</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/apache-kafka-single-node-practice-guide-3okf</guid>
      <description>&lt;h2&gt;
  
  
  Your Personal Message Delivery System
&lt;/h2&gt;

&lt;p&gt;Welcome to your hands-on Kafka learning journey! In this guide, we'll build a complete Kafka system on a single machine - perfect for learning, testing, and understanding how everything works together.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 What We're Building
&lt;/h2&gt;

&lt;p&gt;Think of this as creating your own &lt;strong&gt;Digital Post Office&lt;/strong&gt; on your computer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────┐
│     YOUR LAPTOP (Single Machine)        │
│                                         │
│  ┌───────────────────────────────┐    │
│  │    KAFKA BROKER (Port 9092)   │    │
│  │         Your Post Office      │    │
│  ├───────────────────────────────┤    │
│  │                               │    │
│  │  📬 Topic: "customer-orders"  │    │
│  │  📬 Topic: "payment-alerts"   │    │
│  │  📬 Topic: "user-activity"    │    │
│  │                               │    │
│  └───────────────────────────────┘    │
│           ↑              ↓             │
│      PRODUCERS      CONSUMERS          │
│   (Send messages) (Receive messages)   │
└─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important Note:&lt;/strong&gt; Single-node setup is ONLY for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Learning and experimentation&lt;/li&gt;
&lt;li&gt;✅ Development and testing&lt;/li&gt;
&lt;li&gt;✅ Understanding Kafka concepts&lt;/li&gt;
&lt;li&gt;❌ NOT for production use (no fault tolerance!)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠 Step 1: Installation &amp;amp; Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option A: Using Docker (Recommended - Easiest!)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Generate a unique Cluster ID&lt;/span&gt;
&lt;span class="nv"&gt;CLUSTER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; apache/kafka:latest /opt/kafka/bin/kafka-storage.sh random-uuid&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Generated Cluster ID: &lt;/span&gt;&lt;span class="nv"&gt;$CLUSTER_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# 2. Create a docker-compose.yml file with the generated ID&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; docker-compose.yml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
services:
  kafka1:
    image: apache/kafka:latest
    container_name: kafka1
    ports:
      - "9093:9093"
    volumes:
      - ./kafka-data/kafka1:/var/lib/kafka/data
    networks:
      - kafka-bridge
    environment:
      KAFKA_BROKER_ID: 1
      CLUSTER_ID: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
      KAFKA_PROCESS_ROLES: broker,controller
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka1:29092,EXTERNAL://localhost:9093
      KAFKA_LISTENERS: CONTROLLER://:9092,EXTERNAL://0.0.0.0:9093,INTERNAL://:29092
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka1:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_LOG_DIRS: /var/lib/kafka/data

networks:
  kafka-bridge:
    driver: bridge

volumes:
  kafka-data:
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# 3. Start Kafka&lt;/span&gt;
docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;

&lt;span class="c"&gt;# 4. Check if it's running&lt;/span&gt;
docker ps

&lt;span class="c"&gt;# Expected output:&lt;/span&gt;
&lt;span class="c"&gt;# CONTAINER ID   IMAGE                  STATUS         PORTS&lt;/span&gt;
&lt;span class="c"&gt;# abc123def456   apache/kafka:latest    Up 10 seconds  0.0.0.0:9093-&amp;gt;9093/tcp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Alternative: Manual Cluster ID Generation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# If you prefer to set it manually, you can generate and copy the ID:&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; apache/kafka:latest /opt/kafka/bin/kafka-storage.sh random-uuid

&lt;span class="c"&gt;# Output example: MkU3OEVBNTcwNTJENDM2Qk&lt;/span&gt;
&lt;span class="c"&gt;# Then paste this ID into CLUSTER_ID in docker-compose.yml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Understanding the Configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────┐
│           YOUR DOCKER KAFKA SETUP               │
├─────────────────────────────────────────────────┤
│                                                 │
│  Container: kafka1                              │
│  ┌───────────────────────────────────────────┐ │
│  │  Port 9093 (External) ← You connect here │ │
│  │  Port 29092 (Internal) ← Container-only  │ │
│  │  Port 9092 (Controller) ← Management     │ │
│  └───────────────────────────────────────────┘ │
│                     ↓                           │
│  Volume: ./kafka-data/kafka1                    │
│  (Your data persists here!)                     │
│                                                 │
└─────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What Each Port Does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;9093&lt;/strong&gt; (EXTERNAL): Use this from your laptop (localhost:9093)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;29092&lt;/strong&gt; (INTERNAL): Used by containers talking to each other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;9092&lt;/strong&gt; (CONTROLLER): Kafka's internal coordination&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Data Persistence:&lt;/strong&gt;&lt;br&gt;
Your messages are saved in &lt;code&gt;./kafka-data/kafka1&lt;/code&gt; directory. Even if you stop the container, your data remains!&lt;/p&gt;
&lt;h2&gt;
  
  
  🎪 Step 2: Your First Kafka Topic
&lt;/h2&gt;

&lt;p&gt;Let's create our coffee shop's order board!&lt;/p&gt;
&lt;h3&gt;
  
  
  Create a Topic
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Using Docker:&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-topics.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; coffee-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--partitions&lt;/span&gt; 3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;What This Creates:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: "coffee-orders" (3 sections on your order board)

┌─────────────────────────────────────────┐
│         COFFEE ORDERS BOARD             │
├─────────────────────────────────────────┤
│                                         │
│  Section 0    Section 1    Section 2   │
│  (Partition)  (Partition)  (Partition) │
│  ┌────────┐  ┌────────┐  ┌────────┐   │
│  │ Order 1│  │ Order 2│  │ Order 3│   │
│  │ Order 4│  │ Order 5│  │ Order 6│   │
│  │  ...   │  │  ...   │  │  ...   │   │
│  └────────┘  └────────┘  └────────┘   │
└─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  List All Topics
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-topics.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  View Topic Details
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-topics.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--describe&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; coffee-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output Explanation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: coffee-orders
PartitionCount: 3          ← Your order board has 3 sections
ReplicationFactor: 1       ← Only 1 copy (single node)
Partition: 0
  Leader: 1                ← Broker 1 manages this section
  Replicas: 1              ← Only one copy exists
  Isr: 1                   ← In-sync replicas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ☕ Step 3: Sending Orders (Producer)
&lt;/h2&gt;

&lt;p&gt;Now let's be the cashier and take some orders!&lt;/p&gt;

&lt;h3&gt;
  
  
  Start the Console Producer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-console-producer.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; coffee-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Type these orders (press Enter after each):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"customer":"Alice","drink":"Latte","size":"Medium","price":4.50}
{"customer":"Bob","drink":"Espresso","size":"Small","price":3.00}
{"customer":"Charlie","drink":"Cappuccino","size":"Large","price":5.50}
{"customer":"Diana","drink":"Mocha","size":"Medium","price":4.75}
{"customer":"Eve","drink":"Americano","size":"Large","price":3.50}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What's Happening:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You (Cashier)                  Kafka                    Storage
     │                           │                         │
     │──Order: Alice's Latte────→│                         │
     │                           │──Save to Partition 0───→│
     │                           │                         │
     │──Order: Bob's Espresso───→│                         │
     │                           │──Save to Partition 1───→│
     │                           │                         │
     │──Order: Charlie's Capp.──→│                         │
     │                           │──Save to Partition 2───→│
     │                           │                         │
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Press Ctrl+C to stop the producer&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧑‍🍳 Step 4: Processing Orders (Consumer)
&lt;/h2&gt;

&lt;p&gt;Now let's be the barista and read the orders!&lt;/p&gt;

&lt;h3&gt;
  
  
  Start the Console Consumer (Read from Beginning)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-console-consumer.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; coffee-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-beginning&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;You'll see all the orders scroll by:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"customer":"Alice","drink":"Latte","size":"Medium","price":4.50}
{"customer":"Bob","drink":"Espresso","size":"Small","price":3.00}
{"customer":"Charlie","drink":"Cappuccino","size":"Large","price":5.50}
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What's Happening:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Storage                    Kafka                    Barista (You)
   │                         │                          │
   │←──Request all orders────│                          │
   │                         │                          │
   │──Send order 1──────────→│──Alice's Latte─────────→│
   │──Send order 2──────────→│──Bob's Espresso────────→│
   │──Send order 3──────────→│──Charlie's Cappuccino──→│
   │                         │                          │
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Start Another Consumer (Real-time Only)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Open a NEW terminal and run:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-console-consumer.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; coffee-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This consumer only sees &lt;strong&gt;new&lt;/strong&gt; orders (like a new barista who just arrived).&lt;/p&gt;




&lt;h2&gt;
  
  
  🎭 Step 5: Multiple Producers &amp;amp; Consumers
&lt;/h2&gt;

&lt;p&gt;Let's simulate a busy coffee shop with multiple cashiers and baristas!&lt;/p&gt;

&lt;h3&gt;
  
  
  Experiment Setup
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Terminal 1 (Cashier A - Producer):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-console-producer.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; coffee-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Terminal 2 (Cashier B - Producer):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-console-producer.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; coffee-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Terminal 3 (Barista A - Consumer):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-console-consumer.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; coffee-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-beginning&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Terminal 4 (Barista B - Consumer):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; kafka1 /opt/kafka/bin/kafka-console-consumer.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic&lt;/span&gt; coffee-orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9093 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-beginning&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Now:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Type orders in Terminal 1 and 2 (both cashiers taking orders)&lt;/li&gt;
&lt;li&gt;Watch them appear in Terminal 3 and 4 (both baristas see ALL orders)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Visual:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cashier A ──┐
            ├──→ ORDER BOARD ──┬──→ Barista A (sees all orders)
Cashier B ──┘    (Kafka)       └──→ Barista B (sees all orders)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kafka</category>
      <category>docker</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Understanding Kafka Complete Architecture Flow - Advanced🎯</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Wed, 19 Nov 2025 19:07:56 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/kafka-complete-architecture-flow-advanced-43c9</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/kafka-complete-architecture-flow-advanced-43c9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Please read the last two articles in my Kafka series before this one — this part gets serious.&lt;/strong&gt; &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🌐 The Big Picture: Two Brains Working Together
&lt;/h2&gt;

&lt;p&gt;Think of Kafka as a well-organized company with two main components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────┐
│           KAFKA CLUSTER                     │
│                                             │
│  ┌────────────────────────────────────┐    │
│  │  CONTROLLERS (The Brain 🧠)        │    │
│  │  • Manage who does what            │    │
│  │  • Track what's happening          │    │
│  │  • Make decisions                  │    │
│  └──────────────┬─────────────────────┘    │
│                 ↓ Commands &amp;amp; Updates       │
│  ┌────────────────────────────────────┐    │
│  │  BROKERS (The Workers 💪)          │    │
│  │  • Store the actual data           │    │
│  │  • Serve producers and consumers   │    │
│  │  • Follow controller's instructions│    │
│  └────────────────────────────────────┘    │
└─────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple Analogy:&lt;/strong&gt; Controllers are like managers who plan and coordinate, while Brokers are employees who do the actual work.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Part 1: SETUP - Controllers Organize Everything
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Controllers Start and Elect Leader
&lt;/h3&gt;

&lt;p&gt;When Kafka starts, multiple controllers use the &lt;strong&gt;Raft Election&lt;/strong&gt; algorithm to choose one leader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controller-1    Controller-2    Controller-3
     │               │               │
     └───────Raft Election───────────┘
                     ↓
          One becomes LEADER ⭐
                     │
            ┌────────────────┐
            │ Controller-1   │
            │   (LEADER) ⭐   │ ← Makes all decisions!
            └────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like choosing a class monitor who manages everything.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 2: Controllers Create Metadata Registry
&lt;/h3&gt;

&lt;p&gt;The Controller Leader creates a comprehensive "notebook" 📒 of everything happening in the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────┐
│        METADATA REGISTRY                 │
├──────────────────────────────────────────┤
│                                          │
│ TOPICS:                                  │
│  • "orders" → 3 partitions               │
│  • "payments" → 2 partitions             │
│                                          │
│ BROKERS:                                 │
│  • Broker-1 → Alive ✅ (IP: 192.168.1.10)│
│  • Broker-2 → Alive ✅ (IP: 192.168.1.11)│
│  • Broker-3 → Alive ✅ (IP: 192.168.1.12)│
│                                          │
│ WHO'S IN CHARGE (Leaders):               │
│  • orders-partition-0 → Broker-1         │
│  • orders-partition-1 → Broker-2         │
│  • orders-partition-2 → Broker-3         │
│                                          │
│ BACKUPS (Followers):                     │
│  • orders-partition-0 → Broker-2, Broker-3│
│  • orders-partition-1 → Broker-3, Broker-1│
│  • orders-partition-2 → Broker-1, Broker-2│
└──────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like a school register showing which classes exist, which teachers are present, who teaches which subject, and who are the substitute teachers.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Controller Tells Brokers Their Jobs
&lt;/h3&gt;

&lt;p&gt;The controller assigns specific roles to each broker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controller ⭐ → Broker-1: "You are the LEADER for orders-partition-0"
                         "You are a BACKUP for orders-partition-2"

Controller ⭐ → Broker-2: "You are the LEADER for orders-partition-1"
                         "You are a BACKUP for orders-partition-0"

Controller ⭐ → Broker-3: "You are the LEADER for orders-partition-2"
                         "You are a BACKUP for orders-partition-1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like a manager assigning tasks to employees.&lt;/p&gt;




&lt;h2&gt;
  
  
  📤 Part 2: PRODUCER SENDS DATA
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 4: Producer Wants to Send Message
&lt;/h3&gt;

&lt;p&gt;Your application (Producer) has data to send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────┐
│  I have a message:       │
│  • Topic: "orders"       │
│  • Key: "user_123"       │
│  • Value: {order data}   │
│                          │
│  "Where do I send this?" │
└──────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like having a letter but not knowing which post office to use.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 5: Producer Asks ANY Broker for Information
&lt;/h3&gt;

&lt;p&gt;The producer can connect to &lt;strong&gt;any broker&lt;/strong&gt; to get routing information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer ──────────► Broker-1
"Where do I send     "Let me check
messages for         my copy of
'orders' topic?"     the registry..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Point:&lt;/strong&gt; Every broker has a copy of the controller's metadata!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────────────────────┐
│  Broker-1's Copy of Metadata:     │
│  • orders-partition-0 → Broker-1  │
│  • orders-partition-1 → Broker-2  │
│  • orders-partition-2 → Broker-3  │
└───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like asking a postman for directions - he has a map (copy of registry).&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 6: Producer Calculates Which Partition
&lt;/h3&gt;

&lt;p&gt;The producer's client library automatically determines the target partition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Hash the key: hash("user_123") = 456789
2. Divide by partitions: 456789 % 3 = 0
3. Result: Goes to Partition 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like a sorting machine that knows exactly which box to put each item in.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 7: Producer Sends to Correct Broker
&lt;/h3&gt;

&lt;p&gt;Now the producer sends directly to the partition leader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer ───────────► Broker-1 (Leader for P0)

Broker-1 receives:
1. ✅ Validates it's the leader for P0
2. 💾 Writes to disk: /kafka/data/orders-0/
3. 📝 Assigns offset: 1251
4. ✅ Sends "OK!" back to producer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like mailing a letter to the correct post office that handles your area.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 8: Broker Replicates to Followers (Background)
&lt;/h3&gt;

&lt;p&gt;After writing, the leader broker automatically replicates to followers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Broker-1 (Leader P0) ───COPY MESSAGE───► Broker-2 (Follower P0)
                                          ✅ Copied!
         │◄──────────ACK (Copied!)───────┤

Broker-1 (Leader P0) ───COPY MESSAGE───► Broker-3 (Follower P0)
                                          ✅ Copied!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Data now exists on 3 brokers! 💪&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like making photocopies of important documents and storing them in different safes.&lt;/p&gt;




&lt;h2&gt;
  
  
  📥 Part 3: CONSUMER READS DATA
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 9: Consumer Wants to Read Messages
&lt;/h3&gt;

&lt;p&gt;Your application (Consumer) wants to read data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────┐
│  I want to read from:    │
│  • Topic: "orders"       │
│  • Group: "my-group"     │
│                          │
│  "How do I start?"       │
└──────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like wanting to read a book but not knowing which library has it.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 10: Consumer Connects and Gets Metadata
&lt;/h3&gt;

&lt;p&gt;The consumer connects to &lt;strong&gt;any broker&lt;/strong&gt; to get cluster information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumer ────────────► Broker-2
"Tell me everything    "Here's the full
about 'orders'"        cluster map!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Broker returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────────────────────┐
│  Topic "orders" info:             │
│  • Partition 0 → Leader: Broker-1 │
│  • Partition 1 → Leader: Broker-2 │
│  • Partition 2 → Leader: Broker-3 │
└───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like getting a mall directory showing which stores are on which floor.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 11: Consumer Joins Group (Controller Coordinates)
&lt;/h3&gt;

&lt;p&gt;The consumer joins a consumer group for coordinated reading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumer → Broker → Controller ⭐
"I want to join      "Let me assign
group 'my-group'"    partitions..."

Controller decides:
┌───────────────────────────────────┐
│  Group "my-group" has 1 consumer  │
│  Topic "orders" has 3 partitions  │
│                                   │
│  Assignment:                      │
│  Consumer-A → [P0, P1, P2]        │
│  (gets all 3 partitions)          │
└───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like a teacher assigning homework to students.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 12: Consumer Reads and Tracks Progress
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;How Consumer Manages Reading Position:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STARTUP (Once):
Consumer → Broker: "Where did I leave off?"
Broker → Consumer: "P0: offset 1250, P1: offset 890, P2: offset 2100"
Consumer stores in memory ✅

CONTINUOUS READING:
Consumer fetches using local memory (no broker queries!)
• Fetch from P0: offset 1250 → 1300 → 1350 (tracked in memory)
• Fetch from P1: offset 890 → 940 → 990 (tracked in memory)
• Fetch from P2: offset 2100 → 2150 → 2200 (tracked in memory)

PERIODIC COMMIT (Every 5 seconds or after batch):
Consumer → Broker: "Save progress: P0=1350, P1=990, P2=2200"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🔥 KEY POINTS:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consumer reads position from broker &lt;strong&gt;ONCE&lt;/strong&gt; at startup&lt;/li&gt;
&lt;li&gt;Tracks current position &lt;strong&gt;IN MEMORY&lt;/strong&gt; while reading&lt;/li&gt;
&lt;li&gt;Saves progress back to broker &lt;strong&gt;PERIODICALLY&lt;/strong&gt; (every 5 seconds by default)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like checking your bookmark when opening a book, remembering your page while reading, and updating the bookmark occasionally.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 13: Consumer Pulls Data from Brokers
&lt;/h3&gt;

&lt;p&gt;Consumer fetches data in parallel from all partition leaders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumer ───────► Broker-1 (P0) → Returns 50 events
        ├────────► Broker-2 (P1) → Returns 50 events
        └────────► Broker-3 (P2) → Returns 50 events

Total: 150 events fetched!
         ↓
   Process all events
   (Your business logic)
         ↓
   All done! ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like reading from multiple books at the same time, keeping track of your progress in each.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 Part 4: FAILURE HANDLING
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SCENARIO A: Broker Fails (Controller Handles)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Broker-1 crashes! 💥

STEP 1: Controller Detects Failure
Controller ⭐: "Broker-1 stopped responding!"

STEP 2: Controller Checks Metadata
┌───────────────────────────────────┐
│  Partition 0 (orders):            │
│  • Leader: Broker-1 💀            │
│  • Followers: Broker-2 ✅, Broker-3 ✅│
│                                   │
│  Need new leader for P0!          │
└───────────────────────────────────┘

STEP 3: Controller Elects New Leader
Controller ⭐ → Broker-2: "You are now LEADER for P0!"
Broker-2: "OK! I'm the new leader!"

STEP 4: Controller Updates Metadata
┌───────────────────────────────────┐
│  Partition 0 (orders):            │
│  • Leader: Broker-2 ⭐ (NEW!)     │
│  • Followers: Broker-3 ✅         │
│  • Broker-1: 💀 (removed)         │
└───────────────────────────────────┘

STEP 5: Controller Notifies Everyone
Controller → All: "Metadata changed! P0 leader is now Broker-2!"

Total time: 2-3 seconds! ⚡
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like when a teacher is absent, the principal quickly assigns a substitute.&lt;/p&gt;




&lt;h3&gt;
  
  
  SCENARIO B: Consumer Fails (Controller Rebalances)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumer-A crashes! 💥

STEP 1: Group Coordinator Detects
Coordinator: "Consumer-A missed 3 heartbeats!"

STEP 2: Coordinator Triggers Rebalance
Coordinator → Controller: "Group 'my-group' needs rebalancing!"
Controller → Other Consumers: "Stop! Rebalancing..."

STEP 3: Controller Reassigns Partitions
Before:
Consumer-A: [P0, P1] 💀 (dead)
Consumer-B: [P2] ✅

After:
Consumer-B: [P0, P1, P2] ✅ (takes over all!)

STEP 4: Controller Notifies Consumer-B
Controller → Consumer-B: "You now read P0, P1, P2"

Consumer-B resumes reading:
✅ Loads last saved positions
✅ Continues from where Consumer-A left off
✅ No messages lost!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Simple:&lt;/strong&gt; Like when one waiter is sick, another takes over their tables.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎨 The Complete Picture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────────────────────────┐
│                   KAFKA CLUSTER                        │
│                                                        │
│  ┌───────────────────────────────────────────────┐    │
│  │     CONTROLLERS (The Managers 🧠)             │    │
│  │                                               │    │
│  │  Controller-1 ⭐  Controller-2  Controller-3  │    │
│  │    (Leader)      (Follower)    (Follower)    │    │
│  │                                               │    │
│  │  Maintains METADATA REGISTRY                  │    │
│  │  • Who's alive?                               │    │
│  │  • Who's the leader?                          │    │
│  │  • Who reads what?                            │    │
│  └──────────────────┬────────────────────────────┘    │
│                     ↓ Commands &amp;amp; Notifications        │
│  ┌───────────────────────────────────────────────┐    │
│  │     BROKERS (The Workers 💪)                  │    │
│  │                                               │    │
│  │  Broker-1      Broker-2      Broker-3        │    │
│  │  P0 (L)⭐      P1 (L)⭐      P2 (L)⭐         │    │
│  │  P1 (F)        P2 (F)        P0 (F)          │    │
│  │  P2 (F)        P0 (F)        P1 (F)          │    │
│  │                                               │    │
│  │  Stores &amp;amp; Serves Data                         │    │
│  └───────────────────────────────────────────────┘    │
│         ↑              ↑              ↑               │
└─────────┼──────────────┼──────────────┼───────────────┘
          │              │              │
          ↓              ↓              ↓
    Producer-1     Producer-2     Producer-3
          │              │              │
          └──────────────┴──────────────┘
                         │
         All query metadata from any broker
                         │
          ┌──────────────┴──────────────┐
          ↓                             ↓
    Consumer-A                    Consumer-B
    Group: g1                     Group: g1
    Reads: P0,P1                  Reads: P2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📋 Key Roles Summary
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Controller (The Boss 👔)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;MANAGES:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Who's alive? (broker health)&lt;/li&gt;
&lt;li&gt;✅ Who's in charge? (partition leaders)&lt;/li&gt;
&lt;li&gt;✅ Who reads what? (consumer assignments)&lt;/li&gt;
&lt;li&gt;✅ What exists? (topics, partitions)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DECIDES:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ New leader when broker fails&lt;/li&gt;
&lt;li&gt;✅ Partition assignments for consumers&lt;/li&gt;
&lt;li&gt;✅ Where new partitions go&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NOTIFIES:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Tells brokers their jobs&lt;/li&gt;
&lt;li&gt;✅ Updates everyone on changes&lt;/li&gt;
&lt;li&gt;✅ Coordinates rebalancing&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Broker (The Worker 👷)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;STORES:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Actual data on disk&lt;/li&gt;
&lt;li&gt;✅ Log files for partitions&lt;/li&gt;
&lt;li&gt;✅ Copy of metadata (from controller)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SERVES:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Producer write requests&lt;/li&gt;
&lt;li&gt;✅ Consumer read requests&lt;/li&gt;
&lt;li&gt;✅ Metadata queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;REPLICATES:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Copies data to followers&lt;/li&gt;
&lt;li&gt;✅ Syncs with leader&lt;/li&gt;
&lt;li&gt;✅ Reports status to controller&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Producer (The Sender 📤)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;DOES:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Creates messages&lt;/li&gt;
&lt;li&gt;✅ Queries metadata (from any broker)&lt;/li&gt;
&lt;li&gt;✅ Calculates partition (key hash)&lt;/li&gt;
&lt;li&gt;✅ Sends to correct broker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DOESN'T CARE ABOUT:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Controllers (transparent)&lt;/li&gt;
&lt;li&gt;❌ Followers (writes only to leader)&lt;/li&gt;
&lt;li&gt;❌ Other producers&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Consumer (The Receiver 📥)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;DOES:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Joins consumer group&lt;/li&gt;
&lt;li&gt;✅ Gets partition assignment&lt;/li&gt;
&lt;li&gt;✅ Tracks reading position in memory&lt;/li&gt;
&lt;li&gt;✅ Pulls from leader brokers&lt;/li&gt;
&lt;li&gt;✅ Saves progress periodically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DOESN'T CARE ABOUT:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ How controller assigns partitions&lt;/li&gt;
&lt;li&gt;❌ Follower replicas&lt;/li&gt;
&lt;li&gt;❌ Other consumer groups&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 The Magic: Why This Works So Well
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Separation of Concerns
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CONTROLLERS think&lt;/strong&gt; 🧠&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BROKERS work&lt;/strong&gt; 💪&lt;/li&gt;
&lt;li&gt;Controllers don't handle data&lt;/li&gt;
&lt;li&gt;Brokers don't make decisions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Like:&lt;/strong&gt; Managers plan, workers execute&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Everything Has a Backup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Controllers: 3 copies (1 leader + 2 followers)&lt;/li&gt;
&lt;li&gt;Partitions: 3 copies (1 leader + 2 followers)&lt;/li&gt;
&lt;li&gt;Metadata: All brokers have a copy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; If anything fails, backups take over!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Distributed = Fast + Reliable
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multiple brokers = Parallel processing&lt;/li&gt;
&lt;li&gt;Multiple partitions = Load distribution&lt;/li&gt;
&lt;li&gt;Multiple replicas = No data loss&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Like:&lt;/strong&gt; Many checkout lanes at a store&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Automatic Recovery
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Broker fails → Controller elects new leader (seconds)&lt;/li&gt;
&lt;li&gt;Consumer fails → Controller reassigns partitions (seconds)&lt;/li&gt;
&lt;li&gt;Controller fails → Another controller becomes leader (seconds)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;All automatic! No human intervention needed!&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I also took some help from Claude to understand and make a few concepts more visual.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>kafka</category>
      <category>distributedsystems</category>
      <category>go</category>
    </item>
    <item>
      <title>🧠 Kafka Broker vs Controller - Complete Guide</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Tue, 18 Nov 2025 19:05:53 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/kafka-broker-vs-controller-complete-guide-32fg</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/kafka-broker-vs-controller-complete-guide-32fg</guid>
      <description>&lt;h2&gt;
  
  
  Understanding the Two Critical Roles in Kafka's Architecture
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Big Picture
&lt;/h2&gt;

&lt;p&gt;In Kafka 4.0 (with KRaft), servers can perform &lt;strong&gt;two distinct roles&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Analogy&lt;/th&gt;
&lt;th&gt;Primary Function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Broker&lt;/strong&gt; 📦&lt;/td&gt;
&lt;td&gt;Library Shelf Manager&lt;/td&gt;
&lt;td&gt;Handles data storage and delivery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Controller&lt;/strong&gt; 🎮&lt;/td&gt;
&lt;td&gt;Library Head Librarian&lt;/td&gt;
&lt;td&gt;Manages catalog and coordinates operations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Quick Tip:&lt;/strong&gt; Think of Kafka as a digital library system. Brokers are the staff who shelve and retrieve books, while Controllers are the head librarians who maintain the catalog and coordinate everything.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Evolution: Before and After
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ The Old Way (Before Kafka 4.0)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Two separate systems to manage!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────┐
│  ZooKeeper Cluster  │ ← External dependency
│   (The Brain 🧠)    │    Must maintain separately
│                     │    Additional complexity
└──────────┬──────────┘
           │
           ↓ Manages metadata
┌─────────────────────┐
│   Kafka Brokers     │
│ (Data handlers only)│
│  • Store data       │
│  • Serve clients    │
└─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Challenges:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two systems to deploy, monitor, and maintain&lt;/li&gt;
&lt;li&gt;ZooKeeper expertise required&lt;/li&gt;
&lt;li&gt;Additional infrastructure costs&lt;/li&gt;
&lt;li&gt;Complex failure scenarios&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ✅ The New Way (Kafka 4.0+ with KRaft)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Self-contained, all-in-one system!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────────────────────────┐
│      KAFKA CLUSTER (Self-Managed)     │
│                                       │
│  CONTROLLERS (Built-in Brain 🧠)      │
│  ┌──────┐  ┌──────┐  ┌──────┐       │
│  │Ctrl-1│  │Ctrl-2│  │Ctrl-3│       │
│  │Leader│  │Follow│  │Follow│       │
│  └──┬───┘  └──────┘  └──────┘       │
│     │                                │
│     ↓ Manages metadata               │
│  ┌──────┐  ┌──────┐  ┌──────┐       │
│  │Brkr-1│  │Brkr-2│  │Brkr-3│       │
│  │ 📦   │  │ 📦   │  │ 📦   │       │
│  └──────┘  └──────┘  └──────┘       │
└───────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Single system to manage&lt;/li&gt;
&lt;li&gt;✅ No external dependencies&lt;/li&gt;
&lt;li&gt;✅ Faster metadata operations&lt;/li&gt;
&lt;li&gt;✅ Simpler deployment&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Role 1: The Broker (Library Shelf Manager 📦)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What It Does
&lt;/h3&gt;

&lt;p&gt;The Broker is the &lt;strong&gt;data handler&lt;/strong&gt; - it stores and serves data to producers and consumers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-World Analogy
&lt;/h3&gt;

&lt;p&gt;Imagine a &lt;strong&gt;library shelf manager&lt;/strong&gt; who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Receives new books from publishers (messages from producers)&lt;/li&gt;
&lt;li&gt;Organizes them on specific shelves (partitions)&lt;/li&gt;
&lt;li&gt;Retrieves books when patrons request them (serves consumers)&lt;/li&gt;
&lt;li&gt;Maintains backup copies in storage rooms (replication)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Key Responsibilities
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1️⃣ Storing Data 💾
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Broker stores topic partitions on disk:

/var/kafka/data/
├── product-catalog-0/
│   ├── 00000000.log  ← Actual message data
│   ├── 00001000.log
│   └── offset: 1250
│
├── product-catalog-2/
│   └── Backup copy from Broker-3
│
└── customer-events-1/
    └── offset: 450
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2️⃣ Handling Producer Requests 📤
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Receives messages from producers&lt;/li&gt;
&lt;li&gt;Appends to partition logs&lt;/li&gt;
&lt;li&gt;Assigns unique offsets&lt;/li&gt;
&lt;li&gt;Sends acknowledgments back&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3️⃣ Handling Consumer Requests 📥
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Serves read requests from consumers&lt;/li&gt;
&lt;li&gt;Fetches data from partitions&lt;/li&gt;
&lt;li&gt;Tracks consumer positions&lt;/li&gt;
&lt;li&gt;Manages consumer offsets&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4️⃣ Replication 🔄
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Copies data between leader and follower partitions&lt;/li&gt;
&lt;li&gt;Ensures data redundancy&lt;/li&gt;
&lt;li&gt;Maintains in-sync replicas (ISR)&lt;/li&gt;
&lt;li&gt;Handles failover scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  5️⃣ Providing Metadata 📋
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Tells clients about cluster topology&lt;/li&gt;
&lt;li&gt;Shares partition locations&lt;/li&gt;
&lt;li&gt;Provides leader information&lt;/li&gt;
&lt;li&gt;Responds to bootstrap requests&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Visual: Broker in Action
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Producers                  Consumers
            │                          │
            ↓ Write                    ↑ Read
    ┌───────────────────────────────────┐
    │         BROKER-1 (Server)         │
    ├───────────────────────────────────┤
    │                                   │
    │  product-catalog-0/ (Leader)      │
    │  ├─ Messages: 1-1250              │
    │  └─ Actively serving clients      │
    │                                   │
    │  product-catalog-2/ (Follower)    │
    │  └─ Syncing from Broker-3         │
    │                                   │
    │  customer-events-1/ (Leader)      │
    │  └─ Messages: 1-450               │
    └───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Role 2: The Controller (Head Librarian 🎮)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What It Does
&lt;/h3&gt;

&lt;p&gt;The Controller is the &lt;strong&gt;brain/orchestrator&lt;/strong&gt; - it manages cluster state and coordinates operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-World Analogy
&lt;/h3&gt;

&lt;p&gt;Imagine a &lt;strong&gt;head librarian&lt;/strong&gt; who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doesn't shelve books personally (no data handling)&lt;/li&gt;
&lt;li&gt;Maintains the master catalog (metadata)&lt;/li&gt;
&lt;li&gt;Decides which staff manages which sections (partition assignment)&lt;/li&gt;
&lt;li&gt;Tracks all library locations and staff availability (broker health)&lt;/li&gt;
&lt;li&gt;Coordinates responses when staff call in sick (leader election)&lt;/li&gt;
&lt;li&gt;If the head librarian is unavailable, an assistant takes over immediately&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Key Responsibilities
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1️⃣ Cluster State Management 🗺️
&lt;/h4&gt;

&lt;p&gt;The Controller maintains the &lt;strong&gt;single source of truth&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Topic Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Topic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transaction-stream"&lt;/span&gt;
    &lt;span class="na"&gt;Partitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
    &lt;span class="na"&gt;Replication Factor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;Leaders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Partition-0&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Broker-1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Partition-1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Broker-2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Partition-2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Broker-3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Partition-3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Broker-1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Partition-4&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Broker-2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Partition-5&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Broker-3&lt;/span&gt;

&lt;span class="na"&gt;Broker Registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Broker-1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;✅ Online, 15 partitions&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Broker-2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;✅ Online, 18 partitions&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Broker-3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;✅ Online, 17 partitions&lt;/span&gt;

&lt;span class="na"&gt;Consumer Groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Group "data-analytics"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Members&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Consumer-A&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Consumer-B&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Consumer-C&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;Coordinator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Broker-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2️⃣ Leader Election ⭐
&lt;/h4&gt;

&lt;p&gt;When a partition leader fails, the Controller:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Detects the failure immediately&lt;/li&gt;
&lt;li&gt;Selects a new leader from in-sync replicas&lt;/li&gt;
&lt;li&gt;Updates cluster metadata&lt;/li&gt;
&lt;li&gt;Notifies all brokers&lt;/li&gt;
&lt;li&gt;Clients automatically redirect to new leader&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example Scenario:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:  transaction-stream-0 Leader = Broker-1 ✅
         Broker-1 crashes! 💥
After:   transaction-stream-0 Leader = Broker-2 ⭐ (promoted!)
         Time taken: ~2-3 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3️⃣ Cluster Change Notification 📢
&lt;/h4&gt;

&lt;p&gt;The Controller broadcasts changes to all brokers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🆕 New topic created → notify all brokers&lt;/li&gt;
&lt;li&gt;⚠️ Broker goes down → redistribute partitions&lt;/li&gt;
&lt;li&gt;⭐ New leader elected → update routing&lt;/li&gt;
&lt;li&gt;🔧 Configuration changed → apply updates&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4️⃣ Broker Lifecycle Management 🔄
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Manages broker registration&lt;/li&gt;
&lt;li&gt;Handles broker join/leave events&lt;/li&gt;
&lt;li&gt;Smooth handoff during shutdowns&lt;/li&gt;
&lt;li&gt;Updates cluster membership&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  5️⃣ Administrative Operations ⚙️
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Topic creation/deletion&lt;/li&gt;
&lt;li&gt;Partition reassignment&lt;/li&gt;
&lt;li&gt;Configuration changes&lt;/li&gt;
&lt;li&gt;Quota management&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Visual: Controller Quorum
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    CONTROLLER QUORUM (High Availability)

┌──────────┐  ┌──────────┐  ┌──────────┐
│  Ctrl-1  │  │  Ctrl-2  │  │  Ctrl-3  │
│ (LEADER) │◄─┤(Follower)│◄─┤(Follower)│
│    ⭐    │  │          │  │          │
├──────────┤  ├──────────┤  ├──────────┤
│ • Makes  │  │ • Standby│  │ • Standby│
│   all    │  │ • Ready  │  │ • Ready  │
│   decis- │  │   to     │  │   to     │
│   ions   │  │   take   │  │   take   │
│ • Notif- │  │   over   │  │   over   │
│   ies    │  │ • Syncs  │  │ • Syncs  │
│   brokers│  │   data   │  │   data   │
└────┬─────┘  └──────────┘  └──────────┘
     │
     ↓ Commands &amp;amp; notifications
┌────────────────────────────────────┐
│            BROKERS                 │
│  ┌────┐    ┌────┐    ┌────┐      │
│  │Br-1│    │Br-2│    │Br-3│      │
│  └────┘    └────┘    └────┘      │
└────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always use an &lt;strong&gt;odd number&lt;/strong&gt; of controllers (3, 5, 7)&lt;/li&gt;
&lt;li&gt;Uses &lt;strong&gt;Raft consensus&lt;/strong&gt; algorithm&lt;/li&gt;
&lt;li&gt;Requires &lt;strong&gt;majority&lt;/strong&gt; to function (e.g., 2 out of 3)&lt;/li&gt;
&lt;li&gt;If majority fails, cluster cannot make decisions&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Combined vs Dedicated Roles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option 1: Combined Role (Development/Testing)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Each node runs BOTH broker + controller&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────┐
│     NODE-1          │
│ ┌─────────────────┐ │
│ │   Controller    │ │
│ │   (Leader) ⭐   │ │
│ └─────────────────┘ │
│         +           │
│ ┌─────────────────┐ │
│ │     Broker      │ │
│ │   (Data 📦)     │ │
│ └─────────────────┘ │
└─────────────────────┘

Same for NODE-2 and NODE-3
(with follower controllers)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Simple setup&lt;/li&gt;
&lt;li&gt;✅ Fewer machines (cost-effective)&lt;/li&gt;
&lt;li&gt;✅ Good for development/testing&lt;/li&gt;
&lt;li&gt;✅ Small-scale production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Resource contention (metadata + data compete)&lt;/li&gt;
&lt;li&gt;❌ Less stable under high load&lt;/li&gt;
&lt;li&gt;❌ Harder to scale independently&lt;/li&gt;
&lt;li&gt;❌ "Noisy neighbor" problem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best For:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local development&lt;/li&gt;
&lt;li&gt;Testing environments&lt;/li&gt;
&lt;li&gt;Small production deployments (&amp;lt;10 brokers)&lt;/li&gt;
&lt;li&gt;Low-traffic applications&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Option 2: Dedicated Roles (Production)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Separate controller nodes from broker nodes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEDICATED CONTROLLERS (Metadata Only)
┌──────────┐  ┌──────────┐  ┌──────────┐
│  Ctrl-1  │  │  Ctrl-2  │  │  Ctrl-3  │
│ (Leader) │  │(Follower)│  │(Follower)│
├──────────┤  ├──────────┤  ├──────────┤
│ 4GB RAM  │  │ 4GB RAM  │  │ 4GB RAM  │
│ 2 CPU    │  │ 2 CPU    │  │ 2 CPU    │
│ Small VM │  │ Small VM │  │ Small VM │
└────┬─────┘  └──────────┘  └──────────┘
     │
     ↓ Manages

DEDICATED BROKERS (Data Only)
┌──────────┐  ┌──────────┐  ┌──────────┐
│  Brkr-1  │  │  Brkr-2  │  │  Brkr-3  │
│   📦     │  │   📦     │  │   📦     │
├──────────┤  ├──────────┤  ├──────────┤
│ 64GB RAM │  │ 64GB RAM │  │ 64GB RAM │
│ 16 CPU   │  │ 16 CPU   │  │ 16 CPU   │
│ TB disk  │  │ TB disk  │  │ TB disk  │
└──────────┘  └──────────┘  └──────────┘

... scale to 100+ brokers as needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Maximum stability (isolated operations)&lt;/li&gt;
&lt;li&gt;✅ Independent scaling&lt;/li&gt;
&lt;li&gt;✅ Optimized resources per role&lt;/li&gt;
&lt;li&gt;✅ Better fault tolerance&lt;/li&gt;
&lt;li&gt;✅ Industry standard for production&lt;/li&gt;
&lt;li&gt;✅ Can upgrade independently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ More machines (higher cost)&lt;/li&gt;
&lt;li&gt;❌ More complex setup&lt;/li&gt;
&lt;li&gt;❌ Overkill for small deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best For:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Production environments&lt;/li&gt;
&lt;li&gt;High-traffic applications&lt;/li&gt;
&lt;li&gt;Enterprise deployments&lt;/li&gt;
&lt;li&gt;Systems requiring 24/7 uptime&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-World Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example: Controller Leader Failover
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Main controller experiences hardware failure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEFORE (Normal Operations):
Controller-1 (LEADER) ⭐ → Managing all metadata
Controller-2 (Follower) → Standby backup
Controller-3 (Follower) → Standby backup

━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Hardware failure on Controller-1! 💥
━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Detection (within seconds):
Controller-2: "Leader timeout detected!"
Controller-3: "Leader timeout detected!"
        │
        ↓ Raft Consensus Election

AFTER (2-3 seconds):
Controller-1 (OFFLINE) 💀
Controller-2 (LEADER) ⭐ → PROMOTED! Takes over all duties
Controller-3 (Follower) → Continues standby

✅ Service continues without interruption!
✅ No data lost!
✅ Brokers still serving all requests!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔍 Question on Kraft’s Leader Election Algorithm
&lt;/h3&gt;

&lt;p&gt;In &lt;strong&gt;Kraft’s leader election algorithm&lt;/strong&gt;, correctness proofs often assume an &lt;strong&gt;odd number of nodes&lt;/strong&gt; to avoid symmetry and tie-breaking issues.&lt;br&gt;&lt;br&gt;
But in real distributed systems, nodes can &lt;strong&gt;fail at any time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;If a node fails mid-execution and the system is left with an &lt;em&gt;even&lt;/em&gt; number of active nodes, how does the algorithm still guarantee that a &lt;em&gt;unique leader&lt;/em&gt; is elected?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Would love to hear your views and interpretations on this!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>kafka</category>
      <category>eventdriven</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Understanding Kafka Architecture - The Complete Mental Model 🧠</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Mon, 17 Nov 2025 21:15:58 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/kafka-architecture-the-complete-mental-model-2k52</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/kafka-architecture-the-complete-mental-model-2k52</guid>
      <description>&lt;p&gt;How all the pieces fit together to create a powerful streaming platform&lt;/p&gt;




&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Understand the "Big Picture"&lt;/strong&gt; - How events, topics, partitions, producers, consumers, brokers, and consumer groups all work together as one cohesive system.&lt;/p&gt;

&lt;p&gt;Think of this as getting a &lt;strong&gt;bird's eye view&lt;/strong&gt; of the entire Kafka ecosystem! 🦅&lt;/p&gt;




&lt;h2&gt;
  
  
  Building Block #1: The Event (Foundation)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What It Is
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;fundamental unit&lt;/strong&gt; - an immutable fact representing something that happened.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────┐
│           EVENT/RECORD              │
├─────────────────────────────────────┤
│ Key: user_456                       │
│ Value: {"action": "purchase"}       │
│ Timestamp: 2025-11-18 14:30:00     │
└─────────────────────────────────────┘

Everything in Kafka revolves around these!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Building Block #2: The Kafka Cluster (Infrastructure)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What It Is
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;collection of servers&lt;/strong&gt; working together - NOT just one server!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        KAFKA CLUSTER
┌─────────────────────────────────┐
│                                 │
│  ┌────────┐  ┌────────┐        │
│  │Broker 1│  │Broker 2│  ...   │
│  │Server 1│  │Server 2│        │
│  └────────┘  └────────┘        │
│                                 │
│  ┌────────┐  ┌────────┐        │
│  │Broker 3│  │Broker 4│  ...   │
│  │Server 3│  │Server 4│        │
│  └────────┘  └────────┘        │
│                                 │
└─────────────────────────────────┘

Network of powerful servers!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What Brokers Do
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Store&lt;/strong&gt; your events&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle&lt;/strong&gt; requests from applications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensure&lt;/strong&gt; the system stays available even if one fails&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Multiple Brokers?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; → Handle massive amounts of data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fault Tolerance&lt;/strong&gt; → Keep running even if servers fail&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Modern Kafka (4.0+)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Brokers are &lt;strong&gt;self-managing&lt;/strong&gt; using KRaft protocol&lt;/li&gt;
&lt;li&gt;They coordinate with each other internally&lt;/li&gt;
&lt;li&gt;No external ZooKeeper needed! 🎉&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Visualize:&lt;/strong&gt; A resilient network of powerful servers ready to handle your data streams.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building Block #3: Topics (Organization)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What It Is
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;logical name/category&lt;/strong&gt; for a stream of related events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KAFKA CLUSTER
├── Topic: "user-signups" 👤
├── Topic: "payment-transactions" 💰
├── Topic: "sensor-readings" 🌡️
└── Topic: "order-events" 📦
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Characteristics
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Distributed Across Brokers&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Single topic doesn't live on just ONE broker:

Topic: "orders"
├── Partition 0 → Broker 1
├── Partition 1 → Broker 2
└── Partition 2 → Broker 3

This distribution = SCALE! 🚀
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Durable Storage&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Events stored for configurable retention period&lt;/li&gt;
&lt;li&gt;Can be re-read multiple times&lt;/li&gt;
&lt;li&gt;Not deleted after consumption&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Building Block #4: Partitions (Parallelism)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What It Is
&lt;/h3&gt;

&lt;p&gt;Each topic is &lt;strong&gt;divided into ordered lanes&lt;/strong&gt; called partitions.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Multi-Lane Highway Analogy 🛣️
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: "orders" (3 partitions)

┌────────────────────────────────────────────────────┐
│               MULTI-LANE HIGHWAY                   │
├────────────────────────────────────────────────────┤
│                                                    │
│  Lane 0 (Partition 0): Order1 → Order2 → Order3  │
│  ═════════════════════════════════════════════►   │
│                                                    │
│  Lane 1 (Partition 1): Order4 → Order5 → Order6  │
│  ═════════════════════════════════════════════►   │
│                                                    │
│  Lane 2 (Partition 2): Order7 → Order8 → Order9  │
│  ═════════════════════════════════════════════►   │
│                                                    │
└────────────────────────────────────────────────────┘

Each lane (partition) processes traffic (events) 
independently but IN ORDER within that lane!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Properties
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Ordered Within Partition ✅
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition 0:
Event A (offset 0) → Event B (offset 1) → Event C (offset 2)

Consumer always sees: A, then B, then C
ORDER GUARANTEED within the partition!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. NO Order Across Partitions ❌
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition 0: Event A (time: 10:00)
Partition 1: Event B (time: 09:59)

Consumer might see B before A
NO ORDER GUARANTEE across different partitions!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Each Partition Lives on a Broker
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: "payments" (3 partitions)

Partition 0 → Broker 1 (Server 1)
Partition 1 → Broker 2 (Server 2)
Partition 2 → Broker 3 (Server 3)

Load is DISTRIBUTED across servers! ⚖️
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Partitions?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enable parallelism&lt;/strong&gt; → Multiple producers/consumers work simultaneously&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribute load&lt;/strong&gt; → Spread data across multiple servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale horizontally&lt;/strong&gt; → Add more partitions = more throughput&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Building Block #5: Producers (Data Writers)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What It Is
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Your application code&lt;/strong&gt; that sends/publishes events to Kafka topics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;         PRODUCERS (Entry Ramps)

Mobile App 📱 ──┐
                │
Web Server 🌐 ──┼──► Kafka Topic: "events"
                │      ├─► Partition 0
IoT Device 🌡️ ──┘      ├─► Partition 1
                       └─► Partition 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How Producers Work
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Option 1: Automatic Partition Selection (No Key)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer sends events WITHOUT key:

Event 1 → Partition 0 (round-robin)
Event 2 → Partition 1 (round-robin)
Event 3 → Partition 2 (round-robin)
Event 4 → Partition 0 (round-robin)
...

Result: EVEN DISTRIBUTION across partitions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Option 2: Key-Based Routing (With Key)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer sends events WITH key:

Event (key: user_123) → Partition 1
Event (key: user_123) → Partition 1 (SAME!)
Event (key: user_456) → Partition 2
Event (key: user_456) → Partition 2 (SAME!)
Event (key: user_123) → Partition 1 (SAME!)

Result: ALL events with SAME KEY go to SAME PARTITION
        This maintains ORDER for related events! 🎯
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Visual Example: Key-Based Routing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer: E-commerce Website

Order from user_123:
┌──────────────────────┐
│ Key: user_123        │
│ Value: Order details │
└──────────────────────┘
         ↓
    Kafka hashes key
         ↓
    Always → Partition 1

Another order from user_123:
┌──────────────────────┐
│ Key: user_123        │
│ Value: Order details │
└──────────────────────┘
         ↓
    Kafka hashes key
         ↓
    Always → Partition 1 (SAME!)

✅ All user_123 orders processed IN ORDER!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Producer Behavior
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous&lt;/strong&gt; → Send and move on (don't wait for consumer)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High throughput&lt;/strong&gt; → Can send thousands of events per second&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fire and forget&lt;/strong&gt; → Ensures speed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Visualize:&lt;/strong&gt; Entry ramps onto a highway, directing traffic into specific lanes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building Block #6: Consumers (Data Readers)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What It Is
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Your application code&lt;/strong&gt; that reads/subscribes to events from topics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;         Kafka Topic: "orders"
                 ↓
         ┌───────┴───────┐
         │               │
    Consumer A      Consumer B
         ↓               ↓
   Analytics App    Email Service

Each reads INDEPENDENTLY with its own position (offset)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Properties
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Pull-Based Model
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traditional Systems:        Kafka:
Server → PUSHES → Client   Client ← PULLS ← Server

Benefits of Pull:
✅ Consumer controls pace
✅ Can process at own speed
✅ Can pause/resume
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Independent Reading
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Multiple consumers can read SAME topic:

Topic: "transactions"
     ↓
     ├──► Consumer A (reads everything)
     ├──► Consumer B (reads everything)
     └──► Consumer C (reads everything)

Each maintains its OWN offset (reading position)
Nobody affects anyone else! 🎭
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Offset Tracking
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition 0:
┌────┬────┬────┬────┬────┬────┐
│ 0  │ 1  │ 2  │ 3  │ 4  │ 5  │ ...
└────┴────┴────┴────┴────┴────┘
              ↑
         Consumer's
         current offset
         (remembers position)

If consumer stops and restarts:
✅ Resumes from last offset (position 2)
✅ No messages skipped
✅ No messages duplicated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Building Block #7: Consumer Groups (Team Work)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What It Is
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;collection of consumer instances&lt;/strong&gt; working together as a team to process events.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Team Analogy 👥
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Team A (Consumer Group "analytics"):
Worker 1, Worker 2, Worker 3

Team B (Consumer Group "email"):
Worker 4, Worker 5

Team C (Consumer Group "archiving"):
Worker 6, Worker 7, Worker 8

Each TEAM gets its own FULL COPY of the event stream!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How Consumer Groups Work
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Rule: One Partition = One Consumer (within group)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: "orders" (3 partitions)

Consumer Group "order-processors" (3 consumers):

Partition 0 ──► Consumer A ┐
Partition 1 ──► Consumer B ├─ Group "order-processors"
Partition 2 ──► Consumer C ┘

✅ Each partition assigned to EXACTLY ONE consumer
✅ Work is DIVIDED among team members
✅ Parallel processing! ⚡
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example: Load Distribution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scenario 1: More partitions than consumers

Topic: 4 partitions
Group: 2 consumers

Partition 0 ──┐
Partition 1 ──┼──► Consumer A
               │
Partition 2 ──┤
Partition 3 ──┴──► Consumer B

Each consumer handles 2 partitions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scenario 2: More consumers than partitions

Topic: 2 partitions
Group: 3 consumers

Partition 0 ──► Consumer A
Partition 1 ──► Consumer B
                Consumer C (IDLE - no partition assigned)

Extra consumers sit idle (but ready for failover!)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scenario 3: Perfect match

Topic: 3 partitions
Group: 3 consumers

Partition 0 ──► Consumer A
Partition 1 ──► Consumer B
Partition 2 ──► Consumer C

Perfectly balanced! ⚖️
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multiple Consumer Groups (Independent Processing)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: "news-feed"
     │
     ├──► Group A "website-updates"
     │    ├─ Consumer 1 → Partition 0
     │    ├─ Consumer 2 → Partition 1
     │    └─ Consumer 3 → Partition 2
     │
     ├──► Group B "archiving"
     │    ├─ Consumer 1 → Partition 0
     │    ├─ Consumer 2 → Partition 1
     │    └─ Consumer 3 → Partition 2
     │
     └──► Group C "sentiment-analysis"
          └─ Consumer 1 → All partitions

✅ Each group processes SAME data INDEPENDENTLY
✅ Each group maintains its OWN offsets
✅ Groups don't affect each other
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automatic Failover (Self-Healing)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before failure:
Partition 0 ──► Consumer A ✅
Partition 1 ──► Consumer B ✅
Partition 2 ──► Consumer C ✅

Consumer B fails! 💥

After automatic rebalancing (seconds):
Partition 0 ──► Consumer A ✅
Partition 1 ──► Consumer A ✅ (took over!)
Partition 2 ──► Consumer C ✅

Or:
Partition 0 ──► Consumer A ✅
Partition 1 ──► Consumer C ✅ (took over!)
Partition 2 ──► Consumer C ✅

✅ No data loss!
✅ Processing continues!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Visualize:&lt;/strong&gt; Teams of workers where each team processes the full stream, but within each team, workers divide up the lanes (partitions) to work in parallel.&lt;/p&gt;




&lt;h2&gt;
  
  
  THE GRAND PICTURE: How Everything Works Together 🎯
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Complete Data Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STEP 1: PRODUCERS CREATE EVENTS
┌────────────────────────────────────────┐
│ Mobile App, Website, IoT Devices, etc. │
└────────────────┬───────────────────────┘
                 ↓
          Generate Events

STEP 2: EVENTS SENT TO TOPICS
┌─────────────────────────────────────────┐
│  Event with key "user_123"              │
│  → Kafka hashes key                     │
│  → Routes to specific partition         │
└────────────────┬────────────────────────┘
                 ↓
           Topic: "orders"

STEP 3: PARTITIONS STORE EVENTS
┌─────────────────────────────────────────┐
│ Partition 0 (Broker 1): [E1, E2, E3]   │
│ Partition 1 (Broker 2): [E4, E5, E6]   │
│ Partition 2 (Broker 3): [E7, E8, E9]   │
└────────────────┬────────────────────────┘
                 ↓
        Ordered, Immutable Log

STEP 4: CONSUMER GROUPS PULL EVENTS
┌─────────────────────────────────────────┐
│ Group "analytics":                      │
│   Consumer A reads Partition 0          │
│   Consumer B reads Partition 1          │
│   Consumer C reads Partition 2          │
│                                         │
│ Group "email":                          │
│   Consumer D reads Partition 0          │
│   Consumer E reads Partition 1, 2       │
└────────────────┬────────────────────────┘
                 ↓
         Process in parallel
         at their own pace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Visual: Complete System Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                    KAFKA CLUSTER                            │
│                                                             │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐     │
│   │Broker 1 │  │Broker 2 │  │Broker 3 │  │Broker 4 │     │
│   ├─────────┤  ├─────────┤  ├─────────┤  ├─────────┤     │
│   │ P0 (L)  │  │ P1 (L)  │  │ P2 (L)  │  │ P3 (L)  │     │
│   │ P1 (F)  │  │ P2 (F)  │  │ P3 (F)  │  │ P0 (F)  │     │
│   │ P2 (F)  │  │ P3 (F)  │  │ P0 (F)  │  │ P1 (F)  │     │
│   └─────────┘  └─────────┘  └─────────┘  └─────────┘     │
│        ↑                           ↓                       │
│    WRITE                         READ                      │
└────────┼───────────────────────────┼──────────────────────┘
         │                           │
    ┌────┴────┐               ┌─────┴──────┐
    │PRODUCERS│               │CONSUMER    │
    │         │               │GROUPS      │
    │📱 App   │               │            │
    │🌐 Web   │               │Group A:    │
    │🌡️ IoT   │               │ C1, C2, C3 │
    │         │               │            │
    └─────────┘               │Group B:    │
                              │ C4, C5     │
                              └────────────┘

Legend:
P0 = Partition 0
(L) = Leader
(F) = Follower (replica)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Real-World Example: E-Commerce Order System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Complete Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SCENARIO: Customer places an order on website

1️⃣ PRODUCER (Website) creates event:
┌──────────────────────────────────┐
│ Key: customer_789                │
│ Value: {                         │
│   order_id: "ORD-456",          │
│   items: ["laptop", "mouse"],   │
│   total: 1200                    │
│ }                                │
└──────────────────────────────────┘
         ↓

2️⃣ Kafka routes to TOPIC and PARTITION:
Topic: "orders"
Key "customer_789" → Partition 1 (always same partition!)
         ↓

3️⃣ BROKERS store in partition:
Broker 2 (Leader for Partition 1):
┌────────────────────────────────┐
│ Partition 1:                   │
│ Offset 100: ORD-453           │
│ Offset 101: ORD-454           │
│ Offset 102: ORD-456 ← NEW!    │
└────────────────────────────────┘

Broker 3 (Follower):           Broker 4 (Follower):
┌──────────────────────┐       ┌──────────────────────┐
│ Partition 1 (copy):  │       │ Partition 1 (copy):  │
│ Offset 102: ORD-456  │       │ Offset 102: ORD-456  │
└──────────────────────┘       └──────────────────────┘
         ↓                              ↓
    REPLICATED for durability!

4️⃣ MULTIPLE CONSUMER GROUPS process independently:

Group "payment-processing":
  Consumer A reads Partition 1 → Charges credit card

Group "inventory":
  Consumer B reads Partition 1 → Updates stock

Group "email":
  Consumer C reads Partition 1 → Sends confirmation

Group "analytics":
  Consumer D reads Partition 1 → Updates dashboard

✅ All process SAME order
✅ All work INDEPENDENTLY
✅ Each at their own pace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Principles That Make It All Work
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Distribution
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────┐
│ Work spread across many servers  │
│ ✅ Scalability                   │
│ ✅ Parallel processing           │
└──────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Immutability
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────┐
│ Events never change or deleted   │
│ ✅ Can be replayed               │
│ ✅ Multiple consumers can read   │
└──────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Parallelism
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────┐
│ Multiple partitions processed    │
│ simultaneously                    │
│ ✅ High throughput               │
│ ✅ Efficient resource use        │
└──────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Fault Tolerance in Action
&lt;/h2&gt;

&lt;h3&gt;
  
  
  When Broker Fails
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:
Broker 1 (P0-Leader) ✅
Broker 2 (P0-Follower) ✅
Broker 3 (P0-Follower) ✅

Broker 1 fails! 💥

After (2-3 seconds):
Broker 1 (P0-Leader) 💀
Broker 2 (P0-Leader) ⭐ Promoted!
Broker 3 (P0-Follower) ✅

✅ System keeps running
✅ No data loss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When Consumer Fails
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:
Partition 0 → Consumer A ✅
Partition 1 → Consumer B ✅
Partition 2 → Consumer C ✅

Consumer B fails! 💥

After (seconds):
Partition 0 → Consumer A ✅
Partition 1 → Consumer A ✅ Took over!
Partition 2 → Consumer C ✅

✅ Processing continues
✅ No events missed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Summary: The Mental Model Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The 7 Components
&lt;/h3&gt;

&lt;p&gt;✅ &lt;strong&gt;Events&lt;/strong&gt; - The data (immutable facts)&lt;br&gt;
✅ &lt;strong&gt;Cluster&lt;/strong&gt; - Network of servers&lt;br&gt;
✅ &lt;strong&gt;Brokers&lt;/strong&gt; - Individual servers in cluster&lt;br&gt;
✅ &lt;strong&gt;Topics&lt;/strong&gt; - Categories for events&lt;br&gt;
✅ &lt;strong&gt;Partitions&lt;/strong&gt; - Ordered lanes within topics&lt;br&gt;
✅ &lt;strong&gt;Producers&lt;/strong&gt; - Apps that write events&lt;br&gt;
✅ &lt;strong&gt;Consumers&lt;/strong&gt; - Apps that read events&lt;br&gt;
✅ &lt;strong&gt;Consumer Groups&lt;/strong&gt; - Teams that work together&lt;/p&gt;
&lt;h3&gt;
  
  
  The Flow
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producers → Topics → Partitions → Brokers
                                    ↓
                            Consumer Groups
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  The Guarantees
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Order&lt;/strong&gt; within a partition&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Scalability&lt;/strong&gt; through distribution&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Durability&lt;/strong&gt; through replication&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Fault tolerance&lt;/strong&gt; through automatic failover&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Parallel processing&lt;/strong&gt; through partitions and consumer groups&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Your Mental Model
&lt;/h2&gt;

&lt;p&gt;Think of Kafka as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🏭 A highly organized factory where:
   • Multiple assembly lines (partitions) run in parallel
   • Workers (producers) add items to lines
   • Quality checkers (consumers) inspect items
   • Teams (consumer groups) divide the work
   • Multiple facilities (brokers) ensure continuity
   • Everything is tracked and never lost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;You now have a complete bird's eye view of Apache Kafka!&lt;/strong&gt; 🦅&lt;/p&gt;

&lt;p&gt;This mental model will be invaluable as you build applications and dive deeper into Kafka's capabilities. Every detail you learn will fit into this bigger picture! 🎯&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>eventdriven</category>
      <category>programming</category>
      <category>go</category>
    </item>
    <item>
      <title>🎮 Understanding Linux Cgroups</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Sun, 16 Nov 2025 15:38:59 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/understanding-linux-cgroups-2kf1</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/understanding-linux-cgroups-2kf1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 I'm Building My Own Container Runtime!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is part of a complete series where I'm building &lt;a href="https://github.com/a-ZINC/Conti" rel="noopener noreferrer"&gt;&lt;strong&gt;Conti&lt;/strong&gt;&lt;/a&gt; - a container runtime from scratch. Check it out on GitHub!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About This Series:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm sharing everything I learn while building my own container runtime&lt;/li&gt;
&lt;li&gt;Most concepts come from videos, documentation, and LLM-assisted learning (for educational purposes)&lt;/li&gt;
&lt;li&gt;Focus: Understanding through practice - raw Linux commands and practical implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Important&lt;/strong&gt;: When building your own container, DON'T copy code from sources - it kills the fun! Write it yourself, break things, debug, and learn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why Build Your Own?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deep understanding of how containers really work&lt;/li&gt;
&lt;li&gt;Master low-level Linux concepts&lt;/li&gt;
&lt;li&gt;Learn by doing, not just reading&lt;/li&gt;
&lt;li&gt;It's incredibly fun when things finally click!&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What are Cgroups?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Control Groups (Cgroups)&lt;/strong&gt; are a Linux kernel feature that allows you to allocate, limit, and monitor system resources for processes and groups of processes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Formula
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cgroups = Resource Control + Resource Isolation + Resource Accounting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Do We Need Cgroups?
&lt;/h3&gt;

&lt;p&gt;Imagine you're running a web server that hosts multiple applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce Store&lt;/strong&gt;: Needs 8GB RAM, 40% CPU&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics Dashboard&lt;/strong&gt;: Needs 4GB RAM, 30% CPU
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email Service&lt;/strong&gt;: Needs 2GB RAM, 20% CPU&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without cgroups, these applications could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Steal resources from each other&lt;/li&gt;
&lt;li&gt;❌ Cause system crashes&lt;/li&gt;
&lt;li&gt;❌ Create unpredictable performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With cgroups, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Guarantee each application gets its resources&lt;/li&gt;
&lt;li&gt;✅ Prevent any single app from hogging the system&lt;/li&gt;
&lt;li&gt;✅ Maintain stable, predictable performance&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-World Analogy
&lt;/h2&gt;

&lt;p&gt;Think of a &lt;strong&gt;shopping mall&lt;/strong&gt; with limited parking spaces:&lt;/p&gt;

&lt;h3&gt;
  
  
  Without Cgroups (No Rules)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Early shoppers take all parking spaces&lt;/li&gt;
&lt;li&gt;Late arrivals have nowhere to park&lt;/li&gt;
&lt;li&gt;Chaos and complaints&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  With Cgroups (Managed Parking)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Restaurant customers&lt;/strong&gt;: 40 spaces reserved&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Movie theater guests&lt;/strong&gt;: 30 spaces reserved&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retail shoppers&lt;/strong&gt;: 30 spaces reserved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each group is guaranteed their allocation, and no group can exceed their limit.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Cgroups Work
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step-by-Step Process
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Define Resource Groups
   └─&amp;gt; Create named groups for each resource type

2. Set Resource Limits
   └─&amp;gt; Assign specific limits to each group

3. Launch Applications
   └─&amp;gt; Start apps within their assigned groups

4. Kernel Enforces Limits
   └─&amp;gt; Automatic enforcement, no manual intervention needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cgroup Hierarchy
&lt;/h3&gt;

&lt;p&gt;All cgroups live in the filesystem at &lt;code&gt;/sys/fs/cgroup/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/sys/fs/cgroup/
├── memory/          # RAM control
├── cpu/             # CPU time control
├── cpuset/          # CPU core assignment
├── blkio/           # Disk I/O control
├── net_cls/         # Network control
└── devices/         # Device access control
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Resource Types
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Memory Control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Maximum RAM allocation&lt;/li&gt;
&lt;li&gt;Swap space limits&lt;/li&gt;
&lt;li&gt;Out-of-memory (OOM) handling&lt;/li&gt;
&lt;li&gt;Memory usage tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. CPU Control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;CPU percentage allocation&lt;/li&gt;
&lt;li&gt;CPU core assignment (pinning)&lt;/li&gt;
&lt;li&gt;Scheduling priorities&lt;/li&gt;
&lt;li&gt;Multi-core management&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Network Control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Bandwidth limitations&lt;/li&gt;
&lt;li&gt;Priority queuing&lt;/li&gt;
&lt;li&gt;Traffic shaping&lt;/li&gt;
&lt;li&gt;Network class assignments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Disk I/O Control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Read/write speed limits&lt;/li&gt;
&lt;li&gt;IOPS (operations per second)&lt;/li&gt;
&lt;li&gt;Device-specific quotas&lt;/li&gt;
&lt;li&gt;Priority levels&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Memory Management
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating a Memory Control Group
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: You want to run a data processing script that shouldn't use more than 20MB of RAM.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Create the Control Group
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a new control group called 'data_processor'&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; memory:data_processor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Set Memory Limit
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set memory limit to 20MB (20 × 1024 × 1024 = 20,971,520 bytes)&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; memory.limit_in_bytes&lt;span class="o"&gt;=&lt;/span&gt;20971520 data_processor

&lt;span class="c"&gt;# Also limit swap to prevent workarounds&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; memory.memsw.limit_in_bytes&lt;span class="o"&gt;=&lt;/span&gt;20971520 data_processor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Run Your Application
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Execute the script within the control group&lt;/span&gt;
cgexec &lt;span class="nt"&gt;-g&lt;/span&gt; memory:data_processor python3 process_data.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What Happens When Memory Limit Is Exceeded?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application starts
    ↓
Allocates memory
    ↓
Reaches 20MB limit
    ↓
Tries to allocate more
    ↓
┌─────────────────┐
│ Kernel detects  │
│   violation     │
└────────┬────────┘
         ↓
┌─────────────────┐
│  OOM Killer     │
│  Activated      │
└────────┬────────┘
         ↓
   Process killed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Monitoring Memory Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check current memory usage&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /sys/fs/cgroup/memory/data_processor/memory.usage_in_bytes

&lt;span class="c"&gt;# Check if OOM killer was triggered&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /sys/fs/cgroup/memory/data_processor/memory.oom_control
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  CPU Control
&lt;/h2&gt;

&lt;p&gt;There are &lt;strong&gt;two methods&lt;/strong&gt; to control CPU usage:&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 1: Hard Limits (CFS Quota)
&lt;/h3&gt;

&lt;p&gt;Use this when you need &lt;strong&gt;absolute limits&lt;/strong&gt; that are always enforced.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Formula
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CPU Limit % = (cfs_quota_us / cfs_period_us) × 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cfs_period_us&lt;/code&gt;: Time window (default: 100,000 μs = 100ms)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cfs_quota_us&lt;/code&gt;: CPU time allowed in that window&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example: Limit to 35% CPU
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Step 1: Create control group&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; cpu:video_encoder

&lt;span class="c"&gt;# Step 2: Set 35% limit&lt;/span&gt;
&lt;span class="c"&gt;# 35% of 100,000 = 35,000 microseconds&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.cfs_quota_us&lt;span class="o"&gt;=&lt;/span&gt;35000 video_encoder

&lt;span class="c"&gt;# Step 3: Run application&lt;/span&gt;
cgexec &lt;span class="nt"&gt;-g&lt;/span&gt; cpu:video_encoder ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; input.mp4 output.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Common CPU Percentages
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Desired CPU&lt;/th&gt;
&lt;th&gt;cfs_quota_us&lt;/th&gt;
&lt;th&gt;Calculation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;td&gt;10,000&lt;/td&gt;
&lt;td&gt;10,000 / 100,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;25,000&lt;/td&gt;
&lt;td&gt;25,000 / 100,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;50,000&lt;/td&gt;
&lt;td&gt;50,000 / 100,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;75,000&lt;/td&gt;
&lt;td&gt;75,000 / 100,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Method 2: Soft Limits (CPU Shares)
&lt;/h3&gt;

&lt;p&gt;Use this when you want &lt;strong&gt;proportional sharing&lt;/strong&gt; during resource contention.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Concept
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Maximum value: &lt;strong&gt;1024&lt;/strong&gt; (represents 100%)&lt;/li&gt;
&lt;li&gt;Only enforced when multiple processes compete for CPU&lt;/li&gt;
&lt;li&gt;If CPU is idle, processes can use more than their share&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The Formula
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Process CPU % = (process_shares / total_shares) × 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example: Three Applications Sharing CPU
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: You have three services running:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web Server&lt;/strong&gt;: Should get 50% during contention&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background Jobs&lt;/strong&gt;: Should get 30% during contention&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt;: Should get 20% during contention
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create control groups&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; cpu:web_server
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; cpu:background_jobs
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; cpu:monitoring

&lt;span class="c"&gt;# Set CPU shares&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.shares&lt;span class="o"&gt;=&lt;/span&gt;512 web_server      &lt;span class="c"&gt;# 512/1024 = 50%&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.shares&lt;span class="o"&gt;=&lt;/span&gt;307 background_jobs &lt;span class="c"&gt;# 307/1024 ≈ 30%&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.shares&lt;span class="o"&gt;=&lt;/span&gt;205 monitoring      &lt;span class="c"&gt;# 205/1024 ≈ 20%&lt;/span&gt;

&lt;span class="c"&gt;# Launch applications&lt;/span&gt;
cgexec &lt;span class="nt"&gt;-g&lt;/span&gt; cpu:web_server nginx
cgexec &lt;span class="nt"&gt;-g&lt;/span&gt; cpu:background_jobs python worker.py
cgexec &lt;span class="nt"&gt;-g&lt;/span&gt; cpu:monitoring ./monitor.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hard Limits vs Soft Limits
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Hard Limits (Quota)&lt;/th&gt;
&lt;th&gt;Soft Limits (Shares)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Absolute ceiling&lt;/td&gt;
&lt;td&gt;Relative distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enforcement&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Always active&lt;/td&gt;
&lt;td&gt;Only during contention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Idle CPU&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Wasted if limit reached&lt;/td&gt;
&lt;td&gt;Fully utilized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use Case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strict isolation&lt;/td&gt;
&lt;td&gt;Flexible sharing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Analogy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Speed limiter in car&lt;/td&gt;
&lt;td&gt;Highway lanes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Visualization
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Hard Limit (30% quota)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CPU Available: 100%
Process usage: 30% ████████
Unused:        70% (wasted even if CPU is idle)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Soft Limit (30% shares, no contention)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CPU Available: 100%
Process usage: 100% ████████████████████████████████
(Can use full CPU when alone)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Soft Limit (30% shares, with contention)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CPU Available: 100%
Process 1:     30% ████████
Process 2:     40% ███████████
Process 3:     30% ████████
(Shares enforced when competing)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Practical Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example 1: Development Environment
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: You're running Docker containers for development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: 2GB RAM, 40% CPU&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Server&lt;/strong&gt;: 1GB RAM, 30% CPU&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis Cache&lt;/strong&gt;: 512MB RAM, 20% CPU
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Database container&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; memory,cpu:dev_database
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; memory.limit_in_bytes&lt;span class="o"&gt;=&lt;/span&gt;2147483648 dev_database
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.cfs_quota_us&lt;span class="o"&gt;=&lt;/span&gt;40000 dev_database

&lt;span class="c"&gt;# API Server container&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; memory,cpu:dev_api
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; memory.limit_in_bytes&lt;span class="o"&gt;=&lt;/span&gt;1073741824 dev_api
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.cfs_quota_us&lt;span class="o"&gt;=&lt;/span&gt;30000 dev_api

&lt;span class="c"&gt;# Redis Cache container&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; memory,cpu:dev_redis
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; memory.limit_in_bytes&lt;span class="o"&gt;=&lt;/span&gt;536870912 dev_redis
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.cfs_quota_us&lt;span class="o"&gt;=&lt;/span&gt;20000 dev_redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 2: Machine Learning Training
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Training ML model that needs lots of resources but shouldn't crash the system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create control group with generous limits&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; memory,cpu:ml_training
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; memory.limit_in_bytes&lt;span class="o"&gt;=&lt;/span&gt;16106127360 ml_training  &lt;span class="c"&gt;# 15GB&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.cfs_quota_us&lt;span class="o"&gt;=&lt;/span&gt;300000 ml_training  &lt;span class="c"&gt;# 300% (3 full cores)&lt;/span&gt;

&lt;span class="c"&gt;# Run training script&lt;/span&gt;
cgexec &lt;span class="nt"&gt;-g&lt;/span&gt; memory,cpu:ml_training python train_model.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 3: CI/CD Pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Running automated tests that shouldn't hog server resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create control group for CI jobs&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; memory,cpu:ci_runner
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; memory.limit_in_bytes&lt;span class="o"&gt;=&lt;/span&gt;4294967296 ci_runner  &lt;span class="c"&gt;# 4GB&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.shares&lt;span class="o"&gt;=&lt;/span&gt;256 ci_runner  &lt;span class="c"&gt;# Low priority (25% share)&lt;/span&gt;

&lt;span class="c"&gt;# Run tests&lt;/span&gt;
cgexec &lt;span class="nt"&gt;-g&lt;/span&gt; memory,cpu:ci_runner npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 4: Multi-Tenant Web Hosting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Hosting multiple customer websites on one server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Customer A - Premium tier&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; memory,cpu:customer_a
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; memory.limit_in_bytes&lt;span class="o"&gt;=&lt;/span&gt;8589934592 customer_a  &lt;span class="c"&gt;# 8GB&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.shares&lt;span class="o"&gt;=&lt;/span&gt;768 customer_a  &lt;span class="c"&gt;# 75% share&lt;/span&gt;

&lt;span class="c"&gt;# Customer B - Standard tier&lt;/span&gt;
cgcreate &lt;span class="nt"&gt;-g&lt;/span&gt; memory,cpu:customer_b
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; memory.limit_in_bytes&lt;span class="o"&gt;=&lt;/span&gt;4294967296 customer_b  &lt;span class="c"&gt;# 4GB&lt;/span&gt;
cgset &lt;span class="nt"&gt;-r&lt;/span&gt; cpu.shares&lt;span class="o"&gt;=&lt;/span&gt;256 customer_b  &lt;span class="c"&gt;# 25% share&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>containers</category>
      <category>go</category>
      <category>devops</category>
    </item>
    <item>
      <title>Understanding Container Magic: The Overlay Filesystem Story</title>
      <dc:creator>Ajinkya Singh</dc:creator>
      <pubDate>Thu, 13 Nov 2025 19:04:16 +0000</pubDate>
      <link>https://dev.to/ajinkya_singh_2c02bd40423/understanding-container-magic-the-overlay-filesystem-story-37dh</link>
      <guid>https://dev.to/ajinkya_singh_2c02bd40423/understanding-container-magic-the-overlay-filesystem-story-37dh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 I'm Building My Own Container Runtime!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is part of a complete series where I'm building &lt;a href="https://github.com/a-ZINC/Conti" rel="noopener noreferrer"&gt;&lt;strong&gt;Conti&lt;/strong&gt;&lt;/a&gt; - a container runtime from scratch. Check it out on GitHub!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About This Series:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm sharing everything I learn while building my own container runtime&lt;/li&gt;
&lt;li&gt;Most concepts come from videos, documentation, and LLM-assisted learning (for educational purposes)&lt;/li&gt;
&lt;li&gt;Focus: Understanding through practice - raw Linux commands and practical implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Important&lt;/strong&gt;: When building your own container, DON'T copy code from sources - it kills the fun! Write it yourself, break things, debug, and learn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why Build Your Own?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deep understanding of how containers really work&lt;/li&gt;
&lt;li&gt;Master low-level Linux concepts&lt;/li&gt;
&lt;li&gt;Learn by doing, not just reading&lt;/li&gt;
&lt;li&gt;It's incredibly fun when things finally click!&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;How modern containers achieve incredible efficiency and isolation&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🎬 Act 1: The Party Problem
&lt;/h2&gt;

&lt;p&gt;Imagine you're organizing a massive tech conference with three separate tracks happening simultaneously:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎨 The Design Track&lt;/strong&gt; - UI/UX designers discussing Figma and Sketch&lt;br&gt;&lt;br&gt;
&lt;strong&gt;💻 The DevOps Track&lt;/strong&gt; - Engineers exploring Kubernetes and CI/CD&lt;br&gt;&lt;br&gt;
&lt;strong&gt;🤖 The AI Track&lt;/strong&gt; - Researchers presenting machine learning models&lt;/p&gt;

&lt;p&gt;Each track needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A presentation room (isolated space)&lt;/li&gt;
&lt;li&gt;Audio/visual equipment (shared resources)&lt;/li&gt;
&lt;li&gt;Custom materials (track-specific content)&lt;/li&gt;
&lt;li&gt;Whiteboards for notes (temporary changes)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Expensive Approach ❌
&lt;/h3&gt;

&lt;p&gt;You could buy &lt;strong&gt;three complete sets&lt;/strong&gt; of everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 projectors @ $2,000 each = $6,000&lt;/li&gt;
&lt;li&gt;3 sound systems @ $1,500 each = $4,500&lt;/li&gt;
&lt;li&gt;3 furniture sets @ $3,000 each = $9,000&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Total: $19,500&lt;/strong&gt; 😱&lt;/p&gt;
&lt;h3&gt;
  
  
  The Smart Approach ✅
&lt;/h3&gt;

&lt;p&gt;What if you could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Share&lt;/strong&gt; the expensive equipment (projectors, furniture)&lt;/li&gt;
&lt;li&gt;Give each track &lt;strong&gt;private notebooks&lt;/strong&gt; for their own notes&lt;/li&gt;
&lt;li&gt;Let them &lt;strong&gt;customize&lt;/strong&gt; only what they need&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Total: $6,500 + 3 notebooks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is exactly what overlay filesystems do for containers!&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🏗️ Act 2: Understanding the Architecture
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The Three-Layer Cake 🎂
&lt;/h3&gt;

&lt;p&gt;Think of the overlay filesystem as a delicious three-layer cake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────┐
│     🍰 MERGED LAYER (What You See)   │ ← The complete cake you eat
│     Combines everything below        │
├─────────────────────────────────────┤
│     ✏️  UPPER LAYER (Your Changes)   │ ← Your frosting and decorations
│     Read/Write - Personal Edits      │
├─────────────────────────────────────┤
│     📦 LOWER LAYER (Base Recipe)     │ ← The original cake (untouched)
│     Read-Only - Shared Foundation    │
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  🎯 The Lower Layer (The Foundation)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read-only&lt;/strong&gt; - Like a published cookbook&lt;/li&gt;
&lt;li&gt;Contains your base operating system (Ubuntu, Alpine Linux)&lt;/li&gt;
&lt;li&gt;Shared across ALL containers&lt;/li&gt;
&lt;li&gt;Never gets modified&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ✍️ The Upper Layer (Your Workspace)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read/write&lt;/strong&gt; - Your personal notepad&lt;/li&gt;
&lt;li&gt;Stores all YOUR changes&lt;/li&gt;
&lt;li&gt;Unique to each container&lt;/li&gt;
&lt;li&gt;Where creativity happens!&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  👀 The Merged Layer (The Magic View)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;What users actually see and interact with&lt;/li&gt;
&lt;li&gt;Automatically combines Lower + Upper&lt;/li&gt;
&lt;li&gt;Feels like one complete filesystem&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎪 Act 3: The Copy-on-Write Magic Show
&lt;/h2&gt;

&lt;p&gt;Let me show you the most clever trick in the container world: &lt;strong&gt;Copy-on-Write (COW)&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario: The Recipe Book 📖
&lt;/h3&gt;

&lt;p&gt;Imagine you have a &lt;strong&gt;master recipe book&lt;/strong&gt; (lower layer) with 100 recipes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day 1&lt;/strong&gt;: You read "Chocolate Cake" → &lt;em&gt;No copying needed!&lt;/em&gt;&lt;br&gt;&lt;br&gt;
You're just reading from the shared book. Fast and efficient!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day 2&lt;/strong&gt;: You want to modify "Chocolate Cake" → &lt;em&gt;NOW the magic happens!&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STEP 1: System spots you editing
   ↓
STEP 2: "Hold on! Let me copy this page to YOUR notebook!"
   ↓
STEP 3: Copy "Chocolate Cake" to upper layer
   ↓
STEP 4: You modify YOUR copy
   ↓
STEP 5: Original recipe stays pristine ✨
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Result:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Master book: Still has original "Chocolate Cake" ✅&lt;/li&gt;
&lt;li&gt;Your notebook: Has your modified "Spicy Chocolate Cake" ✅&lt;/li&gt;
&lt;li&gt;Everyone else: Still sees the original recipe ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real Container Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Container starts with nginx.conf from base image&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/nginx/nginx.conf
→ Reading from LOWER layer &lt;span class="o"&gt;(&lt;/span&gt;shared base image&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# You edit the config file&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"worker_processes 4;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/nginx/nginx.conf
→ System COPIES file to UPPER layer
→ Your edit goes into YOUR copy
→ Base image remains unchanged!

&lt;span class="c"&gt;# Your change is private to YOUR container&lt;/span&gt;
→ 1000 other nginx containers still see the original
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎯 Act 4: The Real-World Impact
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before Overlay FS: The Dark Ages 😱
&lt;/h3&gt;

&lt;p&gt;Launching 100 web applications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App 1:  Ubuntu (500MB) + Node.js (100MB) = 600MB
App 2:  Ubuntu (500MB) + Node.js (100MB) = 600MB
App 3:  Ubuntu (500MB) + Node.js (100MB) = 600MB
...
App 100: Ubuntu (500MB) + Node.js (100MB) = 600MB

TOTAL: 60,000 MB (60 GB!) 💀
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After Overlay FS: The Renaissance ✨
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shared Ubuntu:     500MB (one time!)
Shared Node.js:    100MB (one time!)
App 1 changes:     2MB
App 2 changes:     3MB
App 3 changes:     1MB
...
App 100 changes:   2MB

TOTAL: 600MB + 200MB changes = 800MB 🎉

SAVED: 59.2 GB (98.7% reduction!)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🛠️ Act 5: Hands-On Workshop
&lt;/h2&gt;

&lt;p&gt;Let's build our own overlay filesystem step-by-step!&lt;/p&gt;

&lt;h3&gt;
  
  
  Workshop Setup: Three Coffee Shops ☕
&lt;/h3&gt;

&lt;p&gt;You're running three coffee shops, each needs menus and custom recipes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Create the Directory Structure
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Our shared base (the franchise template)&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; coffee-franchise/&lt;span class="o"&gt;{&lt;/span&gt;base,shop-downtown,shop-uptown,shop-campus&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; coffee-franchise/work-&lt;span class="o"&gt;{&lt;/span&gt;downtown,uptown,campus&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; coffee-franchise/merged-&lt;span class="o"&gt;{&lt;/span&gt;downtown,uptown,campus&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;cd &lt;/span&gt;coffee-franchise

&lt;span class="c"&gt;# Create shared base menu (lower layer)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"1. Espresso - &lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; base/menu.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"2. Latte - &lt;/span&gt;&lt;span class="nv"&gt;$4&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; base/menu.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"3. Cappuccino - &lt;/span&gt;&lt;span class="nv"&gt;$4&lt;/span&gt;&lt;span class="s2"&gt;.50"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; base/menu.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Standard Coffee Brewing Guide"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; base/brewing.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Mount Downtown Shop (First Container)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the overlay filesystem&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;mount &lt;span class="nt"&gt;-t&lt;/span&gt; overlay overlay &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;lowerdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;base,upperdir&lt;span class="o"&gt;=&lt;/span&gt;shop-downtown,workdir&lt;span class="o"&gt;=&lt;/span&gt;work-downtown &lt;span class="se"&gt;\&lt;/span&gt;
  merged-downtown

&lt;span class="c"&gt;# Check what's visible&lt;/span&gt;
&lt;span class="nb"&gt;ls &lt;/span&gt;merged-downtown/
&lt;span class="c"&gt;# Output: menu.txt  brewing.txt (from base!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Make Shop-Specific Changes
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Downtown caters to business people - add premium options&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"4. Cold Brew - &lt;/span&gt;&lt;span class="nv"&gt;$5&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; merged-downtown/menu.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Downtown Specialty: Extra Strong!"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; merged-downtown/special.txt

&lt;span class="c"&gt;# Check what happened:&lt;/span&gt;
&lt;span class="nb"&gt;ls &lt;/span&gt;base/
&lt;span class="c"&gt;# Output: menu.txt  brewing.txt (unchanged!)&lt;/span&gt;

&lt;span class="nb"&gt;ls &lt;/span&gt;shop-downtown/
&lt;span class="c"&gt;# Output: menu.txt  special.txt (YOUR changes only!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4: Create Another Shop (Second Container)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Mount campus shop&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;mount &lt;span class="nt"&gt;-t&lt;/span&gt; overlay overlay &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;lowerdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;base,upperdir&lt;span class="o"&gt;=&lt;/span&gt;shop-uptown,workdir&lt;span class="o"&gt;=&lt;/span&gt;work-uptown &lt;span class="se"&gt;\&lt;/span&gt;
  merged-uptown

&lt;span class="c"&gt;# Campus caters to students - add budget options&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"4. Small Coffee - &lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; merged-uptown/menu.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Campus Special: Student Discount 20%!"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; merged-uptown/special.txt

&lt;span class="c"&gt;# Each shop sees different menus!&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;merged-downtown/special.txt
&lt;span class="c"&gt;# Output: Downtown Specialty: Extra Strong!&lt;/span&gt;

&lt;span class="nb"&gt;cat &lt;/span&gt;merged-uptown/special.txt
&lt;span class="c"&gt;# Output: Campus Special: Student Discount 20%!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🎊 What We Achieved:
&lt;/h3&gt;

&lt;p&gt;✅ &lt;strong&gt;One base menu&lt;/strong&gt; shared across all shops&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Custom modifications&lt;/strong&gt; per shop&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Complete isolation&lt;/strong&gt; - changes don't affect others&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Massive space savings&lt;/strong&gt; - one copy of common files&lt;/p&gt;


&lt;h2&gt;
  
  
  🎭 Act 6: The Delete Mystery
&lt;/h2&gt;

&lt;p&gt;What happens when you delete a file from the lower layer?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Try to delete the base menu from downtown&lt;/span&gt;
&lt;span class="nb"&gt;rm &lt;/span&gt;merged-downtown/menu.txt

&lt;span class="c"&gt;# The file disappears from downtown view... but wait!&lt;/span&gt;
&lt;span class="nb"&gt;ls &lt;/span&gt;merged-downtown/
&lt;span class="c"&gt;# Output: brewing.txt  special.txt (menu.txt is gone!)&lt;/span&gt;

&lt;span class="c"&gt;# Check the other shop&lt;/span&gt;
&lt;span class="nb"&gt;ls &lt;/span&gt;merged-uptown/
&lt;span class="c"&gt;# Output: menu.txt  brewing.txt  special.txt (still there!)&lt;/span&gt;

&lt;span class="c"&gt;# The secret: a WHITEOUT file&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; shop-downtown/
&lt;span class="c"&gt;# Output: c--------- 1 root root 0, 0 menu.txt (special marker!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Magic:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Instead of deleting from base (impossible - it's read-only!), the system creates a special "whiteout" marker that hides the file &lt;em&gt;only in your view&lt;/em&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🚀 Act 7: Real Container Architecture
&lt;/h2&gt;

&lt;p&gt;Here's how Docker/Kubernetes actually use this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────┐
│   YOUR RUNNING CONTAINER (Merged)       │
│   What you see when you 'docker exec'   │
├─────────────────────────────────────────┤
│   CONTAINER LAYER (Upper) ✏️            │
│   - Your app logs                        │
│   - Temp files                           │
│   - Runtime changes                      │
├─────────────────────────────────────────┤
│   APP LAYER (Lower 3) 📱                │
│   - Your application code                │
│   - App dependencies                     │
├─────────────────────────────────────────┤
│   RUNTIME LAYER (Lower 2) ⚙️            │
│   - Python/Node.js/Java                  │
│   - Libraries                            │
├─────────────────────────────────────────┤
│   BASE OS LAYER (Lower 1) 🏗️            │
│   - Ubuntu/Alpine Linux                  │
│   - Core utilities                       │
└─────────────────────────────────────────┘
     ↑
     └─ All "Lower" layers are SHARED!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Dockerfile Connection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:20.04           # ← Lower Layer 1 (shared!)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;python3  &lt;span class="c"&gt;# ← Lower Layer 2 (shared!)&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; app.py /app/           # ← Lower Layer 3 (shared!)&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python3", "app.py"]    # ← Upper Layer (YOUR changes!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each line creates a layer. When you run 1000 containers from this image:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ubuntu layer&lt;/strong&gt;: Stored ONCE&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python layer&lt;/strong&gt;: Stored ONCE
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App layer&lt;/strong&gt;: Stored ONCE&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime changes&lt;/strong&gt;: 1000 unique upper layers (small!)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>docker</category>
      <category>containers</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
