The distant sound of seagulls, maritime bells, and ship horns echoed through the wharves of ports; and suddenly out of the fog, a monolithic shadow makes its way from the horizon into the pier. Ahhh, yes, the illusive Moby Dock, Pulling, Communicating, Building and Publishing... A creature that would entertain even the likes of Captain Ahab; who would be all so very intrigued, and envious to finally have spotted, found and understood it. Even Captain Ahab would not stand a chance to uncover all of what exists in the digital ocean. So it is up to us to uncover the stuff of legends within our realm of possibilities.

What is Docker?

To go back, Docker is a computer program that can perform virtualization at the operating-system level. It was first released in 2013 by dotCloud, which started as an Open Source project, but who are now known to be Docker, Inc. At its essence, Docker can be more easily known as a light-weight alternative to virtual machines. Which are known as Containers, and have very significant differences between virtual machines. On one hand, in the past, virtual machines may run separate instances of an operating system, with each having its own dedicated resource, etc. Where as Docker can have multiple containers run on the same operating system, and share resources to keep each container running, completely separate, and even containers not knowing those other containers are running. However, containers are not Virtual Machines, and comparing them to Virtual Machines don\'t do them justice.

Some other ideas about Docker and things to take away from this are:

  • [X] Docker containers, or containers, allow you to package your apps and keep them consistent anywhere, and everywhere.
  • [X] Reduction in infrastructure and hardware requirements, without the need for too much cost, and investment.
  • [X] Docker boosts IT, developer productivity and innovation within organizations.

What are Containers?

Without going too far into depth on what containers actually are. In Layman\'s Terms Containers really just are a process running on the host Operating System. I want to keep this conversation to a minimum, as many times it is found that Docker containers are confused with Virtual Machines. Where as a virtual machine is a full-on instance of an operating system, Docker simply borrows parts of an operating system, for an easier understanding, have a look at the illustration below.

Container Anatomy

As the architecture above describes. Our app runs within a container, that sits above the Docker Engine. With enough creativity, you can run a number of applications at once, and have them all communicate in harmony with each other. LEMP stack, or LEMPP, or hell, any stack that you put enough time and effort in.

Dockerfile

Using a Dockerfile may actually make things a little easier to understand. To put it into more simple terms, this is the equivalent of running various shell commands for a system at setup and create, but a few more levels up, instead of simply just installing applications, libraries, binaries, and running our own apps. We add images of operating systems, whether that is Ubuntu, or Kali, or even just running a simple python application you have built, is up to to you and the task at hand. A Dockerfile gives you the flexibility to create and reuse without repetition, and from any software developer or coders perspective, Don\'t Repeat Yourself is always the best way to go.

FROM - An image that exists within the docker registry, such as ubuntu or python. You should be very careful what images you use, it is known that many images are uploaded with malicious intent, so be very aware of what images you are using. 
COPY - Equivalent of the cp command, copies files from a local path into your docker image 
ADD - Similar to ADD but really not as stable, it\'s better to just use COPY. 
ENV - Allows you to set environment variables that your container will need, things like passwords, usernames... or even PATHS for certain applications and libraries. CUDA anyone? 
RUN - Run various commands that are part of a base image, say FROM ubuntu. apt-get update && apt-get upgrade anyone? 
VOLUME - Allows you specify a virtual mounting point... say you would like to just mount a file or directory locally, you can do this. 
USER - Many times, docker runs on root by default... We\'ll figure out how to get around this eventually. 
WORKDIR - Allows you to set a default working directory when you enter your docker container, or even that the docker container will use 
EXPOSE - Lets you expose various ports, useful for things like Nginx, SQL, or just about anything you need a port for 
ONBUILD - I\'ve never had a use for this.

All of the above commands are the most common and used within a Dockerfile. To build a good image, is to understand what the purpose of your image is, and I want to give you the tools that will help you understand and create efficient Docker images. Our program will be a simple python script that will run after we build the image and run it with the docker command. Before doing anything, let\'s open up a terminal and navigate to your user home.

Setup

cd ~/ mkdir -p myProject/ && cd myProject/ 
touch requirements.txt && echo requests==2.9.1 >> requirements.txt 
touch helloWorld.py 
vim helloWorld.py 

Once you have completed that, let\'s get started on our python script! If you want to exit vim, press the esc key, then type :q! (the ! is for any unsaved edits) and:w is to write any changes to the file... :w! is to forcibly write those changes... but we will learn more about that later on. Feel free to copy this code into your terminal, but be aware, python is very sensitive about spacing issues, so make sure that you only use four spaces, no tabs, when you\'re lining up your code.

