👋 Want to chat? Feel free to say hey!

Getting to Know Docker: Running Your First Container

Date

July 2020

Category

Fun with Code

Why Should I Learn About Containers?

“I’m a designer – why should I learn about how to use Docker and containers?”
Good question!

Here are a few reasons:

  • You want to have the ability to test and contribute to your dev team early and often.
  • It will help you collaborate with your team to make your projects easily sharable.
  • It will help you speak the same language as your development team.
  • Docker will make your development environment repeatable and reusable.
  • While also making your environment easily resettable, without having to untangle broken dependencies if you make a mistake.
  • Already have a team staging area? That’s ok – wouldn’t you like to have a way to rebuild your own staging area with the newest changes on demand?

Pretty much the best reason is so you can create an isolated local environment for your work, so you have a less of this:

So What is a Container?

Not quite.
A simplified description of how containers work is:

If you’ve ever used a virtual machine on your computer you’ll notice that containers are similar in a lot of ways.

The easy way I like to think about it is that virtual machines run an entire alternate operating system on the machine, whereas containers sandbox processes so that multiple services can be run on top of a shared machine.

It’s a lot more efficient and a lot quicker for our use cases.

Containers and Images

Containers are broken up into two core concepts – images and containers.

Images are snapshots that are made to be a starting state for a container.

Images are built using snapshots from modified containers or are built using Dockerfiles which are instructions for how the image should be built (more information on building your own images will be in a separate part of this series).

Containers are instances of an image that have been launched.

For the sake of this walkthrough, we’ll be using pre-made images which are found in the Docker Hub which can be found here: https://hub.docker.com/

Starting Your First Docker Container

First off download and install Docker Desktop on your local machine:

Windows:
https://download.docker.com/win/stable/Docker%20Desktop%20Installer.exe

Mac:
https://download.docker.com/mac/stable/Docker.dmg

The installer will walk you through the rest of the installation process.

After that has completed, start by opening your Terminal (or Powershell if you’re using Windows) and enter the following:

docker ps -a
docker run hello-world
docker ps -a

So what just happened there?

So we started by running docker ps which lists running containers and then add a -a flag to the end which will list all containers.

Nothing’s currently showing since we haven’t started any containers yet.

Then we use docker run hello-world which tells docker to create a new container using the hello-world image.

The hello-world image is automatically pulled from Docker Hub and can be found here: https://hub.docker.com/_/hello-world.

As the container runs you will see its output in your terminal as is shown above.

Now at this point, when you run docker ps -a for the second time you’ll see a new container, (in this case, recursing_johnson) which has run with the Exited status.

This is ok since the hello-world image is built to be run in a container and then exit as soon as it’s completed.

Naming Your New Container

So you’ve created your first container, but let’s say you want to give it its own name and not use the generated name like recursing_johnson. You can do that using the --name flag in your docker run command.

docker run --name dockerfordesigners hello-world
docker ps -a

You’ll see that there is a new container named dockerfordesigners which will have run your hello-world image.

Running a Backgrounded (Detached) Container

docker run -d --name testingsilent hello-world
docker ps -a

When you first run docker run -d hello-world you’ll notice that a string of letters and numbers is printed instead of the container’s output.

This is the full container ID which has been created and is running in the background of your terminal (so there are no inputs or outputs).

When you go docker ps -a though you’ll notice there’s a new container, testingsilent which has been created and run.

Basic Ports & Networking

For this part of the demonstration we’re going to switch over to using an nginx image which is a web server which can serve our HTML files:

docker run -d --name testingnginx nginx
docker ps -a

Awesome – so as with above the latest nginx image is now running silently in a container the same way hello-world was.

You’ll also notice that the testingnginx container is running with a Running status. This is because nginx’s image is not built to exit as soon as it has finished executing.

That’s all great – but how do we actually see what’s actually running on the server? We can’t currently access the running container through our browser because it doesn’t currently have access to the network.

We can remedy this by add the -p flag which will help us map the ports needed locally using [your-machine-port:container-port].

In nginx’s documentation in Docker Hub we can see that port 80 is the port which is being exposed which we’re looking to mount from the container to the local machine.

docker run -d -p 8095:80 --name testingnginxports nginx
docker ps -a

At this point, if I go to my browser and go to http://localhost:8095/ I’ll be able to see your nginx welcome page as is shown above.

Mounting Files to a Container

Also known as “how can I get my working files into the container?”.

The easiest way to get your working files into the container is by using bind mounts to map a directory or a file locally to a directory or file inside the container, using [host-folder-or-file:container-folder-or-file].

Again, we’re able to see from nginx’s documentation that /usr/share/nginx/html is the directory in the container which contains the file which will be served.

docker run -d -p 8096:80 --name testingnginxmount -v /Users/martin/documents/GitHub/DockerForDesigners/html:/usr/share/nginx/html nginx

It’s also possible to volume mount individual files as seen below:

docker run -d -p 8097:80 --name testingnginxfilemount -v /Users/martin/documents/GitHub/DockerForDesigners/html/index.html:/usr/share/nginx/html/index.html nginx

When we run these, I’m able to see my “Hello World” HTML which is in the index.html as shown above.

Using a Specific Image Version

Finally, let’s say there is a specific version of an image you’d like to use if you use the syntax imagename:tag Docker will be able to pull that specific image and run it in a container.

When a tag is not used, the image will always default to imagename:latest.

For example, let’s say I’m browsing the tags which are available for nginx (https://hub.docker.com/_/nginx?tab=tags) and see that I’d like to run version 1.17.6. I’d be able to select this version using the command below:

docker run -d --name testing1176 nginx:1.17.6
docker ps -a

Pinning the version of your images is especially important when you’re running software that has only been tested in a certain configuration or you’re trying to create a repeatable, reusable environment.

Cleaning Up Your System

The last element we’ll be looking up in this part of the tutorial is cleaning up after yourself. As you can see we’ve got quite a few containers running:

docker ps -a

Stopping & Removing Individual Containers

You can stop a container by simply going docker stop [container-name].
Similarily once a container is stopped you can remove the container with docker rm [container-name].

One thing that a lot of people don’t talk about is removing the volume data which the container created in case you want to start completely from scratch. You’re able to remove this data using the -v flag using docker rm -v [container-name].

For example to remove testingnginx:

docker stop testingnginx
docker rm -v testingnginx

Mass Cleanup (Using Prune)

A basic way to mass cleanup your machine is by using the system prune command.

docker system prune

This will remove:

  • All stopped containers
  • All networks not used by at least one container
  • All dangling images
  • All build cache

A more advanced prune is also available as:

docker system prune -a --volumes

This will remove:

  • All stopped containers
  • All networks not used by at least one container
  • All volumes not used by at least one container (with the --volumes flag)
  • All images without at least one container associated to them (with the -a flag)
  • All build cache

Next Steps

In the next parts of this series I’ll be looking to cover:

  • Running commands in your container and running an interactive container.
  • Volume Mounts and Copying Files
  • Using multiple containers together and having them talk to each other (setting up WordPress using their famous “5 Minute Install” in Docker).
  • Building your first Image (using Dockerfiles).
  • Using Docker Compose to define and run multiple containers at the same time.

Hopefully, this will give you a good foundation to start playing with Docker and experimenting with running your first containers.

Feel free to get in touch if you’d like to ask any questions or would like any other subject answered in a later part of the series.