Goal
By the end, students will understand:
- What a Dockerfile is
- What a Docker image is
- What a Docker container is
- How DevOps engineers package and run applications
- How to expose an application to a browser
Real DevOps Scenario
A developer created a small website.
As a DevOps engineer, your job is to package this website into a Docker image so it can run the same way on:
- your laptop
- another developer’s laptop
- a test server
- production server
- Kubernetes later
This solves the common problem:
It works on my machine, but not on the server.
Docker helps us make the environment consistent.
Step 1: Create Project Folder
mkdir docker-website-lab
cd docker-website-lab
Why?
We create one folder for our application files.
This folder will contain:
docker-website-lab
├── index.html
└── Dockerfile
Step 2: Create a Simple Website File
touch index.html
Open the file:
nano index.html
Paste this:
<!DOCTYPE html>
<html>
<head>
<title>Docker Lab</title>
</head>
<body>
<h1>Hello from Docker!</h1>
<h2>This website is running inside a container.</h2>
<p>Created by a DevOps student.</p>
</body>
</html>
Save:
CTRL + O
ENTER
CTRL + X
Why?
This is our simple application.
In real companies, this could be:
- React frontend
- Node.js backend
- Python API
- Java application
For beginners, we start with HTML because it is easy to see in the browser.
Step 3: Create a Dockerfile
touch Dockerfile
Open it:
nano Dockerfile
Paste this:
FROM nginx:latest
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
Save:
CTRL + O
ENTER
CTRL + X
Step 4: Understand the Dockerfile
Line 1
FROM nginx:latest
Meaning
We are using an existing Nginx image.
Nginx is a web server.
A web server is responsible for showing websites in the browser.
Why DevOps engineers use this
Instead of installing Nginx manually on every server, we use a ready-made Docker image.
Without Docker:
Install Linux
Install Nginx
Configure Nginx
Copy website files
Start Nginx
Fix errors
With Docker:
Use nginx image
Copy website
Run container
Line 2
COPY index.html /usr/share/nginx/html/index.html
Meaning
Docker copies our website file into the Nginx web folder.
Nginx serves files from:
/usr/share/nginx/html/
Why DevOps engineers do this
The application must be inside the image.
When we move the image to another machine, the website goes with it.
Line 3
EXPOSE 80
Meaning
The container will listen on port 80.
Port 80 is the default HTTP web port.
Important
EXPOSE 80 does not publish the port to your laptop automatically.
It only documents that the application inside the container uses port 80.
We still need -p when running the container.
Step 5: Check Files
ls
Expected result:
Dockerfile index.html
Why?
Before building the image, we must make sure Dockerfile and application files are in the same folder.
Step 6: Build Docker Image
docker build -t student-website:v1 .
Meaning
docker build
Build a Docker image.
-t student-website:v1
Give the image a name and version.
.
Use the current folder as the build context.
Docker will look for the Dockerfile in this folder.
Why DevOps engineers do this
In real DevOps work, we build Docker images after developers push code to GitHub.
Example CI/CD pipeline:
Developer pushes code
↓
GitHub Actions/Jenkins starts
↓
Docker image is built
↓
Image is tested
↓
Image is pushed to ECR/Docker Hub
↓
Application is deployed
Expected Result
You should see something like:
Successfully built ...
Successfully tagged student-website:v1
Step 7: Check Docker Images
docker images
Expected result:
REPOSITORY TAG
student-website v1
nginx latest
What happened?
Docker created an image named:
student-website:v1
The image contains:
- Nginx
- Your
index.html - Configuration needed to run the website
Step 8: Run Container
docker run -d -p 8080:80 --name my-website student-website:v1
Explain the command
docker run
Create and start a container.
-d
Detached mode. Run in the background.
-p 8080:80
Port mapping.
8080
Port on your laptop.
80
Port inside the container.
--name my-website
Name the container.
student-website:v1
Image used to create the container.
Very Important Port Explanation
Container has its own private network.
Nginx runs inside the container on port 80.
Your laptop browser cannot directly access container port 80 unless we publish it.
That is why we use:
-p 8080:80
Meaning:
Browser on laptop
http://localhost:8080
↓
Docker forwards traffic
↓
Container port 80
↓
Nginx
↓
index.html
Step 9: Check Running Container
docker ps
Expected result:
CONTAINER ID IMAGE PORTS
abc123 student-website:v1 0.0.0.0:8080->80/tcp
Meaning
The container is running.
Port 8080 on your computer is connected to port 80 inside the container.
Step 10: Open Website
Open browser:
http://localhost:8080
Expected result:
Hello from Docker!
This website is running inside a container.
Created by a DevOps student.
What did we achieve?
We packaged and ran a website inside Docker.
The website is not running directly on your laptop.
It is running inside a container.
Step 11: View Container Logs
docker logs my-website
Why?
DevOps engineers check logs to troubleshoot applications.
When something is not working, logs help answer:
- Did the app start?
- Did users send requests?
- Are there errors?
- Is the app crashing?
When you refresh the browser, logs should show HTTP requests.
Step 12: Enter the Container
docker exec -it my-website bash
Now you are inside the container.
Run:
pwd
ls
cd /usr/share/nginx/html
ls
cat index.html
Exit:
exit
Why?
DevOps engineers sometimes enter containers to troubleshoot.
For example:
- check files
- check environment variables
- check running processes
- check configuration
But in production, we avoid changing things manually inside containers.
Containers should be recreated from images.
Step 13: Stop Container
docker stop my-website
Check:
docker ps
Expected result:
No running container named my-website
But if you run:
docker ps -a
You will still see it.
Meaning
docker stop stops the container, but does not delete it.
Step 14: Start Container Again
docker start my-website
Check:
docker ps
Open again:
http://localhost:8080
Meaning
The same stopped container can be started again.
Step 15: Remove Container
docker rm -f my-website
Meaning
This deletes the container.
The image still exists.
Check:
docker images
You should still see:
student-website v1
Step 16: Run Again from Same Image
docker run -d -p 8080:80 --name my-website student-website:v1
Important Lesson
Even after deleting the container, we can create a new container from the same image.
Image = template
Container = running instance
Example:
One image
↓
Many containers
Step 17: Make a Change to Website
Open index.html again:
nano index.html
Change this line:
<h1>Hello from Docker!</h1>
to:
<h1>Hello from Docker Version 2!</h1>
Save.
Step 18: Rebuild Image as Version 2
docker build -t student-website:v2 .
Check images:
docker images
Expected:
student-website v1
student-website v2
Why?
In real DevOps, every code change should create a new image version.
Examples:
payment-service:v1
payment-service:v2
payment-service:v3
This helps with:
- deployments
- rollbacks
- release tracking
- troubleshooting
Step 19: Replace Running Container with New Version
Stop and remove old container:
docker rm -f my-website
Run version 2:
docker run -d -p 8080:80 --name my-website student-website:v2
Open:
http://localhost:8080
Expected result:
Hello from Docker Version 2!
Step 20: Clean Up
docker rm -f my-website
docker rmi student-website:v1
docker rmi student-website:v2
Optional:
docker rmi nginx:latest
Final Explanation for Students
Today you acted like a DevOps engineer.
You did this workflow:
Created application file
↓
Created Dockerfile
↓
Built Docker image
↓
Ran container
↓
Opened application in browser
↓
Checked logs
↓
Entered container
↓
Stopped and started container
↓
Created new version
↓
Redeployed new version
Key Concepts
Dockerfile
A recipe that tells Docker how to build an image.
Image
A packaged application with everything needed to run.
Container
A running instance of an image.
Port Mapping
Connects your computer port to the container port.
localhost:8080 → container:80
DevOps Purpose
DevOps engineers use Docker to make applications:
- portable
- repeatable
- consistent
- easy to deploy
- easy to scale
- easier to run in Kubernetes later
Top comments (0)