<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Containerization on </title>
    <link>/tags/containerization/</link>
    <description>Recent content in Containerization on </description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Wed, 22 Jan 2025 22:40:48 +0000</lastBuildDate><atom:link href="/tags/containerization/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>The Docker Handbook</title>
      <link>/posts/the-docker-handbook/</link>
      <pubDate>Wed, 22 Jan 2025 22:40:48 +0000</pubDate>
      
      <guid>/posts/the-docker-handbook/</guid>
      <description>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;&lt;img src=&#34;docker-handbook-preview.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The concept of containerization itself is pretty old, but the emergence of the &lt;a href=&#34;https://docs.docker.com/get-started/overview/#docker-engine&#34;&gt;Docker Engine&lt;/a&gt; in 2013 has made it much easier to containerize your applications.&lt;/p&gt;
&lt;p&gt;According to the &lt;a href=&#34;https://insights.stackoverflow.com/survey/2020#overview&#34;&gt;Stack Overflow Developer Survey - 2020&lt;/a&gt;, &lt;a href=&#34;https://docker.com/&#34;&gt;Docker&lt;/a&gt; is the &lt;a href=&#34;https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-platforms-wanted5&#34;&gt;#1 most wanted platform&lt;/a&gt;, &lt;a href=&#34;https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-platforms-loved5&#34;&gt;#2 most loved platform&lt;/a&gt;, and also the &lt;a href=&#34;https://insights.stackoverflow.com/survey/2020#technology-platforms&#34;&gt;#3 most popular platform&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As in-demand as it may be, getting started can seem a bit intimidating at first. So in this article, we&amp;rsquo;ll be learning everything from basic to intermediate level of containerization. After going through the entire article, you should be able to:&lt;/p&gt;</description>
      <content>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;&lt;img src=&#34;docker-handbook-preview.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The concept of containerization itself is pretty old, but the emergence of the &lt;a href=&#34;https://docs.docker.com/get-started/overview/#docker-engine&#34;&gt;Docker Engine&lt;/a&gt; in 2013 has made it much easier to containerize your applications.&lt;/p&gt;
