{"id":241,"date":"2023-11-15T13:06:51","date_gmt":"2023-11-15T12:06:51","guid":{"rendered":"https:\/\/extendsclass.com\/blog\/?p=241"},"modified":"2023-06-19T21:21:39","modified_gmt":"2023-06-19T19:21:39","slug":"creating-your-first-docker-image-with-dockerfile-a-step-by-step-guide","status":"publish","type":"post","link":"https:\/\/extendsclass.com\/blog\/creating-your-first-docker-image-with-dockerfile-a-step-by-step-guide","title":{"rendered":"Creating Your First Docker Image with Dockerfile: A Step-by-Step Guide"},"content":{"rendered":"\n<p>On Docker Hub, the list of available images is vast, making it easy to create containers from these images.<\/p>\n\n\n\n<p>However, there are times when we need to create our own image. There are several solutions available to us for creating a customized image:<\/p>\n\n\n\n<ol>\n<li>Creating an image from a container: We customize a container based on its writable layer and create a new image from that container.<\/li>\n\n\n\n<li>Creating an image from a Dockerfile.<\/li>\n<\/ol>\n\n\n\n<p>In this tutorial, we will focus on creating an image from a Dockerfile. I will cover the writable layer of containers in a separate article.<\/p>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_47_1 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"ez-toc-toggle-icon-1\"><label for=\"item-69daafda483ec\" aria-label=\"Table of Content\"><span style=\"display: flex;align-items: center;width: 35px;height: 30px;justify-content: center;direction:ltr;\"><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><\/label><input  type=\"checkbox\" id=\"item-69daafda483ec\"><\/a><\/span><\/div>\n<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:\/\/extendsclass.com\/blog\/creating-your-first-docker-image-with-dockerfile-a-step-by-step-guide\/#What_is_a_Dockerfile\" title=\"What is a Dockerfile?\">What is a Dockerfile?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/extendsclass.com\/blog\/creating-your-first-docker-image-with-dockerfile-a-step-by-step-guide\/#Dockerfile_Instructions\" title=\"Dockerfile Instructions\">Dockerfile Instructions<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/extendsclass.com\/blog\/creating-your-first-docker-image-with-dockerfile-a-step-by-step-guide\/#My_First_Dockerfile\" title=\"My First Dockerfile\">My First Dockerfile<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"What_is_a_Dockerfile\"><\/span>What is a Dockerfile?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>A Dockerfile is simply a configuration text file used to create an image. It contains all the necessary instructions for building an image.<\/p>\n\n\n\n<p>This format has several advantages. It enables easy versioning of the image since it is a simple text file, and it also provides a quick overview of the operations performed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Dockerfile_Instructions\"><\/span>Dockerfile Instructions<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>A Dockerfile contains a list of instructions. Here are the basic instructions that we will be using throughout this article:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Instruction<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td>FROM<\/td><td>Image source<\/td><\/tr><tr><td>RUN<\/td><td>Command to be executed to build the image<\/td><\/tr><tr><td>COPY<\/td><td>Add a file to the image<\/td><\/tr><tr><td>WORKDIR<\/td><td>Change the current directory<\/td><\/tr><tr><td>EXPOSE<\/td><td>Ports to be listened on by the container by default<\/td><\/tr><tr><td>CMD<\/td><td>Command to be executed when the container starts up<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>This list is not exhaustive, and I would direct you to the official documentation for a complete reference: <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\" title=\"\">Dockerfile reference<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"My_First_Dockerfile\"><\/span>My First Dockerfile<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Let&#8217;s see how to create an image that runs a web application based on Express.js (a minimalist framework for building web applications with Node.js).<\/p>\n\n\n\n<p>A Dockerfile always begins with the <code>FROM<\/code> instruction, which indicates the base image we will use. We will start with a Ubuntu Linux distribution:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM ubuntu:20.04<\/code><\/pre>\n\n\n\n<p>It is possible to start from scratch by using &#8220;FROM scratch&#8221;.<\/p>\n\n\n\n<p>Next, we will use the <code>RUN<\/code> instruction to execute commands in our container.<\/p>\n\n\n\n<p>We will install Node.js, install npm (useful for installing Express.js), create a folder for our web application, and finally install Express.js:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>RUN apt-get update \\\n\t&amp;&amp; apt-get install -y nodejs \\\n\t&amp;&amp; apt-get install -y npm \\\n\t&amp;&amp; mkdir myapp &amp;&amp; cd myapp &amp;&amp; npm init -y &amp;&amp; npm install express<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-text-align-center has-larger-font-size\">Each instruction in a Dockerfile results in the creation of a layer.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>The number of layers impacts the size of the images, so here we limit the number of instructions by executing multiple commands within a single <code>RUN<\/code> instruction.<\/p>\n\n\n\n<p>Note: The maximum number of layers is limited to 128.<\/p>\n\n\n\n<p>Our goal is to create a small and pointless web application in Node.js that simply returns &#8220;Hello World!&#8221; hardcoded:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const express = require('express')\nconst app = express()\nconst port = 80\n\napp.get('\/', (req, res) =&gt; {\n  res.send('Hello World!')\n})\n\napp.listen(port, () =&gt; {\n  console.log(`Up`)\n})<\/code><\/pre>\n\n\n\n<p>We will add this file to the image:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>COPY app.js \/myapp\/app.js<\/code><\/pre>\n\n\n\n<p>Next, we will change the current directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WORKDIR \/myapp<\/code><\/pre>\n\n\n\n<p>We will set the listening port for our application:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>EXPOSE 80<\/code><\/pre>\n\n\n\n<p>In itself, EXPOSE doesn&#8217;t do anything at the image level, but it serves two purposes:<\/p>\n\n\n\n<p>Documentation: People who view the Dockerfile can know which ports they need to map.<br>&#8220;docker run&#8221; command with automatic port mapping (&#8220;-P&#8221; option): The command can automatically retrieve the ports to be mapped.<br>Lastly, we specify the command to be executed when containers created from our image start up. In our case, we launch our application app.js:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CMD &#91;\"node\", \"app.js\"]<\/code><\/pre>\n\n\n\n<p>Here is our complete Dockerfile:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM ubuntu:20.04\n\nRUN apt-get update \\\n\t&amp;&amp; apt-get install -y nodejs \\\n\t&amp;&amp; apt-get install -y npm \\\n\t&amp;&amp; mkdir myapp &amp;&amp; cd myapp &amp;&amp; npm init -y &amp;&amp; npm install express\n\nCOPY app.js \/myapp\/app.js\n\nWORKDIR \/myapp\n\nEXPOSE 80\n\nCMD &#91;\"node\", \"app.js\"]<\/code><\/pre>\n\n\n\n<p>Our Dockerfile is already written! Now, all that&#8217;s left is to create our image using the &#8220;docker build&#8221; command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker build -t cyrilbois\/mywebapp:latest .<\/code><\/pre>\n\n\n\n<p>The &#8220;-t&#8221; option allows us to specify the name (and tag) of our image.<\/p>\n\n\n\n<p>Our image is finally created! \ud83d\ude0a<\/p>\n\n\n\n<p>If we want to create a container from our image:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker run -d -p 3000:80 --name webapp cyrilbois\/mywebapp:latest<\/code><\/pre>\n\n\n\n<p>Now, we can access our web application:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"623\" height=\"362\" src=\"https:\/\/extendsclass.com\/blog\/wp-content\/uploads\/2023\/06\/dockerfile-web.png\" alt=\"\" class=\"wp-image-242\" srcset=\"https:\/\/extendsclass.com\/blog\/wp-content\/uploads\/2023\/06\/dockerfile-web.png 623w, https:\/\/extendsclass.com\/blog\/wp-content\/uploads\/2023\/06\/dockerfile-web-300x174.png 300w\" sizes=\"(max-width: 623px) 100vw, 623px\" \/><\/figure>\n\n\n\n<p>And there you have it! I hope this tutorial was helpful.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial, we will focus on creating an image from a Dockerfile. I will cover the writable layer of containers in a separate article.<\/p>\n","protected":false},"author":1,"featured_media":226,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_sitemap_exclude":false,"_sitemap_priority":"","_sitemap_frequency":""},"categories":[2],"tags":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/posts\/241"}],"collection":[{"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/comments?post=241"}],"version-history":[{"count":2,"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/posts\/241\/revisions"}],"predecessor-version":[{"id":274,"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/posts\/241\/revisions\/274"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/media\/226"}],"wp:attachment":[{"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/media?parent=241"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/categories?post=241"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/extendsclass.com\/blog\/wp-json\/wp\/v2\/tags?post=241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}