{"id":4840,"date":"2026-07-22T21:55:55","date_gmt":"2026-07-22T16:25:55","guid":{"rendered":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/"},"modified":"2026-07-22T21:55:55","modified_gmt":"2026-07-22T16:25:55","slug":"10-docker-best-practices-to-build-faster-secure-images","status":"publish","type":"post","link":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/","title":{"rendered":"10 Docker Best Practices to Build Faster, Secure Images"},"content":{"rendered":"<p><strong>POST-MORTEM REPORT: INCIDENT #8842-B (REGISTRY OOM-KILL)<\/strong><br \/>\n<strong>DATE:<\/strong> 03:14 AM<br \/>\n<strong>AUTHOR:<\/strong> Senior Systems Architect (Infrastructure\/Core)<br \/>\n<strong>STATUS:<\/strong> Severely Caffeinated \/ Highly Irritated<br \/>\n<strong>SUBJECT:<\/strong> THE MANIFESTO OF EFFICIENCY: WHY YOUR 4GB IMAGE IS A CRIME AGAINST ENGINEERING<\/p>\n<p>It is 3:00 AM. My pager didn&#8217;t just beep; it screamed because our private registry\u2019s storage volume hit 100% capacity and the garbage collector choked to death trying to process a single push. I looked at the logs. I saw the culprit. A &#8220;microservice&#8221;\u2014and I use that term with the same irony one might use to describe a lead-lined coffin\u2014that clocked in at 4.2GB. <\/p>\n<p>Four. Gigabytes. For a Node.js API that returns a JSON object.<\/p>\n<p>I\u2019ve spent the last hour purging the registry and manually cleaning up the overlay2 directories on the build nodes. To ensure I never have to do this again, I am pinning this manifesto. If you push an image over 200MB without a written justification signed in blood, I am revoking your sudo access and moving your desk to the basement.<\/p>\n<p>Here is the &#8220;masterpiece&#8221; I found in the repository. Look at it. Study its failure.<\/p>\n<pre class=\"codehilite\"><code class=\"language-dockerfile\"># THE CRIME SCENE\nFROM ubuntu:latest\nRUN apt-get update\nRUN apt-get install -y nodejs npm python3 build-essential git\nCOPY . \/app\nWORKDIR \/app\nRUN npm install\nENV API_KEY=&quot;secret_key_that_is_now_in_git_history&quot;\nRUN rm -rf \/var\/lib\/apt\/lists\/*\nEXPOSE 3000\nCMD [&quot;npm&quot;, &quot;start&quot;]\n<\/code><\/pre>\n<p>This isn&#8217;t a container; it&#8217;s a virtual machine with an identity crisis. Let\u2019s dissect why this is an objective failure of professional standards.<\/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-6a6149f6409c0\" 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-6a6149f6409c0\"  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\/10-docker-best-practices-to-build-faster-secure-images\/#1_STOP_USING_UBUNTU_FOR_MICROSERVICES\" >1. STOP USING UBUNTU FOR MICROSERVICES<\/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\/10-docker-best-practices-to-build-faster-secure-images\/#2_THE_LAYER_CAKE_IS_A_LIE\" >2. THE LAYER CAKE IS A LIE<\/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\/10-docker-best-practices-to-build-faster-secure-images\/#3_YOUR_DOCKERIGNORE_IS_NON-EXISTENT_AND_IT_SHOWS\" >3. YOUR DOCKERIGNORE IS NON-EXISTENT AND IT SHOWS<\/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\/10-docker-best-practices-to-build-faster-secure-images\/#4_MULTI-STAGE_BUILDS_ARE_NOT_OPTIONAL\" >4. MULTI-STAGE BUILDS ARE NOT OPTIONAL<\/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\/10-docker-best-practices-to-build-faster-secure-images\/#5_ROOT_IS_FOR_KERNELS_NOT_FOR_YOUR_NODE_APP\" >5. ROOT IS FOR KERNELS, NOT FOR YOUR NODE APP<\/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\/10-docker-best-practices-to-build-faster-secure-images\/#6_THE_ENTRYPOINT_VS_CMD_HOLY_WAR\" >6. THE ENTRYPOINT VS CMD HOLY WAR<\/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\/10-docker-best-practices-to-build-faster-secure-images\/#7_CACHE_MISSES_ARE_A_MORAL_FAILURE\" >7. CACHE MISSES ARE A MORAL FAILURE<\/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\/10-docker-best-practices-to-build-faster-secure-images\/#8_THE_OCI_SPEC_DOESNT_CARE_ABOUT_YOUR_FEELINGS\" >8. THE OCI SPEC DOESN&#8217;T CARE ABOUT YOUR FEELINGS<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#THE_CORRECTIVE_ACTION_PLAN\" >THE CORRECTIVE ACTION PLAN<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#Related_Articles\" >Related Articles<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"1_STOP_USING_UBUNTU_FOR_MICROSERVICES\"><\/span>1. STOP USING UBUNTU FOR MICROSERVICES<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Why are you using <code>ubuntu:latest<\/code>? Do you need a full suite of networking tools, a package manager with a massive cache, and a kernel-adjacent userland just to run a Javascript runtime? No. You don&#8217;t. When you pull <code>ubuntu:latest<\/code>, you are pulling roughly 72MB of compressed air that you don&#8217;t need. But it\u2019s not just the size; it\u2019s the attack surface.<\/p>\n<p>Every utility in that base image is a tool for an attacker once they find the inevitable RCE in your poorly-sanitized input fields. If you actually gave a damn about <strong>docker best<\/strong> practices, you\u2019d be using <code>alpine<\/code> or <code>distroless<\/code>. <\/p>\n<p>Alpine 3.19 is 5MB. Five. Megabytes. <\/p>\n<p>&#8220;But Arthur, Alpine uses musl instead of glibc and my native modules won&#8217;t compile!&#8221; Then use a <code>-slim<\/code> Debian-based image like <code>python:3.11-slim-bookworm<\/code> or <code>node:20-slim<\/code>. It\u2019s not hard. It\u2019s laziness. You are trading my sleep for your convenience.<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># Terminal Log: Base Image Comparison\n$ docker images\nREPOSITORY          TAG                 IMAGE ID            SIZE\nubuntu              latest              ba627df2ed29        72.8MB\nnode                20-slim             63399009890d        182MB\nnode                20-alpine           42846937243c        54.1MB\nalpine              3.19                054309236301        7.34MB\n<\/code><\/pre>\n<h2><span class=\"ez-toc-section\" id=\"2_THE_LAYER_CAKE_IS_A_LIE\"><\/span>2. THE LAYER CAKE IS A LIE<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Docker images are a stack of read-only layers. Every <code>RUN<\/code>, <code>COPY<\/code>, or <code>ADD<\/code> command creates a new layer. If you create a 1GB file in one <code>RUN<\/code> command and delete it in the next, your image is still 1GB larger. The file is still there, buried in the previous layer, haunting the storage driver.<\/p>\n<p>In the &#8220;Crime Scene&#8221; Dockerfile above, the junior dev tried to be clever by running <code>RUN rm -rf \/var\/lib\/apt\/lists\/*<\/code> at the end. Too late. The layer containing the <code>apt-get update<\/code> cache was already committed. You\u2019ve just added a new layer that says &#8220;pretend these files aren&#8217;t here,&#8221; while the registry still has to store and transmit the original data.<\/p>\n<p>Look at the history of the 4GB monstrosity:<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># Terminal Log: docker history --human --format &quot;{{.CreatedBy}}: {{.Size}}&quot;\n$ docker history bloated-service:latest\n\/bin\/sh -c #(nop)  CMD [&quot;npm&quot; &quot;start&quot;]: 0B\n\/bin\/sh -c rm -rf \/var\/lib\/apt\/lists\/*: 0B\n\/bin\/sh -c npm install: 2.1GB\n\/bin\/sh -c #(nop) WORKDIR \/app: 0B\n\/bin\/sh -c COPY . \/app: 1.8GB\n\/bin\/sh -c apt-get install -y nodejs npm...: 450MB\n\/bin\/sh -c apt-get update: 28MB\n<\/code><\/pre>\n<p>Notice the <code>COPY . \/app<\/code> taking up 1.8GB? That\u2019s because the <code>.git<\/code> folder, the local <code>node_modules<\/code>, and the <code>dist<\/code> folder were all sucked into the image. Which leads me to my next point.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"3_YOUR_DOCKERIGNORE_IS_NON-EXISTENT_AND_IT_SHOWS\"><\/span>3. YOUR DOCKERIGNORE IS NON-EXISTENT AND IT SHOWS<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If I see one more image containing a <code>.git<\/code> directory, I\u2019m going to start charging the offending developer for the S3 egress fees out of their paycheck. Disk space isn&#8217;t free, despite what your cloud provider tells you.<\/p>\n<p>The &#8220;build context&#8221; is the set of files sent from your local machine (or the CI runner) to the Docker daemon. If you don&#8217;t have a <code>.dockerignore<\/code> file, you are sending everything. In the incident tonight, the junior dev had a <code>tmp\/<\/code> folder full of local test database dumps.<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># Terminal Log: The Build Context Bloat\n$ docker build -t bad-service .\nSending build context to Docker daemon  2.45GB\nStep 1\/10 : FROM ubuntu:latest\n...\n<\/code><\/pre>\n<p>Two and a half gigabytes sent over the network before the build even started. A proper <code>.dockerignore<\/code> should be your first line of defense. It should look like this:<\/p>\n<pre class=\"codehilite\"><code class=\"language-text\">.git\nnode_modules\nnpm-debug.log\nDockerfile\n.dockerignore\n.env\ntmp\/\ndist\/\n<\/code><\/pre>\n<h2><span class=\"ez-toc-section\" id=\"4_MULTI-STAGE_BUILDS_ARE_NOT_OPTIONAL\"><\/span>4. MULTI-STAGE BUILDS ARE NOT OPTIONAL<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>This is the hill I will die on. You do not need <code>gcc<\/code>, <code>make<\/code>, or <code>python<\/code> in your production image just because one of your dependencies needed to compile a C++ binding during installation. <\/p>\n<p>Multi-stage builds allow you to create a &#8220;build&#8221; container with all the heavy tools and then copy only the compiled artifacts into a &#8220;run&#8221; container. This is how you get an image from 4GB down to 40MB.<\/p>\n<p>If you don&#8217;t use multi-stage builds, you are essentially shipping a factory along with the car you built. It\u2019s inefficient, it\u2019s bloated, and it\u2019s a security nightmare.<\/p>\n<pre class=\"codehilite\"><code class=\"language-dockerfile\"># THE RIGHT WAY: Multi-Stage\nFROM node:20-alpine AS builder\nWORKDIR \/app\nCOPY package*.json .\/\nRUN npm ci --only=production\n\nFROM node:20-alpine\nWORKDIR \/app\n# Copy only the necessary bits from the builder\nCOPY --from=builder \/app\/node_modules .\/node_modules\nCOPY . .\nUSER node\nCMD [&quot;node&quot;, &quot;index.js&quot;]\n<\/code><\/pre>\n<h2><span class=\"ez-toc-section\" id=\"5_ROOT_IS_FOR_KERNELS_NOT_FOR_YOUR_NODE_APP\"><\/span>5. ROOT IS FOR KERNELS, NOT FOR YOUR NODE APP<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The &#8220;Crime Scene&#8221; Dockerfile runs as root. By default, everything in a container runs as root. If an attacker escapes your application via a vulnerability, they aren&#8217;t just a user; they are the king of the container. If you\u2019ve been foolish enough to mount <code>\/var\/run\/docker.sock<\/code> into the container (and I know some of you are doing it for &#8220;monitoring&#8221;), they now have root access to the host.<\/p>\n<p>Stop it. <\/p>\n<p>Most reputable base images provide a non-privileged user. For Node, it\u2019s <code>node<\/code>. For others, you should create one. Use a high UID\/GID (like 10001) to avoid collisions with host users. <\/p>\n<pre class=\"codehilite\"><code class=\"language-dockerfile\">RUN addgroup -S appgroup &amp;&amp; adduser -S appuser -G appgroup\nUSER appuser\n<\/code><\/pre>\n<p>This isn&#8217;t just &#8220;best practice&#8221; fluff; it\u2019s the difference between a minor patch and a company-wide data breach. When you run as a non-root user, you limit the syscalls an attacker can leverage. You make their life harder. That is your job.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"6_THE_ENTRYPOINT_VS_CMD_HOLY_WAR\"><\/span>6. THE ENTRYPOINT VS CMD HOLY WAR<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>I see people using <code>CMD [\"npm\", \"start\"]<\/code> and it makes my blood boil. Why? Because <code>npm<\/code> does not pass signals (like <code>SIGTERM<\/code>) to the underlying process. <\/p>\n<p>When Kubernetes or the OOM killer tries to shut down your container, it sends a <code>SIGTERM<\/code>. If your app is wrapped in <code>npm<\/code> or a shell script that doesn&#8217;t exec, the app never sees the signal. It keeps running until the 10-second grace period expires and the kernel brutally murders it with a <code>SIGKILL<\/code>. This leads to corrupted database connections and lost state.<\/p>\n<p>Use <code>ENTRYPOINT<\/code> for the executable and <code>CMD<\/code> for the arguments, or just use <code>CMD<\/code> to call the binary directly. And for the love of all that is holy, use the &#8220;exec form&#8221; (the JSON array <code>[\"executable\", \"param\"]<\/code>), not the &#8220;shell form&#8221; (<code>executable param<\/code>). The shell form spawns <code>\/bin\/sh -c<\/code>, which\u2014surprise\u2014doesn&#8217;t pass signals.<\/p>\n<pre class=\"codehilite\"><code class=\"language-dockerfile\"># Correct Signal Handling\nENTRYPOINT [&quot;\/sbin\/tini&quot;, &quot;--&quot;]\nCMD [&quot;node&quot;, &quot;index.js&quot;]\n<\/code><\/pre>\n<p>(Yes, use <code>tini<\/code>. It handles zombie processes. Look it up.)<\/p>\n<h2><span class=\"ez-toc-section\" id=\"7_CACHE_MISSES_ARE_A_MORAL_FAILURE\"><\/span>7. CACHE MISSES ARE A MORAL FAILURE<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The junior&#8217;s Dockerfile had <code>COPY . \/app<\/code> <em>before<\/em> <code>RUN npm install<\/code>. This means every time a single character changes in a README file, the Docker cache for <code>npm install<\/code> is invalidated. The build system then has to re-download the entire internet.<\/p>\n<p>This is why our CI pipeline took 15 minutes instead of 30 seconds. <\/p>\n<p>If you actually gave a damn about <strong>docker best<\/strong> practices, you\u2019d copy the dependency manifests first, install, and <em>then<\/em> copy the source code. The source code changes often; the dependencies don&#8217;t.<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># Terminal Log: Cache Miss Evidence\n$ docker build -t service:latest .\nStep 4\/10 : COPY . \/app\n ---&gt; Using cache\nStep 5\/10 : RUN npm install\n ---&gt; Running in a1b2c3d4e5f6\n# ... 5 minutes of downloading ...\n<\/code><\/pre>\n<p>By reordering the commands, you ensure that the <code>npm install<\/code> layer is only rebuilt when <code>package.json<\/code> changes. This is basic. This is Day 1 stuff.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"8_THE_OCI_SPEC_DOESNT_CARE_ABOUT_YOUR_FEELINGS\"><\/span>8. THE OCI SPEC DOESN&#8217;T CARE ABOUT YOUR FEELINGS<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We are moving to a world of OCI (Open Container Initiative) compliance. This means your containers need to be predictable, reproducible, and lean. The syscall overhead of a bloated container is non-trivial. When the kernel has to manage thousands of unnecessary file descriptors and memory mappings for a &#8220;microservice&#8221; that thinks it&#8217;s a full Debian install, performance degrades.<\/p>\n<p>I ran a <code>trivy<\/code> scan on the image that crashed the registry. The results were a horror show.<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># Terminal Log: Trivy Scan Results (The Bloated Image)\n$ trivy image bloated-service:latest\nTotal: 482 (UNKNOWN: 5, LOW: 156, MEDIUM: 220, HIGH: 82, CRITICAL: 19)\n\nCRITICAL: CVE-2023-XXXX (glibc), CVE-2023-YYYY (openssl)...\n<\/code><\/pre>\n<p>Nineteen critical vulnerabilities. Nineteen ways for a script kiddie to turn our cluster into a Monero miner. Now, look at the scan of the optimized image using <code>alpine<\/code> and multi-stage builds:<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># Terminal Log: Trivy Scan Results (The Optimized Image)\n$ trivy image optimized-service:latest\nTotal: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)\n<\/code><\/pre>\n<p>Zero vulnerabilities. Zero. And the size?<\/p>\n<pre class=\"codehilite\"><code class=\"language-bash\"># Terminal Log: Final df -h Comparison\n$ df -h \/var\/lib\/docker\nFilesystem      Size  Used Avail Use% Mounted on\n# BEFORE OPTIMIZATION\n\/dev\/nvme0n1    100G   98G  1.5G  99% \/var\/lib\/docker\n# AFTER PURGING AND OPTIMIZING\n\/dev\/nvme0n1    100G   12G  82G   13% \/var\/lib\/docker\n<\/code><\/pre>\n<p>We went from 99% utilization to 13%. The registry is breathing again. The SRE team is going back to sleep. I, however, am staying awake to write a script that will automatically reject any PR containing a Dockerfile that uses <code>ubuntu:latest<\/code> or lacks a <code>.dockerignore<\/code>.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"THE_CORRECTIVE_ACTION_PLAN\"><\/span>THE CORRECTIVE ACTION PLAN<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Effective immediately:<br \/>\n1. <strong>Mandatory Multi-Stage Builds:<\/strong> No exceptions. If your final image contains a compiler, the build fails.<br \/>\n2. <strong>Base Image Whitelist:<\/strong> Use <code>alpine<\/code>, <code>distroless<\/code>, or <code>-slim<\/code> variants.<br \/>\n3. <strong>No Root:<\/strong> All containers must define a <code>USER<\/code>.<br \/>\n4. <strong>Layer Optimization:<\/strong> Manifests (<code>package.json<\/code>, <code>requirements.txt<\/code>, <code>go.mod<\/code>) must be copied and installed <em>before<\/em> the application source.<br \/>\n5. <strong>Secrets:<\/strong> Any secret found in a Dockerfile layer (even if deleted in a later layer) will result in an immediate revocation of production access. Use a secret manager or mount them as build secrets.<\/p>\n<p>I don&#8217;t care about &#8220;velocity&#8221; if that velocity is driving us off a cliff. Speed without stability is just a slow-motion car crash. <\/p>\n<p>Now, if you&#8217;ll excuse me, I&#8217;m going to find another pot of coffee and delete the junior&#8217;s <code>latest<\/code> tags from the registry. If you have questions, read the documentation. Don&#8217;t Slack me. I&#8217;m &#8220;Away&#8221; until noon.<\/p>\n<p><strong>FIX YOUR DOCKERFILES.<\/strong><\/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\/machine-learning-best-practices-a-guide-to-success-2\/\">Machine Learning Best Practices A Guide To Success 2<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/how-to-install-php-7-3-on-centos-8\/\">How To Install Php 7 3 On Centos 8<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/mastering-javascript-code-10-essential-tips-for-success\/\">Mastering Javascript Code 10 Essential Tips For Success<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>POST-MORTEM REPORT: INCIDENT #8842-B (REGISTRY OOM-KILL) DATE: 03:14 AM AUTHOR: Senior Systems Architect (Infrastructure\/Core) STATUS: Severely Caffeinated \/ Highly Irritated SUBJECT: THE MANIFESTO OF EFFICIENCY: WHY YOUR 4GB IMAGE IS A CRIME AGAINST ENGINEERING It is 3:00 AM. My pager didn&#8217;t just beep; it screamed because our private registry\u2019s storage volume hit 100% capacity and &#8230; <a title=\"10 Docker Best Practices to Build Faster, Secure Images\" class=\"read-more\" href=\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/\" aria-label=\"Read more  on 10 Docker Best Practices to Build Faster, Secure Images\">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-4840","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>10 Docker Best Practices to Build Faster, Secure Images - 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\/10-docker-best-practices-to-build-faster-secure-images\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"10 Docker Best Practices to Build Faster, Secure Images - ITSupportWale\" \/>\n<meta property=\"og:description\" content=\"POST-MORTEM REPORT: INCIDENT #8842-B (REGISTRY OOM-KILL) DATE: 03:14 AM AUTHOR: Senior Systems Architect (Infrastructure\/Core) STATUS: Severely Caffeinated \/ Highly Irritated SUBJECT: THE MANIFESTO OF EFFICIENCY: WHY YOUR 4GB IMAGE IS A CRIME AGAINST ENGINEERING It is 3:00 AM. My pager didn&#8217;t just beep; it screamed because our private registry\u2019s storage volume hit 100% capacity and ... Read more\" \/>\n<meta property=\"og:url\" content=\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/\" \/>\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-07-22T16:25:55+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=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/\"},\"author\":{\"name\":\"Techie\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\"},\"headline\":\"10 Docker Best Practices to Build Faster, Secure Images\",\"datePublished\":\"2026-07-22T16:25:55+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/\"},\"wordCount\":1480,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/\",\"name\":\"10 Docker Best Practices to Build Faster, Secure Images - ITSupportWale\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\"},\"datePublished\":\"2026-07-22T16:25:55+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/itsupportwale.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"10 Docker Best Practices to Build Faster, Secure Images\"}]},{\"@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":"10 Docker Best Practices to Build Faster, Secure Images - 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\/10-docker-best-practices-to-build-faster-secure-images\/","og_locale":"en_US","og_type":"article","og_title":"10 Docker Best Practices to Build Faster, Secure Images - ITSupportWale","og_description":"POST-MORTEM REPORT: INCIDENT #8842-B (REGISTRY OOM-KILL) DATE: 03:14 AM AUTHOR: Senior Systems Architect (Infrastructure\/Core) STATUS: Severely Caffeinated \/ Highly Irritated SUBJECT: THE MANIFESTO OF EFFICIENCY: WHY YOUR 4GB IMAGE IS A CRIME AGAINST ENGINEERING It is 3:00 AM. My pager didn&#8217;t just beep; it screamed because our private registry\u2019s storage volume hit 100% capacity and ... Read more","og_url":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/","og_site_name":"ITSupportWale","article_publisher":"https:\/\/www.facebook.com\/Itsupportwale-298547177495978","article_published_time":"2026-07-22T16:25:55+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":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#article","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/"},"author":{"name":"Techie","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d"},"headline":"10 Docker Best Practices to Build Faster, Secure Images","datePublished":"2026-07-22T16:25:55+00:00","mainEntityOfPage":{"@id":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/"},"wordCount":1480,"commentCount":0,"publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/","url":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/","name":"10 Docker Best Practices to Build Faster, Secure Images - ITSupportWale","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/#website"},"datePublished":"2026-07-22T16:25:55+00:00","breadcrumb":{"@id":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/itsupportwale.com\/blog\/10-docker-best-practices-to-build-faster-secure-images\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/itsupportwale.com\/blog\/"},{"@type":"ListItem","position":2,"name":"10 Docker Best Practices to Build Faster, Secure Images"}]},{"@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\/4840","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=4840"}],"version-history":[{"count":0,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4840\/revisions"}],"wp:attachment":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/media?parent=4840"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/categories?post=4840"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/tags?post=4840"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}