{"id":329,"date":"2024-04-27T02:21:00","date_gmt":"2024-04-27T02:21:00","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=329"},"modified":"2024-04-27T02:21:00","modified_gmt":"2024-04-27T02:21:00","slug":"reduce-docker-image-size","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=329","title":{"rendered":"How to Reduce Docker Image Size: 6 Optimization Methods"},"content":{"rendered":"<p>If you want to <strong>reduce docker image size<\/strong>, you need to use the standard best practices in <a href=\"https:\/\/devopscube.com\/build-docker-image\/\">building a Docker Image<\/a>.<\/p>\n<p>This blog talks about different optimization techniques that you can quickly implement to make the smallest and <strong>minimal docker image<\/strong>. We will also look at some of the <strong>best tools for Docker Image Optimization<\/strong>.<\/p>\n<p><a href=\"https:\/\/devopscube.com\/what-is-docker\/\" rel=\"noreferrer noopener\">Docker<\/a> as a container engine makes it easy to take a piece of code &amp; run it inside a container. It enables engineers to collect all the code dependencies and files into a single location which can be run anywhere, quite quickly &amp; easily.<\/p>\n<p>The whole concept of &#8220;<strong>run anywhere<\/strong>&#8221; images starts from a simple configuration file called Dockerfile. First, we add all the build instructions, such as the code dependencies, commands, and base image details, in Dockerfile.<\/p>\n<h2 id=\"need-for-docker-image-optimization\">Need for Docker Image Optimization<\/h2>\n<p>Even though the <a href=\"https:\/\/devopscube.com\/what-is-docker\/\">Docker<\/a> build process is easy, many organizations make the mistake of building <strong>bloated Docker images<\/strong> without optimizing the container images.<\/p>\n<p>In typical software development, each service will have multiple versions\/releases, and each version requires more dependencies, commands, and configs. This introduces a challenge in <a href=\"https:\/\/devopscube.com\/docker-image-build-and-promotion-pipeline\/\">Docker image build<\/a>, as now &#8211; the same code requires more time &amp; resources to be built before it can be shipped as a container.<\/p>\n<p>I have seen cases where the initial application image started with 350MB, and over time it grew to more than 1.5 GB.<\/p>\n<p>Also, by installing unwanted libraries, we increase the chance of a <strong>potential security risk<\/strong> by increasing the attack surface.<\/p>\n<p>Therefore, DevOps engineers must<strong> optimize the docker images<\/strong> to ensure that the docker image is not getting bloated after application builds or future releases. Not just for production environments, at every stage in the CI\/CD process, you should optimize your docker images.<\/p>\n<p>Also, with <a href=\"https:\/\/devopscube.com\/docker-container-clustering-tools\/\" rel=\"noreferrer noopener\">container orchestration tools<\/a> like Kubernetes, it is best to have small-sized images to <strong>reduce the image transfer and deploy time<\/strong>.<\/p>\n<h2 id=\"how-to-reduce-docker-image-size\">How to Reduce Docker Image Size?<\/h2>\n<p>If we take a container image of a typical application, it contains a base image, <strong>Dependencies\/Files\/Configs<\/strong>, <strong>and cruft<\/strong> (unwanted software).<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-10-24.png\" class=\"kg-image\" alt=\"Docker application image components.\" loading=\"lazy\" width=\"364\" height=\"494\"><\/figure>\n<p>So it all boils down to how efficiently we can manage these resources inside the container image.<\/p>\n<p>Let&#8217;s look at different <strong>established methods of optimizing Docker images.<\/strong> Additionally, we have given practical examples to understand docker image optimization in real time.<\/p>\n<p>Either you use the examples given in the article or try the optimization techniques on existing Dockerfiles.<\/p>\n<p>The following are the methods by which we can achieve docker image optimization.<\/p>\n<ol>\n<li>Using distroless\/minimal base images<\/li>\n<li>Multistage builds<\/li>\n<li>Minimizing the number of layers<\/li>\n<li>Understanding caching<\/li>\n<li>Using Dockerignore<\/li>\n<li>Keeping application data elsewhere<\/li>\n<\/ol>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Docker Excercise Files:<\/strong><\/b> All the application code, Dockerfiles, and configs used in this article are hosted<a href=\"https:\/\/github.com\/scriptcamp\/docker?ref=devopscube.com\" rel=\"noreferrer noopener\"> this Github repository<\/a>. You can clone it and follow along the tutorial.<\/div>\n<\/div>\n<h2 id=\"method-1-use-minimal-base-images\">Method 1: Use Minimal Base Images<\/h2>\n<p>Your first focus should be on choosing the right base image with a minimal OS footprint.<\/p>\n<p>One such example is alpine base images. Alpine images can be <strong>as small as 5.59MB<\/strong>. It&#8217;s not just small; it&#8217;s very secure as well.<\/p>\n<pre><code>alpine       latest    c059bfaa849c     5.59MB<\/code><\/pre>\n<p>Nginx alpine <strong>base image is only 22MB.<\/strong><\/p>\n<p>By default, it comes with the sh shell that helps debug the container by attaching it.<\/p>\n<p>You can further reduce the base image size using <a href=\"https:\/\/github.com\/GoogleContainerTools\/distroless?ref=devopscube.com\" rel=\"noreferrer noopener\">distroless images<\/a>. It is a stripped-down version of the operating system. Distroless base images are available for Java, Node.js, Python, Rust, etc.<\/p>\n<p>Distroless images are so minimal that they don&#8217;t<strong> even have a shell in them<\/strong>. So, you might ask, then how do we debug applications? They have the debug version of the same image that comes with the busybox for debugging.<\/p>\n<p>Also, most of the distributions now have minimal base images.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note:<\/strong><\/b>You cannot directly use the publicly available base images in project environments. You need to get approval from the enterprise security team to use the base image. In some organizations, the security team itself publishes base images every month after testing &amp; security scanning. Those images would be available in the common organization docker private repository.<\/div>\n<\/div>\n<h2 id=\"method-2-use-docker-multistage-builds\">Method 2: Use Docker Multistage Builds<\/h2>\n<p>The <strong>multistage build pattern<\/strong> is evolved from the concept of <a href=\"https:\/\/blog.alexellis.io\/mutli-stage-docker-builds\/?ref=devopscube.com\" rel=\"noreferrer noopener\">builder pattern<\/a> where we use different Dockerfiles for building and packaging the application code. Even though this pattern helps reduce the image size, it puts little overhead when it comes to building pipelines.<\/p>\n<p>In multistage build, we get similar advantages as the builder pattern. We use<strong> intermediate images<\/strong> (build stages) to compile code, install dependencies, and package files in this approach. The idea behind this is to <strong>eliminate unwanted layers<\/strong> in the image.<\/p>\n<p>After that, only the necessary app files required to run the application are copied over to another image with only the required libraries, i.e., lighter to run the application.<\/p>\n<p>Let&#8217;s see this in action, with the help of a <strong>practical example<\/strong> where we create a simple Nodejs application and optimize its Dockerfile.<\/p>\n<p>First, let&#8217;s create the code. We will have the following folder structure.<\/p>\n<pre><code>\u251c\u2500\u2500 Dockerfile1\n\u251c\u2500\u2500 Dockerfile2\n\u251c\u2500\u2500 env\n\u251c\u2500\u2500 index.js\n\u2514\u2500\u2500 package.json<\/code><\/pre>\n<p>Save the following as <code>index.js<\/code>.<\/p>\n<pre><code>const dotenv=require('dotenv'); \ndotenv.config({ path: '.\/env' });\n\ndotenv.config();\n\nconst express=require(\"express\");\nconst app=express();\n\napp.get('\/',(req,res)=&gt;{\n  res.send(`Learning to Optimize Docker Images with DevOpsCube!`);\n});\n\n\napp.listen(process.env.PORT,(err)=&gt;{\n    if(err){\n        console.log(`Error: ${err.message}`);\n    }else{\n        console.log(`Listening on port ${process.env.PORT}`);\n    }\n  }\n)<\/code><\/pre>\n<p>Save the following as <code>package.json<\/code>.<\/p>\n<pre><code>{\n  \"name\": \"nodejs\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" &amp;&amp; exit 1\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"dotenv\": \"^10.0.0\",\n    \"express\": \"^4.17.2\"\n  }\n}<\/code><\/pre>\n<p>Save the following port variable in a file named <code>env<\/code>.<\/p>\n<pre><code>PORT=8080<\/code><\/pre>\n<p>A simple <code>Dockerfile<\/code> for this application would like this &#8211; Save it as <code>Dockerfile1<\/code>.<\/p>\n<pre><code>FROM node:16\n\nCOPY . .\n\nRUN npm installEXPOSE 3000\n\nCMD [ \"node\", \"index.js\" ]<\/code><\/pre>\n<p>Let&#8217;s see the storage space that it requires by building it.<\/p>\n<pre><code>docker build -t devopscube\/node-app:1.0 --no-cache -f Dockerfile1 .<\/code><\/pre>\n<p>After the build is complete. Let&#8217;s check its size using &#8211;<\/p>\n<pre><code>docker image ls<\/code><\/pre>\n<p>This is what we get.<\/p>\n<pre><code>devopscube\/node-app   1.0       b15397d01cca   22 seconds ago   910MB<\/code><\/pre>\n<p>So the size is <code>910MBs<\/code>.<\/p>\n<p>Now, let&#8217;s use this method to create a multistage build.<\/p>\n<p>We will use <code>node:16<\/code> as the base image, i.e., the image for all the <strong>dependencies &amp; modules installation, <\/strong>after that, we will move the contents into a minimal and lighter &#8216;<code>alpine<\/code>&#8216; based image. The &#8216;<code>alpine<\/code>&#8216; image has the bare minimum utilities &amp; hence is very light.<\/p>\n<p>Here is a pictorial representation of a Docker multistage build.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-9-23.png\" class=\"kg-image\" alt=\"Docker multistage build workflow.\" loading=\"lazy\" width=\"889\" height=\"510\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-9-23.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-9-23.png 889w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Also, in a single <code>Dockerfile<\/code>, you can have multiple stages with different base images. For example, you can have <strong>different stages for build, test, static analysis, and package <\/strong>with different base images.<\/p>\n<p>Let&#8217;s see what the new Dockerfile might look like. We are just copying over the necessary files from the base image to the main image.<\/p>\n<p>Save the following as <code>Dockerfile2<\/code>.<\/p>\n<pre><code>FROM node:16 as build\n\nWORKDIR \/app\nCOPY package.json index.js env .\/\nRUN npm install\n\nFROM node:alpine as main\n\nCOPY --from=build \/app \/\nEXPOSE 8080\nCMD [\"index.js\"]<\/code><\/pre>\n<p>Let&#8217;s see the storage space that it requires by building it.<\/p>\n<pre><code>docker build -t devopscube\/node-app:2.0 --no-cache -f Dockerfile2 .<\/code><\/pre>\n<p>After the build is complete. Let&#8217;s check its size using<\/p>\n<pre><code>docker image ls<\/code><\/pre>\n<p>This is what we get.<\/p>\n<pre><code>devopscube\/node-app   2.0       fa6ae75da252   32 seconds ago   171MB<\/code><\/pre>\n<p>So the <strong>new reduced image size is 171MBs<\/strong> as compared to the image with all dependencies.<\/p>\n<p><em>That&#8217;s an optimization of over 80%!<\/em><\/p>\n<p>However, if we would have used the same base image we used in the build stage, we wouldn&#8217;t see much difference.<\/p>\n<p>You can <strong>further reduce the image size using distroless images<\/strong>. Here is the same <code>Dockerfile<\/code> with a multistage build step that uses the Google nodeJS distroless image instead of alpine.<\/p>\n<pre><code>FROM node:16 as build\n\nWORKDIR \/app\n\nCOPY package.json index.js env .\/\n\nRUN npm install\n\nFROM gcr.io\/distroless\/nodejs\n\nCOPY --from=build \/app \/\n\nEXPOSE 3000\n\nCMD [\"index.js\"]<\/code><\/pre>\n<p>If you build the above Dockerfile, your image will be <strong>118MB<\/strong>,<\/p>\n<pre><code>devopscube\/distroless-node   1.0       302990bc5e76     118MB<\/code><\/pre>\n<h2 id=\"method-3-minimize-the-number-of-layers\">Method 3: Minimize the Number of Layers<\/h2>\n<p>Docker images work in the following way &#8211; each <code>RUN, COPY, FROM<\/code> Dockerfile instructions add a new layer &amp; each layer adds to the build execution time &amp; increases the storage requirements of the image.<\/p>\n<p>Let&#8217;s see this in action, with the help of a practical example: let&#8217;s create a ubuntu image with updated &amp; upgraded libraries, along with some necessary packages installed such as vim, net-tools, dnsutils.<\/p>\n<p>A <code>Dockerfile<\/code> to achieve this would be as follows &#8211; Save this as <code>Dockerfile3<\/code>.<\/p>\n<pre><code>FROM ubuntu:latest\n\nENV DEBIAN_FRONTEND=noninteractive\n\nRUN apt-get update -y\n\nRUN apt-get upgrade -y\n\nRUN apt-get install vim -y\n\nRUN apt-get install net-tools -y\n\nRUN apt-get install dnsutils -y<\/code><\/pre>\n<p>We wish to also look into the build time for this image.<\/p>\n<p>The Docker daemon has an in-built capability to display the total execution time that a Dockerfile is taking.<\/p>\n<p>To enable this feature, take the following steps &#8211;<\/p>\n<ol>\n<li>Create a <code>daemon.json<\/code> file with the following contents at <code>\/etc\/docker\/<\/code><\/li>\n<\/ol>\n<pre><code>{\n  \"experimental\": true\n}<\/code><\/pre>\n<p>2. Execute the following command to enable the feature.<\/p>\n<pre><code>export DOCKER_BUILDKIT=1<\/code><\/pre>\n<p>Let&#8217;s build it and see the storage &amp; build time.<\/p>\n<pre><code>time docker build -t devopscube\/optimize:3.0 --no-cache -f Dockerfile3 .<\/code><\/pre>\n<p>It would display the execution times in the terminal.<\/p>\n<pre><code>time docker build -t devopscube\/optimize:3.0 --no-cache -f Dockerfile3 .\n\n\n[+] Building 117.1s (10\/10) FINISHED                                                                   \n =&gt; [internal] load build definition from Dockerfile                                              \n.\n.\n.\n.                                                                       \n =&gt; =&gt; writing image sha256:9601bcac010062c656dacacbc7c554b8ba552c7174f32fdcbd24ff9c7482a805      0.0s \n =&gt; =&gt; naming to docker.io\/devopscube\/optimize:3.0                                                0.0s \n                                                                                                       \nreal    1m57.219s                                                                                      \nuser\t0m1.062s\nsys\t0m0.911s<\/code><\/pre>\n<p>After the build is complete &#8211; the <strong>execution time comes to be 117.1 seconds<\/strong>.<\/p>\n<p>Let&#8217;s check its size using<\/p>\n<pre><code>docker image ls<\/code><\/pre>\n<p>This is what we get.<\/p>\n<pre><code>devopscube\/optimize  3.0   9601bcac0100   About a minute ago   227MB\n<\/code><\/pre>\n<p>So the <strong>size is 227MBs<\/strong>.<\/p>\n<p>Let&#8217;s combine the RUN commands into a single layer &amp; save it as Dockerfile4.<\/p>\n<pre><code>FROM ubuntu:latest\n\nENV DEBIAN_FRONTEND=noninteractive\n\nRUN apt-get update -y &amp;&amp; \\\n    apt-get upgrade -y &amp;&amp; \\\n    apt-get install --no-install-recommends vim net-tools dnsutils -y<\/code><\/pre>\n<p>In the above RUN command, we have used <code>--no-install-recommends<\/code> flag to disable recommended packages. It is recommended whenever you use <code>install<\/code> in your <code>Dockerfiles<\/code><\/p>\n<p>Let&#8217;s see the storage &amp; build time required by building it.<\/p>\n<pre><code>time docker build -t devopscube\/optimize:4.0 --no-cache -f Dockerfile4 .<\/code><\/pre>\n<p>It would display the execution times in the terminal.<\/p>\n<pre><code>time docker build -t devopscube\/optimize:0.4 --no-cache -f Dockerfile4 .\n\n\n[+] Building 91.7s (6\/6) FINISHED                                                                      \n =&gt; [internal] load build definition from Dockerfile2                                             0.4s\n.\n.\n.  \n =&gt; =&gt; naming to docker.io\/devopscube\/optimize:4.0                                                0.0s \n                                                                                                       \nreal    1m31.874s                                                                                      \nuser\t0m0.884s\nsys\t0m0.679s<\/code><\/pre>\n<p>After the build is complete &#8211; the <strong>execution time comes to be 91.7 seconds.<\/strong><\/p>\n<p>Let&#8217;s check its size using<\/p>\n<pre><code>docker image ls<\/code><\/pre>\n<p>This is what we get.<\/p>\n<pre><code>devopscube\/optimize  4.0   37d746b976e3   42 seconds ago      216MB<\/code><\/pre>\n<p>So the size is 216MBs.<\/p>\n<p>Using this optimization technique, the execution time was reduced from 117.1s to 91.7s &amp; the <strong>storage size was reduced from 227MBs to 216MBs.<\/strong><\/p>\n<h2 id=\"method-4-understanding-caching\">Method 4: Understanding Caching<\/h2>\n<p>Often, the same image has to be rebuilt again &amp; again with slight modifications in code.<\/p>\n<p>As Docker uses layered filesystem, each instruction creates a layer. Due to which, Docker caches the layer and can reuse it if it hasn&#8217;t changed.<\/p>\n<p>Due to this concept, it&#8217;s <strong>recommended to add the lines<\/strong> which are used for installing dependencies &amp; packages earlier inside the <code>Dockerfile<\/code> &#8211; <strong>before the COPY<\/strong> commands.<\/p>\n<p>The reason behind this is that docker would be able to cache the image with the required dependencies, and this <strong>cache can then be used<\/strong> in the following builds when the code gets modified.<\/p>\n<p>Also, <code>COPY<\/code> and <code>ADD<\/code> instructions in a <strong><code>Dockerfile<\/code><\/strong> invalidate the cache for subsequent layers. Which means, Docker will rebuild all the layers after COPY and ADD.<\/p>\n<p>This means, it is recomended to add instructions that are <strong>less likely to change<\/strong> earlier in the Dockerfile.<\/p>\n<p>For example, let&#8217;s take a look at the following two Dockerfiles.<\/p>\n<p><strong>Dockerfile 5<\/strong> (Good Example)<\/p>\n<pre><code>FROM ubuntu:latest\n\nENV DEBIAN_FRONTEND=noninteractive\n\nRUN apt-get update -y &amp;&amp; \\\n    apt-get upgrade -y &amp;&amp; \\\n    apt-get install -y vim net-tools dnsutils\n\nCOPY . .<\/code><\/pre>\n<p><strong>Dockerfile 6<\/strong> (Less Optimal Example)<\/p>\n<pre><code>FROM ubuntu:latest\n\nENV DEBIAN_FRONTEND=noninteractive\n\nCOPY . .\n\nRUN apt-get update -y &amp;&amp; \\\n    apt-get upgrade -y &amp;&amp; \\\n    apt-get install -y vim net-tools dnsutils<\/code><\/pre>\n<p>Docker would be able to <strong>use the cache functionality better<\/strong> with <code>Dockerfile5<\/code> than <code>Dockerfile6<\/code> due to the better placement of the COPY command.<\/p>\n<h2 id=\"method-5-use-dockerignore\">Method 5: Use Dockerignore<\/h2>\n<p>As a rule, only the necessary files need to be copied over the docker image.<\/p>\n<p>Docker can ignore the files present in the working directory if configured in the <strong><code>.dockerignore<\/code> <\/strong>file.<\/p>\n<p>It also improves caching by ignoring unnecessary files and <strong>prevents unnecessary cache invalidation.<\/strong><\/p>\n<p>This feature should be kept in mind while optimizing the docker image.<\/p>\n<h2 id=\"method-6-keep-application-data-elsewhere\">Method 6: Keep Application Data Elsewhere<\/h2>\n<p>Storing <strong>application data<\/strong> in the image will unnecessarily increase the size of the images.<\/p>\n<p>It&#8217;s highly recommended to use the <strong>volume feature<\/strong> of the container runtimes to keep the image separate from the data.<\/p>\n<p>If you are using Kubernetes, ensure<\/p>\n<h2 id=\"docker-image-optimization-tools\">Docker Image Optimization Tools<\/h2>\n<p>Following are some of the open-source tools that will help you optimize the Docker images. You can choose a tool and make it part of your Docker Image Pipeline to ensure only optimized images get created for application deployments.<\/p>\n<ol>\n<li><strong>Dive<\/strong>: It is an image explorer tool that helps you discover layers in the Docker &amp; OCI containers images. Using Dive, you can find ways to optimize your Docker images. Check out the <a href=\"https:\/\/github.com\/wagoodman\/dive?ref=devopscube.com\" rel=\"noreferrer noopener\">Dive Github repo<\/a> for more details.<\/li>\n<li><a href=\"https:\/\/devopscube.com\/slimtoolkit-to-shrink-docker-images\/\"><strong>SlimtoolKit<\/strong><\/a><strong>: <\/strong>It helps you optimize your Docker images for security and size. Check out the <a href=\"https:\/\/github.com\/docker-slim\/docker-slim?ref=devopscube.com\" rel=\"noreferrer noopener\">Docker Slim Github repo<\/a> for more details. You can reduce the docker image size up to 30x using Slim.<\/li>\n<li><a href=\"http:\/\/docker-squash\/?ref=devopscube.com\" rel=\"noreferrer noopener\"><strong>Docker Squash:<\/strong><\/a> This utility helps you to reduce the image size by squashing image layers. The squash feature is also available in the Docker CLI using <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/image_build\/?ref=devopscube.com\" rel=\"noreferrer noopener\">squash flag.<\/a><\/li>\n<\/ol>\n<p>I will keep adding tools to this list.<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>The above methods should help you build optimized Docker images and write better Dockerfiles.<\/p>\n<p>Also, If you follow all the standard container best practices, you can reduce<strong> the docker image size<\/strong> to have lightweight image deployments.<\/p>\n<p>Also, from a DevSecOps perspective, you can use open-source vulnerability scanning tools like <a href=\"https:\/\/devopscube.com\/trivy-security-scanner\/\">Trivy<\/a> to scan Docker images<\/p>\n<p>If you are getting started with your Docker journey, you can check out my article on <a href=\"https:\/\/devopscube.com\/run-docker-in-docker\/\" rel=\"noreferrer noopener\">3 methods to run docker in docker.<\/a><\/p>\n<p>If you are learning container orchestration using Kubernetes, check out comprehensive <a href=\"https:\/\/devopscube.com\/kubernetes-tutorials-beginners\/\">Kubernetes tutorials for beginners<\/a>.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/reduce-docker-image-size\/\" target=\"_blank\" rel=\"noopener noreferrer\">How to Reduce Docker Image Size: 6 Optimization Methods \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/reduce-docker-image-size\/<\/p>\n","protected":false},"author":1,"featured_media":330,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-329","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/329","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=329"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/329\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/330"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=329"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=329"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=329"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}