Docker Deep Dive: Beginner To Advanced

If you’ve ever said:
- “Why does this app work on your machine and not mine?”
- “How do I test this microservice without setting up an environment?”
- “Why does my local build pass but CI fails?”
Then my friend, it’s time to welcome Docker into your life. Think of it as your app’s personal travel agent - it packages everything your app needs and ensures it works the same way everywhere.
Let’s go through practical examples, gotchas, and setups you can try right now on your machine.
Performance optimization goes hand-in-hand with containerization. You can also explore these 5 techniques to reduce page load time..
What is Docker, really?
Docker is a platform to build, ship, and run apps in an isolated, consistent environment — across machines, clouds, and even timezones.
It’s like a neatly packed tiffin box. Everything your app needs — libraries, settings, OS flavor — bundled and ready to go.
Containers
A container is an isolated environment that runs an application.
Why they’re awesome:
- lightweight
- uses OS(kernel) of host
- start quickly
- need less hardware resources
- can be stopped & restarted
- just a process
Docker Image
A Docker image is like a read-only snapshot of your app.
It includes:
- application files
- third party libraries
- environment variables
- cut down OS
Application Code + Dependencies + Config + Base OS = ImageYou build containers from images.
Note: To do hands-on, make sure you have installed Docker Desktop.
Dockerfile
This is your image’s blueprint. Let’s say you want to run a basic NodeJS app:
Example 1: Dockerizing a Node App
// app.js
console.log('Hello from docker container!')# Dockerfile
# Use the latest version of NodeJS
FROM node:24-slim
# Set the working directory
WORKDIR /app
# Copy files
COPY . .
# Start the app
CMD ["node", "app.js"]Then to build the docker image and run the docker container, execute the following commands in your terminal:
# Syntax: docker build -t <image-name> <build-context>
docker build -t hello-node .
docker run hello-nodeSee “Hello from docker container!” in your terminal. It’s working. Yay!
Tips
- Use
COPY ["file", "destination"]for JSON-safe copy. - Ignore unnecessary files using
.dockerignore:
# .dockerignore
node_modules
.git
Dockerfile*
*.logExample 2: Dockerizing a React App
Let’s turn a React app into a container:
# Dockerfile
# Use the latest version of NodeJS
FROM node:24-slim
# Set the working directory
WORKDIR /app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy the rest of the files
COPY . .
# Expose the port
EXPOSE 3000
# Run the app
CMD ["npm", "start"]Let’s again build the docker image and run the docker container:
docker build -t react-app .
docker run react-appNote: ‘slim’ is smaller than full Node images.
RUN vs CMD
Click to read more
| Command | Purpose | Runs during | Example |
|---|---|---|---|
| RUN | Executes at build time to build the image (e.g., install packages). | Docker image build | RUN npm install |
| CMD | Specifies the default command when a container starts. | When container is run | CMD ["node", "app.js"] |
Note: Only one CMD is allowed per Dockerfile; last one overrides previous.
Setting environment variables
This is how we can add environment variables in our Dockerfile.
ENV PUBLIC_URL=https://gauravadhikari.comPort Mapping
By now you can build your docker image and run the docker container, but you can not access the react app in your system. That’s because the react app is running on an isolated environment and its ports aren’t exposed to your system.
This is where port publishing comes in.
You can map ports using the -p flag:
# Syntax: -p <host_port>:<container_port>
docker run -d -p 3000:3000 react-appNow, try to open localhost:3000 tada.., you can access your react app!
Tagging Images
You can tag images to organize them with names and versions:
# Tag image during build
# Syntax: -t <image-name>:<tag> <build-context>
docker build -t my-app:1.0 .
# Tag an existing image with another tag
docker tag my-app:1 my-app:latestManage, Inspect, Debug & Explore
Here are some essential commands to help you manage your Docker environment:
List Docker Images
docker imagesCheck Running Containers
docker psList All Containers (Including Stopped)
docker ps -aRun Container in Background
docker run -d react-appAccess Container Shell
docker exec -it <container_id> bashView Container Logs
docker logs <container_id>Watch Logs in Real-time
docker logs -f <container_id>Stop a Container
docker stop <container_id>Start a Container
docker start <container_id>Restart a Container
docker restart <container_id>Remove a Container
docker rm <container_id>Clean Up Unused Images
docker image prune
docker image rm hello-nodeClean Up Stopped Containers
docker container pruneI hope you enjoyed running the above commands in your terminal, now let’s learn another important topic in Docker, that is Volumes.
Docker Volumes
When a container shuts down or gets deleted, everything inside it usually disappears - so in order to persist important data like databases, log files etc we need Docker Volumes.
To create a docker volume:
docker volume create app-dataTo create / use a volume while running container:
docker run -v app-data:/app/data react-appTo view / inspect volume:
docker volume inspect app-dataThis ensures your data survives even if the container is removed. For example - databases, logs, uploads.
Copying Files Between Host and Containers
While we are here, let’s quickly learn how to copy files to and from a docker container.
| Direction | Command | Example |
|---|---|---|
| Container → Host | docker cp SOURCE DESTINATION | docker cp my_container:/app/logs.txt . |
| Host → Container | docker cp SOURCE DESTINATION | docker cp secret.txt my_container:/app |
Docker Hub
Docker Hub is like the App Store or Play Store, but for Docker containers. You can download ready-made images from Docker Hub — like Node, Nginx, MongoDB etc, you can upload your own images to the Docker Hub so that others can use them.
Publish to Docker Hub
docker login
docker tag react-app username/react-app:1
docker push username/react-app:1Share Locally
# Create tar of the image
docker image save -o react.tar react-app
# Use it like this now
docker image load -i react.tarMulti-stage Builds
Multi-stage builds in Docker let you use multiple FROM statements in a single Dockerfile to build your app in stages.
Why ?
Smaller Final Image — The final image uses
nginx:alpine, not node, which means you’re not shipping node_modules, source code, or the Node.js runtime — just the static files.Better Security — Fewer packages = fewer vulnerabilities. You’re only exposing what’s absolutely needed to serve the app.
Faster Deployments — Smaller images are faster to pull, push, and deploy.
Cleaner Separation — One stage handles building (node), another handles serving (nginx), keeping concerns neatly separated.
# Stage 1: Build
FROM node:24-slim AS build
WORKDIR /app
COPY . .
RUN npm install && npm run build
# Stage 2: Serve
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]TL;DR Cheat Sheet
| Action | Command |
|---|---|
| Build image | docker build -t <name> . |
| Run container | docker run <name> |
| Run with port mapping | docker run -p 3000:3000 <name> |
| Run and auto-remove | docker run --rm -it <name> |
| Enter running container | docker exec -it <container_id> sh |
| See logs | docker logs -f <container_id> |
| List containers | docker ps -a |
| List images | docker images |
| Stop/start container | docker stop <id> / docker start <id> |
| Remove container/image | docker rm <id> / docker rmi <image> |
| Remove stopped containers | docker container prune |
| Pull image | docker pull <image> |
| Persist data (volume) | docker run -v <vol_name>:/app/data <img> |
| Save/load image file | docker image save -o file.tar <img> / docker image load -i file.tar |
| Push to Docker Hub | docker push <username>/<image> |
Frequently Asked Questions
What is Docker and why is it essential for modern application development?
Docker is a platform for building, shipping, and running applications in an isolated, consistent environment. It packages your app with all its dependencies (libraries, settings, OS flavor) into a 'container,' ensuring it works identically across different machines, clouds, and environments. This eliminates common issues like 'it works on my machine' and simplifies testing and deployment.
What is the key difference between a Docker Image and a Docker Container?
A Docker Image is a read-only blueprint or snapshot of your application, including its code, dependencies, configuration, and a cut-down OS. It's what you build. A Docker Container, on the other hand, is a runnable instance of an image. It's an isolated, lightweight process that runs your application, utilizing the host OS kernel and starting quickly.
How do I create a Docker image for my application using a Dockerfile?
A Dockerfile is a text file containing instructions for building a Docker image. You define the base image (e.g., FROM node:24-slim), set the working directory, copy your application files, install dependencies (using RUN commands), and specify the command to run your application (using CMD). You then build the image with docker build -t <image-name> .
How can I run my Dockerized application and access it from my browser?
After building your image (e.g., my-app), you can run it using docker run my-app. To access web applications (like a React app), you need to map ports between the container and your host machine using the -p flag. For example, docker run -p 3000:3000 my-app maps the container's port 3000 to your host's port 3000, allowing you to access it via localhost:3000.
What are the essential Docker commands for managing images and containers?
Key commands include: docker build (to create images), docker run (to start containers), docker ps (to list running containers), docker ps -a (to list all containers), docker images (to list images), docker stop <id> (to stop a container), docker rm <id> (to remove a container), docker rmi <image> (to remove an image), docker logs <id> (to view container logs), and docker exec -it <id> bash (to access a container's shell).
How do Docker Volumes help in persisting data for containers?
Docker Volumes are used to store important data (like databases or log files) outside of the container's writable layer. This ensures that your data survives even if the container is stopped, removed, or replaced. You can create a volume with docker volume create <name> and then mount it to a container using the -v flag: docker run -v <volume_name>:<container_path> <image>.
What are multi-stage builds in Docker and what are their benefits?
Multi-stage builds allow you to use multiple FROM statements in a single Dockerfile, where each FROM statement starts a new build stage. This is beneficial because you can use an intermediate stage to build your application (e.g., compile code, install dependencies) and then copy only the necessary artifacts to a much smaller final image. This results in smaller final image sizes, improved security (fewer packages), and faster deployments.
How can I share my Docker images with other developers or deploy them?
You can share images by pushing them to Docker Hub (a public registry) after logging in and tagging your image: docker login, docker tag <local_image> <username>/<repo_name>:<tag>, docker push <username>/<repo_name>:<tag>. Alternatively, you can save an image as a .tar file locally with docker image save -o image.tar <image_name> and share that file, which can then be loaded by others using docker image load -i image.tar.
What is the functional difference between RUN and CMD commands in a Dockerfile?
RUN commands execute at build time and are used to build the image itself (e.g., installing packages, compiling code). Each RUN command creates a new layer in the image. CMD specifies the default command that will be executed when a container is started from the image. Only one CMD instruction is allowed per Dockerfile; if multiple are present, only the last one takes effect.
Where can I find a quick reference for common Docker commands?
The article includes a 'TL;DR Cheat Sheet' section that provides a concise list of essential Docker commands for actions like building and running images, managing containers, persisting data, and sharing images. This serves as a handy reference for quick lookups.
Final Words
Docker might seem like a lot at first, but once you get it, it feels like magic. No more “it works on my machine” drama.
So go ahead — experiment, break things, fix them, and deploy like it’s no big deal. Your future self will thank you for learning Docker today!