Skip to content

Docker Installation and Usage

Docker provides an official repository for enterprise Linux. The following steps apply to RHEL, CentOS Stream, AlmaLinux, Rocky Linux, and other EL-based distributions.

Terminal window
# Install the DNF plugin that provides config-manager
sudo dnf install -y dnf-plugins-core
# Add the official Docker repository
sudo dnf config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
  1. Install Docker Engine, CLI, and container runtime:

    Terminal window
    sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
  2. Start Docker and enable it at boot:

    Terminal window
    sudo systemctl enable --now docker
  3. Verify the installation:

    Terminal window
    sudo docker version
    sudo docker run hello-world
  4. (Optional) Add the current user to the docker group to avoid using sudo every time:

    Terminal window
    sudo usermod -aG docker $(whoami)

    Log out and log back in for the change to take effect.

Terminal window
# Pull images from Docker Hub
docker pull nginx:latest
docker pull almalinux:9
# Search for images
docker search mariadb
# View local images
docker images
Terminal window
# Run in the foreground, automatically remove on exit
docker run --rm -it almalinux:9 /bin/bash
# Run Nginx in the background
docker run -d --name my-nginx -p 80:80 nginx:latest
# Run MariaDB with environment variables and volume mounts
docker run -d --name my-db \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=your_password \
-v /data/mysql:/var/lib/mysql \
mariadb:10.11
Terminal window
# View running containers
docker ps
# View all containers
docker ps -a
# View container logs
docker logs my-nginx
docker logs -f --tail 100 my-nginx
# View container details
docker inspect my-nginx
# View container resource usage
docker stats
Terminal window
# Stop a container
docker stop my-nginx
# Start a stopped container
docker start my-nginx
# Restart a container
docker restart my-nginx
# Remove a stopped container
docker rm my-nginx
# Force remove a running container
docker rm -f my-nginx
# Remove all stopped containers
docker container prune
# Remove unused images
docker image prune -a
Terminal window
# Enter a container with an interactive terminal
docker exec -it my-nginx /bin/bash
# Execute a command inside a container
docker exec my-nginx nginx -t

Docker Compose is used to define and manage multi-container applications. Docker CE includes the docker compose subcommand (V2) out of the box.

Create docker-compose.yml:

services:
web:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./html:/usr/share/nginx/html:ro
- certbot_data:/etc/letsencrypt:ro
depends_on:
- app
restart: unless-stopped
app:
build: ./app
expose:
- "8000"
environment:
- DATABASE_URL=mysql://root:changeme@db:3306/myapp
depends_on:
- db
restart: unless-stopped
db:
image: mariadb:10.11
environment:
MYSQL_ROOT_PASSWORD: changeme
MYSQL_DATABASE: myapp
volumes:
- db_data:/var/lib/mysql
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
db_data:
certbot_data:
Terminal window
# Start all services (in the background)
docker compose up -d
# View service status
docker compose ps
# View logs
docker compose logs -f
# View logs for a specific service only
docker compose logs -f app
# Rebuild and start
docker compose up -d --build
# Stop all services
docker compose down
# Stop and remove data volumes
docker compose down -v
# Scale service instances
docker compose up -d --scale app=3
FROM almalinux:9-minimal
RUN microdnf install -y python3 python3-pip && \
microdnf clean all
WORKDIR /app
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
USER 1001
CMD ["python3", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Terminal window
# Build the image
docker build -t my-app:v1 .
# Tag the image
docker tag my-app:v1 registry.example.com/my-app:v1
# Push to a private registry
docker push registry.example.com/my-app:v1

Docker uses the overlay2 storage driver by default on EL systems, which is the recommended option.

Terminal window
docker info | grep "Storage Driver"

Edit or create /etc/docker/daemon.json:

{
"storage-driver": "overlay2",
"data-root": "/data/docker",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"registry-mirrors": [
"https://mirror.example.com"
]
}

Restart Docker to apply the configuration:

Terminal window
sudo systemctl restart docker

To migrate Docker data from the default /var/lib/docker to a new location:

  1. Stop Docker:

    Terminal window
    sudo systemctl stop docker
  2. Copy existing data:

    Terminal window
    sudo rsync -aP /var/lib/docker/ /data/docker/
  3. Set data-root in /etc/docker/daemon.json:

    {
    "data-root": "/data/docker"
    }
  4. Start Docker and verify:

    Terminal window
    sudo systemctl start docker
    docker info | grep "Docker Root Dir"
  5. After confirming everything works, remove the old directory:

    Terminal window
    sudo rm -rf /var/lib/docker

Docker manages its own iptables rules. If you are using firewalld, note the following:

Terminal window
# Allow inter-container communication
sudo firewall-cmd --permanent --zone=trusted --add-interface=docker0
sudo firewall-cmd --reload
Terminal window
# View Docker disk usage
docker system df
# Comprehensive cleanup of unused resources
docker system prune -a --volumes
# Export a container as an image
docker commit my-nginx my-nginx-backup:latest
# Export/import image files
docker save -o nginx-backup.tar nginx:latest
docker load -i nginx-backup.tar