How to Create and Run Your First Docker Image
Tags: docker, productivity, devops
Published: 2022-08-23 04:49:00


I've spent the last few weeks diving into the world of Docker containers to understand how they work and how they can be improve our deployment process. While it was clear to me that Docker can provide a huge amount of value to our deployment and ops processes, it took me a while to understand exactly how to use it.

## Images and Containers

Docker has two main concepts that we need to understand: Images and Containers. Images define the environment you application needs in order to run. For node apps, this probably includes things like your source code, `node_modules` directory, and `package.json` and `package-lock.json` files. For static apps, it may just include static HTML. For ruby apps, it may be your source plus your `bundle` file. It all depends on your app.

Images are built from your _source_ and pushed into repository, much like an NPM package or a Ruby gem. Once an image is built and published to a repository, anyone else on your team can pull that image down and use it to to create a _container_, which is effectively just an _instance_ of our image.

The important takeaway is that Images _define_ the application environment while Containers actually _run_ that environment.

## Building a Docker Image

All Docker images are build from a `Dockerfile`. A `Dockerfile` is a file that just has a [set of commands](https://docs.docker.com/engine/reference/builder/){:target="_blank"} telling Docker how to "wrap" the application environment into a reusable Image that can be used to create containers. The contents of a `Dockerfile` looks more or less just like a series of bash commands. These commands are executed when we run `$ docker build` and the output of those commands makes up our image.

## Dockerfile

Your application's Dockerfile should live in your app's repo alongside the source code. It doesn't make a ton of sense for your Dockerfile to live outside of your application's repo since your Dockerfile will be responsible for creating an image that will be used to eventually run the application. Ultimately, the application developer is responsible for writing their own Dockerfile to create their image.

## Your first Dockerfile

Let's create a simple Dockerfile that only contains Nginx. Create a `Dockerfile` and add the following:

```
FROM nginx
```

The `FROM` command is almost always the first command in every `Dockerfile`. It tells Docker that we are basing our image from an already existing image. In this case, we are pulling down the `nginx` image and using it as the basis for our image.

To build this image, run the following command. (Make sure that you are in the same directory as our new Dockerfile.)

```
$ docker build .
```

That's all we need to create our first image! If you run `$ docker images` in your teminal, you should see something like this:

![docker images command output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b7rdbsgougm3k0y47f03.png)

Having our first image is great, but it's only the first step. Now, we need to use that image to create and run a _container_. Run `$ docker images` again. Take note of the `IMAGE ID` (`c431399b6d03` in the image above, we'll call it `<<HASHED_ID>>`). Copy that ID from your terminal and then run the following command:

```
$ docker run -p 8000:80 <<HASHED_ID>>
```

This command tells docker to create and run a container from our image with the ID `<<HASHED_ID>>`. Now, open your browser and navigate to `http://localhost:8000`. You should see the standard nginx splash screen:

![nginx splash screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qa8u9dz2wmcbvusldkk5.png)

Viola! We are now running an Nginx container from an image we created!


## Tagging your Docker image

You may be wondering about the `<<HASHED_ID>>` part from the step above. When we run `docker build`, Docker automatically assigns our image a generated ID so it can be referenced laster. While we can continue to use that ID, it isn't the best developer experience and it's not that easy to remember! When we build our image, we can create a Docker image with a human-readable `tag`. Docker will still create our image with it's generated ID, but it will also tag that ID with whatever name we provide it. Let's rebuild our image and give it the tag `my-first-docker-image`:

```
$ docker build -t my-first-docker-image .
```

If you run `$ docker images` again, you will see that the `Repository` field is now populated with `my-first-docker-image`:

![docker images command output with tagged image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynag73c413xdmculeuxn.png)

Our run command from above can now be changed to:

```
$ docker run -p 8000:80 my-first-docker-image
```

Much better!

## In Summary

Creating Images and running them in Containers is only scratching the surface for what Docker can do. Docker does have a bit of a learning curve, but once you get the hang of it, you won't be able to work without it!

**Enjoy this article? [Subscribe to EasyWebDev!](https://easywebdev.substack.com/)**