Docker Basics

6th February 2021

Coding

If you are reading this then I'm guessing you are looking to learn Docker!

Firstly that is great news since Docker is a super powerful tool to have on your belt.

Docker allow you to run containers which serve specific applications, for example MySQL or Apache.

These containers are based on an image and run as processes, contained in sandboxed filesystems, think of them as super lightweight virtual machines.

This blog post will walk through how to use public images and run them as containers, also we will learn how to create our own images and push them to the Docker Hub for other to make use of.

If all that sounds good, lets get into it!

 

Introduction

This blog post assumes you are running Windows 10 and have Windows Subsystem for Linux (WSL) 2 setup.

If you do not have WSL 2 setup checkout my upcoming blog post on doing this.

 

Installing Docker Desktop

To install Docker on your computer, head over to the Docker website here.

You will probably need to reboot but once done you should have the Docker Desktop app installed.

Docker Hub Application Screenshot

 

Using the Docker Hub

The Docker Hub is a central place to find images for all kind of applications.

These could range from base operating system images like Debian and Ubuntu to applications like MySQL and Apache.

You can explore the images on Docker Hub here.

 

Running Containers

We are now ready to run our first container, for this we will run the Alpine image and run the hostname command.

docker container run alpine hostname

When you run this it will do a number of things:

  • First download the latest alpine image from Docker Hub
  • Start the container
  • Run the hostname command
  • Exit and shutdown the container
PS D:\DockerStuff> docker container run alpine hostname
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
4c0d98bf9879: Already exists
Digest: sha256:08d6ca16c60fe7490c03d10dc339d9fd8ea67c6466dea8d558526b1330a85930
Status: Downloaded newer image for alpine:latest
099b9cc4117a

As you can see on the last line above, it has printed the hostname, docker containers have random hostnames.

There are three ways to run containers:

  • Single Task
  • Interactive
  • Background

Single Task

A new container will be setup and the given command will be run, once run the container will exit.

docker container run alpine hostname

This will pull and start an alpine container, run the hostname command then exit.

Interactive

A new container will be setup and the given command will be run, however this time the session will be interactive, have an allocated tty and be removed after executing.

docker container run --interactive --tty --rm ubuntu bash

or

docker container run -it --rm ubuntu bash
  • --interactive or -i gives an interactive session
  • --tty or -t allocates a pseudo-tty
  • --rm tells Docker to remove the container once done

Background

A new container will run as a background task.

docker container run --detach --name mydb --env MYSQL_ROOT_PASSWORD=password mysql:latest

or

docker container run -de MYSQL_ROOT_PASSWORD=password --name mydb mysql:latest
  • --detach or -d will run the container in the background
  • --name will name the container the given name
  • --env or -e will define environment variables
     

Building Images

Now we know some docker commands and how to run containers, lets create our own image.

This image will create a container that hosts an nginx server with our basic home page.

First you want to create a file called index.html with the following content.

<!DOCTYPE html>

<html>
    <head>
        <title>My Docker Sample Page</title>
    </head>

    <body>
        <h1>Docker Sample Page</h1>
        <p>Welcome to my Docker sample page</p>
        <p>Nice to meet you</p>
    </body>
</html>

Now we want to create a file called Dockerfile with the following content.

FROM nginx:latest

COPY index.html /usr/share/nginx/html

EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]

Lets quickly look at this Dockerfile, it is doing a number of things:

  • Pulling the latest nginx image from Docker Hub
  • Coping the HTML file we just created to the directory /usr/share/nginx/html
  • Exposing port 80 and 443 since these are the ports for web servers
  • Finally, run the command to start the server

We can now build our new image using the following command, be sure to replace my username (smithymx67) with your Docker Hub username.

The 1.0 at the end of the tag indicate the version of this image.

docker image build --tag smithymx67/web-app-example:1.0 .

This command tells Docker to build an image based on this Dockerfile and tag it, the period at the end is important, this tells the command where to find the Dockerfile, the period normally indicates the current working directory. The output you should see is shown below.

PS D:\DockerStuff\web-app> docker image build --tag smithymx67/web-app-example:1.0 .
[+] Building 0.7s (7/7) FINISHED
 => [internal] load build definition from Dockerfile                                                 0.0s
 => => transferring dockerfile: 31B                                                                  0.0s
 => [internal] load .dockerignore                                                                    0.0s
 => => transferring context: 2B                                                                      0.0s
 => [internal] load metadata for docker.io/library/nginx:latest                                      0.6s
 => [internal] load build context                                                                    0.0s
 => => transferring context: 32B                                                                     0.0s
 => [1/2] FROM docker.io/library/nginx:latest@sha256:10b8cc432d56da8b61b070f4c7d2543a9ed17c2b23010b  0.0s
 => CACHED [2/2] COPY index.html /usr/share/nginx/html                                               0.0s
 => exporting to image                                                                               0.0s
 => => exporting layers                                                                              0.0s
 => => writing image sha256:df9215b35118f6aed43a1e532f02574b4c94546276685fa9cc5e2971d16c3be8         0.0s
 => => naming to docker.io/smithymx67/web-app-example:1.0                                            0.0s

You have now built your first Docker image, congratulations!

We can now run this image as a container to test it, to do this run the following command.

docker container run -dp 80:80 --name web-app smithymx67/web-app-example:1.0

We have a new flag here -p, this maps port 80 on the host computer to port 80 inside the container, this will allow us to view the site at http://localhost.

You can view your containers using the container list command.

PS D:\DockerStuff\web-app> docker container ls -a
CONTAINER ID   IMAGE                            COMMAND                  CREATED          STATUS          PORTS                         NAMES
a7309380346d   smithymx67/web-app-example:1.0   "/docker-entrypoint.…"   52 seconds ago   Up 51 seconds   0.0.0.0:80->80/tcp, 443/tcp   web-app

To stop this webserver container run:

docker container stop web-app

To start it again run:

docker container start web-app

 

Pushing Images To Docker Hub

In the previous section we created our own docker image, this is only currently stored locally on your computer.

We can upload this image to the Docker Hub, this has a few benefits:

  • It can be stored securely
  • It can be public or private
  • It will be backed up and allows multiple versions

Pushing to the Docker Hub is super easy and quick, first you need to login to Docker.

docker login

Then run the following to push up the image.

docker image push smithymx67/web-app-example:latest

Notice the version tag at the end is latest, this can be whatever you want it to be, for example, 1.0, 1.4, legacy ect ect

That's it, your image is now on Docker Hub, you can view it on your profile, for example mine is https://hub.docker.com/u/smithymx67.

 

Finishing Up

So that's about it, you have learn how to use docker images, create your own and how to work with containers.

If you found this helpful, or not, please let me know as I'm always looking for ways to improve my content.

You can drop me an email via the details on my contact page.