#90DaysOfDevOps Challenge - Day 17 - Docker Project for DevOps Engineers (Dockerfile)

Cloud Engineer and DevOps enthusiast, just talking about AWS, Docker, Linux, Kubernetes, Python, and automation.
Search for a command to run...

Cloud Engineer and DevOps enthusiast, just talking about AWS, Docker, Linux, Kubernetes, Python, and automation.
No comments yet. Be the first to comment.
The #90DaysOfDevOps Challenge is a dedicated initiative aimed at promoting continuous learning and skill development in the field of DevOps over a 90-day period.
Running your own home lab used to mean expensive hardware, complex networking, and hours of manual configuration. This project changes that. With a single Raspberry Pi, Docker Compose, and a few hundr

Welcome to an advanced hybrid directory demo where we'll guide you through setting up a hybrid environment, connecting to simulated on-premises infrastructure, creating a managed Microsoft AD within AWS, establishing a two-way forest trust, and integ...

Hello DevOps Community! Today marks the completion of the #90DaysOfDevOps Challenge, and it's a moment to reflect on the journey we've undertaken together. Throughout this period, I've engaged with various technologies, refining my skills in the DevO...

In a modern cloud infrastructure setup, creating a robust and scalable 2-tier architecture is essential. Such an architecture helps meet the demands of your applications while ensuring repeatability, reliability, and security. In this article, we'll ...

Welcome to Part 4 of my series on building a comprehensive CI/CD pipeline in AWS. In this article, I will explore AWS CodePipeline, a powerful service for building and deploying applications in a continuous integration and continuous delivery (CI/CD)...

Welcome to Day 17 of the #90DaysOfDevOps challenge. Today, we will dive into Docker and explore a Docker project for DevOps Engineers. In this project, we will learn about Dockerfile, build images, run containers, and push images to repositories.
The very basic building block of a Docker image is a Dockerfile
A Dockerfile is a simple text file with instructions and arguments. Docker can build images automatically by reading the instructions given in a Dockerfile.
In a Dockerfile, Everything on left is an INSTRUCTION, and on right is an ARGUMENT to those instructions. Remember that the file name is "Dockerfile" without any extension.

