Welcome back to Docker Fundamentals. So far, you have learned how to use Docker with existing images from Docker Hub, such as nginx, and how to manage containers using basic commands. This is a great foundation, but in real-world development, you will often need to package your own applications into containers. This is where building custom Docker images becomes essential.
Creating your own Docker images allows you to ensure consistency, repeatability, and portability for your applications. When you build an image, you capture everything your app needs — code, dependencies, and environment — so it can run the same way anywhere Docker is available. This is especially important when you want to share your app with teammates, deploy it to production, or move it between different computers.
In this lesson, you will learn how to create a Docker image for a simple web application. The app will be a tiny web server that says, "Hello from Docker!" when you visit it in your browser. By the end of this lesson, you will know how to write a Dockerfile, build your own image, and run it as a container. This is a key step in becoming comfortable with Docker and using it for your own projects.
Before you start building, let's look at the files you will use in this project. You will work with three main files: app.py, requirements.txt, and Dockerfile. These files will be placed in a folder called docker-app.
The app.py file contains a simple Flask application. When you visit the root URL, it will return the message, "Hello from Docker!" Here is what the file looks like:
The requirements.txt file lists the packages your app needs. In this case, you only need Flask, and you will pin the version to make sure your app always uses the same one:
The Dockerfile is the recipe that tells Docker how to build your image. You will write this file step by step in the next section.
In the upcoming practice section, Docker is already installed for you. This means you can focus on learning how to build and run your app in a container. However, it is important to understand these steps so you can repeat them on your own computer in the future.
The Dockerfile is a plain text file that contains instructions for building your image. Each instruction creates a new layer in the image, and together they define everything your app needs to run.
You will start by choosing a base image. In this case, you will use the official image, specifically the slim version, to keep your image small and efficient. The first line of your Dockerfile will be:
Next, you will set the working directory inside the container to /app. This means all following commands will run in this directory:
You need to copy your dependencies file first. This is done in two steps for efficiency. First, copy the requirements.txt file:
Now, you will install the dependencies listed in requirements.txt using pip. The --no-cache-dir option keeps the image smaller by not storing the downloaded packages:
After the dependencies are installed, copy your application code. This ordering is important because if you change app.py later, Docker can reuse the cached dependency installation layer, making rebuilds faster:
Your web app will listen on port 3000, so you should tell to expose this port. This does not actually publish the port, but it is a helpful hint for anyone using your image:
Now that you have your Dockerfile and application files ready, you can build your Docker image. You will use the docker build command for this. The basic syntax is:
Here, the -t my-web-app option gives your image a name (or "tag"), which makes it easier to refer to later. The . at the end tells Docker to use the current directory as the build context. The build context is everything Docker can see and use during the build, so make sure you are in the docker-app directory when you run this command.
When you run the build command, you will see output like this:
Docker will try to use cached layers if nothing has changed, which makes repeated builds faster. If you change your code or the Dockerfile, Docker will rebuild only the necessary steps.
After building your image, you should check that it exists on your system. You can do this with the docker images command:
You will see output like this:
Your new image, my-web-app, should appear in the list. If you want to see more details about the image, you can use the docker image inspect my-web-app command. This will show you metadata such as the layers, environment variables, and entry point, which can be useful for debugging or understanding how your image is built.
Now you are ready to run your custom image as a container. Use the following command:
This command starts a new container in detached mode (-d), gives it the name my-app-container, and maps port 3000 on your computer (the host) to port 3000 inside the container. Port mapping is important because it allows you to access the web app running inside the container from your browser or with tools like curl.
Once the container is running, you can check that it is up with:
You should see output like this:
To test your app, you can open your browser and go to http://localhost:3000, or use the curl command:
You should see:
This confirms that your container is running and serving your web app correctly.
If something does not work as expected, you can check the status of your container with docker ps and view the logs with:
This will show you the output from your web app, which can help you spot errors or see if the app started correctly.
When you are done, you should stop and remove the container to free up resources. You can do this with:
Some common issues you might run into include using the wrong port mapping (for example, mapping to the wrong host port), not setting the web app to bind to 0.0.0.0 (which would make it unreachable from outside the container), or forgetting to rebuild the image after changing your code. If you change app.py or requirements.txt, remember to rebuild your image with docker build -t my-web-app . before running a new container.
In this lesson, you learned how to write a Dockerfile for a simple web application, build a custom Docker image, and run it as a container. You also practiced checking the image, running the container with port mapping, verifying the app is working, and cleaning up when you are done. These are the core steps for packaging and running your own applications with Docker.
Next, you will get hands-on practice editing the Dockerfile, rebuilding the image, running containers, and troubleshooting common issues. Remember, while the CodeSignal environment has everything ready for you, these steps are the same on your own computer. Mastering them will help you use Docker confidently in any project.