Your Python Script

#!/usr/bin/python3

import requests
import os

my_environment = os.environ.get('my_api_token')

def main():
    print(Hello World from my Docker container image!\n)
    print(my_environment) 
    print('My environment variable printed as a string: %s' % (my_environment))

if __name__ == '__main__':
    main()

Once you have finished writing your code, save it inside of vim by typing :wq! which will save your code to helloWorld.py after that, let\'s get started with your Docker image by running the command touch Dockerfile inside of your ~/myProject/ directory, which will create your Dockerfile on the fly. Once you\'ve completed that step, feel free to run vim Dockerfile and we will run the same :wq! when finishing up. The cool thing about this is that a Dockerfile does not have the same spacing rules as python, so you can copy and paste at your leisure.

Your First Image

# Base image
FROM ubuntu:16.04

# Set our working directory
WORKDIR /myProject

# Download any necessary dependencies, I included pip for both python 2.7 and python 3.5 just so you can get a feel for PyPi or pip
RUN apt-get update \
    && apt-get install -y \
        build-essential python-dev python3-dev python-pip python3-pip

# Add all of our files from our pre-built program, we could also do the same thing with the COPY command 
ADD * /myProject/

# Copy an additional file
COPY requirements.txt /myProject/requirements.txt

# run another command
RUN pip3 install -r requirements.txt

# Optional
# Set any environment variables, say like an API token; this is purely used as an example, so that you can get some ideas on how 
# you can use your newly formed docker image, and the power that lie underneath
ENV my_api_token=just-using-this-as-an-example

# tell your image to do something right away, in this case, launch our helloWorld script
CMD [ python3, /myProject/helloWorld.py ]

Once you\'ve saved your changes in your Dockerfile it\'s time to build our image. Execute the following command docker build -t myproject:v1 .while inside of ~/myProject/ directory and observe the output results. If everything has successful run, you will see that your latest image has been built and can be seen.

Towards thee I roll, thou all-destroying but unconquering whale; to the last I grapple with thee; from hell\'s heart I stab at thee; for hate\'s sake I spit my last breath at thee.

Captain Ahab

~ on 🐳 v18.09.2 took 30s 
➜ docker images
Installing collected packages: requests
Successfully installed requests-2.9.1
You are using pip version 8.1.1, however version 19.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Removing intermediate container 23a4d9d22664
 ---> d33fb2370ee
Step 7/8 : ENV SLACK_BOT_TOKEN="xoxb-426270598675-432707799525-iHfEkiCAPcbwwNxIu
G7d4X17"
 ---> Running in 6f20e843dc1c
Removing intermediate container 6f20e843dc1c
 ---> 8ef6dfa348fa
Step 8/8 : CMD [ "python3", "/myProject/helloWorld.py" ]
 ---> Runing in 4f8b18470a02
Removing intermediate container 4f8b18470a02
 ---> 619868168fba
Successfully built 619868168fba
Successfully tagged myproject:v1

You should see some output like in the above illustration. Ok! Now what? You image was built, let's check it out and see what is available. Run the command docker imagesor docker image ls you should see some information with the name of your image that was built, as well as an Image ID that was generated, like shown in the illustration below

~ on 🐳 v18.09.2 took 2s 
➜ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myproject              v1                 e08564cf538f       5 weeks ago         523MB
<none>               <none>             619868168fba       5 weeks ago         523MB
myproject            latest              86b111eff898       5 weeks ago         523MB
ubuntu                 16.04              13c9f1285025       5 weeks ago         119MB
hello-world           latest              fce289e99eb9      7 months ago       1.84kB

Long Stretch Home

I\'m sure at this point you\'re dying to test it out! Almost like how Captain Ahab died trying to get revenge on Moby Dock! So without further ado, run either of the two commands docker run <image id> or docker container run <image id> if everything was built and coded successfully, you should see the following output as shown in the illustration below

~ on 🐳 v18.09.2 took 2s
Hello World from my Docker container image!

just-using-this-as-an-example
My environment variable printed as a string: just-using-this-as-an-example

Congratulations! You\'ve successfully built a Docker image with a **Dockerfile**, you\'ve also executed your container image and saw how your application did somethings and quit just as expected. Captain Ahab would be proud of you. He is long gone, but his legacy can be continued as the search for the illusive Moby Dock has only begun! I hope that this article has provided some insight into how powerful Docker can be when used in the proper context. If you enjoyed it leave a reaction and a comment, and keep your eye open for the next post!