Containerization has become a fundamental skill for DevOps Engineers, Cloud Engineers, and Software Developers.
However, many beginners learn Docker commands without understanding the complete workflow behind them.
Questions like:
- What exactly is a Docker Image?
- How does a Dockerfile become a running Container?
- Why do we push images to Docker Hub?
- How do organizations deploy the same application everywhere?
are common when starting out.
In this blog, we'll build a simple Node.js application, containerize it using Docker, run it locally, and finally push the image to Docker Hub.
By the end of this guide, you'll understand the complete Docker workflow used in real-world DevOps environments.
Docker Workflow Overview
flowchart LR
A[Application Code] --> B[Dockerfile]
B --> C[Docker Build]
C --> D[Docker Image]
D --> E[Docker Run]
E --> F[Docker Container]
D --> G[Docker Push]
G --> H[Docker Hub]
This is the same workflow followed by developers and DevOps teams worldwide.
What Are We Building?
We'll create a simple Node.js application that returns:
- A welcome message
- Environment information
- Container hostname
This helps us verify that our application is actually running inside a Docker container.
Project Structure
.
āāā Dockerfile
āāā app.js
āāā package.json
Step 1: Create the Node.js Application
app.js
const express = require("express");
const app = express();
const PORT = process.env.PORT || 3000;
const ENV = process.env.ENV_VALUE || "No env set";
const HOSTNAME = process.env.HOSTNAME || require("os").hostname();
app.get("/", (req, res) => {
res.json({
message: "Hello from Simple App (Node)",
env: ENV,
container: HOSTNAME
});
});
app.listen(PORT, () =>
console.log(`Node Hello listening on ${PORT}`)
);
package.json
{
"name": "hello-app-node",
"version": "1.0.0",
"main": "app.js",
"dependencies": {
"express": "^5.2.1"
}
}
Application Architecture
flowchart LR
User --> Browser
Browser --> Container
Container --> NodeJS
NodeJS --> JSONResponse
Whenever a user accesses the application, the request reaches the containerized Node.js application, which returns a JSON response.
Step 2: Create the Dockerfile
A Dockerfile is simply a blueprint that tells Docker how to build an image.
FROM node:24-slim
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
Understanding the Dockerfile
Base Image
FROM node:24-slim
We start with an official lightweight Node.js image from Docker Hub.
Working Directory
WORKDIR /app
Creates and switches to the /app directory inside the container.
Copy Dependency Files
COPY package*.json ./
Copies package files first.
This is considered a Docker best practice because Docker can cache dependency layers and speed up future builds.
Install Dependencies
RUN npm install --production
Installs only production dependencies.
Copy Application Source Code
COPY . .
Copies the entire project into the container.
Expose Application Port
EXPOSE 3000
Documents that the application listens on port 3000.
Start the Application
CMD ["node", "app.js"]
Runs the Node.js application when the container starts.
What Happens During Docker Build?
flowchart TD
A[Dockerfile]
--> B[Pull Node Base Image]
--> C[Create Working Directory]
--> D[Copy package.json]
--> E[Install Dependencies]
--> F[Copy Application Code]
--> G[Create Image Layers]
--> H[Docker Image Ready]
Docker executes each instruction sequentially and creates image layers.
Step 3: Build the Docker Image
Run:
docker build -t madhavnaks/node-app .
Let's understand this command:
docker build
Builds an image from a Dockerfile.
-t
Assigns a tag to the image.
madhavnaks/node-app
Image name.
.
Current directory containing the Dockerfile.
After a successful build you'll see output similar to:
=> naming to docker.io/madhavnaks/node-app
Docker has now created an image locally on your machine.
Step 4: Verify the Image
To see locally available images:
docker images
Example output:
REPOSITORY TAG IMAGE ID SIZE
madhavnaks/node-app latest 42c936686000 234MB
At this point, the image exists but is not running.
Docker Image vs Docker Container
Many beginners confuse these two concepts.
Think of it like this:
- Docker Image = Blueprint
- Docker Container = Running Application
flowchart LR
A[Docker Image]
--> B[Container 1]
A --> C[Container 2]
A --> D[Container 3]
A single image can create multiple containers.
Step 5: Run a Container
Now let's start our application.
docker run -d --name node-app -p 3001:3000 madhavnaks/node-app
Understanding the Command
Detached Mode
-d
Runs the container in the background.
Container Name
--name node-app
Assigns a friendly name to the container.
Port Mapping
-p 3001:3000
Maps:
Host Port ā Container Port
3001 ā 3000
The application listens on port 3000 inside the container but is accessible on port 3001 from your machine.
Step 6: Verify the Container
Check running containers:
docker ps
Expected output:
CONTAINER ID IMAGE STATUS
10265698c978 madhavnaks/node-app Up
Step 7: Access the Application
Open:
http://localhost:3001
Expected response:
{
"message": "Hello from Simple App (Node)",
"env": "No env set",
"container": "10265698c978"
}
Notice the hostname.
The hostname corresponds to the container ID, proving the application is running inside Docker.
Step 8: Login to Docker Hub
Before pushing images, authenticate with Docker Hub.
docker login
Example:
Login Succeeded
Docker is now authorized to push images to your repository.
Why Push Images to Docker Hub?
Docker Hub acts as a centralized registry.
flowchart LR
A[Developer Machine]
-->|Push| B[Docker Hub]
B -->|Pull| C[Server]
B -->|Pull| D[Kubernetes Cluster]
Once an image is pushed, it can be pulled and run from anywhere.
Step 9: Push the Image
Push the image to Docker Hub:
docker push madhavnaks/node-app
Example output:
latest: digest: sha256:d1081ec542f521e100bd886943c13ab7568c663b56e36200e6d846163975f979
This confirms that the image has been successfully uploaded.
Step 10: Verify on Docker Hub
Visit your Docker Hub account.
You should now see:
madhavnaks/node-app
listed under repositories.
You can even share the image with others.
Anyone can now run:
docker pull madhavnaks/node-app
docker run -p 3001:3000 madhavnaks/node-app
without needing your source code.
Real-World DevOps Workflow
In production environments, the workflow usually looks like this:
flowchart LR
A[Developer Writes Code]
--> B[GitHub]
B --> C[CI/CD Pipeline]
C --> D[Docker Build]
D --> E[Docker Hub]
E --> F[Kubernetes Cluster]
This is exactly how modern DevOps teams package and deploy applications.
Key Takeaways
ā Dockerfile defines how an image should be built
ā Docker Build creates an image
ā Docker Run creates a container
ā Docker Hub stores and distributes images
ā One image can create multiple containers
ā Containerization ensures consistency across environments
Conclusion
In this guide, we covered the complete Docker workflow from source code to Docker Hub.
We learned how to:
- Create a Dockerfile
- Build a Docker image
- Run a container
- Verify application execution
- Push images to Docker Hub
- Understand how images move through real-world DevOps pipelines
Mastering these Docker fundamentals is the first step toward advanced topics like Docker Compose, Kubernetes, Helm, CI/CD pipelines, and cloud-native deployments.
If you're learning DevOps, try containerizing applications in different languages such as Python, Java, Go, or .NET to strengthen your understanding of Docker.
Happy Containerizing! š
Top comments (1)
Letsgoo