Docker transforms how you deploy applications by providing lightweight, portable containers that run anywhere.
However, as your containerized applications scale in production, you need to monitor their performance, resource utilization, and health. Good container monitoring helps you find bottlenecks, prevent outages, and optimize resources across your infrastructure.
This guide shows you how to build robust monitoring solutions for your Docker containers.
Prerequisites
Before you start container monitoring, ensure that Docker is installed on your system. This guide assumes you're running Docker version 20.04 or later; however, most concepts are also applicable to earlier versions. You should also know basic Docker concepts like containers, images, and volumes.
Setting up your environment
To get the most out of this tutorial, create a practical environment with multiple containers that you can monitor throughout the guide. This hands-on approach helps you understand monitoring concepts while building real skills.
Start by creating a new directory for your monitoring project:
mkdir docker-monitoring-tutorial && cd docker-monitoring-tutorial
Create a simple web application that you can monitor. First, build a basic Node.js application:
const express = require('express');
const app = express();
const port = 3000;
let requestCount = 0;
let errors = 0;
app.get('/', (req, res) => {
requestCount++;
res.json({
message: 'Hello World!',
requests: requestCount,
uptime: process.uptime()
});
});
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});
app.get('/error', (req, res) => {
errors++;
res.status(500).json({ error: 'Simulated error', count: errors });
});
app.listen(port, () => {
console.log(`App running on port ${port}`);
});
Create a package.json
file:
{
"name": "monitoring-demo",
"version": "1.0.0",
"main": "app.js",
"dependencies": {
"express": "^5.1.0"
},
"scripts": {
"start": "node app.js"
}
}
Now, create a Dockerfile for your application:
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Build and run the application:
docker build -t monitoring-demo .
docker run -d --name web-app -p 3000:3000 monitoring-demo
Verify the application works:
curl http://localhost:3000
{"message":"Hello from containerized app!","timestamp":"2025-07-09T15:38:55.412Z"}%
curl http://localhost:3000/health
Or in the browser like this:
You should see JSON responses confirming the application works. You'll use this application throughout the tutorial to demonstrate various monitoring techniques.
Basic container monitoring with Docker commands
Now that you have a running container, explore Docker's built-in monitoring capabilities. These native tools give you immediate insights without requiring additional software.
Real-time container statistics
The docker stats
command shows live performance data for your running containers:
docker stats web-app
You'll see output like this:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
9d6d833b7fdd web-app 0.00% 40.58MiB / 7.654GiB 0.52% 1.05kB / 0B 0B / 0B 18
Generate some load to see the metrics change. In another terminal, generate some requests:
for i in {1..100}; do curl -s http://localhost:3000 > /dev/null; done
Watch how the CPU percentage and network I/O values increase in the docker stats
output. This real-time feedback helps you understand your container's resource consumption patterns.
To capture a snapshot instead of continuous monitoring:
docker stats --no-stream web-app
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
9d6d833b7fdd web-app 0.00% 43.48MiB / 7.654GiB 0.55% 49.2kB / 56.9kB 0B / 4.1kB 18
Examining container details
While docker stats
shows real-time performance data, you often need more detailed information about your container's configuration and current state. The docker inspect
command provides comprehensive details about how your container is configured and running.
Get complete container information in JSON format:
docker inspect web-app
This produces extensive JSON output with hundreds of configuration details. For monitoring purposes, you'll typically want to extract specific information using formatting options.
Check if any memory limits are configured for your container:
docker inspect web-app --format='{{.HostConfig.Memory}}'
0
A value of 0
indicates no memory limit is set. Verify your container's current running status:
docker inspect web-app --format='{{.State.Status}}'
running
You can also check the boolean running state:
docker inspect web-app --format='{{.State.Running}}'
true
Process monitoring inside containers
Beyond container-level statistics, you need visibility into the processes running inside your containers. This helps identify resource-intensive operations and understand what's happening within your application.
View processes running inside your container using Docker's top command:
docker top web-app
UID PID PPID C STIME TTY TIME CMD
root 1565 1546 0 15:44 ? 00:00:00 npm start
root 1601 1565 0 15:44 ? 00:00:00 node app.js
For more detailed process information:
docker exec web-app ps aux
You'll see the Node.js process and any child processes:
PID USER TIME COMMAND
1 root 0:00 npm start
18 root 0:00 node app.js
25 root 0:00 ps aux
This information helps you identify resource-intensive operations within your containers.
Check system resources from inside the container:
docker exec web-app cat /proc/meminfo | head -5
MemTotal: 8025360 kB
MemFree: 6998344 kB
MemAvailable: 7364392 kB
Buffers: 40008 kB
Cached: 447776 kB
docker exec web-app cat /proc/loadavg
0.25 0.24 0.22 2/326 42
These commands show how the container sees system resources, which can differ from the host system's perspective.
Implementing container health checks
Building on your basic monitoring, implement health checks for your web application. Health checks provide automated container health assessment beyond simply checking if the process runs.
Adding health checks to your application
Health checks go beyond basic process monitoring by actively testing your application's functionality. Docker can automatically run health check commands at regular intervals to verify your application is responding correctly.
First, rebuild your container with a health check. Update the Dockerfile:
FROM node:22-alpine
WORKDIR /app
# Install curl for health checks
RUN apk add --no-cache curl
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["npm", "start"]
The HEALTHCHECK
instruction configures Docker to test your /health
endpoint every 30 seconds. If the health check fails 3 times in a row, Docker marks the container as unhealthy.
Stop the existing container to prepare for the rebuild:
docker stop web-app
Remove the container completely:
docker rm web-app
Build the updated image with health check capabilities:
docker build -t monitoring-demo .
Run the new container with integrated health monitoring:
docker run -d --name web-app -p 3000:3000 monitoring-demo
Monitoring health check results
Now that your container includes health checks, Docker automatically monitors your application's health and reports the status. This provides more reliable monitoring than simply checking if the process is running.
Check the health status of your container:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
64304da1b871 monitoring-demo "docker-entrypoint.s…" 10 seconds ago Up 9 seconds (healthy) 0.0.0.0:3000->3000/tcp web-app
You'll see a status like Up 25 seconds (healthy)
once the health check passes. To see detailed health check information:
docker inspect web-app --format='{{json .State.Health}}' | jq
{
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{
"Start": "2025-07-09T15:55:59.895713385Z",
"End": "2025-07-09T15:55:59.965304843Z",
"ExitCode": 0,
"Output": " % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0{\"status\":\"healthy\",\"timestamp\":\"2025-07-09T15:55:59.960Z\",\"uptime\":4.911826628}\r100 80 100 80 0 0 11999 0 --:--:-- --:--:-- --:--:-- 13333\n"
}
]
}
This command shows the last several health check results, including timestamps and exit codes.
Testing health check failure
Simulate a health check failure by stopping the application inside the container:
docker exec web-app ps aux | grep node
18 root 0:00 node app.js
docker exec web-app kill 18
Monitor the health status in a second terminal:
while true; do docker ps --format 'table {{.Names}}\t{{.Status}}'; sleep 2; done
NAMES STATUS
web-app Up 2 minutes (unhealthy)
You'll see the status change from healthy
to unhealthy
after the configured retries fail. This shows how health checks detect application failures even when the container still runs.
Restart the container to restore normal operation:
docker restart web-app
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f3a1b2c3d4e5 monitoring-demo "docker-entrypoint.s…" 5 minutes ago Up 10 seconds (health: starting) 0.0.0.0:3000->3000/tcp web-app
The status will show (health: starting)
and then change to (healthy)
once the health checks pass again:
NAMES STATUS
web-app Up 38 seconds (healthy)
Container log analysis and monitoring
Now explore container logging, which is crucial for monitoring application behavior and troubleshooting issues. You'll build on your existing setup to implement comprehensive log monitoring.
Accessing and analyzing container logs
Docker captures all output from your application's standard output and error streams. The docker logs
command provides access to these logs for analysis and troubleshooting.
View logs from your web application:
docker logs web-app
> monitoring-demo@1.0.0 start
> node app.js
App running on port 3000
...
For continuous monitoring, use the follow flag to watch logs in real-time:
docker logs -f web-app
Final thoughts
Throughout this tutorial, you've built a solid foundation for Docker container monitoring using basic commands, health checks, and log analysis. These techniques provide essential visibility into your containerized applications and help you detect issues quickly.
As your applications grow, you'll need to expand these techniques with more advanced tools like Prometheus and Grafana. The foundation you've built here will serve you well as you scale your monitoring infrastructure.
For more advanced monitoring techniques, explore the official Docker documentation and consider integrating with cloud-native monitoring solutions.
Thanks for following along with this Docker monitoring tutorial, and happy monitoring!
Make your mark
Join the writer's program
Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.
Write for us
Build on top of Better Stack
Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.
community@betterstack.comor submit a pull request and help us build better products for everyone.
See the full list of amazing projects on github