&lt;p&gt;According to the &lt;a href=&#34;https://insights.stackoverflow.com/survey/2020#overview&#34;&gt;Stack Overflow Developer Survey - 2020&lt;/a&gt;, &lt;a href=&#34;https://docker.com/&#34;&gt;Docker&lt;/a&gt; is the &lt;a href=&#34;https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-platforms-wanted5&#34;&gt;#1 most wanted platform&lt;/a&gt;, &lt;a href=&#34;https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-platforms-loved5&#34;&gt;#2 most loved platform&lt;/a&gt;, and also the &lt;a href=&#34;https://insights.stackoverflow.com/survey/2020#technology-platforms&#34;&gt;#3 most popular platform&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As in-demand as it may be, getting started can seem a bit intimidating at first. So in this article, we&amp;rsquo;ll be learning everything from basic to intermediate level of containerization. After going through the entire article, you should be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Containerize (almost) any application&lt;/li&gt;
&lt;li&gt;Upload custom Docker Images to online registries&lt;/li&gt;
&lt;li&gt;Work with multiple containers using Docker Compose&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Familiarity with the Linux Terminal&lt;/li&gt;
&lt;li&gt;Familiarity with JavaScript (some later projects use JavaScript)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;project-code&#34;&gt;Project Code&lt;/h2&gt;
&lt;p&gt;Code for the example projects can be found in the following repository:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/fhsinchy/docker-handbook-projects/&#34;&gt;https://github.com/fhsinchy/docker-handbook-projects/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can find the complete code in the &lt;a href=&#34;https://github.com/fhsinchy/docker-handbook-projects/tree/completed&#34;&gt;completed&lt;/a&gt; branch.&lt;/p&gt;
&lt;h2 id=&#34;contributions&#34;&gt;Contributions&lt;/h2&gt;
&lt;p&gt;This article is completely open-source and quality contributions are more than welcomed. You can find the full content in the following repository:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/fhsinchy/the-docker-handbook&#34;&gt;https://github.com/fhsinchy/the-docker-handbook&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I usually do my changes and updates on the GitHub version of the article first and then publish them on freeCodeCamp. You can find the always updated and often incomplete version of the article in the following link:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://docker-handbook.farhan.dev/&#34;&gt;https://docker-handbook.farhan.dev/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re looking for the complete and stable version of the article then freeCodeCamp will be the best place to go:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.freecodecamp.org/news/the-docker-handbook/&#34;&gt;https://www.freecodecamp.org/news/the-docker-handbook/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Which ever version of the article you end up reading though, don&amp;rsquo;t forget to let me know your opinion. Constructive criticism is always welcomed.&lt;/p&gt;
&lt;h2 id=&#34;awesome-contributors&#34;&gt;Awesome Contributors&lt;/h2&gt;
&lt;p&gt;I am listing the names of the amazing people who have contributed to this small project in alphabetical order.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ATrogolo&#34;&gt;Andrea Trogolo&lt;/a&gt; - fixed several grammatical mistakes and inconsistencies in code examples.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/bugron&#34;&gt;Arsen Melikyan&lt;/a&gt; - fixed typos and inconsistencies in multiple images and sections.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/dacarley&#34;&gt;David A. Carley&lt;/a&gt; - fixed spelling mistakes in some of the &lt;code&gt;svg&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gamba47&#34;&gt;Emilano Vazquez&lt;/a&gt; - fixed inconsistencies in code explanations.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Dez-BlueRose&#34;&gt;Steven Cook&lt;/a&gt; - fixed mistakes and added new sub-sections with better explanations for some of the topics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks a lot to all of you, I appreciate the effort you guys have put in improving this project. Hoping to collaborate in the future also.&lt;/p&gt;
&lt;h1 id=&#34;introduction-to-containerization-and-docker&#34;&gt;Introduction to Containerization and Docker&lt;/h1&gt;
&lt;p&gt;According to &lt;a href=&#34;https://www.ibm.com/cloud/learn/containerization#toc-what-is-co-r25Smlqq&#34;&gt;IBM&lt;/a&gt; —&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Containerization involves encapsulating or packaging up software code and all its dependencies so that it can run uniformly and consistently on any infrastructure.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, containerization lets you bundle up your software along with all its dependencies in a self-contained package so that it can be run without going through a troublesome setup process.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s consider a real life scenario here. Assume you have developed an awesome book management application that can store information regarding all the books you own and can also serve the purpose of a book lending system for your friends.&lt;/p&gt;
&lt;p&gt;If you make a list of the dependencies, that list may look like as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Express.js&lt;/li&gt;
&lt;li&gt;SQLite3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Well theoretically this should be it. But practically there are some other stuff as well. Turns out &lt;a href=&#34;https://nodejs.org/&#34;&gt;Node.js&lt;/a&gt; uses a build tool known as &lt;code&gt;node-gyp&lt;/code&gt; for building native add-ons and according to the &lt;a href=&#34;https://github.com/nodejs/node-gyp#installation&#34;&gt;installation instruction&lt;/a&gt; in the &lt;a href=&#34;https://github.com/nodejs/node-gyp&#34;&gt;official repository&lt;/a&gt;, this build tool requires Python 2/3 and a proper C/C++ compiler tool-chain. Taking all these into account, the final list of dependencies is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Express.js&lt;/li&gt;
&lt;li&gt;SQLite3&lt;/li&gt;
&lt;li&gt;Python 2/3&lt;/li&gt;
&lt;li&gt;C/C++ tool-chain&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Installing Python 2/3 is pretty straight forward regardless of the platform you&amp;rsquo;re on. Setting-up C/C++ tool-chain is pretty easy on Linux but on Windows and Mac, it&amp;rsquo;s a painful task. On Windows, the C++ build tools package measures at gigabytes and takes quite some time to install. On a Mac, you can either install the gigantic &lt;a href=&#34;https://developer.apple.com/xcode/&#34;&gt;Xcode&lt;/a&gt; application or the much smaller &lt;a href=&#34;https://developer.apple.com/downloads/&#34;&gt;Command Line Tools for Xcode&lt;/a&gt; package. Regardless of the one you install, it still may break on OS updates. In fact, the problem is so prevalent that there are &lt;a href=&#34;https://github.com/nodejs/node-gyp/blob/master/macOS_Catalina.md&#34;&gt;Installation notes for macOS Catalina&lt;/a&gt; available on the official repository.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s assume that you&amp;rsquo;ve gone through all the hassles of setting up the dependencies and have started working on the project. Does that mean you&amp;rsquo;re out of danger now? Of course not.&lt;/p&gt;
&lt;p&gt;What if you have a teammate who uses Windows while you&amp;rsquo;re using Linux. Now you have to consider the inconsistencies of how these two different operating systems handle paths. Or the fact that popular technologies like &lt;a href=&#34;https://nginx.org/&#34;&gt;nginx&lt;/a&gt; are not well optimized to run on Windows. Some technologies i.e. &lt;a href=&#34;https://redis.io/&#34;&gt;Redis&lt;/a&gt; doesn&amp;rsquo;t even come pre-built for Windows.&lt;/p&gt;
&lt;p&gt;Even if you get through the entire development phase, but the person responsible for managing the servers follows the wrong deployment procedure?&lt;/p&gt;
&lt;p&gt;All these issues can be solved if only you could somehow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Develop and run the application inside an isolated environment (known as a container) that matches your final deployment environment.&lt;/li&gt;
&lt;li&gt;Put your application inside a single file (known as an image) along with all its dependencies and necessary deployment configurations.&lt;/li&gt;
&lt;li&gt;And share that image through a central server (known as a registry) that is accessible by anyone with proper authorization.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your teammates, will then be able to download the image from the registry, run the application as it is within an isolated environment free from the platform specific inconsistencies or even deploy directly on a server, given the image comes with all the proper production configurations.&lt;/p&gt;
&lt;p&gt;That is the idea behind containerization. Putting your applications inside a self-contained package making it portable and reproducible across various environments.&lt;/p&gt;
&lt;h4 id=&#34;now-the-question-is-what-role-does-docker-play-here&#34;&gt;Now the question is &amp;ldquo;What role does Docker play here?&amp;rdquo;&lt;/h4&gt;
&lt;p&gt;As I&amp;rsquo;ve already explained, containerization is an idea that solves a myriad of problem in software development by putting things into boxes. This very idea has quite a few implementations. &lt;a href=&#34;https://www.docker.com/&#34;&gt;Docker&lt;/a&gt; is such an implementation. It&amp;rsquo;s an open-source containerization platform that allows you to containerize your applications, share them using public or private registries and also to &lt;a href=&#34;https://docs.docker.com/get-started/orchestration/&#34;&gt;orchestrate&lt;/a&gt; them.&lt;/p&gt;
&lt;p&gt;Now, Docker is not the only containerization tool on the market, it&amp;rsquo;s just the most popular one. Another containerization engine that I love is called &lt;a href=&#34;https://podman.io/&#34;&gt;Podman&lt;/a&gt; developed by Red Hat. Other tools like &lt;a href=&#34;https://github.com/GoogleContainerTools/kaniko&#34;&gt;Kaniko&lt;/a&gt; by Google, &lt;a href=&#34;https://coreos.com/rkt/&#34;&gt;rkt&lt;/a&gt; by CoreOS while being amazing, is not ready to be a drop in replacement for Docker yet.&lt;/p&gt;
&lt;p&gt;Also, if you want some history lessons, you may read the amazing &lt;a href=&#34;https://blog.aquasec.com/a-brief-history-of-containers-from-1970s-chroot-to-docker-2016&#34;&gt;A Brief History of Containers: From the 1970s Till Now&lt;/a&gt; article which covers most of the major turning points for the technology.&lt;/p&gt;
&lt;h1 id=&#34;installing-docker&#34;&gt;Installing Docker&lt;/h1&gt;
&lt;p&gt;Installation of Docker varies greatly depending on the operating system you’re on but it&amp;rsquo;s universally simple across the board. Docker runs flawlessly on all three major platforms, i.e. Mac, Windows and Linux. Among the three, the installation process on Mac is the easiest.&lt;/p&gt;
&lt;h2 id=&#34;installation-on-macos&#34;&gt;Installation on macOS&lt;/h2&gt;
&lt;p&gt;On a mac, all you have to do is navigate to the official &lt;a href=&#34;https://www.docker.com/products/docker-desktop&#34;&gt;download page&lt;/a&gt; and click the &lt;em&gt;Download for Mac (stable)&lt;/em&gt; button. You’ll get a regular looking &lt;em&gt;Apple Disk Image&lt;/em&gt; file and inside the file, there will be the application. All you have to do is drag the file and drop it on your Applications directory.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/drag-docker-in-applications-directory.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;You can start Docker by simply double-clicking the application icon. Once the application start, you&amp;rsquo;ll see the Docker icon appear on your menu-bar.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/docker-icon-in-menubar.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now, open up the terminal and execute &lt;code&gt;docker --version&lt;/code&gt; and &lt;code&gt;docker-compose --version&lt;/code&gt; to ensure the success of the installation.&lt;/p&gt;
&lt;h2 id=&#34;installation-on-windows&#34;&gt;Installation on Windows&lt;/h2&gt;
&lt;p&gt;On Windows, the procedure is almost the same, except there are a few extra steps that you’ll need to go through. The installation steps are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to &lt;a href=&#34;https://docs.microsoft.com/en-us/windows/wsl/install-win10&#34;&gt;this site&lt;/a&gt; and follow the instructions for installing WSL2 on Windows 10.&lt;/li&gt;
&lt;li&gt;Then navigate to the official &lt;a href=&#34;https://www.docker.com/products/docker-desktop&#34;&gt;download page&lt;/a&gt; and click the &lt;em&gt;Download for Windows (stable)&lt;/em&gt; button.&lt;/li&gt;
&lt;li&gt;Double-click the downloaded installer and go through the installation with the defaults.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the installation is done, start &lt;em&gt;Docker Desktop&lt;/em&gt; either from the start menu or your desktop. The docker icon should show up on your taskbar.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/docker-icon-in-taskbar.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now, open up Ubuntu or whatever distribution you&amp;rsquo;ve installed from Microsoft Store. Execute &lt;code&gt;docker --version&lt;/code&gt; and &lt;code&gt;docker-compose --version&lt;/code&gt; commands to make sure that the installation was successful.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/docker-and-compose-version-on-windows.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;You can access Docker from your regular Command Prompt or PowerShell as well. It&amp;rsquo;s just that I prefer using WSL2 over any other command line on Windows.&lt;/p&gt;
&lt;p&gt;Installation of Docker on Linux is the most different one and depending on the distribution you’re on, it may vary even more. But to be honest, the installation is just as easy (if not easier) as the other two platforms.&lt;/p&gt;
&lt;h2 id=&#34;installation-on-linux&#34;&gt;Installation on Linux&lt;/h2&gt;
&lt;p&gt;The Docker Desktop package on Windows or Mac is a collection of tools like &lt;code&gt;Docker Engine&lt;/code&gt;, &lt;code&gt;Docker Compose&lt;/code&gt;, &lt;code&gt;Docker Dashboard&lt;/code&gt;, &lt;code&gt;Kubernetes&lt;/code&gt; and a few other goodies. On Linux however, you don’t get such a bundle. What you do instead is you install all the necessary tools you need manually. Installation procedures for different distributions are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you’re on Ubuntu, you may follow the &lt;a href=&#34;https://docs.docker.com/engine/install/ubuntu/&#34;&gt;Install Docker Engine on Ubuntu&lt;/a&gt; section from the official docs.&lt;/li&gt;
&lt;li&gt;For other distributions, &lt;em&gt;installation per distro&lt;/em&gt; guides are available on the official docs.
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/engine/install/debian/&#34;&gt;Install Docker Engine on Debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/engine/install/fedora/&#34;&gt;Install Docker Engine on Fedora&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/engine/install/centos/&#34;&gt;Install Docker Engine on CentOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you’re on a distribution that is not listed in the docs, you may follow the &lt;a href=&#34;https://docs.docker.com/engine/install/binaries/&#34;&gt;Install Docker Engine from binaries&lt;/a&gt; guide instead.&lt;/li&gt;
&lt;li&gt;Regardless of the procedure you follow, you’ll have to go through some &lt;a href=&#34;https://docs.docker.com/engine/install/linux-postinstall/&#34;&gt;Post-installation steps for Linux&lt;/a&gt; which are very important.&lt;/li&gt;
&lt;li&gt;Once you’re done with the docker installation, you’ll have to install another tool named Docker Compose. You may follow the &lt;a href=&#34;https://docs.docker.com/compose/install/&#34;&gt;Install Docker Compose&lt;/a&gt; guide from the official docs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the installation is done, open up the terminal and execute &lt;code&gt;docker --version&lt;/code&gt; and &lt;code&gt;docker-compose --version&lt;/code&gt; to ensure the success of the installation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/installing-docker/docker-and-compose-version-on-linux.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Although Docker performs quite well regardless of the platform you’re on, I prefer Linux over the others. Throughout the article, I’ll be switching between my &lt;a href=&#34;https://releases.ubuntu.com/20.10/&#34;&gt;Ubuntu 20.10&lt;/a&gt; and &lt;a href=&#34;https://fedoramagazine.org/announcing-fedora-33/&#34;&gt;Fedora 33&lt;/a&gt; workstations.&lt;/p&gt;
&lt;p&gt;Another thing that I would like to clarify right from the get go, is that I won&amp;rsquo;t be using any GUI tool for working with Docker throughout the entire article.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m aware of the nice GUI tools available for different platforms, but learning the common docker commands is one of the prime goals of this article.&lt;/p&gt;
&lt;h1 id=&#34;hello-world-in-docker&#34;&gt;Hello World in Docker&lt;/h1&gt;
&lt;p&gt;Now that you have Docker up and running on your machine, it&amp;rsquo;s time for you to run your first container. Open up the terminal and run the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker run hello-world
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Unable to find image &amp;#39;hello-world:latest&amp;#39; locally
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# latest: Pulling from library/hello-world
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 0e03bdcc26d7: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Digest: sha256:4cf9c47f86df71d48364001ede3a4fcd85ae80ce02ebad74156906caff5378bc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Status: Downloaded newer image for hello-world:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Hello from Docker!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# This message shows that your installation appears to be working correctly.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# To generate this message, Docker took the following steps:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  1. The Docker client contacted the Docker daemon.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  2. The Docker daemon pulled the &amp;#34;hello-world&amp;#34; image from the Docker Hub.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#     (amd64)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  3. The Docker daemon created a new container from that image which runs the
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#     executable that produces the output you are currently reading.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  4. The Docker daemon streamed that output to the Docker client, which sent it
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#     to your terminal.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# To try something more ambitious, you can run an Ubuntu container with:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  $ docker run -it ubuntu bash
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Share images, automate workflows, and more with a free Docker ID:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  https://hub.docker.com/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# For more examples and ideas, visit:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  https://docs.docker.com/get-started/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;a href=&#34;https://hub.docker.com/_/hello-world&#34;&gt;hello-world&lt;/a&gt; image is an example of minimal containerization with Docker. It has a single program compiled from a &lt;a href=&#34;https://github.com/docker-library/hello-world/blob/master/hello.c&#34;&gt;hello.c&lt;/a&gt; file responsible for printing out the message you&amp;rsquo;re seeing on your terminal.&lt;/p&gt;
&lt;p&gt;Now in your terminal, you can use the &lt;code&gt;docker ps -a&lt;/code&gt; command to have a look at all the containers that are currently running or have run in the past:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker ps -a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 128ec8ceab71        hello-world         &amp;#34;/hello&amp;#34;            14 seconds ago      Exited (0) 13 seconds ago                      exciting_chebyshev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the output, a container named &lt;code&gt;exciting_chebyshev&lt;/code&gt; was run with the container id of &lt;code&gt;128ec8ceab71&lt;/code&gt; using the &lt;code&gt;hello-world&lt;/code&gt; image and has &lt;code&gt;Exited (0) 13 seconds ago&lt;/code&gt; where the &lt;code&gt;(0)&lt;/code&gt; exit code means no error was produced during the runtime of the container.&lt;/p&gt;
&lt;p&gt;Now in order to understand what just happened behind the scenes, you&amp;rsquo;ll have to get familiar with the Docker Architecture and three very fundamental concepts of containerization in general, which are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/posts/the-docker-handbook/#container&#34;&gt;Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/posts/the-docker-handbook/#image&#34;&gt;Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/posts/the-docker-handbook/#registry&#34;&gt;Registry&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve listed the three concepts in alphabetical order and will begin my explanations with the first one on the list.&lt;/p&gt;
&lt;h2 id=&#34;container&#34;&gt;Container&lt;/h2&gt;
&lt;p&gt;In the world of containerization, there can not be anything more fundamental than the concept of a container.&lt;/p&gt;
&lt;p&gt;The official Docker &lt;a href=&#34;https://www.docker.com/resources/what-container&#34;&gt;resources&lt;/a&gt; site says, &amp;ldquo;A container is an abstraction at the application layer that packages code and dependencies together. Instead of virtualizing the entire physical machine, containers virtualize the host operating system only.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;You may consider containers as the next generation of virtual machines. Just like virtual machines, containers are completely isolated environments from the host system as well as each other. They are also a lot lighter than the traditional virtual machine hence a large number of containers can be run simultaneously without affecting the performance of the host system.&lt;/p&gt;
&lt;p&gt;Containers and virtual machines are actually different ways of virtualizing your physical hardware. The main difference between these two is the method of virtualization.&lt;/p&gt;
&lt;p&gt;Virtual machines are usually created and managed by a program known as a hypervisor i.e. &lt;a href=&#34;https://www.virtualbox.org/&#34;&gt;Oracle VM VirtualBox&lt;/a&gt;, &lt;a href=&#34;https://www.vmware.com/&#34;&gt;VMware Workstation&lt;/a&gt;, &lt;a href=&#34;https://www.linux-kvm.org/&#34;&gt;KVM&lt;/a&gt;, &lt;a href=&#34;https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/about/&#34;&gt;Microsoft Hyper-V&lt;/a&gt;, etc. This hypervisor program usually sits between the host operating system and the virtual machines to act as a medium of communication.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/hello-world-in-docker/virtual-machines.svg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Each virtual machine comes with its own guest operating system which is just as heavy as the host operating system. Applications running inside a virtual machine communicates with the guest operating system, which talks to the hypervisor, which then in turn talks to the host operating system to allocate necessary resources from the physical infrastructure to the running application.&lt;/p&gt;
&lt;p&gt;As you can see, there is a long chain of communication between applications running inside virtual machines and the physical infrastructure. The application running inside the virtual machine may take only a small amount of resources but the guest operating system adds a noticeable overhead.&lt;/p&gt;
&lt;p&gt;Unlike a virtual machine, a container does the job of virtualization in a smarter way. Instead of having a complete guest operating system inside a container, it just utilizes the host operating system via the container runtime while maintaining isolation just like a traditional virtual machine.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/hello-world-in-docker/containers.svg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The container runtime i.e. Docker sits between the containers and the host operating system instead of a hypervisor. The containers then communicate with the container runtime which then communicates with the host operating system to get necessary resources from the physical infrastructure. As a result of eliminating the entire guest operating system layer, containers are much lighter and less resource-hogging than traditional virtual machines.&lt;/p&gt;
&lt;p&gt;As a demonstration of the point, look at the following code block:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uname -a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Linux alpha-centauri 5.8.0-22-generic #23-Ubuntu SMP Fri Oct 9 00:34:40 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker run alpine uname -a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Linux f08dbbe9199b 5.8.0-22-generic #23-Ubuntu SMP Fri Oct 9 00:34:40 UTC 2020 x86_64 Linux
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the code block above, I have executed the &lt;code&gt;uname -a&lt;/code&gt; command on my host operating system to print out the kernel details. Then on the next line I&amp;rsquo;ve executed the same command inside a container running &lt;a href=&#34;https://alpinelinux.org/&#34;&gt;Alpine Linux&lt;/a&gt;. As can be seen in the output, the container is indeed using the kernel from my host operating system. This goes to prove the point that containers virtualize the host operating system instead of having an operating system of their own.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re on a Windows machine, you&amp;rsquo;ll find out that all the containers uses the WSL2 kernel. It happens because WSL2 acts as the back-end for Docker on Windows. On macOS the default back-end is a VM running on &lt;a href=&#34;https://github.com/moby/hyperkit&#34;&gt;HyperKit&lt;/a&gt; hypervisor.&lt;/p&gt;
&lt;h2 id=&#34;image&#34;&gt;Image&lt;/h2&gt;
&lt;p&gt;Images are multi-layered self-contained files that act as the template for creating containers. They are like a frozen, read-only copy of a container. Images can be exchanged through registries.&lt;/p&gt;
&lt;p&gt;In the past, different container engines had different image formats but later on &lt;a href=&#34;https://opencontainers.org/&#34;&gt;Open Container Initiative (OCI)&lt;/a&gt; defined a standard specification for container images which is complied by the major containerization engines out there. This means that an image built with Docker can be used with another runtime like Podman without any additional hassle.&lt;/p&gt;
&lt;p&gt;Containers are just images in running state. When you obtain an image from the internet and run a container using that, you essentially create another temporary writable layer on top of the previous read-only ones. This concept will become a lot more clearer in upcoming chapters but for now, just keep in mind that images are multi-layered read-only files carrying your application in a desired state inside them.&lt;/p&gt;
&lt;h2 id=&#34;registry&#34;&gt;Registry&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ve already learned about two very important pieces of the puzzle, &lt;em&gt;Container&lt;/em&gt; and &lt;em&gt;Image&lt;/em&gt;. The final piece is &lt;em&gt;Registry&lt;/em&gt;. An image registry is a centralized place where you can upload your images and can also download images created by others. &lt;a href=&#34;https://hub.docker.com/&#34;&gt;Docker Hub&lt;/a&gt; is the default public registry for Docker. Another very popular image registry is &lt;a href=&#34;https://quay.io/&#34;&gt;Quay&lt;/a&gt; by Red Hat. Throughout this article I&amp;rsquo;ll be using Docker Hub as my registry of choice.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/hello-world-in-docker/docker-hub.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;You can share any number of public images on Docker Hub for free. People around the world will be able to download them and use them freely. Images that I&amp;rsquo;ve uploaded are available on my profile (&lt;a href=&#34;https://hub.docker.com/u/fhsinchy&#34;&gt;fhsinchy&lt;/a&gt;) page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/hello-world-in-docker/my-images-on-docker-hub.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Apart from Docker Hub or Quay, you can also create your own image registry for hosting private images. There is also a local registry that runs within your computer that caches images pulled from remote registries.&lt;/p&gt;
&lt;h2 id=&#34;docker-architecture&#34;&gt;Docker Architecture&lt;/h2&gt;
&lt;p&gt;Now that you&amp;rsquo;ve become familiar with most of the fundamental concepts regarding containerization and Docker, it&amp;rsquo;s time for you to understand how Docker as a software has been designed.&lt;/p&gt;
&lt;p&gt;The engine consists of three major components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Docker Daemon:&lt;/strong&gt; The daemon (&lt;code&gt;dockerd&lt;/code&gt;) is a process that keeps running in the background and waits for commands from the client. The daemon is capable of managing various Docker objects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker Client:&lt;/strong&gt; The client  (&lt;code&gt;docker&lt;/code&gt;) is a command-line interface program mostly responsible for transporting commands issued by users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;REST API:&lt;/strong&gt; The REST API acts as a bridge between the daemon and the client. Any command issued using the client passes through the API to finally reach the daemon.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;According to the official &lt;a href=&#34;https://docs.docker.com/get-started/overview/#docker-architecture&#34;&gt;docs&lt;/a&gt;, &amp;ldquo;Docker uses a client-server architecture. The Docker &lt;em&gt;client&lt;/em&gt; talks to the Docker &lt;em&gt;daemon&lt;/em&gt;, which does the heavy lifting of building, running, and distributing your Docker containers&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;You as user will usually execute commands using the client component. The client then use the REST API to reach out to the long running daemon and get your work done.&lt;/p&gt;
&lt;h2 id=&#34;the-full-picture&#34;&gt;The Full Picture&lt;/h2&gt;
&lt;p&gt;Okay, enough talking. Now it&amp;rsquo;s time for you to understand how all these pieces of puzzle you just learned about works in harmony. Before I dive into the explanation of what really happened when you ran &lt;code&gt;docker run hello-world&lt;/code&gt; command, let me show you a little diagram I&amp;rsquo;ve made:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/hello-world-in-docker/docker-run-hello-world.svg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;This image is a slightly modified version of the one found in the official &lt;a href=&#34;https://docs.docker.com/engine/images/architecture.svg&#34;&gt;docs&lt;/a&gt;. The series of events that occurred when you executed the command can be listed as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You execute &lt;code&gt;docker run hello-world&lt;/code&gt; command where &lt;code&gt;hello-world&lt;/code&gt; is the name of an image.&lt;/li&gt;
&lt;li&gt;Docker client reaches out to the daemon, tells it to get the &lt;code&gt;hello-world&lt;/code&gt; image and run a container from that.&lt;/li&gt;
&lt;li&gt;Docker daemon looks for the image within your local repository and realizes that it&amp;rsquo;s not there, hence the &lt;code&gt;Unable to find image &#39;hello-world:latest&#39; locally&lt;/code&gt; line gets printed on your terminal.&lt;/li&gt;
&lt;li&gt;The daemon then reaches out to the default public registry which is Docker Hub and pulls in the latest copy of the &lt;code&gt;hello-world&lt;/code&gt; image, indicated by the &lt;code&gt;latest: Pulling from library/hello-world&lt;/code&gt; line in your terminal.&lt;/li&gt;
&lt;li&gt;Docker daemon then creates a new container from the freshly pulled image.&lt;/li&gt;
&lt;li&gt;Finally Docker daemon runs the container created using the &lt;code&gt;hello-world&lt;/code&gt; image outputting the wall of text on your terminal.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It&amp;rsquo;s the default behavior of Docker daemon to look for images in the hub, that are not present locally. But once an image has been fetched, it&amp;rsquo;ll stay in the local cache. So if you execute the command again, you won&amp;rsquo;t see the following lines in the output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Unable to find image &amp;#39;hello-world:latest&amp;#39; locally
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;latest: Pulling from library/hello-world
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0e03bdcc26d7: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Digest: sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Status: Downloaded newer image for hello-world:latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If there is a newer version of the image available on the public registry, the daemon will fetch the image again. That &lt;code&gt;:latest&lt;/code&gt; is a tag. Images usually have meaningful tags to indicate versions or builds. You&amp;rsquo;ll learn about this in greater detail later on.&lt;/p&gt;
&lt;h1 id=&#34;container-manipulation-basics&#34;&gt;Container Manipulation Basics&lt;/h1&gt;
&lt;p&gt;In the previous sections, you&amp;rsquo;ve learned about the building blocks of Docker and have also run a container using the &lt;code&gt;docker run&lt;/code&gt; command. In this section, you&amp;rsquo;ll be learning about container manipulation in a lot more detail. Container manipulation is one of the most common task you&amp;rsquo;ll be performing every single day so having a proper understanding of the various commands is crucial.&lt;/p&gt;
&lt;p&gt;Keep in mind though, this is not an exhaustive list of all the commands you can execute on Docker. I&amp;rsquo;ll be talking only about the most common ones. Anytime you want to learn more about the available commands, just visit the official &lt;a href=&#34;https://docs.docker.com/engine/reference/commandline/container/&#34;&gt;reference&lt;/a&gt; for the Docker command-line.&lt;/p&gt;
&lt;h2 id=&#34;running-containers&#34;&gt;Running Containers&lt;/h2&gt;
&lt;p&gt;Previously you&amp;rsquo;ve used &lt;code&gt;docker run&lt;/code&gt; to create and start a container using the &lt;code&gt;hello-world&lt;/code&gt; image. The generic syntax for this command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker run &amp;lt;image name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although this is a perfectly valid command, there is a better way of dispatching commands to the &lt;code&gt;docker&lt;/code&gt; daemon. Prior to version &lt;code&gt;1.13&lt;/code&gt;, Docker had only the previously mentioned command syntax. Later on, the command-line was &lt;a href=&#34;https://www.docker.com/blog/whats-new-in-docker-1-13/&#34;&gt;restructured&lt;/a&gt; to have the following syntax:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker &amp;lt;object-type&amp;gt; &amp;lt;command&amp;gt; &amp;lt;options&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this syntax:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;object-type&lt;/code&gt; indicates the type of Docker object you&amp;rsquo;ll be manipulating. This can be a &lt;code&gt;container&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt;, &lt;code&gt;network&lt;/code&gt; or &lt;code&gt;volume&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;command&lt;/code&gt; indicates the task to be carried out by the daemon i.e. &lt;code&gt;run&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;options&lt;/code&gt; can be any valid parameter that can override the default behavior of the command i.e. the &lt;code&gt;--publish&lt;/code&gt; option for port mapping.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, following this syntax, the &lt;code&gt;run&lt;/code&gt; command can be written as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run &amp;lt;image name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;image name&lt;/code&gt; can be of any image from an online registry or your local system. As an example, you can try to run a container using the &lt;a href=&#34;https://hub.docker.com/r/fhsinchy/hello-dock&#34;&gt;fhsinchy/hello-dock&lt;/a&gt; image. This image contains a simple &lt;a href=&#34;https://vuejs.org/&#34;&gt;Vue.js&lt;/a&gt; application that runs on port 80 inside the container. To run a container using this image, execute following command on your terminal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --publish 8080:80 fhsinchy/hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# /docker-entrypoint.sh: Configuration complete; ready for start up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command is pretty self-explanatory. The only portion that may require some explanation is the &lt;code&gt;--publish 8080:80&lt;/code&gt; portion which will be explained in the next sub-section.&lt;/p&gt;
&lt;h2 id=&#34;publishing-ports&#34;&gt;Publishing Ports&lt;/h2&gt;
&lt;p&gt;Containers are isolated environments. Your host system doesn&amp;rsquo;t know anything about what&amp;rsquo;s going on inside a container. Hence, applications running inside a container remains inaccessible from the outside.&lt;/p&gt;
&lt;p&gt;To allow access from outside of a container, you must publish the appropriate port inside the container to a port on your local network. The common syntax for the &lt;code&gt;--publish&lt;/code&gt; or &lt;code&gt;-p&lt;/code&gt; option is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--publish &amp;lt;host port&amp;gt;:&amp;lt;container port&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When you wrote &lt;code&gt;--publish 8080:80&lt;/code&gt; in the previous sub-section, it meant any request sent to port 8080 of your host system will be forwarded to port 80 inside the container.&lt;/p&gt;
&lt;p&gt;Now to access the application on your browser, visit &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; address.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/container-manipulation-basics/hello-dock.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The container can be stopped by simply hitting &lt;code&gt;ctrl + c&lt;/code&gt; key combination while the terminal window is in focus or closing off the terminal window completely.&lt;/p&gt;
&lt;h2 id=&#34;detached-mode&#34;&gt;Detached Mode&lt;/h2&gt;
&lt;p&gt;Another very popular option of the &lt;code&gt;run&lt;/code&gt; command is the &lt;code&gt;--detach&lt;/code&gt; or &lt;code&gt;-d&lt;/code&gt; option. In the example above, in order for the container to keep running, you had to keep the terminal window open. Closing the terminal window also stopped the running container.&lt;/p&gt;
&lt;p&gt;This is because by default containers run in the foreground and attach themselves to the terminal like any other normal program invoked from the terminal. In order to override this behavior and keep a container running in background, you can include the &lt;code&gt;--detach&lt;/code&gt; option to the &lt;code&gt;run&lt;/code&gt; command as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --detach --publish 8080:80 fhsinchy/hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 9f21cb77705810797c4b847dbd330d9c732ffddba14fb435470567a7a3f46cdc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unlike the previous example, you won&amp;rsquo;t get a wall of text thrown at you this time. Instead what you&amp;rsquo;ll get is the ID of the newly created container.&lt;/p&gt;
&lt;p&gt;The order of the options you provide doesn&amp;rsquo;t really matter. If you put the &lt;code&gt;--publish&lt;/code&gt; option before the &lt;code&gt;--detach&lt;/code&gt; option, it&amp;rsquo;ll work just the same. One thing that you have to keep in mind in case of the &lt;code&gt;run&lt;/code&gt; command is that the image name must come last. If you put anything after the image name then that&amp;rsquo;ll be passed as an argument to the container entry-point (explained in the &lt;a href=&#34;/posts/the-docker-handbook/#executing-commands-inside-a-container&#34;&gt;Executing Commands Inside a Container&lt;/a&gt; sub-section) and may result in unexpected situations.&lt;/p&gt;
&lt;h2 id=&#34;listing-containers&#34;&gt;Listing Containers&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;container ls&lt;/code&gt; command can be used to list out containers that are currently running. To do so execute following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 9f21cb777058        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   5 seconds ago       Up 5 seconds        0.0.0.0:8080-&amp;gt;80/tcp   gifted_sammet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see in the output, a container named &lt;code&gt;gifted_sammet&lt;/code&gt; is running. It was created &lt;code&gt;5 seconds ago&lt;/code&gt; and the status is the status is &lt;code&gt;Up 5 seconds,&lt;/code&gt; which indicates that the container is running fine since it&amp;rsquo;s creation.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;CONTAINER ID&lt;/code&gt; is &lt;code&gt;9f21cb777058&lt;/code&gt; which is the first 12 characters of the full container ID. The full container ID is:
&lt;code&gt;9f21cb77705810797c4b847dbd330d9c732ffddba14fb435470567a7a3f46cdc&lt;/code&gt; which is 64 characters long. This full container ID was printed as the output of the &lt;code&gt;docker container run&lt;/code&gt; command in the previous section.&lt;/p&gt;
&lt;p&gt;Listed under the &lt;code&gt;PORTS&lt;/code&gt; column, port 8080 from your local network is pointing towards port 80 inside the container. The name &lt;code&gt;gifted_sammet&lt;/code&gt; is generated by Docker and can be something completely different in your computer.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;container ls&lt;/code&gt; command only lists the containers that are currently running on your system. In order to list out the containers that has run in the past you can use the &lt;code&gt;--all&lt;/code&gt; or &lt;code&gt;-a&lt;/code&gt; option.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls --all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                     PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 9f21cb777058        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   2 minutes ago       Up 2 minutes               0.0.0.0:8080-&amp;gt;80/tcp   gifted_sammet
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 6cf52771dde1        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   3 minutes ago       Exited (0) 3 minutes ago                          reverent_torvalds
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 128ec8ceab71        hello-world           &amp;#34;/hello&amp;#34;                 4 minutes ago       Exited (0) 4 minutes ago                          exciting_chebyshev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see the second container in the list &lt;code&gt;reverent_torvalds&lt;/code&gt; was created earlier and has exited with the status code 0, which indicates that no error was produced during the runtime of the container.&lt;/p&gt;
&lt;h2 id=&#34;naming-or-renaming-containers&#34;&gt;Naming or Renaming Containers&lt;/h2&gt;
&lt;p&gt;By default, every container has two identifiers. They are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CONTAINER ID&lt;/code&gt; - a random 64 characters long string.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NAME&lt;/code&gt; - combination of two random words, joined with an underscore.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Referring to a container based on these two random identifier is kind of inconvenient. It would be great if the containers could be referred to using a name defined by you.&lt;/p&gt;
&lt;p&gt;Naming a container can be achieved using the &lt;code&gt;--name&lt;/code&gt; option. To run another container using the &lt;code&gt;fhsinchy/hello-dock&lt;/code&gt; image with the name &lt;code&gt;hello-dock-container&lt;/code&gt; you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --detach --publish 8888:80 --name hello-dock-container fhsinchy/hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b1db06e400c4c5e81a93a64d30acc1bf821bed63af36cab5cdb95d25e114f5fb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The 8080 port on local network is occupied by the &lt;code&gt;gifted_sammet&lt;/code&gt; container (the container created in the previous sub-section), that&amp;rsquo;s why you&amp;rsquo;ll have to use a different port number i.e. 8888. Now to verify, run the &lt;code&gt;container ls&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b1db06e400c4        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   28 seconds ago      Up 26 seconds       0.0.0.0:8888-&amp;gt;80/tcp   hello-dock-container
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 9f21cb777058        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   4 minutes ago       Up 4 minutes        0.0.0.0:8080-&amp;gt;80/tcp   gifted_sammet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, a new container with the name of &lt;code&gt;hello-dock-container&lt;/code&gt; has been started.&lt;/p&gt;
&lt;p&gt;You can even rename old containers using the &lt;code&gt;container rename&lt;/code&gt; command. Syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container rename &amp;lt;container identifier&amp;gt; &amp;lt;new name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To rename the &lt;code&gt;gifted_sammet&lt;/code&gt; container to &lt;code&gt;hello-dock-container-2&lt;/code&gt; execute following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container rename gifted_sammet hello-dock-container-2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command doesn&amp;rsquo;t yield any output but you can verify that the changes have taken place using the &lt;code&gt;container ls&lt;/code&gt; command. The &lt;code&gt;rename&lt;/code&gt; command works for containers both in running state and stopped state.&lt;/p&gt;
&lt;h2 id=&#34;stopping-or-killing-a-running-container&#34;&gt;Stopping or Killing a Running Container&lt;/h2&gt;
&lt;p&gt;Containers running in the foreground can be stopped by simply closing the terminal window or hitting &lt;code&gt;ctrl + c&lt;/code&gt; key combination. Containers running in the background, however, can not be stopped in the same way.&lt;/p&gt;
&lt;p&gt;There are two commands that deal with this task. The first one is the &lt;code&gt;container stop&lt;/code&gt; command. Generic syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container stop &amp;lt;container identifier&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where &lt;code&gt;container identifier&lt;/code&gt; can either be the id or the name of the container. I hope that you remember the container you started in the previous section. It&amp;rsquo;s still running in the background. Get the identifier for that container using &lt;code&gt;docker container ls&lt;/code&gt; , I&amp;rsquo;ll be using &lt;code&gt;hello-dock-container&lt;/code&gt; container for this demo. Now execute following command to stop the container:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container stop hello-dock-container
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# hello-dock-container
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you use the name as identifier, you&amp;rsquo;ll get the name thrown back to you as output. The &lt;code&gt;stop&lt;/code&gt; command shuts down a container gracefully by sending a &lt;code&gt;SIGTERM&lt;/code&gt; signal. If the container doesn&amp;rsquo;t stop within a certain period, a &lt;code&gt;SIGKILL&lt;/code&gt; signal is sent which shuts down the container immediately.&lt;/p&gt;
&lt;p&gt;In cases where you want to send a &lt;code&gt;SIGKILL&lt;/code&gt; signal instead of a &lt;code&gt;SIGTERM&lt;/code&gt; signal, you may use the &lt;code&gt;container kill&lt;/code&gt; command instead. The &lt;code&gt;container kill&lt;/code&gt; command follows the same syntax as the &lt;code&gt;stop&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container kill hello-dock-container-2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# hello-dock-container-2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;restarting-containers&#34;&gt;Restarting Containers&lt;/h2&gt;
&lt;p&gt;When I say restart I mean two scenarios specifically. They are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restarting a container that has been previously stopped or killed.&lt;/li&gt;
&lt;li&gt;Rebooting a running container.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you&amp;rsquo;ve already learned from a previous sub-section, stopped containers remain in your system. If you want you can restart them. The &lt;code&gt;container start&lt;/code&gt; command can be used to start any stopped or killed container. The syntax of the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container start &amp;lt;container identifier&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can get the list of all containers by executing the &lt;code&gt;container ls --all&lt;/code&gt; command. Then look for the containers with &lt;code&gt;Exited&lt;/code&gt; status.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls --all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                        PORTS               NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b1db06e400c4        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   3 minutes ago       Exited (0) 47 seconds ago                         hello-dock-container
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 9f21cb777058        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   7 minutes ago       Exited (137) 17 seconds ago                       hello-dock-container-2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 6cf52771dde1        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   7 minutes ago       Exited (0) 7 minutes ago                          reverent_torvalds
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 128ec8ceab71        hello-world           &amp;#34;/hello&amp;#34;                 9 minutes ago       Exited (0) 9 minutes ago                          exciting_chebyshev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now to restart the &lt;code&gt;hello-dock-container&lt;/code&gt; container, you may execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container start hello-dock-container
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# hello-dock-container
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you can ensure that the container is running by looking at the list of running containers using the &lt;code&gt;container ls&lt;/code&gt; command. The &lt;code&gt;container start&lt;/code&gt; command starts any container in detached mode by default and retains any port configurations made previously. So if you visit &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; now, you should be able to access the &lt;code&gt;hello-dock&lt;/code&gt; application just like before.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/container-manipulation-basics/hello-dock.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now, in scenarios where you would like to reboot a running container you may use the &lt;code&gt;container restart&lt;/code&gt; command. The &lt;code&gt;container restart&lt;/code&gt; command follows the exact syntax as the &lt;code&gt;container start&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container restart hello-dock-container-2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# hello-dock-container-2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Main difference between the two commands is that the &lt;code&gt;container restart&lt;/code&gt; command attempts to stop the target container and then starts it back whereas the start command just starts a already stopped container.&lt;/p&gt;
&lt;p&gt;In case of a stopped container, both commands are exactly same but in case of a running container, you must use the &lt;code&gt;container restart&lt;/code&gt; command.&lt;/p&gt;
&lt;h2 id=&#34;creating-containers-without-running&#34;&gt;Creating Containers Without Running&lt;/h2&gt;
&lt;p&gt;So far in this section, you&amp;rsquo;ve started containers using the &lt;code&gt;container run&lt;/code&gt; command which is in reality a combination of two separate commands. These commands are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;container create&lt;/code&gt; command creates a container from a given image.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;container start&lt;/code&gt; command starts a container that has been already created.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, to perform the demonstration shown in the &lt;a href=&#34;/posts/the-docker-handbook/#running-containers&#34;&gt;Running Containers&lt;/a&gt; section using these two commands, you can do something like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container create --publish 8080:80 fhsinchy/hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2e7ef5098bab92f4536eb9a372d9b99ed852a9a816c341127399f51a6d053856
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls --all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS               NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2e7ef5098bab        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   30 seconds ago      Created                                 hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Evident by the output of &lt;code&gt;container ls --all&lt;/code&gt; command, a container with the name of &lt;code&gt;hello-dock&lt;/code&gt; has been created using the &lt;code&gt;fhsinchy/hello-dock&lt;/code&gt; image. The &lt;code&gt;STATUS&lt;/code&gt; of the container is &lt;code&gt;Created&lt;/code&gt; at the moment and given it&amp;rsquo;s not running, it won&amp;rsquo;t be listed without the use of the &lt;code&gt;--all&lt;/code&gt; option. Once the container has been created, it can be started using the &lt;code&gt;container start&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container start hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE                 COMMAND                  CREATED              STATUS              PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2e7ef5098bab        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   About a minute ago   Up 29 seconds       0.0.0.0:8080-&amp;gt;80/tcp   hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The container &lt;code&gt;STATUS&lt;/code&gt; has changed from &lt;code&gt;Created&lt;/code&gt; to &lt;code&gt;Up 29 seconds&lt;/code&gt; which indicates that the container is now in running state. The port configuration has also showed up in the &lt;code&gt;PORTS&lt;/code&gt; column which was previously empty.&lt;/p&gt;
&lt;p&gt;Although you can get away with the &lt;code&gt;container run&lt;/code&gt; command for majority of the scenarios, there will be some situations later on in the article that requires the usage of this &lt;code&gt;container create&lt;/code&gt; command.&lt;/p&gt;
&lt;h2 id=&#34;removing-dangling-containers&#34;&gt;Removing Dangling Containers&lt;/h2&gt;
&lt;p&gt;As you&amp;rsquo;ve already seen, containers that have been stopped or killed remain in the system. These dangling containers can take up space or can conflict with newer containers.&lt;/p&gt;
&lt;p&gt;In order to remove a stopped container you can use the &lt;code&gt;container rm&lt;/code&gt; command. The generic syntax is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container rm &amp;lt;container identifier&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To find out which containers are not running, use the &lt;code&gt;container ls --all&lt;/code&gt; command and look for containers with &lt;code&gt;Exited&lt;/code&gt; status.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls --all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                      PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b1db06e400c4        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   6 minutes ago       Up About a minute           0.0.0.0:8888-&amp;gt;80/tcp   hello-dock-container
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 9f21cb777058        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   10 minutes ago      Up About a minute           0.0.0.0:8080-&amp;gt;80/tcp   hello-dock-container-2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 6cf52771dde1        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   10 minutes ago      Exited (0) 10 minutes ago                          reverent_torvalds
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 128ec8ceab71        hello-world           &amp;#34;/hello&amp;#34;                 12 minutes ago      Exited (0) 12 minutes ago                          exciting_chebyshev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen in the output, container with ID &lt;code&gt;6cf52771dde1&lt;/code&gt; and &lt;code&gt;128ec8ceab71&lt;/code&gt; is not running. To remove the &lt;code&gt;6cf52771dde1&lt;/code&gt; you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container rm 6cf52771dde1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 6cf52771dde1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can check if the container was deleted or not by using the &lt;code&gt;container ls&lt;/code&gt; command. You can also remove multiple containers at once by passing their identifiers one after another separated by spaces.&lt;/p&gt;
&lt;p&gt;Or, instead of removing individual containers, if you want to remove all dangling containers at one go, you can use the &lt;code&gt;container prune&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container prune
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Docker will ask for confirmation. You can use the &lt;code&gt;--force&lt;/code&gt; or &lt;code&gt;-f&lt;/code&gt; option to skip this confirmation step. Once done, the &lt;code&gt;container prune&lt;/code&gt; command will show the amount of reclaimed space.&lt;/p&gt;
&lt;p&gt;You can check the container list using the &lt;code&gt;container ls --all&lt;/code&gt; command to make sure that the dangling containers have been removed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls --all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b1db06e400c4        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   8 minutes ago       Up 3 minutes        0.0.0.0:8888-&amp;gt;80/tcp   hello-dock-container
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 9f21cb777058        fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   12 minutes ago      Up 3 minutes        0.0.0.0:8080-&amp;gt;80/tcp   hello-dock-container-2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are following the article exactly as written so far, you should only see the &lt;code&gt;hello-dock-container&lt;/code&gt; and &lt;code&gt;hello-dock-container-2&lt;/code&gt; in the list. I would suggest stopping and removing both containers before going to the next section.&lt;/p&gt;
&lt;p&gt;There is also the &lt;code&gt;--rm&lt;/code&gt; option for the &lt;code&gt;container run&lt;/code&gt; and &lt;code&gt;container start&lt;/code&gt; commands which indicates that you want the containers removed as soon as they&amp;rsquo;re stopped. To start another &lt;code&gt;hello-dock&lt;/code&gt; container with the &lt;code&gt;--rm&lt;/code&gt; option, execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --rm --detach --publish 8888:80 --name hello-dock-volatile fhsinchy/hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 0d74e14091dc6262732bee226d95702c21894678efb4043663f7911c53fb79f3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can use the &lt;code&gt;container ls&lt;/code&gt; command to verify that the container is running:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID   IMAGE                 COMMAND                  CREATED              STATUS              PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 0d74e14091dc   fhsinchy/hello-dock   &amp;#34;/docker-entrypoint.…&amp;#34;   About a minute ago   Up About a minute   0.0.0.0:8888-&amp;gt;80/tcp   hello-dock-volatile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if stop the container and then check again with the &lt;code&gt;container ls --all&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container stop hello-dock-volatile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# hello-dock-volatile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls --all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The container has been removed automatically. From now on I&amp;rsquo;ll use the &lt;code&gt;--rm&lt;/code&gt; option for most of the containers. I&amp;rsquo;ll explicitly mention where it&amp;rsquo;s not needed.&lt;/p&gt;
&lt;h2 id=&#34;running-containers-in-interactive-mode&#34;&gt;Running Containers in Interactive Mode&lt;/h2&gt;
&lt;p&gt;So far you&amp;rsquo;ve only run containers created from either the &lt;a href=&#34;https://hub.docker.com/_/hello-world&#34;&gt;hello-world&lt;/a&gt; image or the &lt;a href=&#34;https://hub.docker.com/r/fhsinchy/hello-dock&#34;&gt;fhsinchy/hello-dock&lt;/a&gt; image. These images are made for executing simple programs that are not interactive.&lt;/p&gt;
&lt;p&gt;Well, all images are not that simple. Images can encapsulate an entire Linux distribution inside them. Popular distributions such as &lt;a href=&#34;https://ubuntu.com/&#34;&gt;Ubuntu&lt;/a&gt;, &lt;a href=&#34;https://fedora.org/&#34;&gt;Fedora&lt;/a&gt;, &lt;a href=&#34;https://debian.org/&#34;&gt;Debian&lt;/a&gt; all have official Docker images available in the hub. Programming languages such as &lt;a href=&#34;https://hub.docker.com/_/python&#34;&gt;python&lt;/a&gt;, &lt;a href=&#34;https://hub.docker.com/_/php&#34;&gt;php&lt;/a&gt;, &lt;a href=&#34;https://hub.docker.com/_/golang&#34;&gt;go&lt;/a&gt; or run-times like &lt;a href=&#34;https://hub.docker.com/_/node&#34;&gt;node&lt;/a&gt;, &lt;a href=&#34;https://hub.docker.com/r/hayd/deno&#34;&gt;deno&lt;/a&gt; all have their official images.&lt;/p&gt;
&lt;p&gt;These images do not just run some pre-configured program. These are instead configured to run a shell by default. In case of the operating system images it can be something like &lt;code&gt;sh&lt;/code&gt; or &lt;code&gt;bash&lt;/code&gt; and in case of the programming languages or run-times, it is usually their default language shell.&lt;/p&gt;
&lt;p&gt;As you may have already learned from your previous experiences with computers, shells are interactive programs. Images configured to run such a program are interactive images. These images require a special &lt;code&gt;-it&lt;/code&gt; option to be passed in the &lt;code&gt;container run&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;As an example, if you run a container using the &lt;code&gt;ubuntu&lt;/code&gt; image by executing &lt;code&gt;docker container run ubuntu&lt;/code&gt; you&amp;rsquo;ll see nothing happens. But if you execute the same command with &lt;code&gt;-it&lt;/code&gt; option, you should land directly on bash inside the Ubuntu container.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --rm -it ubuntu
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# root@dbb1f56b9563:/# cat /etc/os-release
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# NAME=&amp;#34;Ubuntu&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# VERSION=&amp;#34;20.04.1 LTS (Focal Fossa)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ID=ubuntu
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ID_LIKE=debian
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# PRETTY_NAME=&amp;#34;Ubuntu 20.04.1 LTS&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# VERSION_ID=&amp;#34;20.04&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# HOME_URL=&amp;#34;https://www.ubuntu.com/&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# SUPPORT_URL=&amp;#34;https://help.ubuntu.com/&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# BUG_REPORT_URL=&amp;#34;https://bugs.launchpad.net/ubuntu/&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# PRIVACY_POLICY_URL=&amp;#34;https://www.ubuntu.com/legal/terms-and-policies/privacy-policy&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# VERSION_CODENAME=focal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# UBUNTU_CODENAME=focal
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see from the output of the &lt;code&gt;cat /etc/os-release&lt;/code&gt; command, I am indeed interacting with the bash running inside the Ubuntu container.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-it&lt;/code&gt; option sets the stage for you to interact with any interactive program inside a container. This option is actually two separate options mashed together.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;-i&lt;/code&gt; or &lt;code&gt;--interactive&lt;/code&gt; option connects you to the input stream of the container, so that you can send inputs to bash.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;-t&lt;/code&gt; or &lt;code&gt;--tty&lt;/code&gt; option makes sure that you get some good formatting and a native terminal like experience by allocating a pseudo-tty.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You need to use the &lt;code&gt;-it&lt;/code&gt; option whenever you want to run a container in interactive mode. Another example can be running the &lt;code&gt;node&lt;/code&gt; image as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run -it node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Welcome to Node.js v15.0.0.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Type &amp;#34;.help&amp;#34; for more information.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;gt; [&amp;#39;farhan&amp;#39;, &amp;#39;hasin&amp;#39;, &amp;#39;chowdhury&amp;#39;].map(name =&amp;gt; name.toUpperCase())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# [ &amp;#39;FARHAN&amp;#39;, &amp;#39;HASIN&amp;#39;, &amp;#39;CHOWDHURY&amp;#39; ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, any valid JavaScript code can be executed in the node shell. Instead of writing &lt;code&gt;-it&lt;/code&gt; you can instead be more verbose by writing &lt;code&gt;--interactive --tty&lt;/code&gt; separately.&lt;/p&gt;
&lt;h2 id=&#34;executing-commands-inside-a-container&#34;&gt;Executing Commands Inside a Container&lt;/h2&gt;
&lt;p&gt;In the &lt;a href=&#34;/posts/the-docker-handbook/#hello-world-in-docker&#34;&gt;Hello World in Docker&lt;/a&gt; section of this article, you&amp;rsquo;ve seen me executing a command inside an Alpine Linux container. It went something like as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker run alpine uname -a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Linux f08dbbe9199b 5.8.0-22-generic #23-Ubuntu SMP Fri Oct 9 00:34:40 UTC 2020 x86_64 Linux
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this command, I&amp;rsquo;ve executed the &lt;code&gt;uname -a&lt;/code&gt; command inside an Alpine Linux container. Scenarios like this where all you want is to execute a certain command inside a certain container is pretty common.&lt;/p&gt;
&lt;p&gt;Assume that you want encode a string using the &lt;code&gt;base64&lt;/code&gt; program which is something available in almost any Linux or Unix based operating system but not on Windows. In this situation you can quickly spin up a container using images like &lt;a href=&#34;https://hub.docker.com/_/busybox&#34;&gt;busybox&lt;/a&gt; and let it do the job.&lt;/p&gt;
&lt;p&gt;The generic syntax for encoding a string using &lt;code&gt;base64&lt;/code&gt; is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo -n my-secret | base64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# bXktc2VjcmV0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the generic syntax for passing a command to a container that is not running is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run &amp;lt;image name&amp;gt; &amp;lt;command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To perform the base64 encoding using the busybox image, you can execute following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --rm busybox sh -c &amp;#34;echo -n my-secret | base64&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# bXktc2VjcmV0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What happens here is, in a &lt;code&gt;container run&lt;/code&gt; command, whatever you pass after the image name gets passed to the default entry-point of the image. An entrypoint is like a gateway to the image. Most of the images except the executable images (explained in the &lt;a href=&#34;/posts/the-docker-handbook/#working-with-executable-images&#34;&gt;Working With Executable Images&lt;/a&gt; sub-section), uses shell or &lt;code&gt;sh&lt;/code&gt; as the default entry-point. So any valid shell command can be passed to them as arguments.&lt;/p&gt;
&lt;h2 id=&#34;working-with-executable-images&#34;&gt;Working With Executable Images&lt;/h2&gt;
&lt;p&gt;In the previous section, I briefly mentioned executable images. These images are designed in a way to behave like executable programs.&lt;/p&gt;
&lt;p&gt;Take for example my &lt;a href=&#34;https://github.com/fhsinchy/rmbyext&#34;&gt;rmbyext&lt;/a&gt; project. This is a simple python script capable of recursively deleting files of given extensions. To learn more about the project, you can checkout the repository:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/fhsinchy/rmbyext&#34;&gt;https://github.com/fhsinchy/rmbyext&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you have both git and python installed, you can install this script by executing the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install git+https://github.com/fhsinchy/rmbyext.git#egg=rmbyext
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Assuming python has been set-up properly on your system, the script should be available anywhere through the terminal. The generic syntax for using this script is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rmbyext &amp;lt;file extension&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To test it out, open up your terminal inside an empty directory and create some files in it with different extensions. You can use the &lt;code&gt;touch&lt;/code&gt; command to do so. Now, I have a directory on my computer with following files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;touch a.pdf b.pdf c.txt d.pdf e.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# a.pdf  b.pdf  c.txt  d.pdf  e.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To delete all the &lt;code&gt;pdf&lt;/code&gt; files from this directory, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rmbyext pdf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing: PDF
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# a.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# d.pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An executable image for this program should be able to take extensions of files as arguments and delete them just like the &lt;code&gt;rmbyext&lt;/code&gt; program did.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://hub.docker.com/r/fhsinchy/rmbyext&#34;&gt;fhsinchy/rmbyext&lt;/a&gt; image behaves in a similar manner. This image contains a copy of the &lt;code&gt;rmbyext&lt;/code&gt; script and is configured to run the script on a directory &lt;code&gt;/zone&lt;/code&gt; inside the container.&lt;/p&gt;
&lt;p&gt;Now the problem is that containers are isolated from your local system, hence the &lt;code&gt;rmbyext&lt;/code&gt; program running inside the container doesn&amp;rsquo;t have any access to your local file system. So, if somehow you can map the local directory containing the &lt;code&gt;pdf&lt;/code&gt; files to the &lt;code&gt;/zone&lt;/code&gt; directory inside the container, the files should be accessible to the container.&lt;/p&gt;
&lt;p&gt;One way to grant a container direct access to your local file system is by using &lt;a href=&#34;https://docs.docker.com/storage/bind-mounts/&#34;&gt;bind mounts&lt;/a&gt;. A bind mount lets you form a two way data binding between the content of a local file system directory (source) and another directory inside a container (destination). This way any changes made in the destination directory will take effect on the source directory and vise versa.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see a bind mount in action. To delete files using this image instead of the program itself, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --rm -v $(pwd):/zone fhsinchy/rmbyext pdf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing: PDF
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# a.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# d.pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you may have already guessed by seeing the &lt;code&gt;-v $(pwd):/zone&lt;/code&gt; part in the command, &lt;code&gt;-v&lt;/code&gt; or &lt;code&gt;--volume&lt;/code&gt; option is used for creating a bind mount for a container. This option can take three fields separated by colons (&lt;code&gt;:&lt;/code&gt;). The generic syntax for the option is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--volume &amp;lt;local file system directory absolute path&amp;gt;:&amp;lt;container file system directory absolute path&amp;gt;:&amp;lt;read write access&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The third field is optional but you must pass the absolute path of your local directory and the absolute path of the directory inside the container. The source directory in my case is &lt;code&gt;/home/fhsinchy/the-zone&lt;/code&gt; and given my terminal is opened inside the directory, &lt;code&gt;$(pwd)&lt;/code&gt; will be replaced with &lt;code&gt;/home/fhsinchy/the-zone&lt;/code&gt; which contains the previously mentioned &lt;code&gt;.pdf&lt;/code&gt; and &lt;code&gt;.txt&lt;/code&gt; files. You can learn more about &lt;a href=&#34;https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html&#34;&gt;command substitution&lt;/a&gt; if you want to.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--volume&lt;/code&gt; or &lt;code&gt;-v&lt;/code&gt; option is valid for the &lt;code&gt;container run&lt;/code&gt; as well as the &lt;code&gt;container create&lt;/code&gt; commands. Volumes will be explored in greater detail in the upcoming sections so don&amp;rsquo;t worry if you didn&amp;rsquo;t understand it very well here.&lt;/p&gt;
&lt;p&gt;The difference between a regular image and an executable one is that the entry-point for an executable image is set to a custom program instead of &lt;code&gt;sh&lt;/code&gt;, in this case the &lt;code&gt;rmbyext&lt;/code&gt; program and as you&amp;rsquo;ve learned in the previous sub-section, anything you write after the image name in a &lt;code&gt;container run&lt;/code&gt; command gets passed to the entry-point of the image.&lt;/p&gt;
&lt;p&gt;So in the end the &lt;code&gt;docker container run --rm -v $(pwd):/zone fhsinchy/rmbyext pdf&lt;/code&gt; command translates to &lt;code&gt;rmbyext pdf&lt;/code&gt; inside the container. Executable images are not that common in the wild but can be very useful in certain cases, hence learning about them is important.&lt;/p&gt;
&lt;h1 id=&#34;image-manipulation-basics&#34;&gt;Image Manipulation Basics&lt;/h1&gt;
&lt;p&gt;Now that you&amp;rsquo;ve a solid understanding of running containers using images available publicly, it&amp;rsquo;s time for you to learn about creating your very own images.&lt;/p&gt;
&lt;p&gt;In this section, you&amp;rsquo;ll learn the fundamentals of creating images, running containers using them and sharing them online.&lt;/p&gt;
&lt;p&gt;I would suggest you to install &lt;a href=&#34;https://code.visualstudio.com/&#34;&gt;Visual Studio Code&lt;/a&gt; with the official &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker&#34;&gt;Docker Extension&lt;/a&gt; from the marketplace. This will greatly help your development experience.&lt;/p&gt;
&lt;h2 id=&#34;image-creation-basics&#34;&gt;Image Creation Basics&lt;/h2&gt;
&lt;p&gt;As I&amp;rsquo;ve already explained in the &lt;a href=&#34;/posts/the-docker-handbook/#image&#34;&gt;Hello World in Docker&lt;/a&gt; section, images are multi-layered self-contained files that act as the template for creating Docker containers. They are like a frozen, read-only copy of a container.&lt;/p&gt;
&lt;p&gt;In order to create an image using one of your programs you must have a clear vision of what you want from the image. Take the official &lt;a href=&#34;https://hub.docker.com/_/nginx&#34;&gt;nginx&lt;/a&gt; image for example. You can start a container using this image simply by executing the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --rm --detach --name default-nginx --publish 8080:80 nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b379ecd5b6b9ae27c144e4fa12bdc5d0635543666f75c14039eea8d5f38e3f56
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b379ecd5b6b9        nginx               &amp;#34;/docker-entrypoint.…&amp;#34;   8 seconds ago       Up 8 seconds        0.0.0.0:8080-&amp;gt;80/tcp   default-nginx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if you visit &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; in the browser, you&amp;rsquo;ll see a default response page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/image-manipulation-basics/nginx-default.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all nice and good, but what if you want to make a custom NGINX image which functions exactly like the official one, but is built by you? That&amp;rsquo;s completely valid scenario to be honest. In fact, let&amp;rsquo;s do that.&lt;/p&gt;
&lt;p&gt;In order to make a custom NGINX image, you must have a clear picture of what the final state of the image will be. In my opinion the image should be as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The image should have NGINX pre-installed which can be done using a package manager or can be built from source.&lt;/li&gt;
&lt;li&gt;The image should start NGINX automatically upon running.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s simple. If you&amp;rsquo;ve cloned the project repository linked in this article, go inside the project root and look for a directory named &lt;code&gt;custom-nginx&lt;/code&gt; in there. Now, create a new file named &lt;code&gt;Dockerfile&lt;/code&gt; inside that directory. A &lt;code&gt;Dockerfile&lt;/code&gt; is a collection of instructions that once processed by the daemon, results into an image. Content for the &lt;code&gt;Dockerfile&lt;/code&gt; is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM ubuntu:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EXPOSE 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN apt-get update &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get install nginx -y &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Images are multi-layered files and in this file, each line (known as instructions) that you&amp;rsquo;ve written, creates a layer for your image.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every valid &lt;code&gt;Dockerfile&lt;/code&gt; starts with a &lt;code&gt;FROM&lt;/code&gt; instruction. This instruction sets the base image for your resultant image. By setting &lt;code&gt;ubuntu:latest&lt;/code&gt; as the base image here, you get all the goodness of Ubuntu already available in your custom image hence, you can use things like the &lt;code&gt;apt-get&lt;/code&gt; command for easy package installation.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;EXPOSE&lt;/code&gt; instruction is used to indicate the port that needs to be published. Using this instruction doesn&amp;rsquo;t mean that you won&amp;rsquo;t need to &lt;code&gt;--publish&lt;/code&gt; the port. You&amp;rsquo;ll still need to use the &lt;code&gt;--publish&lt;/code&gt; option explicitly. This &lt;code&gt;EXPOSE&lt;/code&gt; instruction works like a documentation for someone who&amp;rsquo;s trying to run a container using your image. It also has some other usages that I won&amp;rsquo;t be discussing here.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;RUN&lt;/code&gt; instruction in a &lt;code&gt;Dockerfile&lt;/code&gt; executes a command inside the container shell. The &lt;code&gt;apt-get update &amp;amp;&amp;amp; apt-get install nginx -y&lt;/code&gt; command checks for updated package versions and installs NGINX. The &lt;code&gt;apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;/code&gt; command is used for clearing the package cache because you don&amp;rsquo;t want any unnecessary baggage in your image. These two commands are simple Ubuntu stuff, nothing fancy. The &lt;code&gt;RUN&lt;/code&gt; instructions here, are written in &lt;code&gt;shell&lt;/code&gt; form. These can also be written in &lt;code&gt;exec&lt;/code&gt; form. You can consult the &lt;a href=&#34;https://docs.docker.com/engine/reference/builder/#run&#34;&gt;official reference&lt;/a&gt; for more information.&lt;/li&gt;
&lt;li&gt;Finally the &lt;code&gt;CMD&lt;/code&gt; instruction sets the default command for your image. This instruction is written in &lt;code&gt;exec&lt;/code&gt; form here comprising of three separate parts. Here, &lt;code&gt;nginx&lt;/code&gt; refers to the NGINX executable. The &lt;code&gt;-g&lt;/code&gt; and &lt;code&gt;daemon off&lt;/code&gt; are options for NGINX. Running NGINX as a single process inside containers is considered a best practice hence the usage of this option. The &lt;code&gt;CMD&lt;/code&gt; instruction can also be written in &lt;code&gt;shell&lt;/code&gt; form. You can consult the &lt;a href=&#34;https://docs.docker.com/engine/reference/builder/#cmd&#34;&gt;official reference&lt;/a&gt; for more information.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that you have a valid &lt;code&gt;Dockerfile&lt;/code&gt; you can build an image out of it. Just like the container related commands, the image related commands can be issued using the following syntax:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image &amp;lt;command&amp;gt; &amp;lt;options&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To build an image using the &lt;code&gt;Dockerfile&lt;/code&gt; you just wrote, open up your terminal inside the &lt;code&gt;custom-nginx&lt;/code&gt; directory and execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon  3.584kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/4 : FROM ubuntu:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; d70eaf7277ea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/4 : EXPOSE 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 9eae86582ec7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 9eae86582ec7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 8235bd799a56
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/4 : RUN apt-get update &amp;amp;&amp;amp;     apt-get install nginx -y &amp;amp;&amp;amp;     apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in a44725cbb3fa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container a44725cbb3fa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 3066bd20292d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/4 : CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 4792e4691660
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 4792e4691660
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 3199372aa3fc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 3199372aa3fc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To perform an image build, the daemon needs two very specific information. These are the name of the &lt;code&gt;Dockerfile&lt;/code&gt; and the build context. In the issued command above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker image build&lt;/code&gt; is the command for building the image. The daemon finds any file named &lt;code&gt;Dockerfile&lt;/code&gt; within the context.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;.&lt;/code&gt; at the end sets the context for this build. The context means the directory accessible by the daemon during the build process.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now to run a container using this image, you can use the &lt;code&gt;container run&lt;/code&gt; command coupled with the image ID that you received as the result of the build process. In my case the id is &lt;code&gt;3199372aa3fc&lt;/code&gt; evident by the &lt;code&gt;Successfully built 3199372aa3fc&lt;/code&gt; line in the previous code block.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --rm --detach --name custom-nginx-packaged --publish 8080:80 3199372aa3fc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ec09d4e1f70c903c3b954c8d7958421cdd1ae3d079b57f929e44131fbf8069a0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ec09d4e1f70c        3199372aa3fc        &amp;#34;nginx -g &amp;#39;daemon of…&amp;#34;   23 seconds ago      Up 22 seconds       0.0.0.0:8080-&amp;gt;80/tcp   custom-nginx-packaged
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To verify, visit &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; and you should see the default response page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/image-manipulation-basics/nginx-default.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;tagging-images&#34;&gt;Tagging Images&lt;/h2&gt;
&lt;p&gt;Just like containers, you can assign custom identifiers to your images instead of relying on the randomly generated ID. In case of an image, it&amp;rsquo;s called tagging instead of naming. The &lt;code&gt;--tag&lt;/code&gt; or &lt;code&gt;-t&lt;/code&gt; option is used in such cases. Generic syntax for the option is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--tag &amp;lt;image repository&amp;gt;:&amp;lt;image tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The repository is usually known as the image name and tag indicates a certain build or version. Take the official &lt;a href=&#34;https://hub.docker.com/_/mysql&#34;&gt;mysql&lt;/a&gt; image for example. If you want to run a container using a specific version of MySQL i.e. 5.7, you can execute &lt;code&gt;docker container run mysql:5.7&lt;/code&gt; where &lt;code&gt;mysql&lt;/code&gt; is the image repository and &lt;code&gt;5.7&lt;/code&gt; is the tag.&lt;/p&gt;
&lt;p&gt;In order to tag your custom NGINX image with &lt;code&gt;custom-nginx:packaged&lt;/code&gt; you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --tag custom-nginx:packaged .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon  1.055MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/4 : FROM ubuntu:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; f63181f19b2f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/4 : EXPOSE 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 53ab370b9efc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 53ab370b9efc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 6d6460a74447
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/4 : RUN apt-get update &amp;amp;&amp;amp;     apt-get install nginx -y &amp;amp;&amp;amp;     apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in b4951b6b48bb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container b4951b6b48bb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; fdc6cdd8925a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/4 : CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 3bdbd2af4f0e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 3bdbd2af4f0e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; f8837621b99d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built f8837621b99d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged custom-nginx:packaged
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing will change except the fact that you can now refer to your image as &lt;code&gt;custom-nginx:packaged&lt;/code&gt; instead of some long random string.&lt;/p&gt;
&lt;p&gt;In cases where you forgot to tag an image during build time, or maybe you want to change the tag, you can use the &lt;code&gt;image tag&lt;/code&gt; command to do that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image tag &amp;lt;image id&amp;gt; &amp;lt;image repository&amp;gt;:&amp;lt;image tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;## or ##
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image tag &amp;lt;image repository&amp;gt;:&amp;lt;image tag&amp;gt; &amp;lt;new image repository&amp;gt;:&amp;lt;new image tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;listing-and-removing-images&#34;&gt;Listing and Removing Images&lt;/h2&gt;
&lt;p&gt;Just like the &lt;code&gt;container ls&lt;/code&gt; command, you can use the &lt;code&gt;image ls&lt;/code&gt; command to list all the images in your local system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# REPOSITORY     TAG        IMAGE ID       CREATED         SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;lt;none&amp;gt;         &amp;lt;none&amp;gt;     3199372aa3fc   7 seconds ago   132MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# custom-nginx   packaged   f8837621b99d   4 minutes ago   132MB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Images listed here can be deleted using the &lt;code&gt;image rm&lt;/code&gt; command. The generic syntax is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image rm &amp;lt;image identifier&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The identifier can be the image ID or image repository. If you use the repository, you&amp;rsquo;ll have to identify the tag as well. To delete the &lt;code&gt;custom-nginx:packaged&lt;/code&gt; image, you may execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image rm custom-nginx:packaged
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Untagged: custom-nginx:packaged
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Deleted: sha256:f8837621b99d3388a9e78d9ce49fbb773017f770eea80470fb85e0052beae242
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Deleted: sha256:fdc6cdd8925ac25b9e0ed1c8539f96ad89ba1b21793d061e2349b62dd517dadf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Deleted: sha256:c20e4aa46615fe512a4133089a5cd66f9b7da76366c96548790d5bf865bd49c4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Deleted: sha256:6d6460a744475a357a2b631a4098aa1862d04510f3625feb316358536fcd8641
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also use the &lt;code&gt;image prune&lt;/code&gt; command to cleanup all un-tagged dangling images as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image prune --force
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Deleted Images:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# deleted: sha256:ba9558bdf2beda81b9acc652ce4931a85f0fc7f69dbc91b4efc4561ef7378aff
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# deleted: sha256:ad9cc3ff27f0d192f8fa5fadebf813537e02e6ad472f6536847c4de183c02c81
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# deleted: sha256:f1e9b82068d43c1bb04ff3e4f0085b9f8903a12b27196df7f1145aa9296c85e7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# deleted: sha256:ec16024aa036172544908ec4e5f842627d04ef99ee9b8d9aaa26b9c2a4b52baa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Total reclaimed space: 59.19MB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--force&lt;/code&gt; or &lt;code&gt;-f&lt;/code&gt; option skips any confirmation questions. You can also use the &lt;code&gt;--all&lt;/code&gt; or &lt;code&gt;-a&lt;/code&gt; option to remove all cached images in your local registry.&lt;/p&gt;
&lt;h2 id=&#34;understanding-the-many-layers-of-an-image&#34;&gt;Understanding the Many Layers of an Image&lt;/h2&gt;
&lt;p&gt;From the very beginning of this article, I&amp;rsquo;ve been saying that images are multi-layered files. In this sub-section I&amp;rsquo;ll demonstrate the various layers of an image and how they play an important role in the build process of an image. For this demonstration, I&amp;rsquo;ll be using the &lt;code&gt;custom-nginx:packaged&lt;/code&gt; image from the previous sub-section.&lt;/p&gt;
&lt;p&gt;To visualize the many layers of an image, you can use the &lt;code&gt;image history&lt;/code&gt; command. The various layers of the &lt;code&gt;custom-nginx:packaged&lt;/code&gt; image can be visualized as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image history custom-nginx:packaged
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 7f16387f7307        5 minutes ago       /bin/sh -c #(nop)  CMD [&amp;#34;nginx&amp;#34; &amp;#34;-g&amp;#34; &amp;#34;daemon…   0B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 587c805fe8df        5 minutes ago       /bin/sh -c apt-get update &amp;amp;&amp;amp;     apt-get ins…   60MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 6fe4e51e35c1        6 minutes ago       /bin/sh -c #(nop)  EXPOSE 80                    0B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# d70eaf7277ea        17 hours ago        /bin/sh -c #(nop)  CMD [&amp;#34;/bin/bash&amp;#34;]            0B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;lt;missing&amp;gt;           17 hours ago        /bin/sh -c mkdir -p /run/systemd &amp;amp;&amp;amp; echo &amp;#39;do…   7B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;lt;missing&amp;gt;           17 hours ago        /bin/sh -c [ -z &amp;#34;$(apt-get indextargets)&amp;#34; ]     0B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;lt;missing&amp;gt;           17 hours ago        /bin/sh -c set -xe   &amp;amp;&amp;amp; echo &amp;#39;#!/bin/sh&amp;#39; &amp;gt; /…   811B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;lt;missing&amp;gt;           17 hours ago        /bin/sh -c #(nop) ADD file:435d9776fdd3a1834…   72.9MB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are eight layers of this image. The upper most layer is the latest one and as you go down, those are older layers. The upper most layer is the one that you usually use for running containers.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s have a closer look at the images beginning from image &lt;code&gt;d70eaf7277ea&lt;/code&gt; to &lt;code&gt;7f16387f7307&lt;/code&gt; image. I&amp;rsquo;ll ignore the bottom four layers where the &lt;code&gt;IMAGE&lt;/code&gt; is &lt;code&gt;&amp;lt;missing&amp;gt;&lt;/code&gt; as they are not of our concern.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve already mentioned in the previous sub-section that each instruction you write in the &lt;code&gt;Dockerfile&lt;/code&gt; will create a layer in the image.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;d70eaf7277ea&lt;/code&gt; was created by &lt;code&gt;/bin/sh -c #(nop)  CMD [&amp;quot;/bin/bash&amp;quot;]&lt;/code&gt; which indicates that the default shell inside Ubuntu has been loaded successfully.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;6fe4e51e35c1&lt;/code&gt; was created by &lt;code&gt;/bin/sh -c #(nop)  EXPOSE 80&lt;/code&gt; which was the second instruction in your code.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;587c805fe8df&lt;/code&gt; was created by &lt;code&gt;/bin/sh -c apt-get update &amp;amp;&amp;amp; apt-get install nginx -y &amp;amp;&amp;amp; apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;/code&gt; which was the third instruction in your code. You can also see that this image has a size of &lt;code&gt;60MB&lt;/code&gt; given all necessary packages were installed during the execution of this instruction.&lt;/li&gt;
&lt;li&gt;Finally the upper most layer &lt;code&gt;7f16387f7307&lt;/code&gt; was created by &lt;code&gt;/bin/sh -c #(nop)  CMD [&amp;quot;nginx&amp;quot;, &amp;quot;-g&amp;quot;, &amp;quot;daemon off;&amp;quot;]&lt;/code&gt; which sets the default command for this image.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, the image comprises of many read-only layers each recording a new set of change to the state triggered by certain instructions. When you start a container using an image, a new layer is written on top of the other layers.&lt;/p&gt;
&lt;p&gt;This layering phenomenon that happens every time you work with Docker has been made possible by an amazing technical concept called union file system. Here, union means union in set theory. According to &lt;a href=&#34;https://en.wikipedia.org/wiki/UnionFS&#34;&gt;Wikipedia&lt;/a&gt; - &amp;ldquo;It allows files and directories of separate file systems, known as branches, to be transparently overlaid, forming a single coherent file system. Contents of directories which have the same path within the merged branches will be seen together in a single merged directory, within the new, virtual filesystem.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;By utilizing this concept, Docker can avoid data duplication, can use previously created layers as cache for later builds and result in compact, efficient images to be used everywhere.&lt;/p&gt;
&lt;h2 id=&#34;building-nginx-from-source&#34;&gt;Building NGINX From Source&lt;/h2&gt;
&lt;p&gt;In the previous sub-section, you&amp;rsquo;ve learned about the &lt;code&gt;FROM&lt;/code&gt;, &lt;code&gt;EXPOSE&lt;/code&gt;, &lt;code&gt;RUN&lt;/code&gt; and &lt;code&gt;CMD&lt;/code&gt; instructions. In this sub-section you&amp;rsquo;ll be learning a lot more about other instructions.&lt;/p&gt;
&lt;p&gt;In this sub-section you&amp;rsquo;ll again create a custom NGINX image but the twist is that you&amp;rsquo;ll be building NGINX from source instead of installing it using some package manager such as &lt;code&gt;apt-get&lt;/code&gt; in the previous example.&lt;/p&gt;
&lt;p&gt;In order to build NGINX from source, you first need the source of NGINX. If you&amp;rsquo;ve cloned my projects repository you&amp;rsquo;ll see a file named &lt;code&gt;nginx-1.19.2.tar.gz&lt;/code&gt; inside the &lt;code&gt;custom-nginx&lt;/code&gt; directory. You&amp;rsquo;ll use this archive as the source for building NGINX.&lt;/p&gt;
&lt;p&gt;Before diving into writing some code, let&amp;rsquo;s plan out the process first. The image creation process this time can be done in seven steps. These are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get a good base image for building the application i.e. &lt;a href=&#34;https://hub.docker.com/_/ubuntu&#34;&gt;ubuntu&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install necessary build dependencies on the base image.&lt;/li&gt;
&lt;li&gt;Copy &lt;code&gt;nginx-1.19.2.tar.gz&lt;/code&gt; file inside the image.&lt;/li&gt;
&lt;li&gt;Extract the contents of the archive and get rid of it.&lt;/li&gt;
&lt;li&gt;Configure the build, compile and install the program using the &lt;code&gt;make&lt;/code&gt; tool.&lt;/li&gt;
&lt;li&gt;Get rid of the extracted source code.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;nginx&lt;/code&gt; executable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that you have a plan, let&amp;rsquo;s begin by opening up old &lt;code&gt;Dockerfile&lt;/code&gt; and update its contet as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM ubuntu:focal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN apt-get update &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get install build-essential\
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libpcre3 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libpcre3-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    zlib1g \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    zlib1g-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libssl1.1 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libssl-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    -y &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY nginx-1.19.2.tar.gz .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN tar -xvf nginx-1.19.2.tar.gz &amp;amp;&amp;amp; rm nginx-1.19.2.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN cd nginx-1.19.2 &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ./configure \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --sbin-path=/usr/bin/nginx \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --conf-path=/etc/nginx/nginx.conf \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --error-log-path=/var/log/nginx/error.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --http-log-path=/var/log/nginx/access.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-pcre \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --pid-path=/var/run/nginx.pid \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-http_ssl_module &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make &amp;amp;&amp;amp; make install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN rm -rf /nginx-1.19.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, the code inside the &lt;code&gt;Dockerfile&lt;/code&gt; reflects the seven steps I talked about beforehand.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;FROM&lt;/code&gt; instruction sets Ubuntu as the base image making an ideal environment for building any application.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;RUN&lt;/code&gt; instruction installs standard packages necessary for building NGINX from source.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;COPY&lt;/code&gt; instruction here is something new. This instruction is responsible for copying the the &lt;code&gt;nginx-1.19.2.tar.gz&lt;/code&gt; file inside the image. The generic syntax for the &lt;code&gt;COPY&lt;/code&gt; instruction is &lt;code&gt;COPY &amp;lt;source&amp;gt; &amp;lt;destination&amp;gt;&lt;/code&gt; where source is in your local filesystem and the destination is inside your image. The &lt;code&gt;.&lt;/code&gt; as the destination means the working directory inside the image which is by default &lt;code&gt;/&lt;/code&gt; unless set otherwise.&lt;/li&gt;
&lt;li&gt;The second &lt;code&gt;RUN&lt;/code&gt; instruction here extracts the contents from the archive using &lt;code&gt;tar&lt;/code&gt; and gets rid of it afterwards.&lt;/li&gt;
&lt;li&gt;The archive file contains a directory called &lt;code&gt;nginx-1.19.2&lt;/code&gt; containing the source code. Hence on the next step, you&amp;rsquo;ll have to &lt;code&gt;cd&lt;/code&gt; inside that directory and perform the build process. You can read the &lt;a href=&#34;https://itsfoss.com/install-software-from-source-code/&#34;&gt;How to Install Software from Source Code… and Remove it Afterwards&lt;/a&gt; article at &lt;a href=&#34;https://itsfoss.com/&#34;&gt;It&amp;rsquo;s Foss&lt;/a&gt; to learn more on the topic.&lt;/li&gt;
&lt;li&gt;Once the build and installation is complete, you remove the &lt;code&gt;nginx-1.19.2&lt;/code&gt; directory using &lt;code&gt;rm&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;On the final step you start NGINX in single process mode just like you did before.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now to build an image using this code, execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --tag custom-nginx:built .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/7 : FROM ubuntu:focal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; d70eaf7277ea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/7 : RUN apt-get update &amp;amp;&amp;amp;     apt-get install build-essential                    libpcre3                     libpcre3-dev                     zlib1g                     zlib1g-dev                     libssl-dev                     -y &amp;amp;&amp;amp;     apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 2d0aa912ea47
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 2d0aa912ea47
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; cbe1ced3da11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/7 : COPY nginx-1.19.2.tar.gz .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 7202902edf3f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/7 : RUN tar -xvf nginx-1.19.2.tar.gz &amp;amp;&amp;amp; rm nginx-1.19.2.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ---&amp;gt; Running in 4a4a95643020
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG EXTRACTION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 4a4a95643020
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; f9dec072d6d6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/7 : RUN cd nginx-1.19.2 &amp;amp;&amp;amp;     ./configure         --sbin-path=/usr/bin/nginx         --conf-path=/etc/nginx/nginx.conf         --error-log-path=/var/log/nginx/error.log         --http-log-path=/var/log/nginx/access.log         --with-pcre         --pid-path=/var/run/nginx.pid         --with-http_ssl_module &amp;amp;&amp;amp;     make &amp;amp;&amp;amp; make install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in b07ba12f921e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG CONFIGURATION AND BUILD STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container b07ba12f921e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 5a877edafd8b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/7 : RUN rm -rf /nginx-1.19.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 947e1d9ba828
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 947e1d9ba828
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; a7702dc7abb7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/7 : CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 3110c7fdbd57
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 3110c7fdbd57
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; eae55f7369d3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built eae55f7369d3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged custom-nginx:built
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code is alright but there are some places where improvements can be made.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instead of hard coding the filename like &lt;code&gt;nginx-1.19.2.tar.gz&lt;/code&gt;, you can create an argument using the &lt;code&gt;ARG&lt;/code&gt; instruction. This way, you&amp;rsquo;ll be able to change the version or filename by just changing the argument.&lt;/li&gt;
&lt;li&gt;Instead of downloading the archive manually, you can let the daemon download the file during the build process. There is another instruction like &lt;code&gt;COPY&lt;/code&gt; called the &lt;code&gt;ADD&lt;/code&gt; instruction which is capable of adding files from the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Open up the &lt;code&gt;Dockerfile&lt;/code&gt; file and update it&amp;rsquo;s content as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM ubuntu:focal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN apt-get update &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get install build-essential\
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libpcre3 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libpcre3-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    zlib1g \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    zlib1g-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libssl1.1 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libssl-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    -y &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARG FILENAME=&amp;#34;nginx-1.19.2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARG EXTENSION=&amp;#34;tar.gz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ADD https://nginx.org/download/${FILENAME}.${EXTENSION} .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN tar -xvf ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; rm ${FILENAME}.${EXTENSION}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN cd ${FILENAME} &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ./configure \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --sbin-path=/usr/bin/nginx \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --conf-path=/etc/nginx/nginx.conf \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --error-log-path=/var/log/nginx/error.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --http-log-path=/var/log/nginx/access.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-pcre \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --pid-path=/var/run/nginx.pid \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-http_ssl_module &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make &amp;amp;&amp;amp; make install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN rm -rf /${FILENAME}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code is almost identical to the previous code block except a new instruction called &lt;code&gt;ARG&lt;/code&gt; on line 13, 14 and the usage of the &lt;code&gt;ADD&lt;/code&gt; instruction on line 16. Explanation for the updated code is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ARG&lt;/code&gt; instruction lets you declare variables like in other languages. These variables  or arguments can later be accessed using the &lt;code&gt;${argument name}&lt;/code&gt; syntax. Here, I&amp;rsquo;ve put the filename &lt;code&gt;nginx-1.19.2&lt;/code&gt; and the file extension &lt;code&gt;tar.gz&lt;/code&gt; in two separate arguments. This way I can switch between newer versions of NGINX or the archive format by making a change in just one place. In the code above, I&amp;rsquo;ve added default values to the variables. Variable values can be passed as options of the &lt;code&gt;image build&lt;/code&gt; command as well. You can consult the &lt;a href=&#34;https://docs.docker.com/engine/reference/builder/#arg&#34;&gt;official reference&lt;/a&gt; for more details.&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;ADD&lt;/code&gt; instruction, I&amp;rsquo;ve formed the download URL dynamically using the arguments declared above. The &lt;code&gt;https://nginx.org/download/${FILENAME}.${EXTENSION}&lt;/code&gt; line will result in something like &lt;code&gt;https://nginx.org/download/nginx-1.19.2.tar.gz&lt;/code&gt; during the build process. You can change the file version or the extension by changing it in just one place thanks to the &lt;code&gt;ARG&lt;/code&gt; instruction.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ADD&lt;/code&gt; instruction doesn&amp;rsquo;t extract files obtained from the internet by default hence, the usage of &lt;code&gt;tar&lt;/code&gt; on line 18.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rest of the code is almost unchanged. You should be able to understand the usage of the arguments by yourself now. Finally let&amp;rsquo;s try to build an image from this updated code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --tag custom-nginx:built-v2 .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/9 : FROM ubuntu:focal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; d70eaf7277ea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/9 : RUN apt-get update &amp;amp;&amp;amp;     apt-get install build-essential                    libpcre3                     libpcre3-dev                     zlib1g                     zlib1g-dev                     libssl-dev                     -y &amp;amp;&amp;amp;     apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; cbe1ced3da11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/9 : ARG FILENAME=&amp;#34;nginx-1.19.2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 33b62a0e9ffb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 33b62a0e9ffb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; fafc0aceb9c8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/9 : ARG EXTENSION=&amp;#34;tar.gz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 5c32eeb1bb11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 5c32eeb1bb11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 36efdf6efacc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/9 : ADD https://nginx.org/download/${FILENAME}.${EXTENSION} .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Downloading [==================================================&amp;gt;]  1.049MB/1.049MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; dba252f8d609
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/9 : RUN tar -xvf ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; rm ${FILENAME}.${EXTENSION}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 2f5b091b2125
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG EXTRACTION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 2f5b091b2125
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 2c9a325d74f1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/9 : RUN cd ${FILENAME} &amp;amp;&amp;amp;     ./configure         --sbin-path=/usr/bin/nginx         --conf-path=/etc/nginx/nginx.conf         --error-log-path=/var/log/nginx/error.log         --http-log-path=/var/log/nginx/access.log         --with-pcre         --pid-path=/var/run/nginx.pid         --with-http_ssl_module &amp;amp;&amp;amp;     make &amp;amp;&amp;amp; make install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 11cc82dd5186
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG CONFIGURATION AND BUILD STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 11cc82dd5186
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 6c122e485ec8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 8/9 : RUN rm -rf /${FILENAME}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 04102366960b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 04102366960b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 6bfa35420a73
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 9/9 : CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 63ee44b571bb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 63ee44b571bb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 4ce79556db1b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 4ce79556db1b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged custom-nginx:built-v2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you should be able to run a container using the &lt;code&gt;custom-nginx:built-v2&lt;/code&gt; image.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --rm --detach --name custom-nginx-built --publish 8080:80 custom-nginx:built-v2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 90ccdbc0b598dddc4199451b2f30a942249d85a8ed21da3c8d14612f17eed0aa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                  NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 90ccdbc0b598        custom-nginx:built-v2   &amp;#34;nginx -g &amp;#39;daemon of…&amp;#34;   2 minutes ago       Up 2 minutes        0.0.0.0:8080-&amp;gt;80/tcp   custom-nginx-built
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A container using the &lt;code&gt;custom-nginx:built-v2&lt;/code&gt; image has been successfully run. The container should be accessible at &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; address now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/the-docker-handbook/image-manipulation-basics/nginx-default.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;And here is the trusty default response page from NGINX. You can visit the &lt;a href=&#34;https://docs.docker.com/engine/reference/builder/&#34;&gt;official reference&lt;/a&gt; site to learn more about the available instructions.&lt;/p&gt;
&lt;h2 id=&#34;optimizing-images&#34;&gt;Optimizing Images&lt;/h2&gt;
&lt;p&gt;The image we built in the last sub-section is functional but very unoptimized. To prove my point let&amp;rsquo;s have a look at the size of the image using the &lt;code&gt;image ls&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# REPOSITORY         TAG       IMAGE ID       CREATED          SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# custom-nginx       built     1f3aaf40bb54   16 minutes ago   343MB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For an image containing only NGINX, that&amp;rsquo;s too much. If you pull the official image and check it&amp;rsquo;s size you&amp;rsquo;ll see how small it is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image pull nginx:stable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# stable: Pulling from library/nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# a076a628af6f: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 45d7b5d3927d: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 5e326fece82e: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 30c386181b68: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# b15158e9ebbe: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Digest: sha256:ebd0fd56eb30543a9195280eb81af2a9a8e6143496accd6a217c14b06acd1419
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Status: Downloaded newer image for nginx:stable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# docker.io/library/nginx:stable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# REPOSITORY         TAG       IMAGE ID       CREATED          SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# custom-nginx       built     1f3aaf40bb54   25 minutes ago   343MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# nginx              stable    b9e1dc12387a   11 days ago      133MB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In order to find out the root cause, let&amp;rsquo;s have a look at the &lt;code&gt;Dockerfile&lt;/code&gt; first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM ubuntu:focal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN apt-get update &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get install build-essential\
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libpcre3 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libpcre3-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    zlib1g \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    zlib1g-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libssl1.1 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libssl-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    -y &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARG FILENAME=&amp;#34;nginx-1.19.2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARG EXTENSION=&amp;#34;tar.gz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ADD https://nginx.org/download/${FILENAME}.${EXTENSION} .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN tar -xvf ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; rm ${FILENAME}.${EXTENSION}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN cd ${FILENAME} &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ./configure \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --sbin-path=/usr/bin/nginx \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --conf-path=/etc/nginx/nginx.conf \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --error-log-path=/var/log/nginx/error.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --http-log-path=/var/log/nginx/access.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-pcre \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --pid-path=/var/run/nginx.pid \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-http_ssl_module &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make &amp;amp;&amp;amp; make install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN rm -rf /${FILENAME}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see on line 3, the &lt;code&gt;RUN&lt;/code&gt; instruction installs a lot of stuff. Although these packages are necessary for building NGINX from source, they are not necessary for running it. Out of the 6 packages that we installed, only two are necessary for running NGINX. These are &lt;code&gt;libpcre3&lt;/code&gt; and &lt;code&gt;zlib1g&lt;/code&gt;. So a better idea can be to uninstall the other packages once the build process is done.&lt;/p&gt;
&lt;p&gt;To do so, update your &lt;code&gt;Dockerfile&lt;/code&gt; as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM ubuntu:focal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EXPOSE 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARG FILENAME=&amp;#34;nginx-1.19.2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARG EXTENSION=&amp;#34;tar.gz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ADD https://nginx.org/download/${FILENAME}.${EXTENSION} .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN apt-get update &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get install build-essential \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libpcre3 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libpcre3-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    zlib1g \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    zlib1g-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libssl1.1 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libssl-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    -y &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tar -xvf ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; rm ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cd ${FILENAME} &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ./configure \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --sbin-path=/usr/bin/nginx \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --conf-path=/etc/nginx/nginx.conf \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --error-log-path=/var/log/nginx/error.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --http-log-path=/var/log/nginx/access.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-pcre \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --pid-path=/var/run/nginx.pid \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-http_ssl_module &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make &amp;amp;&amp;amp; make install &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cd / &amp;amp;&amp;amp; rm -rfv /${FILENAME} &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get remove build-essential \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libpcre3-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    zlib1g-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    libssl-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    -y &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get autoremove -y &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, on line 10 a single &lt;code&gt;RUN&lt;/code&gt; instruction is doing all the necessary heavy-lifting. The exact chain of events is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From line 10 to line 17, all the necessary packages are being installed.&lt;/li&gt;
&lt;li&gt;On line 18, the source code is being extracted and the the downloaded archive gets removed.&lt;/li&gt;
&lt;li&gt;From line 19 to line 28, NGINX is configured, built and installed on the system.&lt;/li&gt;
&lt;li&gt;On line 29, the extracted files from the downloaded archive gets removed.&lt;/li&gt;
&lt;li&gt;From line 30 to line 36, all the unnecessary packages are being uninstalled and cache cleared. The &lt;code&gt;libpcre3&lt;/code&gt; and &lt;code&gt;zlib1g&lt;/code&gt; packages are needed for running NGINX hence they&amp;rsquo;re kept.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may ask why am I doing so much work in a single &lt;code&gt;RUN&lt;/code&gt; instruction instead of nicely splitting them into multiple instructions, like we did previously. Well that&amp;rsquo;s a mistake. If you install packages and then remove them in separate &lt;code&gt;RUN&lt;/code&gt; instructions, they&amp;rsquo;ll live in separate layers of the image. Although the final image will not have the removed packages, their size will still be added to the final image given they exist in one of the layers consisting the image. So make sure you make these kind of changes on a single layer.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s build an image using this &lt;code&gt;Dockerfile&lt;/code&gt; and see the differences.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --tag custom-nginx:built .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon  1.057MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/7 : FROM ubuntu:focal
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; f63181f19b2f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/7 : EXPOSE 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 006f39b75964
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 006f39b75964
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 6943f7ef9376
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/7 : ARG FILENAME=&amp;#34;nginx-1.19.2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in ffaf89078594
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container ffaf89078594
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 91b5cdb6dabe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/7 : ARG EXTENSION=&amp;#34;tar.gz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in d0f5188444b6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container d0f5188444b6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 9626f941ccb2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/7 : ADD https://nginx.org/download/${FILENAME}.${EXTENSION} .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Downloading [==================================================&amp;gt;]  1.049MB/1.049MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; a8e8dcca1be8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/7 : RUN apt-get update &amp;amp;&amp;amp;     apt-get install build-essential                     libpcre3                     libpcre3-dev                     zlib1g                     zlib1g-dev                     libssl-dev                     -y &amp;amp;&amp;amp;     tar -xvf ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; rm ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp;     cd ${FILENAME} &amp;amp;&amp;amp;     ./configure         --sbin-path=/usr/bin/nginx         --conf-path=/etc/nginx/nginx.conf         --error-log-path=/var/log/nginx/error.log         --http-log-path=/var/log/nginx/access.log         --with-pcre         --pid-path=/var/run/nginx.pid         --with-http_ssl_module &amp;amp;&amp;amp;     make &amp;amp;&amp;amp; make install &amp;amp;&amp;amp;     cd / &amp;amp;&amp;amp; rm -rfv /${FILENAME} &amp;amp;&amp;amp;     apt-get remove build-essential                     libpcre3-dev                     zlib1g-dev                     libssl-dev                     -y &amp;amp;&amp;amp;     apt-get autoremove -y &amp;amp;&amp;amp;     apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in e5675cad1260
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION AND BUILD STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container e5675cad1260
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; dc7e4161f975
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/7 : CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in b579e4600247
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container b579e4600247
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 512aa6a95a93
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 512aa6a95a93
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged custom-nginx:built
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# REPOSITORY         TAG       IMAGE ID       CREATED              SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# custom-nginx       built     512aa6a95a93   About a minute ago   81.6MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# nginx              stable    b9e1dc12387a   11 days ago          133MB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, the image size has gone from being 343MB to 81.6MB. The official image is 133MB. This is a pretty optimized build but we can go a bit further in the next sub-section.&lt;/p&gt;
&lt;h2 id=&#34;embracing-alpine-linux&#34;&gt;Embracing Alpine Linux&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve been fiddling around with containers for sometime now, you may have heard about something called &lt;a href=&#34;https://alpinelinux.org/&#34;&gt;Alpine Linux&lt;/a&gt; which is a full-featured &lt;a href=&#34;https://en.wikipedia.org/wiki/Linux&#34;&gt;Linux&lt;/a&gt; distribution like &lt;a href=&#34;https://ubuntu.com/&#34;&gt;Ubuntu&lt;/a&gt;, &lt;a href=&#34;https://www.debian.org/&#34;&gt;Debian&lt;/a&gt; or &lt;a href=&#34;https://getfedora.org/&#34;&gt;Fedora&lt;/a&gt;. But the good thing about Alpine is that it&amp;rsquo;s built around &lt;code&gt;musl&lt;/code&gt; &lt;code&gt;libc&lt;/code&gt; and &lt;code&gt;busybox&lt;/code&gt; and is lightweight. Where the latest &lt;a href=&#34;https://hub.docker.com/_/ubuntu&#34;&gt;ubuntu&lt;/a&gt; image weighs at around 28MB, &lt;a href=&#34;https://hub.docker.com/_/alpine&#34;&gt;alpine&lt;/a&gt; is 2.8MB. Apart from the lightweight nature, Alpine is also secure and is a much better fit for creating containers than the other distributions.&lt;/p&gt;
&lt;p&gt;Although not as user friendly as the other commercial distributions, the transition to Alpine is still very simple. In this sub-section you&amp;rsquo;ll learn about recreating the &lt;code&gt;custom-nginx&lt;/code&gt; image by using the alpine image as its base.&lt;/p&gt;
&lt;p&gt;Open up your &lt;code&gt;Dockerfile&lt;/code&gt; and update its content as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM alpine:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EXPOSE 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARG FILENAME=&amp;#34;nginx-1.19.2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARG EXTENSION=&amp;#34;tar.gz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ADD https://nginx.org/download/${FILENAME}.${EXTENSION} .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN apk add --no-cache pcre zlib &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apk add --no-cache \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            --virtual .build-deps \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            build-base \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            pcre-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            zlib-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            openssl-dev &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tar -xvf ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; rm ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cd ${FILENAME} &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ./configure \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --sbin-path=/usr/bin/nginx \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --conf-path=/etc/nginx/nginx.conf \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --error-log-path=/var/log/nginx/error.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --http-log-path=/var/log/nginx/access.log \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-pcre \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --pid-path=/var/run/nginx.pid \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        --with-http_ssl_module &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    make &amp;amp;&amp;amp; make install &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cd / &amp;amp;&amp;amp; rm -rfv /${FILENAME} &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apk del .build-deps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code is almost identical except a few changes. I&amp;rsquo;ll be listing the changes and will be explaining them as I go:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instead of using &lt;code&gt;apt-get install&lt;/code&gt; for installing packages, we use &lt;code&gt;apk add&lt;/code&gt; and the &lt;code&gt;--no-cache&lt;/code&gt; option means that the downloaded package won&amp;rsquo;t be cached. Likewise &lt;code&gt;apk del&lt;/code&gt; is used instead of &lt;code&gt;apt-get remove&lt;/code&gt; to uninstall packages.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--virtual&lt;/code&gt; option for &lt;code&gt;apk add&lt;/code&gt; command is used for bundling a bunch of packages into a single virtual package for easier management. Packages that are needed only for building the program is labeled as &lt;code&gt;.build-deps&lt;/code&gt; which is then removed on line 29 by executing &lt;code&gt;apk del .build-deps&lt;/code&gt; command. You can learn more about &lt;a href=&#34;https://docs.alpinelinux.org/user-handbook/0.1a/Working/apk.html#_virtuals&#34;&gt;virtuals&lt;/a&gt; in the official docs.&lt;/li&gt;
&lt;li&gt;The package names are a bit different here. Usually every Linux distribution has its package repository available to everyone where you can search for packages. If you know the packages required for a certain task then you can just head over to the designated repository for a distribution and search for it. You can look up Alpine Linux packages on &lt;a href=&#34;https://pkgs.alpinelinux.org/packages&#34;&gt;https://pkgs.alpinelinux.org/packages&lt;/a&gt; link.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now build a new image using this &lt;code&gt;Dockerfile&lt;/code&gt; and see the difference in file size:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --tag custom-nginx:built .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon  1.055MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/7 : FROM alpine:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 7731472c3f2a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/7 : EXPOSE 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 8336cfaaa48d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 8336cfaaa48d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; d448a9049d01
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/7 : ARG FILENAME=&amp;#34;nginx-1.19.2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in bb8b2eae9d74
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container bb8b2eae9d74
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 87ca74f32fbe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/7 : ARG EXTENSION=&amp;#34;tar.gz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in aa09627fe48c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container aa09627fe48c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 70cb557adb10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/7 : ADD https://nginx.org/download/${FILENAME}.${EXTENSION} .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Downloading [==================================================&amp;gt;]  1.049MB/1.049MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; b9790ce0c4d6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/7 : RUN apk add --no-cache pcre zlib &amp;amp;&amp;amp;     apk add --no-cache             --virtual .build-deps             build-base             pcre-dev             zlib-dev             openssl-dev &amp;amp;&amp;amp;     tar -xvf ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; rm ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp;     cd ${FILENAME} &amp;amp;&amp;amp;     ./configure         --sbin-path=/usr/bin/nginx         --conf-path=/etc/nginx/nginx.conf         --error-log-path=/var/log/nginx/error.log         --http-log-path=/var/log/nginx/access.log         --with-pcre         --pid-path=/var/run/nginx.pid         --with-http_ssl_module &amp;amp;&amp;amp;     make &amp;amp;&amp;amp; make install &amp;amp;&amp;amp;     cd / &amp;amp;&amp;amp; rm -rfv /${FILENAME} &amp;amp;&amp;amp;     apk del .build-deps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 0b301f64ffc1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION AND BUILD STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 0b301f64ffc1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; dc7e4161f975
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/7 : CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in b579e4600247
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container b579e4600247
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 3e186a3c6830
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 3e186a3c6830
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged custom-nginx:built
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# REPOSITORY         TAG       IMAGE ID       CREATED         SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# custom-nginx       built     3e186a3c6830   8 seconds ago   12.8MB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where the ubuntu version was 81.6MB, the alpine one has come down to 12.8MB which is a massive gain. Apart from the &lt;code&gt;apk&lt;/code&gt; package manager, there are some other things that differ in Alpine from Ubuntu but they&amp;rsquo;re not that much of big deal. You can just search the internet whenever you get stuck.&lt;/p&gt;
&lt;h2 id=&#34;creating-executable-images&#34;&gt;Creating Executable Images&lt;/h2&gt;
&lt;p&gt;In the previous section you&amp;rsquo;ve worked with the &lt;a href=&#34;https://hub.docker.com/r/fhsinchy/rmbyext&#34;&gt;fhsinchy/rmbyext&lt;/a&gt; image. In this section you&amp;rsquo;ll learn about making such an executable image. To begin with, open up the directory where you&amp;rsquo;ve cloned the repository that came with this article. Code for the &lt;code&gt;rmbyext&lt;/code&gt; application resides inside the sub-directory with the same name.&lt;/p&gt;
&lt;p&gt;Before you start working on the &lt;code&gt;Dockerfile&lt;/code&gt; take a moment to plan out what the final output should be. In my opinion it should be like something as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The image should have python pre-installed.&lt;/li&gt;
&lt;li&gt;It should contain a copy of my &lt;code&gt;rmbyext&lt;/code&gt; script.&lt;/li&gt;
&lt;li&gt;A working directory should be set where the script will be executed.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;rmbyext&lt;/code&gt; script should be set as the entrypoint so the image can take extension names as arguments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To build the above mentioned image, the following steps should be taken:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get a good base image for running python scripts i.e. &lt;a href=&#34;https://hub.docker.com/_/python&#34;&gt;python&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set-up the working directory to an easily accessible directory.&lt;/li&gt;
&lt;li&gt;Install git so that the script can be installed from my github repository.&lt;/li&gt;
&lt;li&gt;Install the script using git and pip.&lt;/li&gt;
&lt;li&gt;Get rid of the build unnecessary packages.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;rmbyext&lt;/code&gt; as the entry-point for this image.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now create a new &lt;code&gt;Dockerfile&lt;/code&gt; inside the &lt;code&gt;rmbyext&lt;/code&gt; directory and put following code in it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM python:3-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WORKDIR /zone
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN apk add --no-cache git &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pip install git+https://github.com/fhsinchy/rmbyext.git#egg=rmbyext &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    apk del git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ENTRYPOINT [ &amp;#34;rmbyext&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Explanation for the instructions in this file is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;FROM&lt;/code&gt; instruction sets &lt;a href=&#34;https://hub.docker.com/_/python&#34;&gt;python&lt;/a&gt; as the base image making an ideal environment for running python scripts. The &lt;code&gt;3-alpine&lt;/code&gt; tag indicates that you want the Alpine variant of Python 3.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;WORKDIR&lt;/code&gt; instruction sets the default working directory to &lt;code&gt;/zone&lt;/code&gt; here. The name of the working directory is completely random here. I found zone to be a fitting name, you may use anything you want.&lt;/li&gt;
&lt;li&gt;Given the &lt;code&gt;rmbyext&lt;/code&gt; script is installed from GitHub, &lt;code&gt;git&lt;/code&gt; is an install time dependency. The &lt;code&gt;RUN&lt;/code&gt; instruction on line 5 installs &lt;code&gt;git&lt;/code&gt; then installs the &lt;code&gt;rmbyext&lt;/code&gt; script using git and pip. It also gets rid of &lt;code&gt;git&lt;/code&gt; afterwards.&lt;/li&gt;
&lt;li&gt;Finally on line 9, the &lt;code&gt;ENTRYPOINT&lt;/code&gt; instruction sets the &lt;code&gt;rmbyext&lt;/code&gt; script as the entry-point for this image.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this entire file, line 9 is the magic that turns this seemingly normal image to an executable one. Now to build the image you can execute following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --tag rmbyext .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon  2.048kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/4 : FROM python:3-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 3-alpine: Pulling from library/python
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 801bfaa63ef2: Already exists
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 8723b2b92bec: Already exists
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 4e07029ccd64: Already exists
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 594990504179: Already exists
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 140d7fec7322: Already exists
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Digest: sha256:7492c1f615e3651629bd6c61777e9660caa3819cf3561a47d1d526dfeee02cf6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Status: Downloaded newer image for python:3-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; d4d4f50f871a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/4 : WORKDIR /zone
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 454374612a91
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 454374612a91
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 7f7e49bc98d2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/4 : RUN apk add --no-cache git &amp;amp;&amp;amp;     pip install git+https://github.com/fhsinchy/rmbyext.git#egg=rmbyext &amp;amp;&amp;amp;     apk del git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 27e2e96dc95a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 27e2e96dc95a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 3c7389432e36
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/4 : ENTRYPOINT [ &amp;#34;rmbyext&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in f239bbea1ca6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container f239bbea1ca6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 1746b0cedbc7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 1746b0cedbc7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged rmbyext:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# REPOSITORY         TAG        IMAGE ID       CREATED         SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# rmbyext            latest     1746b0cedbc7   4 minutes ago   50.9MB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here I haven&amp;rsquo;t provided any tag after the image name so the image has been tagged as &lt;code&gt;latest&lt;/code&gt; by default. You should be able to run the image as you saw in the previous section. Remember to refer to the actual image name you&amp;rsquo;ve set, instead of &lt;code&gt;fhsinchy/rmbyext&lt;/code&gt; here.&lt;/p&gt;
&lt;h2 id=&#34;sharing-your-images-online&#34;&gt;Sharing Your Images Online&lt;/h2&gt;
&lt;p&gt;Now that you know how to make images, it&amp;rsquo;s time to share them with the world. Sharing images online is easy. All you need is an account at any of the online registries. I&amp;rsquo;ll be using &lt;a href=&#34;https://hub.docker.com/&#34;&gt;Docker Hub&lt;/a&gt; here. Navigate to the &lt;a href=&#34;https://hub.docker.com/signup&#34;&gt;Sign Up&lt;/a&gt; page and create a free account. A free account allows you to host unlimited public repositories and one private repository.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve created the account, you&amp;rsquo;ll have to sign in to it using the docker CLI. So open up your terminal and execute following command to do so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker login
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Login with your Docker ID to push and pull images from Docker Hub. If you don&amp;#39;t have a Docker ID, head over to https://hub.docker.com to create one.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Username: fhsinchy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Password:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# WARNING! Your password will be stored unencrypted in /home/fhsinchy/.docker/config.json.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Configure a credential helper to remove this warning. See
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# https://docs.docker.com/engine/reference/commandline/login/#credentials-store
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Login Succeeded
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You&amp;rsquo;ll be prompted for your username and password. If you input them properly, you should be logged in to your account successfully.&lt;/p&gt;
&lt;p&gt;In order to share an image online, the image has to be tagged. You&amp;rsquo;ve already learned about tagging in a previous sub-section. Just to refresh your memory, the generic syntax for the &lt;code&gt;--tag&lt;/code&gt; or &lt;code&gt;-t&lt;/code&gt; option is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--tag &amp;lt;image repository&amp;gt;:&amp;lt;image tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As an example, let&amp;rsquo;s share the &lt;code&gt;custom-nginx&lt;/code&gt; image online. To do so, open up a new terminal window inside the &lt;code&gt;custom-nginx&lt;/code&gt; project directory. To share an image online, you&amp;rsquo;ll have to tag it following the &lt;code&gt;&amp;lt;docker hub username&amp;gt;/&amp;lt;image name&amp;gt;:&amp;lt;image tag&amp;gt;&lt;/code&gt; syntax. My username is &lt;code&gt;fhsinchy&lt;/code&gt; so the command will look like as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --tag fhsinchy/custom-nginx:latest --file Dockerfile.built .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/9 : FROM ubuntu:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; d70eaf7277ea
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/9 : RUN apt-get update &amp;amp;&amp;amp;     apt-get install build-essential                    libpcre3                     libpcre3-dev                     zlib1g                     zlib1g-dev                     libssl-dev                     -y &amp;amp;&amp;amp;     apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; cbe1ced3da11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/9 : ARG FILENAME=&amp;#34;nginx-1.19.2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 33b62a0e9ffb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 33b62a0e9ffb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; fafc0aceb9c8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/9 : ARG EXTENSION=&amp;#34;tar.gz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 5c32eeb1bb11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 5c32eeb1bb11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 36efdf6efacc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/9 : ADD https://nginx.org/download/${FILENAME}.${EXTENSION} .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Downloading [==================================================&amp;gt;]  1.049MB/1.049MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; dba252f8d609
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/9 : RUN tar -xvf ${FILENAME}.${EXTENSION} &amp;amp;&amp;amp; rm ${FILENAME}.${EXTENSION}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 2f5b091b2125
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG EXTRACTION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 2f5b091b2125
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 2c9a325d74f1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/9 : RUN cd ${FILENAME} &amp;amp;&amp;amp;     ./configure         --sbin-path=/usr/bin/nginx         --conf-path=/etc/nginx/nginx.conf         --error-log-path=/var/log/nginx/error.log         --http-log-path=/var/log/nginx/access.log         --with-pcre         --pid-path=/var/run/nginx.pid         --with-http_ssl_module &amp;amp;&amp;amp;     make &amp;amp;&amp;amp; make install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 11cc82dd5186
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG CONFIGURATION AND BUILD STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 11cc82dd5186
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 6c122e485ec8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 8/9 : RUN rm -rf /${FILENAME}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 04102366960b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 04102366960b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 6bfa35420a73
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 9/9 : CMD [&amp;#34;nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 63ee44b571bb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 63ee44b571bb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 4ce79556db1b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 4ce79556db1b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged fhsinchy/custom-nginx:latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this command the &lt;code&gt;fhsinchy/custom-nginx&lt;/code&gt; is the image repository and &lt;code&gt;latest&lt;/code&gt; is the tag. The image name can be anything you want and can not be changed once you&amp;rsquo;ve uploaded the image. The tag can be changed whenever you want and usually reflects the version of the software or different kind of builds.&lt;/p&gt;
&lt;p&gt;Take the &lt;code&gt;node&lt;/code&gt; image as an example. The &lt;code&gt;node:lts&lt;/code&gt; image refers to the long term support version of Node.js whereas the &lt;code&gt;node:lts-alpine&lt;/code&gt; version refers to the Node.js version built for Alpine Linux which is much smaller than the regular one.&lt;/p&gt;
&lt;p&gt;If you do not give the image any tag, it&amp;rsquo;ll be automatically tagged as &lt;code&gt;latest&lt;/code&gt;. But that doesn&amp;rsquo;t mean that the &lt;code&gt;latest&lt;/code&gt; tag will always refer to the latest version. If for some reason you explicitly tag an older version of the image as &lt;code&gt;latest&lt;/code&gt; then Docker will not make any extra effort to cross check that.&lt;/p&gt;
&lt;p&gt;Once the image has been built, you can then upload that by executing the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image push &amp;lt;image repository&amp;gt;:&amp;lt;image tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So in my case the command will be as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image push fhsinchy/custom-nginx:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# The push refers to repository [docker.io/fhsinchy/custom-nginx]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 4352b1b1d9f5: Pushed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# a4518dd720bd: Pushed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 1d756dc4e694: Pushed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# d7a7e2b6321a: Pushed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# f6253634dc78: Mounted from library/ubuntu
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 9069f84dbbe9: Mounted from library/ubuntu
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# bacd3af13903: Mounted from library/ubuntu
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# latest: digest: sha256:ffe93440256c9edb2ed67bf3bba3c204fec3a46a36ac53358899ce1a9eee497a size: 1788
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Depending on the image size, the upload may take some time. Once it&amp;rsquo;s done you should be able to find the image in your hub profile page.&lt;/p&gt;
&lt;h1 id=&#34;containerizing-a-javascript-application&#34;&gt;Containerizing a JavaScript Application&lt;/h1&gt;
&lt;p&gt;Now that you&amp;rsquo;ve got some idea of creating images, it&amp;rsquo;s time to work with something a bit more relevant. In this sub-section, you&amp;rsquo;ll be working with the source code of the &lt;a href=&#34;https://hub.docker.com/r/fhsinchy/hello-dock&#34;&gt;fhsinchy/hello-dock&lt;/a&gt; image that you worked with on a previous section. In the process of containerizing this very simple application, you&amp;rsquo;ll be introduced to volumes and multi-staged builds, two of the most important concepts in Docker.&lt;/p&gt;
&lt;h2 id=&#34;writing-the-development-dockerfile&#34;&gt;Writing The Development Dockerfile&lt;/h2&gt;
&lt;p&gt;To begin with, open up the directory where you&amp;rsquo;ve cloned the repository that came with this article. Code for the &lt;code&gt;hello-dock&lt;/code&gt; application resides inside the sub-directory with the same name.&lt;/p&gt;
&lt;p&gt;This is a very simple JavaScript project powered by the &lt;a href=&#34;https://github.com/vitejs/vite&#34;&gt;vitejs/vite&lt;/a&gt; project. Don&amp;rsquo;t worry though, you don&amp;rsquo;t need to know JavaScript or vite in order to go through this sub-section. Having a basic understanding of &lt;a href=&#34;https://nodejs.org/&#34;&gt;Node.js&lt;/a&gt; and &lt;a href=&#34;https://www.npmjs.com/&#34;&gt;npm&lt;/a&gt; will suffice.&lt;/p&gt;
&lt;p&gt;Just like any other project you&amp;rsquo;ve done in the previous sub-section, you&amp;rsquo;ll begin by making a plan of how you want this application to run. In my opinion, the plan should be as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get a good base image for running JavaScript applications i.e. &lt;a href=&#34;https://hub.docker.com/_/node&#34;&gt;node&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set the default working directory inside the image.&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;package.json&lt;/code&gt; file into the image.&lt;/li&gt;
&lt;li&gt;Install necessary dependencies.&lt;/li&gt;
&lt;li&gt;Copy rest of the project files.&lt;/li&gt;
&lt;li&gt;Start the &lt;code&gt;vite&lt;/code&gt; development server by executing &lt;code&gt;npm run dev&lt;/code&gt; command.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This plan should always come from the developer of the application that you&amp;rsquo;re containerizing. If you&amp;rsquo;re the developer yourself, then you should already have a proper understanding of how this application needs to be run. Now if you put the above mentioned plan inside &lt;code&gt;Dockerfile.dev&lt;/code&gt;, the file should look like as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM node:lts-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EXPOSE 3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;USER node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN mkdir -p /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WORKDIR /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY ./package.json .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CMD [ &amp;#34;npm&amp;#34;, &amp;#34;run&amp;#34;, &amp;#34;dev&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Explanation for this code is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;FROM&lt;/code&gt; instruction here sets the official Node.js image as the base giving you all the goodness of Node.js necessary to run any JavaScript application. The &lt;code&gt;lts-alpine&lt;/code&gt; tag indicates that you want to use the Alpine variant, long term support version of the image. Available tags and necessary documentation for the image can be found on &lt;a href=&#34;https://hub.docker.com/_/node&#34;&gt;node&lt;/a&gt; hub page.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;USER&lt;/code&gt; instruction sets the default user for the image to &lt;code&gt;node&lt;/code&gt;. By default Docker runs containers as the root user and according to &lt;a href=&#34;https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md&#34;&gt;Docker and Node.js Best Practices&lt;/a&gt; this can pose a security threat. So a better idea is to run as a non-root user whenever possible. The node image comes with a non-root user named &lt;code&gt;node&lt;/code&gt; which you can set as the default user using the &lt;code&gt;USER&lt;/code&gt; instruction.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;RUN mkdir -p /home/node/app&lt;/code&gt; instruction creates a directory called &lt;code&gt;app&lt;/code&gt; inside the home directory of the &lt;code&gt;node&lt;/code&gt; user. The home directory for any non-root user in Linux is usually  &lt;code&gt;/home/&amp;lt;user name&amp;gt;&lt;/code&gt; by default.&lt;/li&gt;
&lt;li&gt;Then the &lt;code&gt;WORKDIR&lt;/code&gt; instruction sets the default working directory to the newly created &lt;code&gt;/home/node/app&lt;/code&gt; directory. By default the working directory of any image is the root. You don&amp;rsquo;t want any unnecessary files sprayed all over your root directory, do you? Hence you change the default working directory to something more sensible like &lt;code&gt;/home/node/app&lt;/code&gt; or whatever you like. This working directory will be applicable to any subsequent &lt;code&gt;COPY&lt;/code&gt;, &lt;code&gt;ADD&lt;/code&gt;, &lt;code&gt;RUN&lt;/code&gt; and &lt;code&gt;CMD&lt;/code&gt; instructions.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;COPY&lt;/code&gt; instruction here copies the &lt;code&gt;package.json&lt;/code&gt; file which contains information regarding all the necessary dependencies for this application. The &lt;code&gt;RUN&lt;/code&gt; instruction executes &lt;code&gt;npm install&lt;/code&gt; command which is the default command for installing dependencies using a &lt;code&gt;package.json&lt;/code&gt; file in Node.js projects. The &lt;code&gt;.&lt;/code&gt; at the end represents the working directory.&lt;/li&gt;
&lt;li&gt;The second &lt;code&gt;COPY&lt;/code&gt; instruction copies rest of the content from the current directory (&lt;code&gt;.&lt;/code&gt;) of the host filesystem to the working directory (&lt;code&gt;.&lt;/code&gt;) inside the image.&lt;/li&gt;
&lt;li&gt;Finally, the &lt;code&gt;CMD&lt;/code&gt; instruction here sets the default command for this image which is &lt;code&gt;npm run dev&lt;/code&gt; written in &lt;code&gt;exec&lt;/code&gt; form.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;vite&lt;/code&gt; development server by default runs on port &lt;code&gt;3000&lt;/code&gt; hence adding an &lt;code&gt;EXPOSE&lt;/code&gt; command seemed like a good idea, so there you go.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, to build an image from this &lt;code&gt;Dockerfile.dev&lt;/code&gt; you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --file Dockerfile.dev --tag hello-dock:dev .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/7 : FROM node:lts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; b90fa0d7cbd1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/7 : EXPOSE 3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 722d639badc7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 722d639badc7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; e2a8aa88790e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/7 : WORKDIR /app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 998e254b4d22
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 998e254b4d22
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 6bd4c42892a4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/7 : COPY ./package.json .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 24fc5164a1dc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/7 : RUN npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 23b4de3f930b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 23b4de3f930b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; c17ecb19a210
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/7 : COPY . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; afb6d9a1bc76
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/7 : CMD [ &amp;#34;npm&amp;#34;, &amp;#34;run&amp;#34;, &amp;#34;dev&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in a7ff529c28fe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container a7ff529c28fe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 1792250adb79
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 1792250adb79
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged hello-dock:dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given the filename is not &lt;code&gt;Dockerfile&lt;/code&gt; you have to explicitly pass the filename using the &lt;code&gt;--file&lt;/code&gt; option. A container can be run using this image by executing the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --rm \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --detach \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --publish 3000:3000 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --name hello-dock-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    hello-dock:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 21b9b1499d195d85e81f0e8bce08f43a64b63d589c5f15cbbd0b9c0cb07ae268
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now visit &lt;code&gt;http://127.0.0.1:3000&lt;/code&gt; to see the &lt;code&gt;hello-dock&lt;/code&gt; application in action.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/containerizing-a-javascript-application/hello-dock-dev.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Congratulations on running your first real-world application inside a container. The code you&amp;rsquo;ve just written is okay but there is one big issue with it and there are a few places where it can be improved. Let&amp;rsquo;s begin with the issue first.&lt;/p&gt;
&lt;h2 id=&#34;working-with-bind-mounts&#34;&gt;Working With Bind Mounts&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve worked with any front-end JavaScript framework before, you should know that the development servers in these frameworks usually come with a hot reload feature. That is if you make a change in your code, the server will reload automatically reflecting any changes you&amp;rsquo;ve made immediately.&lt;/p&gt;
&lt;p&gt;But if you make any change in your code right now, you&amp;rsquo;ll see nothing happening to your application running in the browser. The reason behind this is the fact that you&amp;rsquo;re making changes in the code that you have in your local file system but the application you&amp;rsquo;re seeing in the browser resides inside the container file system.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/containerizing-a-javascript-application/local-vs-container-file-system.svg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;To solve this issue, you can again make use of a &lt;a href=&#34;https://docs.docker.com/storage/bind-mounts/&#34;&gt;bind mount&lt;/a&gt;. You&amp;rsquo;ve already had a brief encounter of bind mounts in the &lt;a href=&#34;/posts/the-docker-handbook/#working-with-executable-images&#34;&gt;Working With Executable Images&lt;/a&gt; sub-section.&lt;/p&gt;
&lt;p&gt;Using bind mounts, you can easily mount one of your local file system directory inside a container. Instead of making a copy of the local file system, the bind mount can reference the local file system directly from inside the container.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/containerizing-a-javascript-application/bind-mounts.svg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;This way, any changes you make to your local source code will reflect immediately inside the container,  triggering the hot reload feature of &lt;code&gt;vite&lt;/code&gt; development server. Changes made to the file system inside the container will reflect on your local file system as well.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ve in the &lt;a href=&#34;/posts/the-docker-handbook/#working-with-executable-images&#34;&gt;Working With Executable Images&lt;/a&gt; sub-section, bind mounts can be created using the &lt;code&gt;--volume&lt;/code&gt; or &lt;code&gt;-v&lt;/code&gt; option for the &lt;code&gt;container run&lt;/code&gt; or &lt;code&gt;container start&lt;/code&gt; commands. Just to remind you, the generic syntax is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--volume &amp;lt;local file system directory absolute path&amp;gt;:&amp;lt;container file system directory absolute path&amp;gt;:&amp;lt;read write access&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Stop your previously started &lt;code&gt;hello-dock-dev&lt;/code&gt; container, and start a new container by executing the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --rm \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --publish 3000:3000 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --name hello-dock-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --volume $(pwd):/home/node/app \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    hello-dock:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# sh: 1: vite: not found
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm ERR! code ELIFECYCLE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm ERR! syscall spawn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm ERR! file sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm ERR! errno ENOENT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm ERR! hello-dock@0.0.0 dev: `vite`
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm ERR! spawn ENOENT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm ERR!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm ERR! Failed at the hello-dock@0.0.0 dev script.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm WARN Local package.json exists, but node_modules missing, did you mean to install?
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Keep in mind, I&amp;rsquo;ve omitted the &lt;code&gt;--detach&lt;/code&gt; option and that&amp;rsquo;s to demonstrate a very important point. As you can see that the application is not running at all now.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because although the usage of a volume solves the issue of hot reloads, it introduces another one. If you have any previous experience with Node.js, you may know that the dependencies of a Node.js project lives inside the &lt;code&gt;node_modules&lt;/code&gt; directory on the project root.&lt;/p&gt;
&lt;p&gt;Now that you&amp;rsquo;re mounting the project root on your local file system as a volume inside the container, the content inside the container gets replaced along with the &lt;code&gt;node_modules&lt;/code&gt; directory containing all the dependencies.  Hence the &lt;code&gt;vite&lt;/code&gt; package goes missing.&lt;/p&gt;
&lt;h2 id=&#34;working-with-anonymous-volumes&#34;&gt;Working With Anonymous Volumes&lt;/h2&gt;
&lt;p&gt;This problem here can be solved using an anonymous volume. An anonymous volume is identical to a bind mount except the fact that you don&amp;rsquo;t need to specify the source directory here. The generic syntax for creating an anonymous volume is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--volume &amp;lt;container file system directory absolute path&amp;gt;:&amp;lt;read write access&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So the final command for starting the &lt;code&gt;hello-dock&lt;/code&gt; container with both volumes should be as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --rm \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --detach \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --publish 3000:3000 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --name hello-dock-dev \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --volume $(pwd):/home/node/app \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --volume /home/node/app/node_modules \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    hello-dock:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 53d1cfdb3ef148eb6370e338749836160f75f076d0fbec3c2a9b059a8992de8b
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, Docker will take the entire &lt;code&gt;node_modules&lt;/code&gt; directory from inside the container and tuck it away in some other directory managed by the Docker daemon on your host file system and will mount that directory as &lt;code&gt;node_modules&lt;/code&gt; inside the container.&lt;/p&gt;
&lt;h2 id=&#34;performing-multi-staged-builds&#34;&gt;Performing Multi-Staged Builds&lt;/h2&gt;
&lt;p&gt;So far in this section, you&amp;rsquo;ve built an image for running a JavaScript application in development mode. Now if you want to build the image in production mode, some new challenges show up. In development mode the &lt;code&gt;npm run serve&lt;/code&gt; command starts a development server that serves the application to the user. That server not only serves the files but also provides the hot reload feature.&lt;/p&gt;
&lt;p&gt;In production mode, the &lt;code&gt;npm run build&lt;/code&gt; command compiles all your JavaScript code into some static HTML, CSS and JavaScript files. To run these files you don&amp;rsquo;t need node or any other runtime dependencies. All you need is a server like &lt;code&gt;nginx&lt;/code&gt; for example.&lt;/p&gt;
&lt;p&gt;So to create an image where the application runs in production mode, you can take the following steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;node&lt;/code&gt; as the base image and build the application.&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;nginx&lt;/code&gt; inside the node image and use that to serve the static files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach is a completely valid but the problem is that the &lt;code&gt;node&lt;/code&gt; image is big and most of the stuff it carries is unnecessary to serve your static files. A better approach to this scenario is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;node&lt;/code&gt; image as the base and build the application.&lt;/li&gt;
&lt;li&gt;Copy the files created using the &lt;code&gt;node&lt;/code&gt; image to a &lt;code&gt;nginx&lt;/code&gt; image.&lt;/li&gt;
&lt;li&gt;Create the final image based on &lt;code&gt;nginx&lt;/code&gt; and discard all &lt;code&gt;node&lt;/code&gt; related stuff.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This way your image only contains the files that are needed and becomes really handy. This approach is a multi-staged build. To perform such a build, create a new &lt;code&gt;Dockerfile&lt;/code&gt; inside your &lt;code&gt;hello-dock&lt;/code&gt; project directory and put following content in there:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM node:lts-alpine as builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WORKDIR /app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY ./package.json ./
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN npm run build
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM nginx:stable-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EXPOSE 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY --from=builder /app/dist /usr/share/nginx/html
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see the &lt;code&gt;Dockerfile&lt;/code&gt; looks a lot like your previous ones with a few oddities. Explanation for this file is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Line 1 starts the first stage of the build using &lt;code&gt;node:lts-alpine&lt;/code&gt; as the base image. The &lt;code&gt;as builder&lt;/code&gt; syntax assigns a name to this stage so that it can be referred to later on.&lt;/li&gt;
&lt;li&gt;From line 3 to line 9, it&amp;rsquo;s standard stuff that you&amp;rsquo;ve seen many times before. The &lt;code&gt;RUN npm run build&lt;/code&gt; command actually compiles the entire application and tucks it inside &lt;code&gt;/app/dist&lt;/code&gt; directory where &lt;code&gt;/app&lt;/code&gt; is the working directory and &lt;code&gt;/dist&lt;/code&gt; is the default output directory for &lt;code&gt;vite&lt;/code&gt; applications.&lt;/li&gt;
&lt;li&gt;Line 11 starts the second stage of the build using &lt;code&gt;nginx:stable-alpine&lt;/code&gt; as the base image.&lt;/li&gt;
&lt;li&gt;The NGINX server runs on port 80 by default hence the line &lt;code&gt;EXPOSE 80&lt;/code&gt; is added.&lt;/li&gt;
&lt;li&gt;The last line is a &lt;code&gt;COPY&lt;/code&gt; instruction. The &lt;code&gt;--from=builder&lt;/code&gt; part indicates that you want to copy some files from the &lt;code&gt;builder&lt;/code&gt; stage. After that it&amp;rsquo;s a standard copy instruction where &lt;code&gt;/app/dist&lt;/code&gt; is the source and &lt;code&gt;/usr/share/nginx/html&lt;/code&gt; is the destination. The destination used here is the default site path for NGINX so any static file you put inside there will be automatically served.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see the resultant image is a &lt;code&gt;nginx&lt;/code&gt; base image containing only the files necessary for running the application. To build this image execute following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --tag hello-dock:prod .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/9 : FROM node:lts-alpine as builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 72aaced1868f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/9 : WORKDIR /app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in e361c5c866dd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container e361c5c866dd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 241b4b97b34c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/9 : COPY ./package.json ./
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 6c594c5d2300
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/9 : RUN npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 6dfabf0ee9f8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm WARN deprecated fsevents@2.1.3: Please update to v 2.2.x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;gt; esbuild@0.8.29 postinstall /app/node_modules/esbuild
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;gt; node install.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm notice created a lockfile as package-lock.json. You should commit this file.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.1.2 (node_modules/chokidar/node_modules/fsevents):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {&amp;#34;os&amp;#34;:&amp;#34;darwin&amp;#34;,&amp;#34;arch&amp;#34;:&amp;#34;any&amp;#34;} (current: {&amp;#34;os&amp;#34;:&amp;#34;linux&amp;#34;,&amp;#34;arch&amp;#34;:&amp;#34;x64&amp;#34;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm WARN hello-dock@0.0.0 No description
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm WARN hello-dock@0.0.0 No repository field.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# npm WARN hello-dock@0.0.0 No license field.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# added 327 packages from 301 contributors and audited 329 packages in 35.971s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 26 packages are looking for funding
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#   run `npm fund` for details
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# found 0 vulnerabilities
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 6dfabf0ee9f8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 21fd1b065314
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/9 : COPY . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 43243f95bff7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/9 : RUN npm run build
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 4d918cf18584
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;gt; hello-dock@0.0.0 build /app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;gt; vite build
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# - Building production bundle...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# [write] dist/index.html 0.39kb, brotli: 0.15kb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# [write] dist/_assets/docker-handbook-github.3adb4865.webp 12.32kb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# [write] dist/_assets/index.eabcae90.js 42.56kb, brotli: 15.40kb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# [write] dist/_assets/style.0637ccc5.css 0.16kb, brotli: 0.10kb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# - Building production bundle...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Build completed in 1.71s.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 4d918cf18584
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 187fb3e82d0d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/9 : EXPOSE 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in b3aab5cf5975
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container b3aab5cf5975
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; d6fcc058cfda
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 8/9 : FROM nginx:stable-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# stable: Pulling from library/nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 6ec7b7d162b2: Already exists
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 43876acb2da3: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 7a79edd1e27b: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# eea03077c87e: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# eba7631b45c5: Pull complete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Digest: sha256:2eea9f5d6fff078ad6cc6c961ab11b8314efd91fb8480b5d054c7057a619e0c3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Status: Downloaded newer image for nginx:stable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 05f64a802c26
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 9/9 : COPY --from=builder /app/dist /usr/share/nginx/html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 8c6dfc34a10d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 8c6dfc34a10d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged hello-dock:prod
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the image has been built, you may run a new container by executing the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --rm \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --detach \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --name hello-dock-prod \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --publish 8080:80 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    hello-dock:prod
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 224aaba432bb09aca518fdd0365875895c2f5121eb668b2e7b2d5a99c019b953
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The running application should be available on &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; address:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/containerizing-a-javascript-application/hello-dock-prod.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here you can see my &lt;code&gt;hello-dock&lt;/code&gt; application in all it&amp;rsquo;s glory. Multi-staged builds can be very useful if you&amp;rsquo;re building large applications with a lot of dependencies. If configured properly, images built in multiple stages can be very optimized and compact.&lt;/p&gt;
&lt;h2 id=&#34;ignoring-unnecessary-files&#34;&gt;Ignoring Unnecessary Files&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve been working with &lt;code&gt;git&lt;/code&gt; for some time now, you may know about the &lt;code&gt;.gitignore&lt;/code&gt; files in projects, containing a list of files and directories to be excluded from the repository. Well Docker has a similar concept. The &lt;code&gt;.dockerignore&lt;/code&gt; file contains a list of files and directories to be excluded from image builds. You can find a pre-created &lt;code&gt;.dockerignore&lt;/code&gt; file in the &lt;code&gt;hello-dock&lt;/code&gt; directory.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*Dockerfile*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*docker-compose*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;node_modules
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This &lt;code&gt;.dockerignore&lt;/code&gt; file has to be in the build context. Files and directories mentioned here will be ignored by the &lt;code&gt;COPY&lt;/code&gt; instruction but if you do a bind mount, the &lt;code&gt;.dockerignore&lt;/code&gt; file will have no effect. I&amp;rsquo;ve added &lt;code&gt;.dockerignore&lt;/code&gt; files where necessary in the project repository.&lt;/p&gt;
&lt;h1 id=&#34;network-manipulation-basics&#34;&gt;Network Manipulation Basics&lt;/h1&gt;
&lt;p&gt;So far in this article, you&amp;rsquo;ve only worked with single container projects. But in real life, the majority of projects that you&amp;rsquo;ll have to work with will have at least more than one container and to be honest, working with a bunch of containers can be a little difficult if you don&amp;rsquo;t understand the nuances of container isolation. So in this section of the article you&amp;rsquo;ll get familiar with basic networking with Docker and will work hands on with a small multi-container project.&lt;/p&gt;
&lt;p&gt;Well you&amp;rsquo;ve already learned in the previous section that containers are isolated environments. Now consider a scenario where you have a &lt;code&gt;notes-api&lt;/code&gt; application powered by &lt;a href=&#34;https://expressjs.com/&#34;&gt;Express.js&lt;/a&gt; and a &lt;a href=&#34;https://www.postgresql.org/&#34;&gt;PostgreSQL&lt;/a&gt; database server running in two separate containers.&lt;/p&gt;
&lt;p&gt;These two containers are completely isolated from each other and oblivious about each other&amp;rsquo;s existence. &lt;strong&gt;So how do you connect the two? Ain&amp;rsquo;t that a challenge?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You may think of two possible solution to this problem. They are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Accessing the database server using an exposed port.&lt;/li&gt;
&lt;li&gt;Accessing the database server using its IP address and default port.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first one is exposing a port from the &lt;code&gt;postgres&lt;/code&gt; container and the &lt;code&gt;notes-api&lt;/code&gt; will connect through that. Assuming that the exposed port from the &lt;code&gt;postgres&lt;/code&gt; container is 5432. Now if you try to connect to &lt;code&gt;127.0.0.1:5432&lt;/code&gt; from inside the &lt;code&gt;notes-api&lt;/code&gt; container, you&amp;rsquo;ll find that the &lt;code&gt;notes-api&lt;/code&gt; can&amp;rsquo;t find the database server at all.&lt;/p&gt;
&lt;p&gt;The reason is that when you&amp;rsquo;re saying &lt;code&gt;127.0.0.1&lt;/code&gt; inside the &lt;code&gt;notes-api&lt;/code&gt; container, you&amp;rsquo;re simply referring to the &lt;code&gt;localhost&lt;/code&gt; of that container and that container only. The &lt;code&gt;postgres&lt;/code&gt; server simply doesn&amp;rsquo;t exist there. As a result the &lt;code&gt;notes-api&lt;/code&gt; application failed to connect.&lt;/p&gt;
&lt;p&gt;The second solution you may think of is finding the exact IP address of the &lt;code&gt;postgres&lt;/code&gt; container using &lt;code&gt;container inspect&lt;/code&gt; command and use that with the port. Assuming the name of the &lt;code&gt;postgres&lt;/code&gt; container is &lt;code&gt;notes-api-db-server&lt;/code&gt; you can easily get the IP address by executing the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container inspect --format=&amp;#39;{{range .NetworkSettings.Networks}} {{.IPAddress}} {{end}}&amp;#39; notes-api-db-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  172.17.0.2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now given the default port for &lt;code&gt;postgres&lt;/code&gt; is &lt;code&gt;5432&lt;/code&gt;, you can very easily access the database server by connecting to &lt;code&gt;172.17.0.2:5432&lt;/code&gt; from the &lt;code&gt;notes-api&lt;/code&gt; container.&lt;/p&gt;
&lt;p&gt;There are problems in this approach as well. Using IP addresses to refer to a container is not recommended. Also, if the container gets destroyed and recreated, the IP address may change. Keeping track of these changing IP addresses can be pretty hectic.&lt;/p&gt;
&lt;p&gt;Now that I&amp;rsquo;ve dismissed the possible wrong answers to the original question, the correct answer is, &lt;strong&gt;you connect them by putting them under a user-defined bridge network.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;network-basics&#34;&gt;Network Basics&lt;/h2&gt;
&lt;p&gt;Network in Docker is another logical object like container and image. Just like the other two, there is a plethora of commands under the &lt;code&gt;docker network&lt;/code&gt; group for manipulating networks. To list out the networks in your system, execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# NETWORK ID     NAME      DRIVER    SCOPE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# c2e59f2b96bd   bridge    bridge    local
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 124dccee067f   host      host      local
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 506e3822bf1f   none      null      local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should see three networks in your system. Now look at the &lt;code&gt;DRIVER&lt;/code&gt; column of the table here. These drivers are can be treated as the type of network. By default, Docker has five networking drivers. They are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bridge&lt;/code&gt; - The default networking driver in Docker. This can be used when multiple containers are running in standard mode and needs to communicate with each other.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;host&lt;/code&gt; - Removes the network isolation completely. Any container running under a &lt;code&gt;host&lt;/code&gt; network is basically attached to the network of the host system.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;none&lt;/code&gt; - This driver disables networking for containers altogether. I haven&amp;rsquo;t&amp;rsquo; found any use-case for this yet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;overlay&lt;/code&gt; - This is used for connecting multiple Docker daemons across computers and is out of the scope of this article.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;macvlan&lt;/code&gt; - Allows assignment of MAC addresses to containers making them function like physical devices in a network.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also third-party plugins that allow you to integrate Docker with specialized network stacks. Out of the five mentioned above, you&amp;rsquo;ll only work with &lt;code&gt;bridge&lt;/code&gt; networking driver in this article.&lt;/p&gt;
&lt;h2 id=&#34;creating-a-user-defined-bridge&#34;&gt;Creating a User-Defined Bridge&lt;/h2&gt;
&lt;p&gt;Before you start creating your own bridge, I would like to take some time to discuss the default bridge network that comes with Docker. Let&amp;rsquo;s begin by listing all the networks on your system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# NETWORK ID     NAME      DRIVER    SCOPE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# c2e59f2b96bd   bridge    bridge    local
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 124dccee067f   host      host      local
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 506e3822bf1f   none      null      local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, Docker comes with a default bridge network named &lt;code&gt;bridge&lt;/code&gt;. Any container you run will be automatically attached to this bridge network:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --rm --detach --name hello-dock --publish 8080:80 fhsinchy/hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# a37f723dad3ae793ce40f97eb6bb236761baa92d72a2c27c24fc7fda0756657d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network inspect --format=&amp;#39;{{range .Containers}}{{.Name}}{{end}}&amp;#39; bridge
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Containers attached to the default bridge network can communicate with each others using IP addresses which I have already discouraged on the previous sub-section.&lt;/p&gt;
&lt;p&gt;A user-defined bridge however has some extra feature over the default one. According to the official &lt;a href=&#34;https://docs.docker.com/network/bridge/#differences-between-user-defined-bridges-and-the-default-bridge&#34;&gt;docs&lt;/a&gt; on this topic, some notable extra features are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User-defined bridges provide automatic DNS resolution between containers:&lt;/strong&gt; This means containers attached to the same network can communicate with each others using the container name. So if you have two containers named &lt;code&gt;notes-api&lt;/code&gt; and &lt;code&gt;notes-db&lt;/code&gt; the API container will be able to connect to the database container using the &lt;code&gt;notes-db&lt;/code&gt; name.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User-defined bridges provide better isolation:&lt;/strong&gt; All containers are attached to the default bridge network by default which can cause conflicts among them. Attaching containers to a user-defined bridge can ensure better isolation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Containers can be attached and detached from user-defined networks on the fly:&lt;/strong&gt; During a container’s lifetime, you can connect or disconnect it from user-defined networks on the fly. To remove a container from the default bridge network, you need to stop the container and recreate it with different network options.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that you&amp;rsquo;ve learned quite a lot about a user-defined network, it&amp;rsquo;s time to create one for yourself. A network can be created using the &lt;code&gt;network create&lt;/code&gt; command. The generic syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network create &amp;lt;network name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To create a network with the name &lt;code&gt;skynet&lt;/code&gt; execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network create skynet
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 7bd5f351aa892ac6ec15fed8619fc3bbb95a7dcdd58980c28304627c8f7eb070
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# NETWORK ID     NAME     DRIVER    SCOPE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# be0cab667c4b   bridge   bridge    local
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 124dccee067f   host     host      local
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 506e3822bf1f   none     null      local
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 7bd5f351aa89   skynet   bridge    local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see a new network has been created with the given name. No container is currently attached to this network. In the next sub-section, you&amp;rsquo;ll learn about attaching containers to a network.&lt;/p&gt;
&lt;h2 id=&#34;attaching-containers-to-a-network&#34;&gt;Attaching Containers to a Network&lt;/h2&gt;
&lt;p&gt;There are mostly two ways of attaching a container to a network. You can use the &lt;code&gt;network connect&lt;/code&gt; command to attach a container to a network. The generic syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network connect &amp;lt;network identifier&amp;gt; &amp;lt;container identifier&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To connect the &lt;code&gt;hello-dock&lt;/code&gt; container to the &lt;code&gt;skynet&lt;/code&gt; network, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network connect skynet hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network inspect --format=&amp;#39;{{range .Containers}} {{.Name}} {{end}}&amp;#39; skynet
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network inspect --format=&amp;#39;{{range .Containers}} {{.Name}} {{end}}&amp;#39; bridge
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see from the outputs of the two &lt;code&gt;network inspect&lt;/code&gt; commands, the &lt;code&gt;hello-dock&lt;/code&gt; container is now attached to both the &lt;code&gt;skynet&lt;/code&gt; and the default &lt;code&gt;bridge&lt;/code&gt; network.&lt;/p&gt;
&lt;p&gt;The second way of attaching a container to a network is by using the &lt;code&gt;--network&lt;/code&gt; option for &lt;code&gt;container run&lt;/code&gt; or &lt;code&gt;container create&lt;/code&gt; commands. The generic syntax for the option is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--network &amp;lt;network identifier&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To run another &lt;code&gt;hello-dock&lt;/code&gt; container to the attached to the same network, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run --network skynet --rm --name alpine-box -it alpine sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# lands you into alpine linux shell
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/ # ping hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# PING hello-dock (172.18.0.2): 56 data bytes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.191 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.103 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.139 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=3 ttl=64 time=0.142 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=4 ttl=64 time=0.146 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=5 ttl=64 time=0.095 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=6 ttl=64 time=0.181 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=7 ttl=64 time=0.138 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=8 ttl=64 time=0.158 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=9 ttl=64 time=0.137 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=10 ttl=64 time=0.145 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=11 ttl=64 time=0.138 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 64 bytes from 172.18.0.2: seq=12 ttl=64 time=0.085 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--- hello-dock ping statistics ---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;13 packets transmitted, 13 packets received, 0% packet loss
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;round-trip min/avg/max = 0.085/0.138/0.191 ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, running &lt;code&gt;ping hello-dock&lt;/code&gt; from inside the &lt;code&gt;alpine-box&lt;/code&gt; container works because both of the containers are under the same user-defined bridge network and automatic DNS resolution is working.&lt;/p&gt;
&lt;p&gt;Keep in mind though, in order for the automatic DNS resolution to work you must assign custom names to the containers. Using the randomly generated name will not work.&lt;/p&gt;
&lt;h2 id=&#34;detaching-containers-from-a-network&#34;&gt;Detaching Containers from a Network&lt;/h2&gt;
&lt;p&gt;In the previous sub-section you&amp;rsquo;ve learned about attaching containers to a network. In this sub-section, you&amp;rsquo;ll learn about how to detach them. The &lt;code&gt;network disconnect&lt;/code&gt; command can be used for this task. The generic syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network disconnect &amp;lt;network identifier&amp;gt; &amp;lt;container identifier&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To detach the &lt;code&gt;hello-dock&lt;/code&gt; container from the &lt;code&gt;skynet&lt;/code&gt; network, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network disconnect skynet hello-dock
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just like the &lt;code&gt;network connect&lt;/code&gt; command, the &lt;code&gt;network disconnect&lt;/code&gt; command doesn&amp;rsquo;t give any output either.&lt;/p&gt;
&lt;h2 id=&#34;getting-rid-of-networks&#34;&gt;Getting Rid of Networks&lt;/h2&gt;
&lt;p&gt;Just like the other logical objects in Docker, networks can be removed using the &lt;code&gt;network rm&lt;/code&gt; command. The generic syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network rm &amp;lt;network identifier&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To remove the &lt;code&gt;skynet&lt;/code&gt; network from your system, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network rm skynet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also use the &lt;code&gt;network prune&lt;/code&gt; command to remove any unused networks from your system. The command also has the &lt;code&gt;-f&lt;/code&gt; or &lt;code&gt;--force&lt;/code&gt; and &lt;code&gt;-a&lt;/code&gt; or &lt;code&gt;--all&lt;/code&gt; options.&lt;/p&gt;
&lt;h1 id=&#34;containerizing-a-multi-container-javascript-application&#34;&gt;Containerizing a Multi-Container JavaScript Application&lt;/h1&gt;
&lt;p&gt;Now that you&amp;rsquo;ve learned enough about networks in Docker, in this sub-section you&amp;rsquo;ll learn to containerize a full-fledged multi-container project. The project you&amp;rsquo;ll be working with is a simple &lt;code&gt;notes-api&lt;/code&gt; powered by Express.js and PostgreSQL.&lt;/p&gt;
&lt;p&gt;In this project there are two containers in total that you&amp;rsquo;ll have to connect using a network. Apart from this, you&amp;rsquo;ll also learn about concepts like environment variables and named volumes. So without further ado, lets jump right in.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-custom-bridge-network&#34;&gt;Setting Up The Custom Bridge Network&lt;/h2&gt;
&lt;p&gt;As you&amp;rsquo;ve learned in the previous section, the containers have to be attached to a user-defined bridge network in order to communicate with each other using container names. To do so, create a network named notes-api-network in your system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network create notes-api-network
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;running-the-database-server&#34;&gt;Running the Database Server&lt;/h2&gt;
&lt;p&gt;The database server in this project is a simple PostgreSQL server and uses the official &lt;a href=&#34;https://hub.docker.com/_/postgres&#34;&gt;postgres&lt;/a&gt; image. According to the official docs, in order to run a container with this image, you must provide the &lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt; environment variable. Apart from this one, I&amp;rsquo;ll also provide a name for the default database using the &lt;code&gt;POSTGRES_DB&lt;/code&gt; environment variable. PostgreSQL by default listens on &lt;code&gt;5432&lt;/code&gt; port, so you need to publish that as well.&lt;/p&gt;
&lt;p&gt;To run the database server you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --detach \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --name=notes-db \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --env POSTGRES_DB=notesdb \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --env POSTGRES_PASSWORD=secret \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --network=notes-api-network \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    postgres:12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# a7b287d34d96c8e81a63949c57b83d7c1d71b5660c87f5172f074bd1606196dc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID   IMAGE         COMMAND                  CREATED              STATUS              PORTS      NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# a7b287d34d96   postgres:12   &amp;#34;docker-entrypoint.s…&amp;#34;   About a minute ago   Up About a minute   5432/tcp   notes-db
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--env&lt;/code&gt; option for the &lt;code&gt;container run&lt;/code&gt; and &lt;code&gt;container create&lt;/code&gt; commands can be used for providing environment variables to a container. As you can see, the database container has been created successfully and is running now.&lt;/p&gt;
&lt;p&gt;Although the container is running, there is a small problem. Databases like PostgreSQL, MongoDB, MySQL persist their data in a directory. PostgreSQL uses the &lt;code&gt;/var/lib/postgresql/data&lt;/code&gt; directory inside the container to persist data. Now what if the container gets destroyed for some reason? You&amp;rsquo;ll lose all your data. To solve this problem, a named volume can be used.&lt;/p&gt;
&lt;h2 id=&#34;working-with-named-volumes&#34;&gt;Working With Named Volumes&lt;/h2&gt;
&lt;p&gt;Previously you&amp;rsquo;ve worked with bind mounts and anonymous volumes. A named volume is very similar to an anonymous volume except the fact that you can refer to a named volume using its name. Volumes are also logical objects in Docker and can be manipulated using the CLI. The &lt;code&gt;volume create&lt;/code&gt; command can be used for creating a named volume.&lt;/p&gt;
&lt;p&gt;The generic syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker volume create &amp;lt;volume name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To create a volume named &lt;code&gt;notes-db-data&lt;/code&gt; you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker volume create notes-db-data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-db-data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker volume ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# DRIVER    VOLUME NAME
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# local     notes-db-data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This volume can now be mounted to &lt;code&gt;/var/lib/postgresql/data&lt;/code&gt; inside the &lt;code&gt;notes-db&lt;/code&gt; container. To do so, stop and remove the &lt;code&gt;notes-db&lt;/code&gt; container:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container stop notes-db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container rm notes-db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-db
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now run a new container and assign the volume using the &lt;code&gt;--volume&lt;/code&gt; or &lt;code&gt;-v&lt;/code&gt; option.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --detach \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --volume notes-db-data:/var/lib/postgresql/data \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --name=notes-db \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --env POSTGRES_DB=notesdb \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --env POSTGRES_PASSWORD=secret \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --network=notes-api-network \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    postgres:12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 37755e86d62794ed3e67c19d0cd1eba431e26ab56099b92a3456908c1d346791
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now inspect the &lt;code&gt;notes-db&lt;/code&gt; container to make sure that the mounting was successful:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container inspect --format=&amp;#39;{{range .Mounts}} {{ .Name }} {{end}}&amp;#39; notes-db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  notes-db-data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the data will be safely stored inside the &lt;code&gt;notes-db-data&lt;/code&gt; volume and can be reused in the future. A bind mount can also be used instead of a named volume here, but I prefer a named volume in such scenarios.&lt;/p&gt;
&lt;h2 id=&#34;accessing-logs-from-a-container&#34;&gt;Accessing Logs From a Container&lt;/h2&gt;
&lt;p&gt;In order to see the logs from a container, you can use the &lt;code&gt;container logs&lt;/code&gt; command. The generic syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container logs &amp;lt;container identifier&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To access the logs from the &lt;code&gt;notes-db&lt;/code&gt; container, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container logs notes-db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# The files belonging to this database system will be owned by user &amp;#34;postgres&amp;#34;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# This user must also own the server process.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# The database cluster will be initialized with locale &amp;#34;en_US.utf8&amp;#34;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# The default database encoding has accordingly been set to &amp;#34;UTF8&amp;#34;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# The default text search configuration will be set to &amp;#34;english&amp;#34;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Data page checksums are disabled.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# fixing permissions on existing directory /var/lib/postgresql/data ... ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# creating subdirectories ... ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# selecting dynamic shared memory implementation ... posix
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# selecting default max_connections ... 100
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# selecting default shared_buffers ... 128MB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# selecting default time zone ... Etc/UTC
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# creating configuration files ... ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# running bootstrap script ... ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# performing post-bootstrap initialization ... ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# syncing data to disk ... ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Success. You can now start the database server using:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#     pg_ctl -D /var/lib/postgresql/data -l logfile start
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# initdb: warning: enabling &amp;#34;trust&amp;#34; authentication for local connections
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# You can change this by editing pg_hba.conf or using the option -A, or
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# --auth-local and --auth-host, the next time you run initdb.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# waiting for server to start....2021-01-25 13:39:21.613 UTC [47] LOG:  starting PostgreSQL 12.5 (Debian 12.5-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:21.621 UTC [47] LOG:  listening on Unix socket &amp;#34;/var/run/postgresql/.s.PGSQL.5432&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:21.675 UTC [48] LOG:  database system was shut down at 2021-01-25 13:39:21 UTC
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:21.685 UTC [47] LOG:  database system is ready to accept connections
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# server started
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CREATE DATABASE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.008 UTC [47] LOG:  received fast shutdown request
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# waiting for server to shut down....2021-01-25 13:39:22.015 UTC [47] LOG:  aborting any active transactions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.017 UTC [47] LOG:  background worker &amp;#34;logical replication launcher&amp;#34; (PID 54) exited with exit code 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.017 UTC [49] LOG:  shutting down
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.056 UTC [47] LOG:  database system is shut down
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# server stopped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# PostgreSQL init process complete; ready for start up.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.135 UTC [1] LOG:  starting PostgreSQL 12.5 (Debian 12.5-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.136 UTC [1] LOG:  listening on IPv4 address &amp;#34;0.0.0.0&amp;#34;, port 5432
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.136 UTC [1] LOG:  listening on IPv6 address &amp;#34;::&amp;#34;, port 5432
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.147 UTC [1] LOG:  listening on Unix socket &amp;#34;/var/run/postgresql/.s.PGSQL.5432&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.177 UTC [75] LOG:  database system was shut down at 2021-01-25 13:39:22 UTC
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 2021-01-25 13:39:22.190 UTC [1] LOG:  database system is ready to accept connections
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Evident by the text in line 57, the database is up and ready for accepting connections from the outside. There is also the &lt;code&gt;--follow&lt;/code&gt; or &lt;code&gt;-f&lt;/code&gt; option for the command which lets you attach the console to the logs output and get a continuous stream of text.&lt;/p&gt;
&lt;h2 id=&#34;attaching-the-database-server-in-case-you-missed-it-earlier&#34;&gt;Attaching The Database Server (in case you missed it earlier)&lt;/h2&gt;
&lt;p&gt;Your container should be connected to the network &amp;ldquo;notes-api-network&amp;rdquo; now. Recall that you can use &lt;code&gt;docker network inspect --format=&#39;{{range .Containers}}{{.Name}}{{end}}&#39; notes-api-network&lt;/code&gt; to verify, and it should look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network inspect --format=&amp;#39;{{range .Containers}}{{.Name}}{{end}}&amp;#39; notes-api-network
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-db
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If that command instead returns a blank line, you can attach the &lt;code&gt;notes-db&lt;/code&gt; container to this network by executing the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker network connect notes-api-network notes-db
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;writing-the-dockerfile&#34;&gt;Writing The Dockerfile&lt;/h2&gt;
&lt;p&gt;Go to the directory where you&amp;rsquo;ve cloned the project codes. Inside there, go inside the &lt;code&gt;notes-api/api&lt;/code&gt; directory, and create a new &lt;code&gt;Dockerfile&lt;/code&gt; in there. Put following code in the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# stage one
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM node:lts-alpine as builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# install dependencies for node-gyp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN apk add --no-cache python make g++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WORKDIR /app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY ./package.json .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN npm install --only=prod
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# stage two
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM node:lts-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EXPOSE 3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ENV NODE_ENV=production
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;USER node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN mkdir -p /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WORKDIR /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY --from=builder /app/node_modules  /home/node/app/node_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CMD [ &amp;#34;node&amp;#34;, &amp;#34;bin/www&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a multi-staged build. The first stage is used for building and installing the dependencies using &lt;code&gt;node-gyp&lt;/code&gt; and the second stage is for running the application. I&amp;rsquo;ll go through the steps briefly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stage 1 uses &lt;code&gt;node:lts-alpine&lt;/code&gt; as its base and uses &lt;code&gt;builder&lt;/code&gt; as the stage name.&lt;/li&gt;
&lt;li&gt;On line 5, we install &lt;code&gt;python&lt;/code&gt;, &lt;code&gt;make&lt;/code&gt; and &lt;code&gt;g++&lt;/code&gt;. The &lt;code&gt;node-gyp&lt;/code&gt; tool requires these three packages to run.&lt;/li&gt;
&lt;li&gt;On line 7, we set &lt;code&gt;/app&lt;/code&gt; directory as the &lt;code&gt;WORKDIR&lt;/code&gt; .&lt;/li&gt;
&lt;li&gt;On line 9 and 10, we copy the &lt;code&gt;package.json&lt;/code&gt; file to the &lt;code&gt;WORKDIR&lt;/code&gt; and installs all the dependencies.&lt;/li&gt;
&lt;li&gt;Stage 2 also uses &lt;code&gt;node-lts:alpine&lt;/code&gt; as the base.&lt;/li&gt;
&lt;li&gt;On line 16, we set the &lt;code&gt;NODE_ENV&lt;/code&gt; environment variable to &lt;code&gt;production&lt;/code&gt;. This is important for the API to run properly.&lt;/li&gt;
&lt;li&gt;From line 18 to line 20, we set the default user to &lt;code&gt;node&lt;/code&gt;, create the &lt;code&gt;/home/node/app&lt;/code&gt; directory and set that as the &lt;code&gt;WORKDIR&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On line 22, we copy all the project files and on line 23 we copy the &lt;code&gt;node_modules&lt;/code&gt; directory from the &lt;code&gt;builder&lt;/code&gt; stage. This directory contains all the built dependencies necessary for running the application.&lt;/li&gt;
&lt;li&gt;On line 25, we set the default command.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To build an image from this &lt;code&gt;Dockerfile&lt;/code&gt;, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker image build --tag notes-api .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon  37.38kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/14 : FROM node:lts-alpine as builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 471e8b4eb0b2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/14 : RUN apk add --no-cache python make g++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 5f20a0ecc04b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (1/21) Installing binutils (2.33.1-r0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (2/21) Installing gmp (6.1.2-r1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (3/21) Installing isl (0.18-r0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (4/21) Installing libgomp (9.3.0-r0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (5/21) Installing libatomic (9.3.0-r0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (6/21) Installing mpfr4 (4.0.2-r1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (7/21) Installing mpc1 (1.1.0-r1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (8/21) Installing gcc (9.3.0-r0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (9/21) Installing musl-dev (1.1.24-r3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (10/21) Installing libc-dev (0.7.2-r0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (11/21) Installing g++ (9.3.0-r0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (12/21) Installing make (4.2.1-r2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (13/21) Installing libbz2 (1.0.8-r1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (14/21) Installing expat (2.2.9-r1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (15/21) Installing libffi (3.2.1-r6)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (16/21) Installing gdbm (1.13-r1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (17/21) Installing ncurses-terminfo-base (6.1_p20200118-r4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (18/21) Installing ncurses-libs (6.1_p20200118-r4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (19/21) Installing readline (8.0.1-r0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (20/21) Installing sqlite-libs (3.30.1-r2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# (21/21) Installing python2 (2.7.18-r0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Executing busybox-1.31.1-r9.trigger
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# OK: 212 MiB in 37 packages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 5f20a0ecc04b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 637ca797d709
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/14 : WORKDIR /app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 846361b57599
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 846361b57599
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 3d58a482896e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/14 : COPY ./package.json .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 11b387794039
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/14 : RUN npm install --only=prod
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 2e27e33f935d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  added 269 packages from 220 contributors and audited 1137 packages in 140.322s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 4 packages are looking for funding
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#   run `npm fund` for details
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# found 0 vulnerabilities
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 2e27e33f935d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; eb7cb2cb0b20
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/14 : FROM node:lts-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 471e8b4eb0b2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/14 : EXPOSE 3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 4ea24f871747
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 4ea24f871747
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 1f0206f2f050
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 8/14 : ENV NODE_ENV=production
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 5d40d6ac3b7e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 5d40d6ac3b7e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 31f62da17929
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 9/14 : USER node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 0963e1fb19a0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 0963e1fb19a0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 0f4045152b1c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 10/14 : RUN mkdir -p /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 0ac591b3adbd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 0ac591b3adbd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 5908373dfc75
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 11/14 : WORKDIR /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 55253b62ff57
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 55253b62ff57
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 2883cdb7c77a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 12/14 : COPY . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 8e60893a7142
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 13/14 : COPY --from=builder /app/node_modules  /home/node/app/node_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 27a85faa4342
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 14/14 : CMD [ &amp;#34;node&amp;#34;, &amp;#34;bin/www&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 349c8ca6dd3e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 349c8ca6dd3e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 9ea100571585
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 9ea100571585
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged notes-api:latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before you run a container using this image, make sure the database container is running, and is attached to the &lt;code&gt;notes-api-network&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container inspect notes-db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#     {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#         ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#         &amp;#34;State&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;Status&amp;#34;: &amp;#34;running&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;Running&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;Paused&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;Restarting&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;OOMKilled&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;Dead&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;Pid&amp;#34;: 11521,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;ExitCode&amp;#34;: 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;Error&amp;#34;: &amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;StartedAt&amp;#34;: &amp;#34;2021-01-26T06:55:44.928510218Z&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;FinishedAt&amp;#34;: &amp;#34;2021-01-25T14:19:31.316854657Z&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#         },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#         ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#         &amp;#34;Mounts&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;Type&amp;#34;: &amp;#34;volume&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;Name&amp;#34;: &amp;#34;notes-db-data&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;Source&amp;#34;: &amp;#34;/var/lib/docker/volumes/notes-db-data/_data&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;Destination&amp;#34;: &amp;#34;/var/lib/postgresql/data&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;Driver&amp;#34;: &amp;#34;local&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;Mode&amp;#34;: &amp;#34;z&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;RW&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;Propagation&amp;#34;: &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#         ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#         ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#         &amp;#34;NetworkSettings&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             &amp;#34;Networks&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;bridge&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;IPAMConfig&amp;#34;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;Links&amp;#34;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;Aliases&amp;#34;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;NetworkID&amp;#34;: &amp;#34;e4c7ce50a5a2a49672155ff498597db336ecc2e3bbb6ee8baeebcf9fcfa0e1ab&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;EndpointID&amp;#34;: &amp;#34;2a2587f8285fa020878dd38bdc630cdfca0d769f76fc143d1b554237ce907371&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;Gateway&amp;#34;: &amp;#34;172.17.0.1&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;IPAddress&amp;#34;: &amp;#34;172.17.0.2&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;IPPrefixLen&amp;#34;: 16,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;IPv6Gateway&amp;#34;: &amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;GlobalIPv6Address&amp;#34;: &amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;GlobalIPv6PrefixLen&amp;#34;: 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;MacAddress&amp;#34;: &amp;#34;02:42:ac:11:00:02&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;DriverOpts&amp;#34;: null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 &amp;#34;notes-api-network&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;IPAMConfig&amp;#34;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;Links&amp;#34;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;Aliases&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                         &amp;#34;37755e86d627&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;NetworkID&amp;#34;: &amp;#34;06579ad9f93d59fc3866ac628ed258dfac2ed7bc1a9cd6fe6e67220b15d203ea&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;EndpointID&amp;#34;: &amp;#34;5b8f8718ec9a5ec53e7a13cce3cb540fdf3556fb34242362a8da4cc08d37223c&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;Gateway&amp;#34;: &amp;#34;172.18.0.1&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;IPAddress&amp;#34;: &amp;#34;172.18.0.2&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;IPPrefixLen&amp;#34;: 16,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;IPv6Gateway&amp;#34;: &amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;GlobalIPv6Address&amp;#34;: &amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;GlobalIPv6PrefixLen&amp;#34;: 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;MacAddress&amp;#34;: &amp;#34;02:42:ac:12:00:02&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                     &amp;#34;DriverOpts&amp;#34;: {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#                 }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#             }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#         }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve shortened the output for easy viewing here. On my system, the &lt;code&gt;notes-db&lt;/code&gt; container is running, uses the &lt;code&gt;notes-db-data&lt;/code&gt; volume and is attached to the &lt;code&gt;notes-api-network&lt;/code&gt; bridge.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;re assured that everything is in place, you can run a new container by executing the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container run \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --detach \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --name=notes-api \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --env DB_HOST=notes-db \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --env DB_DATABASE=notesdb \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --env DB_PASSWORD=secret \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --publish=3000:3000 \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --network=notes-api-network \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    notes-api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# f9ece420872de99a060b954e3c236cbb1e23d468feffa7fed1e06985d99fb919
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should be able to understand this long command by yourself, I&amp;rsquo;ll go through the environment variables briefly. The &lt;code&gt;notes-api&lt;/code&gt; application requires three environment variables to be set. They are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DB_HOST&lt;/code&gt; - This is the host of the database server. Given both the database server and the API is attached to the same user-defined bridge network, the database server can be refereed to using its container name which is &lt;code&gt;notes-db&lt;/code&gt; in this case.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DB_DATABASE&lt;/code&gt; - The database that this API will use. On &lt;a href=&#34;/posts/the-docker-handbook/#running-the-database-server&#34;&gt;Running the Database Server&lt;/a&gt; we set the default database name to &lt;code&gt;notesdb&lt;/code&gt; using the &lt;code&gt;POSTGRES_DB&lt;/code&gt; environment variable. We&amp;rsquo;ll use that here.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DB_PASSWORD&lt;/code&gt; - Password for connecting to the database. This was also set on &lt;a href=&#34;/posts/the-docker-handbook/#running-the-database-server&#34;&gt;Running the Database Server&lt;/a&gt; sub-section using the &lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt; environment variable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To check if the container is running properly or not, you can use the &lt;code&gt;container ls&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS          PORTS                    NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# f9ece420872d   notes-api     &amp;#34;docker-entrypoint.s…&amp;#34;   12 minutes ago   Up 12 minutes   0.0.0.0:3000-&amp;gt;3000/tcp   notes-api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# 37755e86d627   postgres:12   &amp;#34;docker-entrypoint.s…&amp;#34;   17 hours ago     Up 14 minutes   5432/tcp                 notes-db
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The container is running now. You can visit &lt;code&gt;http://127.0.0.1:3000/&lt;/code&gt; to see the API in action.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/containerizing-a-multi-container-javascript-application/bonjour-mon-ami.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The API has five routes in total that you can see inside the &lt;code&gt;/notes-api/api/api/routes/notes.js&lt;/code&gt; file. It was bootstrapped with one of my open-source projects:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/fhsinchy/create-node-rocket-api&#34;&gt;https://github.com/fhsinchy/create-node-rocket-api&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Although the container is running, there is one last thing that you&amp;rsquo;ll have to do before you can start using it. You&amp;rsquo;ll have to run the database migration necessary for setting up the database tables, and you can do that by executing &lt;code&gt;npm run db:migrate&lt;/code&gt; command inside the container.&lt;/p&gt;
&lt;h2 id=&#34;executing-commands-in-a-running-container&#34;&gt;Executing Commands in a Running Container&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ve already learned about executing commands in a stopped container. Another scenario is executing a command inside a running container. For this, you&amp;rsquo;ll have to use the &lt;code&gt;exec&lt;/code&gt; command to execute a custom command inside a running container.&lt;/p&gt;
&lt;p&gt;The generic syntax for the &lt;code&gt;exec&lt;/code&gt; command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container exec &amp;lt;container identifier&amp;gt; &amp;lt;command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To execute &lt;code&gt;npm run db:migrate&lt;/code&gt; inside the &lt;code&gt;notes-api&lt;/code&gt; container, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container exec notes-api npm run db:migrate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;gt; notes-api@ db:migrate /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;gt; knex migrate:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Using environment: production
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Batch 1 run: 1 migrations
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In cases where you want to run an interactive command inside a running container, you&amp;rsquo;ll have to use the &lt;code&gt;-it&lt;/code&gt; flag. As an example, if you want to access the shell running inside the &lt;code&gt;notes-api&lt;/code&gt; container, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker container exec -it notes-api sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# / # uname -a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Linux b5b1367d6b31 5.10.9-201.fc33.x86_64 #1 SMP Wed Jan 20 16:56:23 UTC 2021 x86_64 Linux
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;writing-management-scripts&#34;&gt;Writing Management Scripts&lt;/h2&gt;
&lt;p&gt;Managing a multi-container project along with the network and volumes and stuff means writing a lot of commands. To simplify the process, I usually take help of simple &lt;a href=&#34;https://opensource.com/article/17/1/getting-started-shell-scripting&#34;&gt;shell scripts&lt;/a&gt; and a &lt;a href=&#34;https://opensource.com/article/18/8/what-how-makefile&#34;&gt;Makefile&lt;/a&gt;. You&amp;rsquo;ll find four shell scripts in the &lt;code&gt;notes-api&lt;/code&gt; directory. They are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;boot.sh&lt;/code&gt; - Used for starting the containers if they already exist.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;build.sh&lt;/code&gt; - Creates and runs the containers. It also creates the images, volumes and networks if necessary.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;destroy.sh&lt;/code&gt; - Removes all containers, volumes and networks associated with this project.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stop.sh&lt;/code&gt; - Stops all running containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is also a &lt;code&gt;Makefile&lt;/code&gt; that contains four targets named &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;destroy&lt;/code&gt; each invoking the previously mentioned shell scripts.&lt;/p&gt;
&lt;p&gt;If the container is in running state in your system, executing &lt;code&gt;make stop&lt;/code&gt; should stop all the containers. executing &lt;code&gt;make destroy&lt;/code&gt; should stop the containers and remove everything. Make sure you&amp;rsquo;re running the scripts inside the &lt;code&gt;notes-api&lt;/code&gt; directory (if you&amp;rsquo;re still in &lt;code&gt;notes-api\api&lt;/code&gt;, you can use the command &lt;code&gt;cd ..&lt;/code&gt; to back up one level to the correct directory before running the following):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make destroy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ./shutdown.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# stopping api container ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# api container stopped ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# stopping db container ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# db container stopped ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# shutdown script finished
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ./destroy.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# removing api container ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# api container removed ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# removing db container ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# db container removed ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# removing db data volume ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-db-data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# db data volume removed ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# removing network ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-network
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# network removed ---&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# destroy script finished
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re getting permission denied error than execute &lt;code&gt;chmod +x&lt;/code&gt; on the scripts:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x boot.sh build.sh destroy.sh shutdown.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m not going to explain these scripts because they&amp;rsquo;re simple &lt;code&gt;if-else&lt;/code&gt; statement along with some Docker commands that you&amp;rsquo;ve already seen many times. If you have some understanding of the Linux shell, you should be able to understand the scripts as well.&lt;/p&gt;
&lt;h1 id=&#34;composing-projects-using-docker-compose&#34;&gt;Composing Projects Using Docker-Compose&lt;/h1&gt;
&lt;p&gt;In the previous section, you&amp;rsquo;ve learned about managing a multi-container project and the difficulties of it. Instead of writing so many commands, there is an easier way to manage multi-container projects, a tool called &lt;a href=&#34;https://docs.docker.com/compose/&#34;&gt;Docker Compose&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;According to the Docker &lt;a href=&#34;https://docs.docker.com/compose/&#34;&gt;documentation&lt;/a&gt; - &amp;ldquo;Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Although Compose works in all environments, it&amp;rsquo;s more focused on development and testing. Using Compose on a production environment is not recommended at all.&lt;/p&gt;
&lt;h2 id=&#34;compose-basics&#34;&gt;Compose Basics&lt;/h2&gt;
&lt;p&gt;Go the directory where you&amp;rsquo;ve cloned the repository that came with this article. Go inside the &lt;code&gt;notes-api/api&lt;/code&gt; directory and create a &lt;code&gt;Dockerfile.dev&lt;/code&gt; file. Put the following code in it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# stage one
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM node:lts-alpine as builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# install dependencies for node-gyp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN apk add --no-cache python make g++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WORKDIR /app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY ./package.json .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# stage two
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM node:lts-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ENV NODE_ENV=development
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;USER node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RUN mkdir -p /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WORKDIR /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY --from=builder /app/node_modules /home/node/app/node_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CMD [ &amp;#34;./node_modules/.bin/nodemon&amp;#34;, &amp;#34;--config&amp;#34;, &amp;#34;nodemon.json&amp;#34;, &amp;#34;bin/www&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code is almost identical to the &lt;code&gt;Dockerfile&lt;/code&gt; that you worked with in the previous section. The three differences in this file are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On line 10, we run &lt;code&gt;npm install&lt;/code&gt; instead of &lt;code&gt;npm run install --only=prod&lt;/code&gt; because we want the development dependencies also.&lt;/li&gt;
&lt;li&gt;On line 15, we set the &lt;code&gt;NODE_ENV&lt;/code&gt; environment variable to &lt;code&gt;development&lt;/code&gt; instead of &lt;code&gt;production&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On line 24, we use a tool called &lt;a href=&#34;https://nodemon.io/&#34;&gt;nodemon&lt;/a&gt; to get hot-reload feature for the API.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You already know that this project has two containers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;notes-db&lt;/code&gt; - A database server powered by PostgreSQL.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;notes-api&lt;/code&gt; - A REST API powered by Express.js&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the world of compose, each container that makes up the application is known as a service and the first step to composing a multi-container project is to define these services.&lt;/p&gt;
&lt;p&gt;Just like the Docker daemon uses a &lt;code&gt;Dockerfile&lt;/code&gt; for building images, Docker Compose uses &lt;code&gt;docker-compose.yaml&lt;/code&gt; file to read service definitions from.&lt;/p&gt;
&lt;p&gt;Head to the &lt;code&gt;notes-api&lt;/code&gt; directory and create a new &lt;code&gt;docker-compose.yaml&lt;/code&gt; file. Put following code into the newly created file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;version: &amp;#34;3.8&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;services:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    db:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        image: postgres:12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        container_name: notes-db-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - db-data:/var/lib/postgresql/data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        environment:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            POSTGRES_DB: notesdb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            POSTGRES_PASSWORD: secret
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    api:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        build:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            context: ./api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            dockerfile: Dockerfile.dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        image: notes-api:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        container_name: notes-api-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        environment:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            DB_HOST: db ## same as the database service name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            DB_DATABASE: notesdb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            DB_PASSWORD: secret
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - /home/node/app/node_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - ./api:/home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ports:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - 3000:3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    db-data:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name: notes-db-dev-data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Every valid &lt;code&gt;docker-compose.yaml&lt;/code&gt; file starts by defining the file version. At the time of writing, &lt;code&gt;3.8&lt;/code&gt; is the latest version. You can look up the latest version &lt;a href=&#34;https://docs.docker.com/compose/compose-file/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Blocks in an YAML file are defined by indentation. I will go through each of the blocks and will explain what they do.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;services&lt;/code&gt; block holds the definitions for each of the services or containers in the application. &lt;code&gt;db&lt;/code&gt; and &lt;code&gt;api&lt;/code&gt; are the two services that comprise this project.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;db&lt;/code&gt; block defines a new service in the application and holds necessary information to start the container. Every service requires either a pre-built image or a &lt;code&gt;Dockerfile&lt;/code&gt; to run a container. For the &lt;code&gt;db&lt;/code&gt; service we&amp;rsquo;re using the official PostgreSQL image.&lt;/li&gt;
&lt;li&gt;Unlike the &lt;code&gt;db&lt;/code&gt; service, a pre-built image for the &lt;code&gt;api&lt;/code&gt; service doesn&amp;rsquo;t exist. Hence, we use the &lt;code&gt;Dockerfile.dev&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;volumes&lt;/code&gt; block defines any name volume needed by any of the services. At the time it only enlists &lt;code&gt;db-data&lt;/code&gt; volume used by the &lt;code&gt;db&lt;/code&gt; service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have a high level overview of the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file, lets have a closer look at the individual services.&lt;/p&gt;
&lt;p&gt;Definition code for the &lt;code&gt;db&lt;/code&gt; service is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;db:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    image: postgres:12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    container_name: notes-db-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - db-data:/var/lib/postgresql/data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    environment:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        POSTGRES_DB: notesdb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        POSTGRES_PASSWORD: secret
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;image&lt;/code&gt; key holds the image repository and tag used for this container. We&amp;rsquo;re using the &lt;code&gt;postgres:12&lt;/code&gt; image for running the database container.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;container_name&lt;/code&gt; indicates the name of the container. By default containers are named following &lt;code&gt;&amp;lt;project directory name&amp;gt;_&amp;lt;service name&amp;gt;&lt;/code&gt; syntax. You can override that using &lt;code&gt;container_name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;volumes&lt;/code&gt; array holds the volume mappings for the service and supports named volumes, anonymous volumes, bind mounts. The syntax &lt;code&gt;&amp;lt;source&amp;gt;:&amp;lt;destination&amp;gt;&lt;/code&gt; is identical to what you&amp;rsquo;ve seen before.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;environment&lt;/code&gt; map holds the values of the various environment variables needed for the service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Definition code for the &lt;code&gt;api&lt;/code&gt; service is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;api:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    build:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        context: ./api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        dockerfile: Dockerfile.dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    image: notes-api:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    container_name: notes-api-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    environment:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DB_HOST: db ## same as the database service name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DB_DATABASE: notesdb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DB_PASSWORD: secret
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - /home/node/app/node_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - ./api:/home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ports:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - 3000:3000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;api&lt;/code&gt; service doesn&amp;rsquo;t come with a pre-built image instead what it has is a build configuration. Under the &lt;code&gt;build&lt;/code&gt; block we define the context and the name of the Dockerfile for building an image. You should have an understanding of context and Dockerfile by now so I won&amp;rsquo;t spend time explaining those.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;image&lt;/code&gt; key holds the name of the image to be built. If not assigned the image will be named following the &lt;code&gt;&amp;lt;project directory name&amp;gt;_&amp;lt;service name&amp;gt;&lt;/code&gt; syntax.&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;environment&lt;/code&gt; map, the &lt;code&gt;DB_HOST&lt;/code&gt; variable demonstrates a feature of Compose. That is, you can refer to another service in the same application by using its name. So the &lt;code&gt;db&lt;/code&gt; here, will be replaced by the IP address of the &lt;code&gt;api&lt;/code&gt; service container. The &lt;code&gt;DB_DATABASE&lt;/code&gt; and &lt;code&gt;DB_PASSWORD&lt;/code&gt; variables have to match up with &lt;code&gt;POSTGRES_DB&lt;/code&gt; and &lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt; respectively from the &lt;code&gt;db&lt;/code&gt; service definition.&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;volumes&lt;/code&gt; map, you can see an anonymous volume and a bind mount described. The syntax is identical to what you&amp;rsquo;ve seen in previous sections.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ports&lt;/code&gt; map defines any port mapping. The syntax, &lt;code&gt;&amp;lt;host port&amp;gt;:&amp;lt;container port&amp;gt;&lt;/code&gt; is identical to the &lt;code&gt;--publish&lt;/code&gt; option you used before.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, code for the &lt;code&gt;volumes&lt;/code&gt; is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    db-data:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name: notes-db-dev-data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Any named volume used in any of the services has to be defined here. If you don&amp;rsquo;t define a name, the volume will be named following the &lt;code&gt;&amp;lt;project directory name&amp;gt;_&amp;lt;volume key&amp;gt;&lt;/code&gt; syntax and the key here is &lt;code&gt;db-data&lt;/code&gt;. You can learn about the different options for volume configuration in the official &lt;a href=&#34;https://docs.docker.com/compose/compose-file/compose-file-v3/#volumes&#34;&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;what-about-the-network-bridge&#34;&gt;What About the Network Bridge?&lt;/h2&gt;
&lt;p&gt;You may have noticed that there is no network bridge creation section in this YAML file. While the docker-compose specification supports adding network configuration to the file, docker-compose has &lt;a href=&#34;https://docs.docker.com/compose/networking/&#34;&gt;a helpful feature&lt;/a&gt; that automatically creates a bridge network for the composed project, and assigns a name based on the directory name (or project-name, if defined with the &lt;code&gt;--project-name&lt;/code&gt; switch or the &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt; environment variable).  So, since this file doesn&amp;rsquo;t include that information, you can look for a &amp;ldquo;notes-api_default&amp;rdquo; network after bringing up the composed project below.&lt;/p&gt;
&lt;h2 id=&#34;starting-services&#34;&gt;Starting Services&lt;/h2&gt;
&lt;p&gt;There are a few ways of starting services defined in a YAML file. The first command that you&amp;rsquo;ll learn about is the &lt;code&gt;up&lt;/code&gt; command. The &lt;code&gt;up&lt;/code&gt; command builds any missing images, creates containers and starts them in one go.&lt;/p&gt;
&lt;p&gt;Before you execute the command though, make sure you&amp;rsquo;ve opened your terminal in the same directory where the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file is. This is very important for every &lt;code&gt;docker-compose&lt;/code&gt; command you execute.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker-compose --file docker-compose.yaml up --detach
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating network &amp;#34;notes-api_default&amp;#34; with the default driver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating volume &amp;#34;notes-db-dev-data&amp;#34; with default driver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Building api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon  37.38kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/13 : FROM node:lts-alpine as builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 471e8b4eb0b2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/13 : RUN apk add --no-cache python make g++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 197056ec1964
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 197056ec1964
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 6609935fe50b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/13 : WORKDIR /app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 17010f65c5e7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 17010f65c5e7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; b10d12e676ad
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/13 : COPY ./package.json .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 600d31d9362e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/13 : RUN npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in a14afc8c0743
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  Removing intermediate container a14afc8c0743
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 952d5d86e361
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/13 : FROM node:lts-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 471e8b4eb0b2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/13 : ENV NODE_ENV=development
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 0d5376a9e78a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 0d5376a9e78a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 910c081ce5f5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 8/13 : USER node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in cfaefceb1eff
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container cfaefceb1eff
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 1480176a1058
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 9/13 : RUN mkdir -p /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 3ae30e6fb8b8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 3ae30e6fb8b8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; c391cee4b92c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 10/13 : WORKDIR /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 6aa27f6b50c1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 6aa27f6b50c1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 761a7435dbca
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 11/13 : COPY . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; b5d5c5bdf3a6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 12/13 : COPY --from=builder /app/node_modules /home/node/app/node_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 9e1a19960420
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 13/13 : CMD [ &amp;#34;./node_modules/.bin/nodemon&amp;#34;, &amp;#34;--config&amp;#34;, &amp;#34;nodemon.json&amp;#34;, &amp;#34;bin/www&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 5bdd62236994
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 5bdd62236994
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 548e178f1386
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 548e178f1386
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged notes-api:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating notes-api-dev ... done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating notes-db-dev  ... done
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--detach&lt;/code&gt; or &lt;code&gt;-d&lt;/code&gt; option here functions same as the one you&amp;rsquo;ve seen before. The &lt;code&gt;--file&lt;/code&gt; or &lt;code&gt;-f&lt;/code&gt; option is only needed if the YAML file is not named &lt;code&gt;docker-compose.yaml&lt;/code&gt; but I&amp;rsquo;ve used here for demonstration purpose.&lt;/p&gt;
&lt;p&gt;Apart from the the &lt;code&gt;up&lt;/code&gt; command there is the &lt;code&gt;start&lt;/code&gt; command. The main difference between these two is the &lt;code&gt;start&lt;/code&gt; command doesn&amp;rsquo;t create missing containers, only starts existing containers. It&amp;rsquo;s basically same as the &lt;code&gt;container start&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--build&lt;/code&gt; option for the &lt;code&gt;up&lt;/code&gt; command forces a rebuild of the images. There are some other options for the &lt;code&gt;up&lt;/code&gt; command that you can see on official &lt;a href=&#34;https://docs.docker.com/compose/reference/up/&#34;&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;listing-services&#34;&gt;Listing Services&lt;/h2&gt;
&lt;p&gt;Although service containers started by Compose can be listed using the &lt;code&gt;container ls&lt;/code&gt; command, there is the &lt;code&gt;ps&lt;/code&gt; command for listing containers defined in the YAML only.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker-compose ps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#     Name                   Command               State           Ports
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# -------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev   docker-entrypoint.sh ./nod ...   Up      0.0.0.0:3000-&amp;gt;3000/tcp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-db-dev    docker-entrypoint.sh postgres    Up      5432/tcp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s not as informative as the &lt;code&gt;container ls&lt;/code&gt; output, but useful when you have tons of containers running simultaneously.&lt;/p&gt;
&lt;h2 id=&#34;executing-commands-inside-a-running-service&#34;&gt;Executing Commands Inside a Running Service&lt;/h2&gt;
&lt;p&gt;I hope you remember from the previous section that you have to run some migration scripts to create the database tables for this API. Just like the &lt;code&gt;container exec&lt;/code&gt; command, there is an &lt;code&gt;exec&lt;/code&gt; command for &lt;code&gt;docker-compose&lt;/code&gt;. Generic syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker-compose exec &amp;lt;service name&amp;gt; &amp;lt;command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To execute the &lt;code&gt;npm run db:migrate&lt;/code&gt; command inside the &lt;code&gt;api&lt;/code&gt; service, you can execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker-compose exec api npm run db:migrate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;gt; notes-api@ db:migrate /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# &amp;gt; knex migrate:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Using environment: development
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Batch 1 run: 1 migrations
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unlike the &lt;code&gt;container exec&lt;/code&gt; command, you don&amp;rsquo;t need to pass the &lt;code&gt;-it&lt;/code&gt; flag for interactive sessions. &lt;code&gt;docker-compose&lt;/code&gt; does that automatically.&lt;/p&gt;
&lt;h2 id=&#34;accessing-logs-from-a-running-service&#34;&gt;Accessing Logs From a Running Service&lt;/h2&gt;
&lt;p&gt;You can also use the &lt;code&gt;logs&lt;/code&gt; command to retrieve logs from a running service. The generic syntax for the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker-compose logs &amp;lt;service name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To access the logs from the &lt;code&gt;api&lt;/code&gt; service execute the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker-compose logs api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Attaching to notes-api-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] 2.0.7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] reading config ./nodemon.json
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] to restart at any time, enter `rs`
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] or send SIGHUP to 1 to restart
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] ignoring: *.test.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] watching path(s): *.*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] watching extensions: js,mjs,json
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] starting `node bin/www`
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] forking
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] child pid: 19
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | [nodemon] watching 18 files
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# notes-api-dev | app running -&amp;gt; http://127.0.0.1:3000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is just a portion from the log output. You can kind of hook into the output stream of the service and get the logs in real-time by using the &lt;code&gt;-f&lt;/code&gt; or &lt;code&gt;--follow&lt;/code&gt; option. Any later log will show up instantly in the terminal as long as you don&amp;rsquo;t exit by pressing &lt;code&gt;ctrl + c&lt;/code&gt; key combination or closing the window. The container will keep running even if you exit out of the log window.&lt;/p&gt;
&lt;h2 id=&#34;stopping-services&#34;&gt;Stopping Services&lt;/h2&gt;
&lt;p&gt;For stopping services, there are two approaches that you can take. The first one is the &lt;code&gt;down&lt;/code&gt; command. The &lt;code&gt;down&lt;/code&gt; command stops all running containers and removes them from the system. It also removes any networks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker-compose down --volumes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Stopping notes-api-dev ... done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Stopping notes-db-dev  ... done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing notes-api-dev ... done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing notes-db-dev  ... done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing network notes-api_default
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing volume notes-db-dev-data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--volumes&lt;/code&gt; option indicates that you want to remove any named volume defined in the &lt;code&gt;volumes&lt;/code&gt; block. You can learn about the additional options for the &lt;code&gt;down&lt;/code&gt; command in the official &lt;a href=&#34;https://docs.docker.com/compose/reference/down/&#34;&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another command for stopping services is the &lt;code&gt;stop&lt;/code&gt; command which functions identically to the &lt;code&gt;container stop&lt;/code&gt; command. It stops all the containers for the application and keeps the contianers. These containers can later be started with the &lt;code&gt;start&lt;/code&gt; or &lt;code&gt;up&lt;/code&gt; command.&lt;/p&gt;
&lt;h2 id=&#34;composing-a-full-stack-application&#34;&gt;Composing a Full-stack Application&lt;/h2&gt;
&lt;p&gt;In this sub-section, we&amp;rsquo;ll be adding a front-end to our notes API and turn it into a complete fullstack application. I won&amp;rsquo;t be explaining any of the &lt;code&gt;Dockerfile.dev&lt;/code&gt; files in this sub-section (except the one for the &lt;code&gt;nginx&lt;/code&gt; service) as they are identical to some of the others you&amp;rsquo;ve already seen in previous sub-sections.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve cloned the project code repository, then go inside the &lt;code&gt;fullstack-notes-application&lt;/code&gt; directory. Each directory inside the project root contains the code for each services and the corresponding &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before we start with the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file let&amp;rsquo;s look at a diagram of how the application is going to work:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/composing-projects-using-docker-compose/fullstack-application-design.svg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Instead of accepting requests directly like we previously did, in this application, all the requests will be first received by a NGINX (lets call it router) service. The router will then see if the requested end-point has &lt;code&gt;/api&lt;/code&gt; in it. If yes, the router will route the request to the back-end or if not, the router will route the request to the front-end.&lt;/p&gt;
&lt;p&gt;The reason behind doing this is that when you run a front-end application it doesn&amp;rsquo;t run inside a container. It runs on the browser, served from a container. As a result, Compose networking doesn&amp;rsquo;t work as expected and the front-end application fails to find the &lt;code&gt;api&lt;/code&gt; service.&lt;/p&gt;
&lt;p&gt;NGINX on the other hand runs inside a container and can communicate with the different services across the entire application.&lt;/p&gt;
&lt;p&gt;I will not get into the configuration of NGINX here. That topic is kinda out of scope of this article. But if you want to have a look at it, go ahead and checkout the &lt;code&gt;/notes-api/nginx/development.conf&lt;/code&gt; and &lt;code&gt;/notes-api/nginx/production.conf&lt;/code&gt; files. Code for the &lt;code&gt;/notes-api/nginx/Dockerfile.dev&lt;/code&gt; is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FROM nginx:stable-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY ./development.conf /etc/nginx/conf.d/default.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All it does is copy the configuration file to &lt;code&gt;/etc/nginx/conf.d/default.conf&lt;/code&gt; inside the container.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start writing the &lt;code&gt;docker-compose.yaml&lt;/code&gt; file. Apart from the &lt;code&gt;api&lt;/code&gt; and &lt;code&gt;db&lt;/code&gt; services there will be the &lt;code&gt;client&lt;/code&gt; and &lt;code&gt;nginx&lt;/code&gt; services. There will also be some network definitions that I&amp;rsquo;ll get into shortly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;version: &amp;#34;3.8&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;services:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    db:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        image: postgres:12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        container_name: notes-db-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - db-data:/var/lib/postgresql/data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        environment:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            POSTGRES_DB: notesdb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            POSTGRES_PASSWORD: secret
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - backend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    api:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        build:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            context: ./api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            dockerfile: Dockerfile.dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        image: notes-api:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        container_name: notes-api-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - /home/node/app/node_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - ./api:/home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        environment:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            DB_HOST: db ## same as the database service name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            DB_PORT: 5432
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            DB_USER: postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            DB_DATABASE: notesdb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            DB_PASSWORD: secret
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - backend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    client:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        build:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            context: ./client
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            dockerfile: Dockerfile.dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        image: notes-client:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        container_name: notes-client-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - /home/node/app/node_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - ./client:/home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - frontend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    nginx:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        build:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            context: ./nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            dockerfile: Dockerfile.dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        image: notes-router:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        container_name: notes-router-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        restart: unless-stopped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ports:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - 8080:80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - backend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - frontend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    db-data:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name: notes-db-dev-data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    frontend:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name: fullstack-notes-application-network-frontend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        driver: bridge
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    backend:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name: fullstack-notes-application-network-backend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        driver: bridge
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The file is almost identical to the previous one you worked with. Only thing that needs some explanation is the network configuration. Code for the &lt;code&gt;networks&lt;/code&gt; block is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    frontend:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name: fullstack-notes-application-network-frontend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        driver: bridge
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    backend:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name: fullstack-notes-application-network-backend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        driver: bridge
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve defined two bridge networks. By default Compose creates a bridge network and attaches all containers to that. In this project however, I wanted proper network isolation. So I defined two networks, one for the front-end services and one for the back-end  services.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also added &lt;code&gt;networks&lt;/code&gt; block in each of the service definitions. This way the the &lt;code&gt;api&lt;/code&gt; and &lt;code&gt;db&lt;/code&gt; service will be attached to one network and the &lt;code&gt;client&lt;/code&gt; service will be attached to a separate network. The &lt;code&gt;nginx&lt;/code&gt; service however will be attached to both the networks so that it can perform as router between the front-end and back-end services.&lt;/p&gt;
&lt;p&gt;Start all the services by executing following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker-compose --file docker-compose.yaml up --detach
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating network &amp;#34;fullstack-notes-application-network-backend&amp;#34; with driver &amp;#34;bridge&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating network &amp;#34;fullstack-notes-application-network-frontend&amp;#34; with driver &amp;#34;bridge&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating volume &amp;#34;notes-db-dev-data&amp;#34; with default driver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Building api
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon  37.38kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/13 : FROM node:lts-alpine as builder
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 471e8b4eb0b2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/13 : RUN apk add --no-cache python make g++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in 8a4485388fd3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container 8a4485388fd3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 47fb1ab07cc0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/13 : WORKDIR /app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in bc76cc41f1da
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container bc76cc41f1da
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 8c03fdb920f9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/13 : COPY ./package.json .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; a1d5715db999
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/13 : RUN npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Running in fabd33cc0986
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;### LONG INSTALLATION STUFF GOES HERE ###
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Removing intermediate container fabd33cc0986
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; e09913debbd1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/13 : FROM node:lts-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 471e8b4eb0b2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/13 : ENV NODE_ENV=development
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; b7c12361b3e5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 8/13 : USER node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; f5ac66ca07a4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 9/13 : RUN mkdir -p /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 60094b9a6183
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 10/13 : WORKDIR /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 316a252e6e3e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 11/13 : COPY . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 3a083622b753
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 12/13 : COPY --from=builder /app/node_modules /home/node/app/node_modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 707979b3371c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 13/13 : CMD [ &amp;#34;./node_modules/.bin/nodemon&amp;#34;, &amp;#34;--config&amp;#34;, &amp;#34;nodemon.json&amp;#34;, &amp;#34;bin/www&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; f2da08a5f59b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built f2da08a5f59b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged notes-api:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Building client
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon  43.01kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/7 : FROM node:lts-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 471e8b4eb0b2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/7 : USER node
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 4be5fb31f862
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 3/7 : RUN mkdir -p /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 1fefc7412723
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 4/7 : WORKDIR /home/node/app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; d1470d878aa7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 5/7 : COPY ./package.json .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; bbcc49475077
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 6/7 : RUN npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 860a4a2af447
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 7/7 : CMD [ &amp;#34;npm&amp;#34;, &amp;#34;run&amp;#34;, &amp;#34;serve&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 11db51d5bee7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 11db51d5bee7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged notes-client:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Building nginx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Sending build context to Docker daemon   5.12kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 1/2 : FROM nginx:stable-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; f2343e2e2507
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Step 2/2 : COPY ./development.conf /etc/nginx/conf.d/default.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; Using cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#  ---&amp;gt; 02a55d005a98
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully built 02a55d005a98
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Successfully tagged notes-router:dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating notes-client-dev ... done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating notes-api-dev    ... done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating notes-router-dev ... done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Creating notes-db-dev     ... done
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now visit &lt;code&gt;http://localhost:8080&lt;/code&gt; and voilà!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/composing-projects-using-docker-compose/notes-application.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Try adding and deleting notes to see if the application works properly or not. The project also comes with shell scripts and a &lt;code&gt;Makefile&lt;/code&gt;. Explore them to see how you can run this project without the help of &lt;code&gt;docker-compose&lt;/code&gt; like you did in the previous section.&lt;/p&gt;
</content>
    </item>
    
  </channel>
</rss>
