{"id":4911,"date":"2026-10-18T23:28:24","date_gmt":"2026-10-18T17:58:24","guid":{"rendered":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/"},"modified":"2026-10-18T23:28:24","modified_gmt":"2026-10-18T17:58:24","slug":"docker-container-explained-a-complete-guide-for-beginners","status":"publish","type":"post","link":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/","title":{"rendered":"Docker Container Explained: A Complete Guide for Beginners"},"content":{"rendered":"<p>I remember when servers had physical buttons you could press, and if something broke, you could smell the ozone. There was a dignity in the hum of a SCSI drive spinning up, a physical manifestation of data being moved by magnetism and sheer willpower. You knew exactly where your bits were. They were on that platter, in that rack, connected by a Category 5 cable you crimped yourself. But today? Today, my CTO\u2014a man who thinks &#8220;latency&#8221; is something that only happens to his Zoom calls\u2014has decided that our rock-solid legacy monolith, a piece of software that has outlasted three of his predecessors, needs to be &#8220;containerized.&#8221;<\/p>\n<p>The sheer insanity of the modern stack is enough to make a grown man weep. We are now in an era where developers are too lazy to manage a library dependency, so their solution is to ship an entire damn operating system userland just to run a thirty-line Python script. You want to run a &#8220;Hello World&#8221; app? Better pull a 500MB Debian slim image, layer on some build-essential tools, and then wonder why your &#8220;docker container&#8221; is eating 2GB of RAM before it even hits the first instruction pointer. It\u2019s a nesting doll of inefficiency. We\u2019ve traded understanding for abstraction, and the cost is a catastrophic loss of mechanical sympathy. Every time I see a developer pull a random image from a public registry, I see a security nightmare wrapped in a performance degradation, smothered in a layer of &#8220;I don&#8217;t want to learn how <code>ldconfig<\/code> works.&#8221; We are building cathedrals out of sand, and the tide of technical debt is coming in fast.<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_80 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6ad5f027bcc0b\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6ad5f027bcc0b\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#H2_The_Lie_of_Portability\" >H2: The Lie of Portability<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#H2_The_Technical_Autopsy_Namespaces_and_the_Illusion_of_Isolation\" >H2: The Technical Autopsy: Namespaces and the Illusion of Isolation<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#H2_Cgroups_The_Throttling_of_Reality\" >H2: Cgroups: The Throttling of Reality<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#H2_The_Layered_Lie_OverlayFS_and_the_Death_of_Disk_IO\" >H2: The Layered Lie: OverlayFS and the Death of Disk I\/O<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#H2_Breaking_the_Toy_Seccomp_and_the_Security_Theater\" >H2: Breaking the Toy: Seccomp and the Security Theater<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#H2_Why_Your_Layering_Strategy_is_a_Garbage_Fire\" >H2: Why Your Layering Strategy is a Garbage Fire<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#H2_The_PID_1_Problem_Zombie_Reaping_in_the_Void\" >H2: The PID 1 Problem: Zombie Reaping in the Void<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#The_Bitter_End\" >The Bitter End<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#Related_Articles\" >Related Articles<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"H2_The_Lie_of_Portability\"><\/span>H2: The Lie of Portability<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>They told me a &#8220;docker container&#8221; would make our deployment &#8220;portable.&#8221; That\u2019s the first lie they teach you in DevOps school. Portability is a myth sold to people who don&#8217;t understand the Linux ABI (Application Binary Interface). You aren&#8217;t &#8220;portable&#8221;; you are just shipping your mess to someone else&#8217;s kernel. <\/p>\n<p>Back in my day, we didn&#8217;t have 5.15.0-76-generic to bail us out of every syscall mismatch. We had to ensure our binaries were statically linked or that our <code>LD_LIBRARY_PATH<\/code> was surgically precise. Now, people think that because they wrapped their garbage in a container, it\u2019ll run the same on a Raspberry Pi as it does on a Dual-Socket Xeon. It won&#8217;t. You\u2019re still tethered to the host kernel. If your &#8220;docker container&#8221; expects a specific kernel feature\u2014say, a certain <code>io_uring<\/code> behavior\u2014and the host is running an older LTS kernel, your &#8220;portable&#8221; app is going to dump core faster than a 1990s BBS on a bad phone line.<\/p>\n<p>Let\u2019s look at what this &#8220;portability&#8221; actually looks like under the hood. It\u2019s not magic. It\u2019s just a series of smoke and mirrors managed by <code>runc<\/code>. When you run <code>docker inspect<\/code>, you see the sheer volume of metadata required just to pretend that a process is isolated.<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># docker inspect legacy-monolith-container\n[\n    {\n        &quot;Id&quot;: &quot;a1b2c3d4e5f6...&quot;,\n        &quot;Created&quot;: &quot;2023-10-27T14:22:01.123456789Z&quot;,\n        &quot;Path&quot;: &quot;\/usr\/bin\/python3&quot;,\n        &quot;Args&quot;: [\n            &quot;app.py&quot;\n        ],\n        &quot;State&quot;: {\n            &quot;Status&quot;: &quot;running&quot;,\n            &quot;Running&quot;: true,\n            &quot;Paused&quot;: false,\n            &quot;Restarting&quot;: false,\n            &quot;OOMKilled&quot;: false,\n            &quot;Dead&quot;: false,\n            &quot;Pid&quot;: 12345,\n            &quot;ExitCode&quot;: 0,\n            &quot;Error&quot;: &quot;&quot;,\n            &quot;StartedAt&quot;: &quot;2023-10-27T14:22:02.987654321Z&quot;,\n            &quot;FinishedAt&quot;: &quot;0001-01-01T00:00:00Z&quot;\n        },\n        &quot;GraphDriver&quot;: {\n            &quot;Data&quot;: {\n                &quot;LowerDir&quot;: &quot;\/var\/lib\/docker\/overlay2\/abc\/diff:\/var\/lib\/docker\/overlay2\/def\/diff&quot;,\n                &quot;MergedDir&quot;: &quot;\/var\/lib\/docker\/overlay2\/ghi\/merged&quot;,\n                &quot;UpperDir&quot;: &quot;\/var\/lib\/docker\/overlay2\/ghi\/diff&quot;,\n                &quot;WorkDir&quot;: &quot;\/var\/lib\/docker\/overlay2\/ghi\/work&quot;\n            },\n            &quot;Name&quot;: &quot;overlay2&quot;\n        }\n    }\n]\n<\/code><\/pre>\n<p>Look at that <code>GraphDriver<\/code>. That\u2019s OverlayFS. Every time your application tries to write a log file, the kernel has to traverse those layers, find the file, copy it to the <code>UpperDir<\/code>, and then finally commit the write. You\u2019ve just turned a simple I\/O operation into a scavenger hunt for the VFS (Virtual File System). The &#8220;context switching overhead&#8221; alone is enough to make me want to retire to a farm with no electricity.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"H2_The_Technical_Autopsy_Namespaces_and_the_Illusion_of_Isolation\"><\/span>H2: The Technical Autopsy: Namespaces and the Illusion of Isolation<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>A &#8220;docker container&#8221; is not a virtual machine. It\u2019s a fancy word for a process that has been lied to by the kernel. We use Linux Namespaces to create this illusion. It\u2019s a series of <code>unshare()<\/code> and <code>clone()<\/code> syscalls that tell a process it\u2019s the only thing running on the box. <\/p>\n<p>If I run <code>strace<\/code> on the creation of a container, I don&#8217;t see a &#8220;magic box&#8221; being built. I see the raw, gritty reality of the kernel being told to partition its resources.<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># strace -f -e trace=clone,unshare docker run --rm alpine sleep 1\n...\n[pid 12400] unshare(CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWNET|CLONE_NEWUSER) = 0\n[pid 12400] clone(child_stack=NULL, flags=CLONE_VM|CLONE_VFORK|SIGCHLD) = 12401\n...\n<\/code><\/pre>\n<p>There it is. <code>CLONE_NEWPID<\/code>. That\u2019s the kernel telling the process, &#8220;Congratulations, you are now PID 1.&#8221; But it\u2019s a lie. On the host, that process is just another entry in the task list, likely PID 12401. This leads to the &#8220;PID 1 zombie reaping&#8221; problem. In a real system, <code>init<\/code> (or <code>systemd<\/code>, if you must) handles orphaned child processes. In your &#8220;docker container,&#8221; if your entrypoint doesn&#8217;t know how to handle <code>SIGCHLD<\/code>, you end up with a process table full of ghosts. You\u2019ve created a graveyard because you couldn&#8217;t be bothered to write a proper init script.<\/p>\n<p>And don&#8217;t get me started on <code>CLONE_NEWNET<\/code>. Look at the output of <code>ip addr<\/code> inside one of these things:<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># docker exec legacy-monolith-container ip addr\n1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000\n    link\/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1\/8 scope host lo\n       valid_lft forever preferred_lft forever\n24: eth0@if25: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default \n    link\/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0\n    inet 172.17.0.2\/16 brd 172.17.255.255 scope global eth0\n       valid_lft forever preferred_lft forever\n<\/code><\/pre>\n<p><code>eth0@if25<\/code>. That <code>@if25<\/code> is a pointer to a <code>veth<\/code> pair on the host. Every packet your app sends has to traverse a virtual bridge (<code>docker0<\/code>), go through a NAT (Network Address Translation) layer, and hit the host&#8217;s <code>iptables<\/code> rules before it even smells a real network card. You\u2019re adding microseconds of latency to every request so that your developers don&#8217;t have to learn how to bind to a specific IP address. It\u2019s offensive.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"H2_Cgroups_The_Throttling_of_Reality\"><\/span>H2: Cgroups: The Throttling of Reality<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If Namespaces are about what you can <em>see<\/em>, Control Groups (cgroups) are about what you can <em>touch<\/em>. This is where the &#8220;docker container&#8221; gets its lunch money taken away by the kernel&#8217;s CFS (Completely Fair Scheduler). <\/p>\n<p>The CTO wants &#8220;resource isolation.&#8221; He wants to ensure the legacy monolith doesn&#8217;t starve the new, shiny (and bloated) microservices. So he sets memory limits. But the JVM or the Python runtime doesn&#8217;t know it\u2019s in a cgroup. It looks at <code>\/proc\/meminfo<\/code> (which isn&#8217;t namespaced by default) and thinks it has 128GB of RAM, then tries to allocate a massive heap, only to be brutally murdered by the OOM (Out of Memory) Killer because the cgroup limit was set to 2GB.<\/p>\n<p>Back in the day, if a process ran out of memory, it was because you didn&#8217;t have enough physical DIMMs. Now, it\u2019s because some YAML-wrangler forgot to account for the overhead of the container itself.<\/p>\n<p>Let\u2019s see what happens when we actually enforce these limits. I\u2019ll set a hard limit of 10MB on a container and try to run something that needs 20MB.<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># docker run --rm --memory=&quot;10m&quot; alpine python3 -c &quot;x = ' ' * 20 * 1024 * 1024&quot;\nKilled\n# dmesg | tail -n 5\n[34567.89] memory: usage 10240kB, limit 10240kB, failcnt 123\n[34567.90] Memory cgroup out of memory: Killed process 12500 (python3) total-vm:45678kB, anon-rss:9876kB, file-rss:1234kB, shmem-rss:0kB\n<\/code><\/pre>\n<p>The kernel doesn&#8217;t care about your &#8220;graceful shutdown.&#8221; It sees a violation and it sends a <code>SIGKILL<\/code>. No cleanup, no log flushing, just instant death. And because you\u2019re running in a &#8220;docker container,&#8221; you probably don&#8217;t even have persistent logs set up correctly, so the evidence of why it died vanishes into the ether.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"H2_The_Layered_Lie_OverlayFS_and_the_Death_of_Disk_IO\"><\/span>H2: The Layered Lie: OverlayFS and the Death of Disk I\/O<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We need to talk about the filesystem. Docker uses a &#8220;copy-on-write&#8221; (CoW) strategy. It sounds efficient, but in practice, it\u2019s a &#8220;copy-on-write filesystem fragmentation&#8221; nightmare. Every layer in your Dockerfile is a new directory in <code>\/var\/lib\/docker\/overlay2<\/code>. When you run <code>apt-get update<\/code>, you aren&#8217;t just updating a list; you are creating a massive delta that has to be managed by the kernel.<\/p>\n<p>If you have a deep chain of layers, every <code>open()<\/code> syscall has to check every single layer to see if the file exists there. It\u2019s a linear search through the directory stack. <\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># ls -l \/var\/lib\/docker\/overlay2\/\ntotal 0\ndrwx------ 4 root root 72 Oct 27 14:00 1a2b3c4d5e6f7g8h9i0j...\ndrwx------ 4 root root 72 Oct 27 14:00 2b3c4d5e6f7g8h9i0j1a...\ndrwx------ 4 root root 72 Oct 27 14:00 3c4d5e6f7g8h9i0j1a2b...\n...\n<\/code><\/pre>\n<p>And God help you if you\u2019re doing heavy disk I\/O inside the container without using a volume. You\u2019re writing to the &#8220;upper&#8221; layer of the OverlayFS, which means the kernel is doing double the work for every write. You\u2019re not just writing to a block device; you\u2019re writing to a virtualized filesystem that\u2019s sitting on top of another filesystem. It\u2019s like trying to run a marathon while wearing three layers of heavy winter coats.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"H2_Breaking_the_Toy_Seccomp_and_the_Security_Theater\"><\/span>H2: Breaking the Toy: Seccomp and the Security Theater<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The industry loves to talk about how &#8220;secure&#8221; containers are. &#8220;It\u2019s a sandbox!&#8221; they cry. No, it\u2019s a sieve. By default, a &#8220;docker container&#8221; has access to a wide array of syscalls that it has no business touching. To &#8220;secure&#8221; it, we use <code>seccomp<\/code> (Secure Computing Mode) to filter syscalls. But nobody actually writes custom seccomp profiles because it\u2019s hard and requires knowing how your application actually works\u2014a skill that seems to be in short supply these days.<\/p>\n<p>Let\u2019s purposefully break a container by giving it a restrictive seccomp profile. I\u2019ll create a profile that forbids the <code>mkdir<\/code> syscall.<\/p>\n<pre class=\"codehilite\"><code class=\"language-json\">\/\/ no-mkdir.json\n{\n    &quot;defaultAction&quot;: &quot;SCMP_ACT_ALLOW&quot;,\n    &quot;syscalls&quot;: [\n        {\n            &quot;name&quot;: &quot;mkdir&quot;,\n            &quot;action&quot;: &quot;SCMP_ACT_ERRNO&quot;,\n            &quot;args&quot;: []\n        }\n    ]\n}\n<\/code><\/pre>\n<p>Now, let\u2019s try to run a simple command:<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># docker run --rm --security-opt seccomp=no-mkdir.json alpine mkdir \/test\nmkdir: can't create directory '\/test': Operation not permitted\n<\/code><\/pre>\n<p>Error code <code>EPERM<\/code>. This is what happens when the kernel actually does its job. But in the real world, developers just run everything as <code>root<\/code> inside the container because &#8220;it\u2019s easier,&#8221; and then they run the container with <code>--privileged<\/code> because they can&#8217;t figure out why their app can&#8217;t talk to the hardware. At that point, you haven&#8217;t built a sandbox; you&#8217;ve built a ladder for attackers to climb directly into your kernel.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"H2_Why_Your_Layering_Strategy_is_a_Garbage_Fire\"><\/span>H2: Why Your Layering Strategy is a Garbage Fire<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>I\u2019ve seen Dockerfiles that look like they were written by someone trying to win an obfuscated C contest. <\/p>\n<pre class=\"codehilite\"><code class=\"language-dockerfile\">FROM ubuntu:latest\nRUN apt-get update\nRUN apt-get install -y python3\nRUN apt-get install -y pip\nCOPY . \/app\nRUN pip install -r \/app\/requirements.txt\nCMD [&quot;python3&quot;, &quot;\/app\/app.py&quot;]\n<\/code><\/pre>\n<p>Every single <code>RUN<\/code> command here creates a new layer. You\u2019ve just created a 1GB image for a 5MB application. You\u2019re storing the <code>apt<\/code> cache in your image forever. You\u2019re storing the build tools you only needed for the <code>pip install<\/code> phase. <\/p>\n<p>Back when disk space was expensive, we cared about this. Now, we just throw S3 buckets at the problem and wonder why our CI\/CD pipeline takes twenty minutes to pull an image. We\u2019ve lost the art of the &#8220;multi-stage build,&#8221; or better yet, the art of just building a static binary and putting it in a <code>scratch<\/code> image. But no, we need the whole <code>ubuntu:latest<\/code> userland because &#8220;I might need to <code>ls<\/code> inside the container to debug it.&#8221; Here\u2019s a tip: if you need to <code>ls<\/code> inside your production container to see what\u2019s wrong, your observability stack is a failure, and so are you.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"H2_The_PID_1_Problem_Zombie_Reaping_in_the_Void\"><\/span>H2: The PID 1 Problem: Zombie Reaping in the Void<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>I touched on this earlier, but it deserves its own section because it\u2019s the most common &#8220;docker container&#8221; failure I see in the wild. In Linux, when a process dies, it becomes a &#8220;zombie&#8221; (defunct) until its parent calls <code>wait()<\/code> or <code>waitpid()<\/code> to collect its exit code. If the parent dies, the process is orphaned and re-parented to PID 1.<\/p>\n<p>In a normal system, PID 1 is <code>init<\/code>, which is designed to reap these zombies. In a container, your application is PID 1. If your Python script spawns a shell command and doesn&#8217;t explicitly wait for it, that shell process stays in the process table forever as a zombie.<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># docker exec legacy-monolith-container ps aux\nPID   USER     TIME  COMMAND\n    1 root      0:00 python3 app.py\n   10 root      0:00 [sh] &lt;defunct&gt;\n   11 root      0:00 [sh] &lt;defunct&gt;\n   12 root      0:00 [sh] &lt;defunct&gt;\n<\/code><\/pre>\n<p>Eventually, you hit the <code>max_pid<\/code> limit of the host, and the entire server stops being able to fork new processes. The &#8220;docker container&#8221; didn&#8217;t crash, but it killed the host anyway. This is why tools like <code>tini<\/code> exist\u2014to act as a tiny init for people who don&#8217;t know how to handle signals. We are adding <em>another<\/em> layer of abstraction just to fix the problems caused by the <em>first<\/em> layer of abstraction.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Bitter_End\"><\/span>The Bitter End<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>So here I am, sitting in a room that is far too quiet because all the servers are in &#8220;the cloud&#8221; (which, let&#8217;s be honest, is just a warehouse in Virginia owned by a book salesman), trying to migrate a perfectly functional monolith into this &#8220;docker container&#8221; hellscape. I\u2019ve spent the last six hours debugging why the <code>veth<\/code> pair is dropping packets because of an MTU mismatch that wouldn&#8217;t have existed if we were just running on bare metal.<\/p>\n<p>We\u2019ve traded the smell of ozone and the tactile satisfaction of a physical toggle switch for a &#8220;dashboard&#8221; that shows us &#8220;green bubbles&#8221; while the underlying kernel is screaming in agony. We\u2019ve replaced systems engineering with YAML templating. We\u2019ve decided that it\u2019s better to ship 1GB of redundant garbage than to spend twenty minutes understanding our dependencies.<\/p>\n<p>The CTO is happy. The developers are happy because they can &#8220;ship faster.&#8221; But I\u2019m looking at the <code>strace<\/code> output, and I\u2019m looking at the <code>cgroup<\/code> pressure stalls, and I know the truth. We haven&#8217;t solved anything. We\u2019ve just hidden the complexity under so many layers of virtualization that when it finally breaks\u2014and it will\u2014nobody will have the slightest clue how to fix it. They\u2019ll just try to &#8220;restart the container&#8221; and hope the magic returns. <\/p>\n<p>I\u2019m going home. I have a 1984 IBM Model M keyboard waiting for me. At least when I press a key on that, I know exactly which spring is pushing back. There\u2019s no abstraction there. Just physics. And right now, physics is the only thing I still trust.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Related_Articles\"><\/span>Related Articles<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Explore more insights and best practices:<\/p>\n<ul>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/docker-best-practices-optimize-your-container-workflow\/\">Docker Best Practices Optimize Your Container Workflow<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/how-to-install-latest-php-7-3-on-ubuntu-18-04\/\">How To Install Latest Php 7 3 On Ubuntu 18 04<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/whatsapps-long-awaited-security-feature-launched\/\">Whatsapps Long Awaited Security Feature Launched<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>I remember when servers had physical buttons you could press, and if something broke, you could smell the ozone. There was a dignity in the hum of a SCSI drive spinning up, a physical manifestation of data being moved by magnetism and sheer willpower. You knew exactly where your bits were. They were on that &#8230; <a title=\"Docker Container Explained: A Complete Guide for Beginners\" class=\"read-more\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/\" aria-label=\"Read more  on Docker Container Explained: A Complete Guide for Beginners\">Read more<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4911","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Docker Container Explained: A Complete Guide for Beginners - ITSupportWale<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Docker Container Explained: A Complete Guide for Beginners - ITSupportWale\" \/>\n<meta property=\"og:description\" content=\"I remember when servers had physical buttons you could press, and if something broke, you could smell the ozone. There was a dignity in the hum of a SCSI drive spinning up, a physical manifestation of data being moved by magnetism and sheer willpower. You knew exactly where your bits were. They were on that ... Read more\" \/>\n<meta property=\"og:url\" content=\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/\" \/>\n<meta property=\"og:site_name\" content=\"ITSupportWale\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-18T17:58:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"512\" \/>\n\t<meta property=\"og:image:height\" content=\"512\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Techie\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Techie\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/\"},\"author\":{\"name\":\"Techie\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\"},\"headline\":\"Docker Container Explained: A Complete Guide for Beginners\",\"datePublished\":\"2026-10-18T17:58:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/\"},\"wordCount\":2145,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/\",\"name\":\"Docker Container Explained: A Complete Guide for Beginners - ITSupportWale\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\"},\"datePublished\":\"2026-10-18T17:58:24+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/itsupportwale.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Docker Container Explained: A Complete Guide for Beginners\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"name\":\"ITSupportWale\",\"description\":\"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides\",\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\",\"name\":\"itsupportwale\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"contentUrl\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"width\":1119,\"height\":144,\"caption\":\"itsupportwale\"},\"image\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\",\"name\":\"Techie\",\"sameAs\":[\"https:\/\/itsupportwale.com\",\"iswblogadmin\"],\"url\":\"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Docker Container Explained: A Complete Guide for Beginners - ITSupportWale","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/","og_locale":"en_US","og_type":"article","og_title":"Docker Container Explained: A Complete Guide for Beginners - ITSupportWale","og_description":"I remember when servers had physical buttons you could press, and if something broke, you could smell the ozone. There was a dignity in the hum of a SCSI drive spinning up, a physical manifestation of data being moved by magnetism and sheer willpower. You knew exactly where your bits were. They were on that ... Read more","og_url":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/","og_site_name":"ITSupportWale","article_publisher":"https:\/\/www.facebook.com\/Itsupportwale-298547177495978","article_published_time":"2026-10-18T17:58:24+00:00","og_image":[{"width":512,"height":512,"url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png","type":"image\/png"}],"author":"Techie","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Techie","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#article","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/"},"author":{"name":"Techie","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d"},"headline":"Docker Container Explained: A Complete Guide for Beginners","datePublished":"2026-10-18T17:58:24+00:00","mainEntityOfPage":{"@id":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/"},"wordCount":2145,"commentCount":0,"publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/","url":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/","name":"Docker Container Explained: A Complete Guide for Beginners - ITSupportWale","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/#website"},"datePublished":"2026-10-18T17:58:24+00:00","breadcrumb":{"@id":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/itsupportwale.com\/blog\/docker-container-explained-a-complete-guide-for-beginners\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/itsupportwale.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Docker Container Explained: A Complete Guide for Beginners"}]},{"@type":"WebSite","@id":"https:\/\/itsupportwale.com\/blog\/#website","url":"https:\/\/itsupportwale.com\/blog\/","name":"ITSupportWale","description":"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides","publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/itsupportwale.com\/blog\/#organization","name":"itsupportwale","url":"https:\/\/itsupportwale.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","contentUrl":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","width":1119,"height":144,"caption":"itsupportwale"},"image":{"@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Itsupportwale-298547177495978"]},{"@type":"Person","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d","name":"Techie","sameAs":["https:\/\/itsupportwale.com","iswblogadmin"],"url":"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/"}]}},"_links":{"self":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4911","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/comments?post=4911"}],"version-history":[{"count":0,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4911\/revisions"}],"wp:attachment":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/media?parent=4911"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/categories?post=4911"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/tags?post=4911"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}