The following table contains the important Dockerfile instructions and their explanation.
| Dockerfile Instruction | Explanation |
| FROM | To specify the base image which can be pulled from a container registry (Docker hub, GCR, Quay, ECR, etc) |
| RUN | Executes commands during the image build process. |
| ENV | Sets environment variables inside the image. It will be available during build time as well as in a running container. If you want to set only build-time variables, use ARG instruction. |
| COPY | Copies local files and directories to the image |
| EXPOSE | Specifies the port to be exposed for the Docker container. |
| ADD | It is a more feature-rich version of the COPY instruction. It also allows copying from the URL that is the source and tar file auto-extraction into the image. However, usage of COPY command is recommended over ADD. If you want to download remote files, use curl or get using RUN. |
| WORKDIR | Sets the current working directory. You can reuse this instruction in a Dockerfile to set a different working directory. If you set WORKDIR, instructions like RUN, CMD, ADD, COPY, or ENTRYPOINT gets executed in that directory. |
| VOLUME | It is used to create or mount the volume to the Docker container |
| USER | Sets the username and UID when running the container. You can use this instruction to set a non-root user of the container. |
| LABEL | It is used to specify metadata information of Docker image |
| ARG | It is used to set build-time variables with key and value. the ARG variables will not be available when the container is running. If you want to persist a variable on a running container, use ENV. |
| CMD | It is used to execute a command in a running container. There can be only one CMD, if multiple CMD there then it only applies to the last one. It can be overridden from the Docker CLI. |
| ENTRYPOINT | Specifies the commands that will execute when the Docker container starts. If you don’t specify any ENTRYPOINT, it defaults to /bin/sh -c. You can also override ENTRYPOINT using the --entrypoint flag using CLI. |
Let's go through the essential components of a Dockerfile:
The base image is the starting point for your Docker image. It provides the underlying operating system and environment for your application. You can choose from a wide range of pre-built base images available on Docker Hub, such as Alpine Linux, Ubuntu, or specific language runtimes like Node.js or Python.
FROM node:14
In the example above, we are using the official Node.js base image with version 14. This image includes Node.js and its runtime environment, which is suitable for running Node.js applications.
The working directory is the location inside the container where your application code will be copied. It is a good practice to set the working directory to a specific path.
WORKDIR /app
In this case, we set the working directory to /app.
Next, you need to copy your application code and any necessary files to the working directory in the container. This ensures that the container has all the required files to run your application.
COPY package*.json ./
The above line copies the package.json and package-lock.json files from the host directory to the current working directory in the container.
After copying the necessary files, you can install your application's dependencies using package managers like npm or pip.
RUN npm install
This command installs the Node.js dependencies based on the package.json file.
Once the dependencies are installed, you can copy the rest of your application code to the working directory in the container.
COPY . .
This line copies all the files and folders from the host directory to the current working directory in the container.
If your application listens on a specific port, you need to expose that port in the Dockerfile.
EXPOSE 3000
In this example, we expose port 3000, which is the default port for a Node.js web application.
Finally, you need to define the command that will be executed when the container starts.
CMD ["node", "app.js"]
This command specifies that the node command should be executed, and the app.js file should be the entry point for your application.
By combining these instructions in a Dockerfile, you can build an image that encapsulates your application and its dependencies. This image can be run as a container on any system with Docker installed, providing a consistent and isolated environment for your application.
# Use the official Node.js base image with version 14
FROM node:14
# Set the working directory to /app
WORKDIR /app
# Copy package.json and package-lock.json to the working directory
COPY package*.json ./
# Install the Node.js dependencies
RUN npm install
# Copy the application code to the working directory
COPY . .
# Expose port 3000
EXPOSE 3000
# Define the command to start the application
CMD ["node", "app.js"]
In the example above, we start with the official Node.js base image with version 14. We set the working directory to /app and copy the package.json and package-lock.json files to the working directory. Then, we install the Node.js dependencies using npm install. Next, we copy the rest of the application code to the working directory. We expose port 3000 to allow external access to the application running inside the container. Finally, we define the command to start the application, specifying node app.js as the entry point.
This example covers the essential elements of a Dockerfile, including the base image selection, working directory setup, copying files, installing dependencies, exposing ports, and defining the command. You can modify this example according to your specific application requirements, such as using a different base image, exposing different ports, or changing the entry point command.
# app.py
# Importing the Flask class from the flask module
from flask import Flask
# Creating an instance of the Flask application
app = Flask(__name__)
# Defining a route decorator for the root URL ("/")
@app.route('/')
def hello():
# Returning the string "Hello, World!" as the response to the request
return "Hello, World!"
# Checking if the script is being executed directly (not imported as a module)
if __name__ == '__main__':
# Running the Flask application
# Starts a development server on the specified host (0.0.0.0) and port (3000) to handle incoming requests
app.run(host='0.0.0.0', port=3000)
# Use the official Python 3 base image
FROM python:3
# Set the working directory inside the container
WORKDIR /app
# Install Flask library using pip
RUN pip install flask
# Copy the app.py file from the local directory to the working directory inside the container
COPY app.py /app/
# Expose port 3000 to allow external access
EXPOSE 3000
# Set the command to run when the container starts
CMD [ "python", "./app.py" ]
This Dockerfile and Python code demonstrate containerizing a simple Flask web application. The Dockerfile sets up the environment and exposes port 3000. The Python code creates a Flask app that responds with "Hello, World!" for the root URL. By building and running the Docker image, the Flask app becomes accessible on port 3000.

First, we build the docker image from the Dockerfile
docker build -t my-web-app .
Then, we run a container using the image created
docker run -d -p 3000:3000 my-web-app
We can check if the docker container is running by running docker ps

We can verify if the application is running by accessing http://127.0.0.1:3000/ in our preferred browser

Log in to Docker Hub using the docker login command:
docker login
Tag your local image with the repository name:
docker tag my-web-app estebanmorenoit/my-web-app
Push the image to Docker Hub:
docker push estebanmorenoit/my-web-app


Here you can find 'my-web-app' repository after following the above steps
Congratulations on completing Day 17 of the #90DaysOfDevOps challenge. Today, we explored Docker and its capabilities for containerization and management. We gained practical experience in building, running, and pushing Docker images.
As we progress to Day 18, we have an exciting Docker project lined up specifically for DevOps Engineers. This project will introduce us to Docker Compose, a powerful tool for orchestrating multi-container applications. We will learn how to define and manage complex application stacks using a simple YAML file. Stay tuned!