Introduction to Docker - Docker Series Part 1
Tags: beginners, docker, devops, linux
Published: 2019-12-02 18:06:35

<h2>What is Docker</h2>
<p>Many of the ideas from virtual containers can be linked to the historical use of their physical counterparts. Traditionally, containers have allowed us to isolate, store and ship different types of items in a single body (such as a transport ship, warehouse, etc). In computing, containerization allows us to separate and run multiple virtual operating systems  on a single host machine. Docker provides features that make creating and interacting with these virtual systems simple.</p>
<h3>Containerization vs Virtual Machines</h3>
<p>Readers familiar with virtual machines might notice that containers seem to be filling a similar role - that is correct! However, containers have a key advantage that makes them a better choice in most situations. Virtual machines emulate the entire virtual operating system (including a virtual kernel) using a software called a hypervisor. Docker on the other hand uses, a background process (a daemon) that is able to simulate the operating system of the container using only the kernel of the host operating system. This significantly reduces startup time, CPU memory requirements and computational speed, which can save the user a lot of money (especially when using a cloud service provider).</p>
<img src="https://thepracticaldev.s3.amazonaws.com/i/l6zu2c2xj7rtp0a6jdex.png"  />
<h3>Benefits and Use Cases of Docker</h3>
<p>Using Docker, the most popular container system, has many benefits due to the large amount of features and rich ecosystem that it provides. Some of its most notable features, for which future posts will go into more detail, are listed here: </p>
<ul><li>When developing software, it can be hard to ensure that the environment and dependencies on the developers machine will be the same as those on a remote server. Software can be loaded into a container and shipped to the server, ensuring that it behaves as it did on the local machine.</li><li>Docker containers provide various ways to interface with each other, allowing the formation of container networks.</li><li>A large community has formed around Docker. New Docker containers can be setup quickly, using the container blueprints (more commonly known  as "Docker Images") of other users. Thanks to DockerHub, many databases, monitoring tools, and other pieces of complex software can be initialized instantly.</li><li>Many tools and cloud providers offer Docker integrations, as it is the industry standard.</li></ul>
<h3>Installing Docker</h3>
<p>An installer for Windows and Mac can be installed from Docker Hub. If you are on a Linux machine, you will need to use the command line.  Here is how to install Docker on Ubuntu:</p>
<pre><code class="language-bash">curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce
sudo service docker start
sudo docker run hello-world</code></pre>
<p>The previous code will install Docker and then start the daemon. Once Docker is up and running, it will try to run a "hello-world" container on your machine - if Docker does not find an "Image" with that name on your computer, it will attempt to download it from DockerHub. If everything worked, you should see a "hello world" prompt.
<h2>What exactly is a Docker Image?</h2>
<p>A docker image can be thought of as a blueprint for a docker container - every docker container is built using a docker image. Think of when you first started your computer for the first time - what were the first steps that you took? You probably installed some software that you were going to need and made some configurations. You can think of a docker image in a similar manner, in that it is essentially a compiled list of steps that docker will execute to build your container.  These steps are defined in a Dockerfile - I will be discussing how to create these in the next part of this series.</p>
<h3>What is DockerHub?</h3>
<p>Docker has many users, many of which have made their Docker images available publically via a service called DockerHub. Most software is available in the form of a docker image that you can download and run in seconds, saving you the need to install it or define your own image. Images on DockerHub are versioned, meaning that you can choose the best fit for your technology stack. Many companies actually create official docker images for their software and publish them, giving you a degree of certainty that your container will work as expected. Because of all of these features provided with DockerHub, I suggest you always check whether an image for some software you are trying to install already exists.</p>
<img src="https://thepracticaldev.s3.amazonaws.com/i/s7x2wxc0ymsji0jtftsb.png"/>
<p>DockerHub also gives you the ability to upload your own Docker images. This has several benefits - you can help the community by creating an image that might be useful to a larger group of users or you can upload your application container as a private image and then simply download it straight to your remote server using the Docker client.</p>
<h3>Image Versioning with Tags</h3>
<p>Docker has a versioning system in place for container images - it is called "tags". On DockerHub, you will see a list of tags for each image that you can use to choose what version of a given image you want to build. These usually relate to the version of the software running in the container, but can also include specific settings or configurations. For example, a lot of vendors release tags for their container images which are based on <a href="https://wiki.alpinelinux.org/wiki/Main_Page">Alpine Linux</a>, an extremely lightweight Linux distribution designed specifically for running in containers.</p>
<img src="https://thepracticaldev.s3.amazonaws.com/i/4k5gh2ihfa6nriu93q2g.png" />
<h3>Environment Variables</h3>
<p>Just like on any operating system, Docker containers can have environment variables that can help define the behavior of components installed on the system. Images on DockerHub often have a list of environment variables with descriptions,  which are set once the container is built, allowing the user to customize the software. </p>
<img src="https://thepracticaldev.s3.amazonaws.com/i/cxhfaiwzl75id5veflp5.png"/>
<h3>What makes a good Image?</h3>
<ul><li>If a Docker image is an "official" image, it can be assumed that it meets a high quality standard</li><li>The image only has the necessary components installed to execute the task it is meant to, without causing unnecessary overhead</li><li>It allows the user to configure the comtainer using descriptive environment variables</li><li>It provides a wide range of tags, allowing the user to choose older versions of the software that might work better with their techstack</li><li>Make sure that the Docker Image is used by a lot of people, usually indicated by the number of downloads and stars that particular image has</li><li>There are tools (such as Anchore) which can help you analyze an image and help detect any security flaws with your configurations</li></ul>
<h3>Pulling an Image</h3>
<p>For this example, I am going to be using the official MySQL image. After executing the following code, I see that docker begins to download (or "pull") the MySQL image:</p>
<pre><code class="language-bash">docker pull mysql:8</code></pre>
<p>You might be wondering why I added ":8" to the name of my image. As aforementioned, images can have tags, usually representing different versions of that image. With this syntax, I am saying that I want to pull the version of my image which correlates to the tag "8", which in this case means that I will be getting an image for a container running MySQL version 8. By default, if you do not specify a tag, you will get the latest image that was uploaded (which can also be retrieved by setting "latest" as the tag). I usually specify a tag for my docker images, so that I can always be sure I know what version to reference when I run into issues - this is personal preference, of course.</p>
<h3>Building and Running a Container</h3>
<p>Once pulled, docker stores our image for future use. If we want to use our image for a container, we need to build the container and start it. Note: If you execute a command to try and run a container based on an image that does not exist locally, docker will download that image automatically from the hub.</p>
<pre><code class="language-bash">docker run --name mysql-container -e MYSQL_ROOT_PASSWORD=password -d mysql:8</code></pre>
<p>The previous command will build and run a container named "mysql-container". Our MySQL image has several parameters that we can specify, which are specific to that particular image. You can usually see what parameters (or "environment variables") are available for a given image on DockerHub. When inspecting the variables for the official MySQL image, we can see that the MYSQL_ROOT_PASSWORD variable is in fact mandatory. We want to repeatedly use the pattern -e MY_ENVIRONMENT_VARIABLE=myvalue for each variable that we want to define, when running our container via the command line.</p>
<p>Upon entering the previous command, we want to confirm that our new container has been built using the image we defined. Enter the following commands:</p>
<pre><code class="language-bash">docker ps
docker stop mysql-container</code></pre>
<p>The first command will list all running containers. The second command will stop a container with the name that we pass as the argument, in this case "mysql-container". Hopefully, the first command showed you that our container was in fact running! In the next tutorial, we will take a deeper dive into the different Docker commands that are available.</p>