
How to Install and Use Docker on Ubuntu 24 – Complete Guide
If you’re diving into containerization in 2024, Docker on Ubuntu 24 is pretty much the perfect combo for your server adventures. This guide will walk you through everything from the initial installation to running your first containers, managing images, and even some neat tricks that’ll make your sysadmin life easier. Whether you’re setting up a development environment, deploying microservices, or just want to mess around with isolated applications without breaking your host system, this complete walkthrough has got you covered with real commands, practical examples, and the kind of gotchas that usually bite you at 2 AM.
How Docker Works – The Container Magic Explained
Docker is essentially a lightweight virtualization platform that uses Linux containers (LXC) under the hood, but with way more bells and whistles. Unlike traditional VMs that virtualize entire operating systems, Docker containers share the host OS kernel while maintaining process isolation. Think of it as having separate apartments in the same building rather than separate houses.
The architecture consists of:
- Docker Engine – The runtime that manages containers
- Images – Read-only templates for creating containers
- Containers – Running instances of images
- Docker Hub – Cloud-based registry for sharing images
- Dockerfile – Text files with instructions to build images
Here’s the cool part: a typical Docker container uses about 10-50MB of RAM compared to VMs that typically consume 500MB-2GB just for the guest OS. That’s why you can run dozens of containers on a modest VPS without breaking a sweat.
Step-by-Step Installation on Ubuntu 24
Let’s get Docker running on your Ubuntu 24 system. I’ll show you both the official method and the quick-and-dirty approach.
Method 1: Official Docker Repository (Recommended)
First, let’s prep the system and add Docker’s official GPG key:
# Update package index
sudo apt update
# Install prerequisites
sudo apt install apt-transport-https ca-certificates curl software-properties-common
# Add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add Docker repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Now install Docker:
# Update package index again
sudo apt update
# Install Docker CE
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Start and enable Docker service
sudo systemctl start docker
sudo systemctl enable docker
# Verify installation
sudo docker --version
sudo docker run hello-world
Method 2: Convenience Script (Quick but Less Secure)
For testing environments or when you’re feeling lucky:
# Download and run Docker's convenience script
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Add your user to docker group (optional but recommended)
sudo usermod -aG docker $USER
newgrp docker
Post-Installation Setup
Add your user to the docker group to avoid typing sudo every time:
# Add current user to docker group
sudo usermod -aG docker $USER
# Apply group changes (or logout/login)
newgrp docker
# Test without sudo
docker run hello-world
Essential Docker Commands and Real-World Examples
Now for the fun stuff. Let’s run through the commands you’ll actually use day-to-day.
Container Management
# Pull an image from Docker Hub
docker pull nginx:latest
# Run a container
docker run -d --name my-nginx -p 80:80 nginx:latest
# List running containers
docker ps
# List all containers (including stopped)
docker ps -a
# Stop a container
docker stop my-nginx
# Remove a container
docker rm my-nginx
# Run interactive container
docker run -it ubuntu:22.04 /bin/bash
Image Management
# List local images
docker images
# Remove an image
docker rmi nginx:latest
# Build image from Dockerfile
docker build -t my-app:v1.0 .
# Tag an image
docker tag my-app:v1.0 my-app:latest
# Push to registry
docker push my-app:v1.0
Real-World Example: Setting Up a LAMP Stack
Let’s create a complete web development environment:
# Create a network for our services
docker network create lamp-network
# Run MySQL database
docker run -d \
--name mysql-db \
--network lamp-network \
-e MYSQL_ROOT_PASSWORD=rootpass123 \
-e MYSQL_DATABASE=webapp \
-e MYSQL_USER=webuser \
-e MYSQL_PASSWORD=webpass123 \
-v mysql-data:/var/lib/mysql \
mysql:8.0
# Run PHP-Apache container
docker run -d \
--name web-server \
--network lamp-network \
-p 8080:80 \
-v $(pwd)/html:/var/www/html \
php:8.1-apache
# Install MySQL extension in PHP container
docker exec web-server docker-php-ext-install mysqli pdo pdo_mysql
Using Docker Compose for Complex Setups
Create a docker-compose.yml
file for the same LAMP stack:
version: '3.8'
services:
web:
image: php:8.1-apache
ports:
- "8080:80"
volumes:
- ./html:/var/www/html
depends_on:
- db
networks:
- lamp-network
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass123
MYSQL_DATABASE: webapp
MYSQL_USER: webuser
MYSQL_PASSWORD: webpass123
volumes:
- mysql-data:/var/lib/mysql
networks:
- lamp-network
volumes:
mysql-data:
networks:
lamp-network:
driver: bridge
Deploy with:
# Start the entire stack
docker compose up -d
# View logs
docker compose logs -f
# Stop everything
docker compose down
# Stop and remove volumes
docker compose down -v
Docker vs Alternatives: Performance and Use Case Comparison
Solution | Resource Usage | Startup Time | Isolation Level | Best Use Case |
---|---|---|---|---|
Docker | Low (10-50MB) | 1-3 seconds | Process-level | Microservices, CI/CD |
VMware/VirtualBox | High (500MB-2GB+) | 30-60 seconds | Hardware-level | Complete OS isolation |
LXC/LXD | Medium (50-200MB) | 5-10 seconds | OS-level | System containers |
Podman | Low (similar to Docker) | 1-3 seconds | Process-level | Rootless containers |
Advanced Use Cases and Automation
CI/CD Pipeline Integration
Docker shines in continuous integration. Here’s a GitLab CI example:
# .gitlab-ci.yml
stages:
- build
- test
- deploy
build:
stage: build
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
test:
stage: test
script:
- docker run --rm $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA npm test
deploy:
stage: deploy
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker stop my-app || true
- docker rm my-app || true
- docker run -d --name my-app -p 80:3000 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
only:
- main
Container Health Monitoring
Set up proper health checks and monitoring:
# Dockerfile with health check
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# Run with restart policy
docker run -d \
--name resilient-nginx \
--restart unless-stopped \
-p 80:80 \
my-nginx-app
Multi-Stage Builds for Production
Optimize your images with multi-stage builds:
# Dockerfile
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Production stage
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
USER node
CMD ["npm", "start"]
Common Pitfalls and How to Avoid Them
The Bad: Resource Hogging
# DON'T do this - runs without limits
docker run -d nginx
# DO this - set resource limits
docker run -d \
--memory="512m" \
--cpus="1.0" \
--name limited-nginx \
nginx
The Ugly: Security Vulnerabilities
# BAD - running as root
FROM ubuntu
RUN apt-get update && apt-get install -y python3
CMD ["python3", "app.py"]
# GOOD - running as non-root user
FROM ubuntu
RUN apt-get update && apt-get install -y python3
RUN useradd -m appuser
USER appuser
CMD ["python3", "app.py"]
Storage Management
Clean up regularly to avoid filling your disk:
# Remove unused containers, networks, images
docker system prune -a
# Remove specific volumes
docker volume ls
docker volume rm volume_name
# Monitor disk usage
docker system df
Integration with Other Tools
Docker plays well with modern DevOps tools:
- Kubernetes – For orchestrating containers at scale
- Portainer (https://www.portainer.io/) – Web-based Docker management
- Watchtower – Automatic container updates
- Traefik (https://traefik.io/) – Reverse proxy and load balancer
Quick Portainer setup:
# Install Portainer
docker volume create portainer_data
docker run -d \
-p 8000:8000 \
-p 9443:9443 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
Performance Optimization Tips
Here are some tricks I’ve learned from running Docker in production:
- Use .dockerignore – Exclude unnecessary files from build context
- Leverage layer caching – Order Dockerfile commands by change frequency
- Use specific tags – Avoid
:latest
in production - Monitor container metrics – Use tools like cAdvisor or Prometheus
# Monitor resource usage
docker stats
# Inspect container details
docker inspect container_name
# View container logs
docker logs -f --tail 100 container_name
Scaling and Production Considerations
When you’re ready to move beyond a single server, consider these options:
- Docker Swarm – Built-in orchestration for small to medium deployments
- Kubernetes – Industry standard for large-scale container orchestration
- Load balancing – Use HAProxy or Nginx for distributing traffic
For high-traffic applications, you might want to consider a dedicated server to ensure consistent performance and resource availability.
Interesting Facts and Statistics
Some Docker trivia that might blow your mind:
- Docker containers share the host kernel, making them up to 10x more efficient than VMs
- The largest Docker image I’ve seen was 15GB (someone dockerized Windows Server – don’t ask)
- Netflix runs over 1 million containers in production
- Docker Hub hosts over 100,000 containerized applications
- A typical Docker daemon can manage 1000+ containers on a single host
Troubleshooting Common Issues
Here are solutions to problems you’ll inevitably encounter:
Permission Denied Errors
# If you get permission denied
sudo chmod 666 /var/run/docker.sock
# Or better, add user to docker group (shown earlier)
Container Won’t Start
# Check logs for errors
docker logs container_name
# Run interactively to debug
docker run -it image_name /bin/bash
Port Already in Use
# Find what's using the port
sudo netstat -tulpn | grep :80
# Use different host port
docker run -p 8081:80 nginx
Conclusion and Recommendations
Docker on Ubuntu 24 is a game-changer for anyone serious about modern server management. The combination gives you incredible flexibility for development, testing, and production deployments while keeping resource usage minimal. Whether you’re running a simple blog or a complex microservices architecture, Docker containers provide the isolation and portability that makes scaling and maintenance actually enjoyable.
When to use Docker:
- Microservices architectures
- Development environment standardization
- CI/CD pipelines
- Application modernization
- Testing multiple software versions
When to consider alternatives:
- High-security applications requiring kernel isolation (use VMs)
- Windows-specific applications (use Windows containers or VMs)
- Single-tenant applications with simple deployment needs
Start small with a few containers on a modest VPS, learn the ropes, and gradually expand your Docker expertise. The investment in learning containerization will pay dividends in your infrastructure management, deployment speed, and overall peace of mind. Plus, your future self will thank you when you can spin up identical environments in seconds rather than hours.
Remember: containers are not silver bullets, but they’re pretty close to being silver-plated, semi-automatic deployment rifles. Use them wisely, monitor them properly, and they’ll serve you well in your server adventures.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.