{"id":477328,"date":"2022-07-24T11:04:38","date_gmt":"2022-07-24T08:04:38","guid":{"rendered":"https:\/\/en.buradabiliyorum.com\/how-to-create-a-dockerfile-from-an-existing-image\/"},"modified":"2022-07-24T11:04:38","modified_gmt":"2022-07-24T08:04:38","slug":"how-to-create-a-dockerfile-from-an-existing-image","status":"publish","type":"post","link":"https:\/\/buradabiliyorum.com\/en\/how-to-create-a-dockerfile-from-an-existing-image\/","title":{"rendered":"#How to Create a Dockerfile From an Existing Image"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_84 counter-hierarchy ez-toc-counter ez-toc-custom 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-6a2e0b7f065ff\" 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: #dd3333;color:#dd3333\" 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: #dd3333;color:#dd3333\" 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-6a2e0b7f065ff\" checked aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-create-a-dockerfile-from-an-existing-image\/#%E2%80%9CHow_to_Create_a_Dockerfile_From_an_Existing_Image%E2%80%9D\" >&#8220;How to Create a Dockerfile From an Existing Image&#8221;<\/a><ul class='ez-toc-list-level-2' ><li class='ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-create-a-dockerfile-from-an-existing-image\/#The_Objective\" >The Objective<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-create-a-dockerfile-from-an-existing-image\/#The_Docker_History_Command\" >The Docker History Command<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-create-a-dockerfile-from-an-existing-image\/#Automating_Layer_Extraction_with_Whaler_and_Dfimage\" >Automating Layer Extraction with Whaler and Dfimage<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-create-a-dockerfile-from-an-existing-image\/#The_Limitations\" >The Limitations<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-create-a-dockerfile-from-an-existing-image\/#Summary\" >Summary<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n<h1><span class=\"ez-toc-section\" id=\"%E2%80%9CHow_to_Create_a_Dockerfile_From_an_Existing_Image%E2%80%9D\"><\/span>&#8220;How to Create a Dockerfile From an Existing Image&#8221;<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<div>\n<!-- UNCACHED CONTENT --><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"type:primaryImage aligncenter size-full wp-image-14169\" data-pagespeed-no-defer=\"\" src=\"https:\/\/www.howtogeek.com\/wp-content\/uploads\/csit\/2021\/09\/993634a1.png?width=1198&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1\" alt=\"\" width=\"1200\" height=\"675\"\/><\/p>\n<p>Docker images are created by building Dockerfiles. The build process executes the instructions in the Dockerfile to create the filesystem layers that form the final image.<\/p>\n<p>What if you already have an image? Can you retrieve the Dockerfile it was built from? In this article, we\u2019ll look at two methods that can achieve this.<\/p>\n<h2 id=\"the-objective\"><span class=\"ez-toc-section\" id=\"The_Objective\"><\/span>The Objective<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>When you\u2019re building your own Docker images, you should store your Dockerfiles as version controlled files in your source repository. This practice ensures you can always retrieve the instructions used to assemble your images.<\/p>\n<p>Sometimes you won\u2019t have access to a Dockerfile though. Perhaps you\u2019re using an image that\u2019s in a public registry but has an inaccessible source repository. Or you could be working with image snapshots which don\u2019t directly correspond to a versioned Dockerfile. In these cases, you need a technique that can create a Dockerfile from an image on your machine.<\/p>\n<p>Docker doesn\u2019t offer any built-in functionality for achieving this. Built images lack an association with the Dockerfile they were created from. However, you can reverse engineer the build process to produce a good <a href=\"https:\/\/buradabiliyorum.com\/en\/category\/download-scripts-themes-apps\/\" data-internallinksmanager029f6b8e52c=\"9\" title=\"Download Scripts &amp; Themes &amp; Apps\" target=\"_blank\" rel=\"noopener\">app<\/a>roximation of an image\u2019s Dockerfile on-demand.<\/p>\n<h2 id=\"the-docker-history-command\"><span class=\"ez-toc-section\" id=\"The_Docker_History_Command\"><\/span>The Docker History Command<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The <code>docker history<\/code> command reveals the layer history of an image. It shows the command used to build each successive filesystem layer, making it a good starting point when reproducing a Dockerfile.<\/p>\n<p>Here\u2019s a simple Dockerfile for a Node.js application:<\/p>\n<pre>FROM node:16&#13;\nCOPY app.js .&#13;\nRUN app.js --init&#13;\nCMD [\"app.js\"]<\/pre>\n<p>Build the image using <code>docker build<\/code>:<\/p>\n<pre>$ docker build -t node-app:latest .<\/pre>\n<p>Now inspect the image\u2019s layer history with <code>docker history<\/code>:<\/p>\n<pre>$ docker history node-app:latest&#13;\nIMAGE          CREATED          CREATED BY                                      SIZE      COMMENT&#13;\nc06fc21a8eed   8 seconds ago    \/bin\/sh -c #(nop)  CMD [\"app.js\"]               0B        &#13;\n74d58e07103b   8 seconds ago    \/bin\/sh -c .\/app.js --init                      0B        &#13;\n22ea63ef9389   19 seconds ago   \/bin\/sh -c #(nop) COPY file:0c0828d0765af4dd...   50B       &#13;\n424bc28f998d   4 days ago       \/bin\/sh -c #(nop)  CMD [\"node\"]                 0B        &#13;\n&lt;missing&gt;      4 days ago       \/bin\/sh -c #(nop)  ENTRYPOINT [\"docker-entry...   0B        &#13;\n...<\/pre>\n<p>The history includes the complete list of layers in the image, including those inherited from the <code>node:16<\/code> base image. Layers are ordered so the most recent one is first. You can spot where the layers created by the sample Dockerfile begin based on the creation time. These show Docker\u2019s internal representation of the <code>COPY<\/code> and <code>CMD<\/code> instructions used in the Dockerfile.<\/p>\n<p>The <code>docker history<\/code> output is more useful when the table\u2019s limited to just showing each layer\u2019s command. You can disable truncation too to view the full command associated with each layer:<\/p>\n<pre>$ docker history node-app:latest --format \"{{.CreatedBy}}\" --no-trunc&#13;\n\/bin\/sh -c #(nop)  CMD [\"app.js\"]&#13;\n\/bin\/sh -c .\/app.js --init&#13;\n\/bin\/sh -c #(nop) COPY file:0c0828d0765af4dd87b893f355e5dff77d6932d452f5681dfb98fd9cf05e8eb1 in . &#13;\n\/bin\/sh -c #(nop)  CMD [\"node\"]&#13;\n\/bin\/sh -c #(nop)  ENTRYPOINT [\"docker-entrypoint.sh\"]&#13;\n...<\/pre>\n<p>From this list of commands, you can gain an overview of the steps taken to assemble the image. For simple images like this one, this can be sufficient information to accurately reproduce a Dockerfile.<\/p>\n<h2 id=\"automating-layer-extraction-with-whaler-and-dfimage\"><span class=\"ez-toc-section\" id=\"Automating_Layer_Extraction_with_Whaler_and_Dfimage\"><\/span>Automating Layer Extraction with Whaler and Dfimage<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Copying commands out of <code>docker history<\/code> is a laborious process. You also need to s<a href=\"https:\/\/buradabiliyorum.com\/en\/category\/trip-and-travel\/\" data-internallinksmanager029f6b8e52c=\"10\" title=\"Trip &amp; Travel\" target=\"_blank\" rel=\"noopener\">trip<\/a> out the <code>\/bin\/sh -c<\/code> at the start of each line, as Docker handled each instruction as a no-op Bash comment.<\/p>\n<p>Fortunately there are community tools available that can automate Dockerfile creation from an image\u2019s layer history. For the purposes of this article, we\u2019ll focus on <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/github.com\/P3GLEG\/Whaler\">Whaler<\/a> which is packaged into the <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/hub.docker.com\/r\/alpine\/dfimage\"><code>alpine\/dfimage<\/code><\/a> (Dockerfile-from-Image) Docker image by the Alpine organization.<\/p>\n<p>Running the <code>dfimage<\/code> image and supplying a Docker tag will output a Dockerfile that can be used to reproduce the referenced image. You must bind your host\u2019s Docker socket into the <code>dfimage<\/code> container so it can access your image list and pull the tag if needed.<\/p>\n<pre>$ docker run --rm &#13;\n    -v \/var\/run\/docker.sock:\/var\/run\/docker.sock &#13;\n    alpine\/dfimage node-app:latest&#13;\n&#13;\nAnalyzing node-app:latest&#13;\nDocker Version: 20.10.13&#13;\nGraphDriver: overlay2&#13;\nEnvironment Variables&#13;\n|PATH=\/usr\/local\/sbin:\/usr\/local\/bin:\/usr\/sbin:\/usr\/bin:\/sbin:\/bin&#13;\n|NODE_VERSION=16.14.2&#13;\n|YARN_VERSION=1.22.18&#13;\n&#13;\nImage user&#13;\n|User is root&#13;\n&#13;\nDockerfile:&#13;\n...&#13;\nENTRYPOINT [\"docker-entrypoint.sh\"]&#13;\nCMD [\"node\"]&#13;\nCOPY file:bcbc3d5784a8f1017653685866d30e230cae61d0da13dae32525b784383ac75f in .&#13;\n    app.js&#13;\n&#13;\nRUN .\/app.js --init&#13;\nCMD [\"app.js\"]<\/pre>\n<p>The created Dockerfile contains everything you need to go from <code>scratch<\/code> (an empty filesystem) to the final layer of the specified image. It includes all the layers that come from the base image. You can see these in the first <code>ENTRYPOINT<\/code> and <code>CMD<\/code> instructions in the sample output above (the other base image layers have been omitted for brevity\u2019s sake).<\/p>\n<p>With the exception of <code>COPY<\/code>, the instructions specific to our image match what was written in the original Dockerfile. You can now copy these instructions into a new <code>Dockerfile<\/code>, either using the whole <code>dfimage<\/code> output or by taking just the part that pertains to the final image. The latter option is only a possibility if you know the original base image\u2019s identity so you can add a <code>FROM<\/code> instruction to the top of the file.<\/p>\n<h2 id=\"the-limitations\"><span class=\"ez-toc-section\" id=\"The_Limitations\"><\/span>The Limitations<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>In many cases <code>dfimage<\/code> will be able to assemble a usable Dockerfile. Nonetheless it\u2019s not perfect and an exact match is not guaranteed. The extent of the discrepancies compared to the image\u2019s original Dockerfile will vary depending on the instructions that were used.<\/p>\n<p>Not all instructions are captured in the layer history. Unsupported ones will be lost and there\u2019s no way you can determine what they were. The best accuracy is obtained with command and metadata instructions like <code>RUN<\/code>, <code>ENV<\/code>, <code>WORKDIR<\/code>, <code>ENTRYPOINT<\/code>, and <code>CMD<\/code>. <code>RUN<\/code> instructions could still be missing if their command didn\u2019t result in filesystem changes, meaning no new image layer was created.<\/p>\n<p><code>COPY<\/code> and <code>ADD<\/code> instructions present unique challenges. The history doesn\u2019t contain the host file path which was copied into the container. You can see a copy occurred but the source path references the file hash that was copied into the image from the build context.<\/p>\n<p>As you do get the final destination, this can be enough to help you work out what\u2019s been copied and why. You can then use this information to interpolate a new source path into the Dockerfile which you can use for future builds. In other cases, inspecting the file inside the image might help reveal the copy\u2019s purpose so you can determine a meaningful filename for the host path.<\/p>\n<h2 id=\"summary\"><span class=\"ez-toc-section\" id=\"Summary\"><\/span>Summary<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Docker images don\u2019t include a direct way to work backwards to the Dockerfile they were built from. It\u2019s still possible to piece together the build process though. For simple images with few instructions, you can often work out the instructions manually by looking at the <code>CREATED BY<\/code> column in the <code>docker history<\/code> command\u2019s output.<\/p>\n<p>Larger images with more complex build processes are best analyzed by tools like <code>dfimage<\/code>. This does the hard work of parsing the verbose <code>docker history<\/code> output for you, producing a new Dockerfile that\u2019s a best effort match for the likely original.<\/p>\n<p>Reverse engineering efforts aren\u2019t perfect and some Dockerfile instructions are lost or mangled during the build process. Consequently you shouldn\u2019t assume Dockerfiles created in this way are an accurate representation of the original. You might have to make some manual adjustments to <code>ADD<\/code> and <code>COPY<\/code> instructions too, resurrecting host file paths that were converted to build context references.<\/p>\n<\/div>\n<p><script>\n setTimeout(function(){\n  !function(f,b,e,v,n,t,s)\n  {if(f.fbq)return;n=f.fbq=function(){n.callMethod?\n  n.callMethod.apply(n,arguments):n.queue.push(arguments)};\n  if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';\n  n.queue=[];t=b.createElement(e);t.async=!0;\n  t.src=v;s=b.getElementsByTagName(e)[0];\n  s.parentNode.insertBefore(t,s) } (window, document,'script',\n  'https:\/\/connect.facebook.net\/en_US\/fbevents.js');\n   fbq('init', '335401813750447');\n   fbq('track', 'PageView');\n  },3000);\n<\/script><\/p>\n<blockquote><p><strong><span style=\"color: #ff6600;\">If you liked the article, do not forget to share it with your friends. Follow us on\u00a0<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/news.google.com\/publications\/CAAqBwgKMLG0nwswvr63Aw\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Google News<\/a><\/span>\u00a0too, click on the star and choose us from your favorites.<\/span><\/strong><\/p><\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\">For forums sites go to <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/forum.buradabiliyorum.com\/\" target=\"_blank\" rel=\"noopener\">Forum.BuradaBiliyorum.Com<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\"><strong>If you want to read more like this article, you can visit our <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/en.buradabiliyorum.com\/technology\/\" target=\"_blank\" rel=\"noopener\">Technology category.<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<p><span style=\"color: black;\"><a style=\"color: #ff9900;\" href=\"https:\/\/www.howtogeek.com\/devops\/how-to-create-a-dockerfile-from-an-existing-image\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;How to Create a Dockerfile From an Existing Image&#8221; Docker images are created by building Dockerfiles. The build process executes the instructions in the Dockerfile to create the filesystem layers that form the final image. What if you already have an image? Can you retrieve the Dockerfile it was built from? In this article, we\u2019ll&#8230;<\/p>\n","protected":false},"author":1,"featured_media":477329,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/www.howtogeek.com\/wp-content\/uploads\/csit\/2021\/09\/993634a1.png?height=200p&trim=2,2,2,2","fifu_image_alt":"","footnotes":""},"categories":[18],"tags":[],"class_list":["post-477328","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology"],"_links":{"self":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/477328","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/comments?post=477328"}],"version-history":[{"count":0,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/477328\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media\/477329"}],"wp:attachment":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media?parent=477328"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/categories?post=477328"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/tags?post=477328"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}