Brief Docker Introduction
Tags: docker, devops, beginners
Published: 2020-04-17 19:13:29

# What is it?
Docker is a tool that developers use to develop their applications within a controlled environment. Think of it as a customized virtual environment meant to house your application and its needs. This approach ensures applications work consistently on any given computer environment when working with other developers. It also makese maintenance much easier because of the ability to modularize your application components (backend, frontend, database, etc.) into their own virtual environments.

This guide will briefly overview the various fragments of the Docker ecosystem.

# The `Dockerfile`
A Dockerfile contains instructions on how to build your virtual environment and how to start your application within it. Here is a sample with annotations:

```Dockerfile
# The following specifies the base layer on which to build our Dockerfile.
# This is generally the environment we want to start off with.
# The line below tells us we want our application to be in a debian
# linux environment with ruby 2.6.5 installed and configured.
# The base layer is written in the following format:
#   <IMAGE_NAME>:<IMAGE_TAG>
#     - IMAGE_NAME: Usually the environment (ruby, node, postgres, etc.)
#     - IMAGE_TAG: Usually the version (2.6.5, 2.6.5-ubuntu, etc.)
FROM ruby:2.6.5-debian

# RUN tells us to execute a command within our environment.
# The line below will install some packages our application will need.
# The `\` character says to continue the command on the next line.
# Use it to make your code easier to read.
RUN apt-get update -qq && \
    apt-get install -y build-essential libpq-dev nodejs

# Similar to `cd`, the WORKDIR command changes our directory
# within our environment for the remainder of the Dockerfile.
# WORKDIR will also create the directory for us if it does not exist.
# It is generally a good idea to work straight from
# the root (`/`) directory rather than home (`~`).
WORKDIR /app

# The COPY command copies the first item to the second item
# just like the `cp` command would.
# The difference between `cp` and COPY is that the second argument
# here should point to a location within our virtual environment.
# The line below copies our Gemfile, a file which describes
# the list of packages our ruby app is dependant on,
# into our docker environment.
COPY Gemfile ./

# bundle reads the Gemfile we passed into our virtual environment
# and installs our dependencies.
# Note that there is no special difference in running `bundle install`
# on your local machine versus here in a virtual environment.
RUN bundle install

# This line copies everything in our
# current directory on our machine (.)
# into our current working directory
# within the virtual environment (the second .)
COPY . .

# Exposes the port 3000 within our virtual linux environment to our local machine.
# We can then call on this port to communicate with our app
# within this virtual environment as long as our code is
# also configured to listen on this port number.
EXPOSE 3000

# The CMD command is very similar to RUN insofar that it runs arguments.
# The difference is that CMD is considered our final instruction to the Dockerfile.
# Whereas RUN is used to run arguments necessary to build our app,
# CMD is used by docker when we tell it to fire up our environment.
# As such, CMD will generally run your server, start your database, etc.
# The line below starts rails, which is a type of backend server
CMD rails s
```

# Docker Images
Once you have a `Dockerfile`, you can simply run `docker build PATH` to build it, where `PATH` is the root directory of your app. Note that `PATH` must also contain your `Dockerfile`. If you put it in a separate directory, use the `-f` option: `docker build PATH -f DOCKERFILE_PATH`.

Building a `Dockerfile` results in the creation of a docker image. To understand this better, consider how, when you program, your code may be in a human-readable format such as `code.js`. When you compile it, however, the compiler transforms it into a new file with instructions that your computer can understand. Dockerfiles and docker images are similar. You write your instructions in a `Dockerfile`, and then docker will create an image out of it that tells the docker service what to do when running your app in its environment.

**TIP:** Use the `-t NAME:TAG` flag to give your images a custom name and tag. The tag is meant to tell a reader your app's version or state. Possible values may be `1.0.0`, `development` or `latest` (indicating a production-level product).

**TIP:** Use `docker image ls` to list all of the Docker images on your computer.

# Docker Containers
Once your docker image is built, Docker can use it to finally fire up your virtual environment, which is also known as a docker container. When you reach this stage, you can tell your friends that your app is *containerized* or *dockerized*.

**TIP:** Run `docker ps` to show all containers currently running on your machine. Use the `-a` flag to list all containers ever fired up.

**TIP:** Use `docker stop CONTAINER_NAME_OR_ID` to stop a given container using its full name `NAME:TAG` or `ID`. You can also use `docker kill CONTAINER_NAME_OR_ID` to stop the container more abruptly.

**TIP:** Use `docker rm CONTAINER_NAME_OR_ID` to completely remove a container. Don't worry, you can always create it again using your docker image. Your data will **NOT* be erased, as it is stored in a docker volume  instead (which is seaprate from your image and container).

# Docker Volumes
Docker volumes are a means of persisting your container data. In the chance that you restart or remove your container, docker volumes ensure that the data captured inside your containers while it was running is not lost. Docker volumes are stores on your local filesystem. This functionality can be controlled depending on the type of docker volume you choose to implement. There are [three primary options](https://success.docker.com/article/different-types-of-volumes):
* **Host Volume:** Creates a one-to-one mapping of the data between the local directory you specify and the container directory. This is useful for programming projects, as you can edit your code locally and have it updated dynamically inside your container.
* **Anonymous Volume:** You only define which path inside your container you wish to persist and the Docker engine finds a place in your filesystem to keep this data in for you.
* **Named Volume:** Same functionality as anonymous volumes, but you get to name them.

# Docker Compose
Since automation is such an inherent desire in us software developers, the Docker community created a means to automate the process of building and running Dockerfiles into a single utility called `docker-compose`. Docker-compose files are written in the `YAML` file format and describe various building instructions such as what containers to create, which `Dockerfile` to use, what volumes to create, and so on.