What is a Dockerfile?
A Dockerfile in it’s simplest form is a file that contains instructions on how to build an Docker image. Although there aren’t any set rules about how Dockerfiles can be built I generally like to imagine them containing 4 primary sections:
- The first portion of the Dockerfile is the base section. This small 1 line section identifies a base image to start from. For example if your first line was
FROM ubuntu:20.04it would tell docker that when it builds the image it should start with the image that contains the Ubuntu 20.04 operating system.
- The second section is the environment section. This is where you get to setup the environment that the rest of the file runs in. You might want to set the working directory (WORKDIR /opt/app) or other variables (ENV PORT=”3000″) to use later on.
- The third section is the work section. This is where all of the work happens. Packages get installed (RUN apt install -y python3), code gets copied over (COPY src/ /opt/app), dependencies get install, code gets compiled, etc.
- The final portion of the Dockerfile is the run section. This is where you get to define what ports your app runs on (EXPOSE 3000), who the app runs as (USER node), and what command to run once the app starts up (CMD [“yarn”, “start”]).
Combining all of these sections creates an Dockerfile with the instructions on what image/os to start with, the environment to run in, what commands it should run, and what to do when the docker image starts up. The next section contains a hands on – step by step guide to creating a Dockerfile.
Creating the Dockerfile
To keep it simple our hands on example will be to create a python dockerized application that says hello world. So let’s jump into it! Create a new file called ‘Dockerfile’ and follow the upcoming steps.
- The first line will include the base image that we’d like to use. Jumping over to Dockerhub there’s an official docker image that already has python setup and ready to go. So instead of using an Ubuntu or Alpine Linux image and running a bunch of install commands I’ll just use the ‘python‘ image. Looking through the tags on that same page I’m going to use ‘3.9-alpine‘ indicating I want python version 3.9 based on the Alpine Linux image. So my first line will be: ‘FROM python:3.9-alpine‘
- The next step will be to set any environment variables we’ll need. The one I always set is the working directory so the next line we’ll add will be ‘WORKDIR /opt‘. We don’t have any other variables to set at this time so we’ll move onto the next step.
- The third section will include all of the work to be done. Since the base image is already setup with python we can jump right into copying our code onto the image. So the next line will be to add our hello.py script ‘COPY hello.py /opt/‘. Note, you’ll need to create a hello.py file in your current directory with the contents ‘print(“Hello World”)’
- The final step is to specify how the image will run. Since we want our hello.py script to run on startup let’s add a ‘CMD’ line to start it up: ‘CMD [“python”,”/opt/hello.py”]‘. With this complete we now have:
FROM python:3.9-alpine WORKDIR /opt COPY hello.py /opt/ CMD ["python","/opt/hello.py"]
Building an image from the Dockerfile
With the Dockerfile in place it’s time to execute those instructions and convert them into an image. The basic syntax to do this is:
docker build <working_dir> -t <image_name>:<image_tag> -f <path_to_dockerfile>
We have 1 relative path in our Dockerfile – the hello.py copy. So we need to make sure we’re in the right local directory when running docker build for it to not error out. We’ll build our image by running:
docker build ./ -t hello:latest -f ./Dockerfile
The output should show each of the steps being processed:
Step 1/4 : FROM python:3.9-alpine ---> 7254f7459375 Step 2/4 : WORKDIR /opt ---> Using cache ---> 98e8d7b2e27c Step 3/4 : COPY hello.py /opt/ ---> 866e30a28d31 Step 4/4 : CMD ["python","/opt/hello.py"] ---> Running in 8020a1558e87 Removing intermediate container 8020a1558e87 ---> 325e042dbe42 Successfully built 325e042dbe42 Successfully tagged hello:latest
We now have a new image ‘hello:latest’ that we can run!
Running your image
To run our new image is pretty simple:
docker run <image>:<tag>
So in our case we’ll run:
docker run hello:latest
And the output should be:
We did it! We built a Dockerfile, turned it into an image, and then ran it! To get more comfortable creating Dockerfiles try installing some pip packages, building a new Dockerfile based on nodejs instead of python, or build an Dockerfile that starts an application and runs it on a certain port.