{"componentChunkName":"component---src-templates-blog-post-js","path":"/02-docker-learning-the-command-line/","result":{"data":{"site":{"siteMetadata":{"title":"Yamenai"}},"markdownRemark":{"id":"f83e3978-14b8-5aa6-9b7e-d6ea968e297e","excerpt":"Part 1: Digging into the Command Line Interface Introduction to Developing with Virtual Machines (VMs) and Docker Learning development on the JavaScript stack…","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/70b899fb262797f5bd4fafa41b1e73e3/2e92a/02-shipping-containers.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 45.94594594594595%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsSAAALEgHS3X78AAAClklEQVQozw3M7S/UAQDA8fsHetmqNz0spTl3nDvhHK5Rc1qeRdxMfu5yugecTsSiY6qZh18omyxp5imE0HqSpC1peUx5zEOo6V2vv3n1efeRaMQJ/Co/E7BnSN0XlDUzuN/7hkycQy7O4lM+iX/FJEHV02jFKdI757g7vEJ273cuPZnGMfCD0YUd1n//ZX7jDxJt4yzBD2cIqJ/Cr34GIVPELuSRlVaIRbiBsqQKVWUD0tu1aO83Mb25S/vXTWpGVxlb3KZpfI1Hn37yYGwVx+ACkvzhDcLal4jvXSOxdY5n3nLeyA8zEqhgQOPOseI4XCoNSCsMnGkq4OPiGjPru3xa3uH1/BZtU1tce7VKeMci8d3LSCZWtumeWmdu9x/j3T20KqW0BvrQFRKEqPbgSFkaXuU23O9koBTtVL6doGPyF2XvV7kyuISx7weWoSXsL5fJeLEXPs2PZPBmNKNFkVx2nEdRLBBckIy2NB2tRUed4Ea1dS+3aqg1qQi1lBHq7EWX14ja2U98Qjavw7Q0x0TQEBGOpM/gylBOAENmT9ydcRyqz8ZVtODZ4uRsURxvUg7TY5TTb/HlbaaKsBQHssw2vIwiuuIudJfL6Dx+gBa5C4/lJ5AMmBV8yFFTle3N/job0jo7brVZuD4qJiI3hGGDC10mT56afRixupGQYkLm6MPX1khwXgseuV2UK3x5cVpGs5cMyS2LnjxjEqlRGuKuXEBvjUd/NZZYQUd0bDAF6UkUmhIpzEjiuhDLxegoUk2ZGMx2hIwsko1W9Of8scUE4bikQ6IreY6yYABRoWZMcZI+lYyhID8mfNxI1Jk4VfgKla2ZgGvNaErfcVEvMGY4SLtBTlualI/20zgNMvZVmTgqmvkPCMe7pMZO+nIAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Containerization\"\n        title=\"Containerization\"\n        src=\"/static/70b899fb262797f5bd4fafa41b1e73e3/fcda8/02-shipping-containers.png\"\n        srcset=\"/static/70b899fb262797f5bd4fafa41b1e73e3/12f09/02-shipping-containers.png 148w,\n/static/70b899fb262797f5bd4fafa41b1e73e3/e4a3f/02-shipping-containers.png 295w,\n/static/70b899fb262797f5bd4fafa41b1e73e3/fcda8/02-shipping-containers.png 590w,\n/static/70b899fb262797f5bd4fafa41b1e73e3/efc66/02-shipping-containers.png 885w,\n/static/70b899fb262797f5bd4fafa41b1e73e3/c83ae/02-shipping-containers.png 1180w,\n/static/70b899fb262797f5bd4fafa41b1e73e3/2e92a/02-shipping-containers.png 2508w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<h2>Part 1: Digging into the Command Line Interface</h2>\n<h3>Introduction to Developing with Virtual Machines (VMs) and Docker</h3>\n<p>Learning development on the JavaScript stack can sometimes be quite frustrating (even with tools like Node or NVM). But this is especially true when you manage different applications with different environment dependencies (or different versions of node, npm etc..) for each app that you’re developing. Maybe you have some legacy apps that you don’t feel like touching, but you want your host machine to have the latest and greatest when you start you next project. That’s understandable and we’ve all been there before.</p>\n<p>I used to reach for VMs for all my work. I have a former love affair with Vagrant. Back when I was working on the LAMP stack, it made managing my various projects dependencies and environments a breeze. The VMs helped to ensure consistent behaviour between my home and work machines. But it is quite a bit of overhead to run and have images for all these VMs stored on my development machine, simply to virtualize the environment I want to run my app on.</p>\n<p>This is when I started learning more about Docker. Docker differentiates itself by not virtualizing the entire stack from OS up, but rather executed by the Docker engine. These containers are much smaller than VMs and thus have faster startup times and better performance. VMs can take several minutes to create and launch whereas Docker containers can be created and launched in just a few seconds. One thing to remember is that all docker containers on a host will share that host’s kernel/OS/hardware. That being said, an application in a Docker container can run anywhere up to twice as fast as in a virtual machine and more containers can share a host because of the shared OS not being duplicated across each VM.</p>\n<h2>About Docker</h2>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/a9f456edd696c7f8ee58346f4e4ba80f/19ab6/02-pier.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 44.5945945945946%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsSAAALEgHS3X78AAACjklEQVQozw3D209SAQDA4fPc1l/Qe2+1HtokcxWNUkLSReJB43YUBck0pPKSiEZWpmXZptaquaZmC3S2IZpJZZRrKptcFA2DmVF2WS9uvf3q2z7hoP02hbWdFDU/xtE9SteTGdp8EbpeLBNeyfDnzzbb23/JfPvN+OIGBUMJpOE4S5EkFQNLWJ/GuDMRo/BBmN1X3iGIPUF2ut4guOdQ9oeZmUuQSm2SSn9nfX2TcGSVybfzPJ14j/fdKp5AmtKhNd5GNvkQz9AeSLKjI4pwLcau7gjC7aFXKPsWUQ/E0A4mePgyzujUHMOvY9zwL+P2hbnqm+f8syWqxtL0hr4wE/3GwlKSsdAadeMb6EfSePxJGrxxhHtDU3SNLuALRgmGokyGlgktfsa3sEXTq5/4Iz9YSW/xIbFFbP0X0cR3/B9TPJv9xNXpDJ7pr9yaWKM3sEx/IIZw0qRAX5NPeaOI2aGl1lWG566bnkf9eCdnGAiEGPEHGZsMMugdoOWOizLnKcz1IoaLIvpKBTqLnMJyBWKlCqFY0nPSpEeuN6C2WNBaLRjs5v8rMTsbqWpupam9nQtXXFS76rDUW9HazBirjZyyGjhkNHHQYCZXkjhQakDQSE7kJU72FF/ikMlFoa0VS10bjuYO7O67GO0Oxp8P4x0Z5oytnqq2+4jOTqyXuylq6ENW08f+6l6OOu6TVd2HoCo2kVNQyl61EZlG4riuHK1UQYnFisZyFtF2nuj8LPGFWUrPXuS07QL5ZTXo7HWcsNaTLTUgk5qQV7SQXeZGOKI8gexYLvuOKsjKU3JYlcexgjxUGjVH1Co8N6+TSUbIrIVp77yJLF+DoqgEpahDrpPIKq5AJtrI0deSpTvHPwMJ2fy6uSCcAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Summer Dock\"\n        title=\"Summer Dock\"\n        src=\"/static/a9f456edd696c7f8ee58346f4e4ba80f/fcda8/02-pier.png\"\n        srcset=\"/static/a9f456edd696c7f8ee58346f4e4ba80f/12f09/02-pier.png 148w,\n/static/a9f456edd696c7f8ee58346f4e4ba80f/e4a3f/02-pier.png 295w,\n/static/a9f456edd696c7f8ee58346f4e4ba80f/fcda8/02-pier.png 590w,\n/static/a9f456edd696c7f8ee58346f4e4ba80f/efc66/02-pier.png 885w,\n/static/a9f456edd696c7f8ee58346f4e4ba80f/c83ae/02-pier.png 1180w,\n/static/a9f456edd696c7f8ee58346f4e4ba80f/19ab6/02-pier.png 1664w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<h3>What is Docker</h3>\n<p>Docker is a tool we can use to isolate and containerize our application and the environment in which it runs from that of our host machine. This allows us to also version our entire “stack” and all the requirements and dependencies for the application to run within version control.</p>\n<h3>Why is Docker so great</h3>\n<p>This is great for a plethora of reasons, but for me, the main advantage is how easily Docker can be run locally and deployed in production and help ensure that what works on my machine will work on every machine.</p>\n<blockquote>\n<p>Note: I have run into instances where some of the terminal commands run to execute/build docker commands/images produce some errors when running on Windows, but with minor testing and tweaking, cross platform compatibility can be achieved.</p>\n</blockquote>\n<h3>What does Docker solve</h3>\n<p>This eliminates the “well, it works on my machine” excuse from your vocabulary. This also helps ensure that any new developer who is on-boarded to your project, once they have git and docker installed, they’ll be ready to run your application.</p>\n<blockquote>\n<p>For our demo, we will be aliasing npm commands to docker commands to make the development cycle more familiar to developers, and so, NPM is a dependency on the host machine, simply to kick start the docker commands.\nThese could also be aliased to bash commands but it would make the integration with CI tools, as we will see later, slightly different. Hence, I chose NPM.</p>\n</blockquote>\n<h2>Getting Started with the Command Line</h2>\n<p><img src=\"/a02a3ada93dec4dcd7c7f7993c218f0b/02-cli.gif\" alt=\"Fear not the terminal\"></p>\n<p><em>Fear not the Terminal</em></p>\n<p>To get started with this demo, you should have Docker installed on your host machine.</p>\n<blockquote>\n<p>This was written and performed on Mac. If you notice any commands that do not work for Windows, please leave a comment to help out other readers. I’ll try to update my notes here too.</p>\n</blockquote>\n<h3>Installing Docker</h3>\n<p>A quick Google search for “install docker” eventually takes you here: <a href=\"https://docs.docker.com/install/\">https://docs.docker.com/install/</a>\nThe installation steps have changed (in terms of where to find the download) a few times. I believe you will need to register for an account with Docker (and/or Docker Hub) but don’t worry, we’ll be using these later to publish our images to a Docker repository.</p>\n<p>Once you’ve completed the installation, join us back here and we’ll review a handful of commands we’ll be using over and over to make our lives easier.</p>\n<blockquote>\n<p><em>Note: Terminology</em>\nWe’ll be using terms like <code class=\"language-text\">build</code>, <code class=\"language-text\">image</code> and <code class=\"language-text\">container</code> a lot in this article, so I wanted to define them upfront.\nthe <code class=\"language-text\">build</code> is the process of taking the steps outlined in the <code class=\"language-text\">Dockerfile</code> (more on that later) to create your <code class=\"language-text\">image</code>.\nthe <code class=\"language-text\">image</code> is like an onion, built up in layers from your <code class=\"language-text\">Dockerfile</code>. This is your primary asset. Kind of like a class definition.\nthe <code class=\"language-text\">container</code> is an instance of your <code class=\"language-text\">image</code>. A <code class=\"language-text\">container</code> is to an <code class=\"language-text\">image</code>, like an <code class=\"language-text\">object</code> is to a <code class=\"language-text\">class</code>. You can have many containers of the same image if required.</p>\n</blockquote>\n<h3>Simple Commands</h3>\n<p>So now docker is running. You can confirm this by running <code class=\"language-text\">docker -v</code> in your terminal. At the time of this article, I am using <code class=\"language-text\">Docker version 18.09.0, build 4d60db4</code>. You don’t need this version, but later in this series, I am planning to use some of the newer features. I’ll try to comment on those sections where a specific version (or newer) would be required.</p>\n<p>Running <code class=\"language-text\">docker</code> in your terminal will give you a long list of commands you can use to manage your Docker assets. Let’s look at a few:</p>\n<h3><code class=\"language-text\">docker ps</code></h3>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># Returns a list of running containers</span>\n$ docker <span class=\"token function\">ps</span>\nCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES</code></pre></div>\n<p>Ok, so we see … nothing. But that’s because we have no containers running.. Let’s build our first image. For this we will pull a predefined image from docker’s repository. It’s time for <code class=\"language-text\">hello-world</code>!</p>\n<h3><code class=\"language-text\">docker pull</code></h3>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ docker pull hello-world\nUsing default tag: latest\nlatest: Pulling from library/hello-world\nd1725b59e92d: Pull complete</code></pre></div>\n<p>This command allows you to pull prebuilt images from repositories like Docker Hub. Let’s see all the repositories we have loaded on our machine.</p>\n<h3><code class=\"language-text\">docker images</code></h3>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ docker images\nREPOSITORY                          TAG                 IMAGE ID            CREATED             SIZE\nhello-world                         latest              4ab4c602aa5e        <span class=\"token number\">3</span> months ago        <span class=\"token number\">1</span>.84kB</code></pre></div>\n<p>This shows us a list of built images that we have on our machines. You can easily bring up any of these in a container using the command we will look at next: <code class=\"language-text\">docker run [IMAGE]:[TAG|&#39;latest&#39;]</code></p>\n<h3><code class=\"language-text\">docker run</code></h3>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># This will pull, and run a container with the image provided</span>\n$ docker run hello-world\n\nHello from Docker<span class=\"token operator\">!</span>\nThis message shows that your installation appears to be working correctly.\n<span class=\"token punctuation\">..</span>.</code></pre></div>\n<p>So what happened here? Basically, first docker looks at your local list of images. Since it didn’t find one tagged as <code class=\"language-text\">hello-world</code> it fell-back to <em>docker hub</em> and downloaded the image from that repo. Once it was pulled, Docker then created a container running this image.</p>\n<p>But if you read the output from our hello world, they already recommend what to try next.</p>\n<blockquote>\n<p>To try something more ambitious, you can run an Ubuntu container with:<br>\n<code class=\"language-text\">$ docker run -it ubuntu bash</code></p>\n</blockquote>\n<p>Let’s see what happens.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ docker run -it ubuntu <span class=\"token function\">bash</span>\nUnable to <span class=\"token function\">find</span> image <span class=\"token string\">'ubuntu:latest'</span> locally\nlatest: Pulling from library/ubuntu\n32802c0cfa4d: Pull complete\nda1315cffa03: Pull complete\nfa83472a3562: Pull complete\nf85999a86bef: Pull complete\nDigest: sha256:6d0e0c26489e33f5a6f0020edface2727db9489744ecc9b4f50c7fa671f23c49\nStatus: Downloaded newer image <span class=\"token keyword\">for</span> ubuntu:latest\nroot@3fab2218a261:/<span class=\"token comment\">#</span></code></pre></div>\n<p>Now we’re inside our Docker container! Crazy right? Try out some simple commands, muck around. Doesn’t matter.. We’ll review how to kill the container shortly. Right now, nothing inside your container is linked to your file system so anything you do in here will not be persisted.</p>\n<p>Go play! I’ll wait…</p>\n<p>Ok. So, before you <code class=\"language-text\">$ exit</code> your container, let’s open a new tab to see a little more of what’s going on. In your new container, let’s try our <code class=\"language-text\">docker ps</code> command again. You should see an entry like this:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ docker <span class=\"token function\">ps</span>\nCONTAINER ID   IMAGE    COMMAND   CREATED              STATUS              PORTS       NAMES\n3fab2218a261   ubuntu   <span class=\"token string\">\"bash\"</span>    About a minute ago   Up About a minute               elated_tesla</code></pre></div>\n<p>We have 2 unique identifiers here that we should take note of, the <code class=\"language-text\">CONTAINER ID</code> and the <code class=\"language-text\">NAME</code>. This will allow us to get back into our container from another terminal window. We can try it by doing the next command we’ll review.</p>\n<h3><code class=\"language-text\">docker exec</code></h3>\n<p>With this docker command, we can execute a command against our running container, and we can even tell docker that we want to remain interactive <code class=\"language-text\">-i</code> and we want to open a terminal <code class=\"language-text\">-t</code> in our command. So, take the <code class=\"language-text\">CONTAINER ID</code> or the <code class=\"language-text\">NAME</code> from your <code class=\"language-text\">docker ps</code> command, and let’s get back into our running container with <code class=\"language-text\">docker exec</code> with out <code class=\"language-text\">-it</code> flag.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ docker <span class=\"token builtin class-name\">exec</span> -it elated_tesla <span class=\"token function\">bash</span>\nroot@3fab2218a261:/<span class=\"token comment\">#</span></code></pre></div>\n<p>And we’re right back in the terminal of our container! Pretty cool, eh? Ok, let’s start cleaning up. Let’s simply exit out of the container in our second terminal window with just <code class=\"language-text\">$ exit</code></p>\n<p>Now, let’s see the command we would use to stop our container if we weren’t logged into the terminal. This is how you will be stopping containers that are running in detached <code class=\"language-text\">-d</code> mode.</p>\n<h3><code class=\"language-text\">docker stop</code></h3>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ docker stop elated_tesla\nelated_tesla</code></pre></div>\n<p>Now, if we run <code class=\"language-text\">docker ps</code> again, we’ll see an empty list. Well, that is a little misleading. Since Docker isn’t <em>persisting</em> to our host machine, it didn’t just kill off everything we’ve done. The container still exists, but we can’t see it. Let’s add a flag to our <code class=\"language-text\">docker ps</code> command.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ docker <span class=\"token function\">ps</span> -a\nCONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS                        PORTS                  NAMES\n3fab2218a261        ubuntu                         <span class=\"token string\">\"bash\"</span>                   <span class=\"token number\">10</span> minutes ago      Exited <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token number\">43</span> seconds ago                            elated_tesla\n6088b6cbbab0        hello-world                    <span class=\"token string\">\"/hello\"</span>                 <span class=\"token number\">13</span> minutes ago      Exited <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token number\">13</span> minutes ago                            upbeat_robinson</code></pre></div>\n<p>Found em! The problem is, they’re still consuming some (not much, but some) resources. Let’s full clear them out. Keep in mind that anything you did inside of the container really will be lost once we fully remove the container. But in this case, that is fully ok. We want a fresh start.</p>\n<h3><code class=\"language-text\">docker rm</code></h3>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ docker <span class=\"token function\">rm</span> elated_tesla\nelated_tesla</code></pre></div>\n<p>Now, when we run <code class=\"language-text\">docker ps -a</code> again, we’ll see this has been removed from our list of stopped containers. However, if we run <code class=\"language-text\">docker images</code> we will see that <code class=\"language-text\">ubuntu</code> is still an image we have on our host machine. This just means when we spin up a new container, we won’t need to download anything from Docker Hub (unless we use a different tag than the one we have locally)</p>\n<blockquote>\n<p>Although we won’t got into it in this article, if system resources ever become an issue, you can run <code class=\"language-text\">docker image prune</code> or <code class=\"language-text\">docker container prune</code> to free up some resources.</p>\n</blockquote>\n<h2>Recap</h2>\n<p>Ok! So, we covered off how to pull images, turn them into containers, start and stop, remove and execute against them. We’re at a pretty good place, we can start to look at building our own custom Docker images! Stay tuned for part 2 where we’ll dockerize a simple Vuejs app!</p>\n<p>Please, feel free to do your happy dance in the meantime ;)</p>\n<p><img src=\"/d3eda569d3a75e2c803b44220df1f337/02-happy-appa.gif\" alt=\"Happy Dance\"></p>","frontmatter":{"title":"Docker for Frontend Devs - Learning the Command Line Interface","date":"February 12, 2019","description":"Learn the Docker CLI (Command Line Interface) to get comfortable managing images, and containers, and understand what Docker is, why we use it and the problems it aims to solve. Using the CLI you'll pull Docker images, create and destroy containers and mount volumes and network interfaces."}}},"pageContext":{"slug":"/02-docker-learning-the-command-line/","previous":{"fields":{"slug":"/01-writing-custom-tslint-rule-from-scratch/"},"frontmatter":{"title":"Writing a Custom TSLint Rule From Scratch"}},"next":{"fields":{"slug":"/03-docker-creating-custom-docker-images/"},"frontmatter":{"title":"Docker for Frontend Devs - Custom Docker Images for Development"}}}},"staticQueryHashes":["240262808","2841359383"]}