Debian Docker Containers
Introduction
Docker containers have revolutionized how we develop, deploy, and run applications. For Debian users, Docker provides a powerful way to create lightweight, portable, and isolated environments for running applications. In this guide, we'll explore how to set up and use Docker containers on Debian systems, understand core concepts, and implement best practices for container management.
Docker containers are standalone, executable packages that include everything needed to run an application: code, runtime, system tools, libraries, and settings. Unlike traditional virtual machines, containers share the host system's kernel, making them more efficient and faster to start.
Prerequisites
Before we begin, ensure you have:
- A Debian system (Debian 10 Buster or newer recommended)
- Root or sudo access
- Basic Linux command line knowledge
Installing Docker on Debian
Let's start by installing Docker on your Debian system:
# Update package information
sudo apt update
# Install required packages
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
# Add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Set up the stable repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Update package information again
sudo apt update
# Install Docker Engine
sudo apt install -y docker-ce docker-ce-cli containerd.io
# Verify installation
sudo docker run hello-world
The last command downloads a test image and runs it in a container. If successful, you'll see a message confirming that your Docker installation is working correctly.
Output:
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
Docker Architecture and Terminology
Before diving deeper, let's understand some key Docker concepts:
- Docker Daemon: The background service running on the host that manages building, running, and distributing Docker containers.
- Docker Client: The command line interface tool that allows users to interact with the Docker daemon.
- Docker Image: A read-only template used to create containers, similar to a snapshot.
- Docker Container: A runnable instance of an image with its own filesystem, networking, and isolated process space.
- Docker Hub: A registry of Docker images where you can find official and community images.
Working with Docker Images
Pulling Images
To download a Docker image from Docker Hub:
# Pull the official Debian image
sudo docker pull debian
# Pull a specific version
sudo docker pull debian:bullseye
Output:
Using default tag: latest
latest: Pulling from library/debian
214ca5fb9032: Pull complete
Digest: sha256:0a90499893e67770366f5d1738475b9dc3c90f7a4241a01d3f3dba8517cca59d
Status: Downloaded newer image for debian:latest
docker.io/library/debian:latest
Listing Images
To see all downloaded images:
sudo docker images
Output:
REPOSITORY TAG IMAGE ID CREATED SIZE
debian latest 4eacea30377a 2 weeks ago 124MB
hello-world latest feb5d9fea6a5 4 months ago 13.3kB
Running Docker Containers
Basic Container Running
To run a container from an image:
# Run a Debian container interactively
sudo docker run -it debian bash
This command starts a new container from the Debian image and opens a bash shell inside it. The -it
flags make the container interactive and allocate a pseudo-TTY.
Once inside the container, you're in an isolated Debian environment. Try some commands:
cat /etc/debian_version
apt update
apt install -y python3
python3 --version
exit # To leave the container
Running Containers in the Background
To run containers in detached mode (background):
# Run a web server container in the background
sudo docker run -d -p 8080:80 --name my-web-server nginx
This command:
-d
: Runs the container in detached mode-p 8080:80
: Maps port 8080 on the host to port 80 in the container--name my-web-server
: Assigns a name to the containernginx
: Uses the nginx image to create a web server
You can now access the web server at http://localhost:8080 on your Debian system.
Listing Running Containers
To see all running containers:
sudo docker ps
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3a7586b842f5 nginx "/docker-entrypoint.…" 10 seconds ago Up 9 seconds 0.0.0.0:8080->80/tcp my-web-server
To see all containers (including stopped ones):
sudo docker ps -a
Managing Docker Containers
Stopping and Starting Containers
# Stop a running container
sudo docker stop my-web-server
# Start a stopped container
sudo docker start my-web-server
Removing Containers
# Stop the container if it's running
sudo docker stop my-web-server
# Remove the container
sudo docker rm my-web-server
Container Logs
To view the logs of a container:
sudo docker logs my-web-server
# Follow the logs in real-time
sudo docker logs -f my-web-server
Creating Custom Docker Images
One of Docker's powerful features is the ability to create your own images.
Using Dockerfile
A Dockerfile is a text document that contains all the commands needed to build an image. Here's a simple example:
- Create a directory for your project:
mkdir my-debian-app
cd my-debian-app
- Create a simple Python application file:
echo 'print("Hello from Debian Docker container!")' > app.py
- Create a Dockerfile:
nano Dockerfile
Add the following content:
# Use Debian as the base image
FROM debian:bullseye
# Update package lists and install Python
RUN apt-get update && \
apt-get install -y python3 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Set the working directory
WORKDIR /app
# Copy the application file
COPY app.py .
# Command to run when the container starts
CMD ["python3", "app.py"]
- Build the image:
sudo docker build -t my-debian-app .
Output:
Sending build context to Docker daemon 3.072kB
Step 1/5 : FROM debian:bullseye
---> 4eacea30377a
Step 2/5 : RUN apt-get update && apt-get install -y python3 && apt-get clean && rm -rf /var/lib/apt/lists/*
---> Running in a7b3056c9703
[...]
Removing intermediate container a7b3056c9703
---> 7d24fc2e13c4
Step 3/5 : WORKDIR /app
[...]
Successfully built 9e494088612a
Successfully tagged my-debian-app:latest
- Run your custom image:
sudo docker run my-debian-app
Output:
Hello from Debian Docker container!
Docker Volumes for Persistent Storage
Containers are ephemeral by nature, meaning any changes made inside a container are lost when the container is removed. Docker volumes solve this problem by providing persistent storage.
Creating and Using Volumes
# Create a volume
sudo docker volume create my-data
# Run a container with the volume mounted
sudo docker run -it --name debian-with-volume -v my-data:/data debian bash
# Inside the container, create a file in the mounted volume
echo "This data will persist" > /data/test.txt
exit
# Remove the container
sudo docker rm debian-with-volume
# Create a new container with the same volume
sudo docker run -it --name new-debian -v my-data:/data debian bash
# Verify the data persists
cat /data/test.txt
exit
You should see your original text, demonstrating that the data persists across different containers.
Docker Networks
Docker networks allow containers to communicate with each other securely.
Creating a Custom Network
# Create a bridge network
sudo docker network create my-network
# Run containers in the custom network
sudo docker run -d --name web --network my-network nginx
sudo docker run -d --name db --network my-network postgres:13
# Containers can now communicate using their names
sudo docker exec web ping db
Docker Compose for Multi-Container Applications
Docker Compose is a tool for defining and running multi-container Docker applications.
Installing Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Creating a Docker Compose File
Create a file named docker-compose.yml
:
version: '3'
services:
web:
image: nginx
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
networks:
- app-network
db:
image: postgres:13
environment:
POSTGRES_PASSWORD: example
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-network
networks:
app-network:
volumes:
db-data:
Running with Docker Compose
# Create a directory for the web content
mkdir -p html
echo "<h1>Hello from Docker Compose!</h1>" > html/index.html
# Start the services
sudo docker-compose up -d
# Stop the services
sudo docker-compose down
Best Practices for Debian Docker Containers
-
Use Official Images: Start with official Debian or application-specific images.
-
Minimize Image Size: Use
.dockerignore
to exclude unnecessary files and multi-stage builds to reduce image size. -
Don't Run as Root: Create a non-root user in your Dockerfile:
FROM debian:bullseye
RUN useradd -ms /bin/bash appuser
USER appuser
-
One Service Per Container: Follow the microservices principle by running one service per container.
-
Use Environment Variables: Make your containers configurable with environment variables.
-
Health Checks: Add health checks to verify if your containers are running correctly:
FROM debian:bullseye
RUN apt-get update && apt-get install -y curl
HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost/ || exit 1
-
Use Docker Compose for Development: Simplify your development workflow with Docker Compose.
-
Regular Updates: Keep your base images and dependencies updated to address security vulnerabilities.
Debugging Docker Containers
When troubleshooting Docker containers on Debian, these commands are useful:
# Check container details
sudo docker inspect my-container
# Enter a running container
sudo docker exec -it my-container bash
# Check resource usage
sudo docker stats
# View container processes
sudo docker top my-container
Security Considerations
- Scan Images: Use tools like Docker Scout or Trivy to scan images for vulnerabilities.
# Example with Trivy
sudo apt install -y trivy
trivy image debian:bullseye
- Limit Capabilities: Reduce container privileges by dropping capabilities:
sudo docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
- Read-Only Filesystem: When possible, use read-only filesystems:
sudo docker run --read-only nginx
Real-world Example: Setting Up a LEMP Stack
Let's create a complete LEMP (Linux, Nginx, MySQL, PHP) stack on Debian using Docker:
- Create a project directory:
mkdir lemp-stack
cd lemp-stack
- Create a
docker-compose.yml
file:
version: '3'
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./www:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
networks:
- lemp-network
php:
image: php:8.0-fpm
volumes:
- ./www:/var/www/html
networks:
- lemp-network
db:
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
volumes:
- db-data:/var/lib/mysql
networks:
- lemp-network
networks:
lemp-network:
volumes:
db-data:
- Create the necessary directories and configuration:
mkdir -p www nginx
- Create an Nginx configuration file:
cat > nginx/default.conf << 'EOF'
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
EOF
- Create a test PHP file:
cat > www/index.php << 'EOF'
<?php
echo "<h1>LEMP Stack on Debian Docker</h1>";
echo "<p>PHP version: " . phpversion() . "</p>";
$dbhost = 'db';
$dbuser = 'myuser';
$dbpass = 'mypassword';
$dbname = 'mydb';
// Create connection
$conn = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
echo "<p>Connected to MySQL successfully!</p>";
$conn->close();
?>
EOF
- Start the LEMP stack:
sudo docker-compose up -d
- Access your LEMP stack at http://localhost
Summary
In this guide, we've covered:
- Installing Docker on Debian systems
- Understanding Docker concepts and architecture
- Working with Docker images and containers
- Creating custom Docker images with Dockerfiles
- Using volumes for persistent storage
- Setting up Docker networks
- Orchestrating multi-container applications with Docker Compose
- Following best practices for Docker security and efficiency
- Implementing a real-world LEMP stack example
Docker containers on Debian provide a powerful, flexible way to deploy applications with consistent environments. By leveraging containers, you can simplify deployment, improve resource utilization, and maintain isolation between applications.
Additional Resources
- Official Docker Documentation
- Debian Wiki: Docker
- Docker Hub for finding official and community images
Exercises
- Create a Dockerfile for a Python web application using Flask.
- Set up a WordPress site using Docker Compose with persistent storage.
- Create a custom bridge network and deploy three containers that communicate with each other.
- Implement a CI/CD pipeline that builds and pushes Docker images for a Debian-based application.
- Configure resource limits (CPU, memory) for Docker containers and observe their behavior under load.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)