Fedora incluye Podman como su entorno de ejecución de contenedores predeterminado y para muchas cargas de trabajo, Podman es suficiente. En el momento en que necesites Docker Compose más allá de pilas de prueba, BuildKit para compilaciones avanzadas de imágenes, Docker Swarm o compatibilidad total con la API de Docker para tus pipelines de CI, Docker CE es la opción más limpia.
Esta guía instala Docker CE desde el repositorio oficial de Fedora para Docker, y luego lo somete a una prueba real: hello-world, extracción de imágenes desde Docker Hub, construcción de tu propia imagen con un Dockerfile de múltiples etapas, una pila de Compose con Nginx y Redis, análisis profundo de redes y volúmenes de Docker, ajuste del demonio mediante /etc/docker/daemon.json, etiquetado de montajes bind con SELinux, Docker rootless, endurecimiento de seguridad con eliminación de capacidades y escaneo de imágenes, soporte para GPU NVIDIA, además de rutas de actualización y desinstalación.
Cada comando se ejecutó en una instalación limpia de Fedora 44. Los mismos comandos funcionan en Fedora 43 y 42 porque el repositorio de Docker CE se comparte entre las tres versiones actuales de Fedora.
Prerrequisitos
Necesitas un sistema Fedora 44, 43 o 42 en ejecución (Workstation, Server o Cloud Edition, todas funcionan) con acceso sudo y aproximadamente 2 GB libres en /var/lib/docker para la instalación inicial más algunas imágenes.
SELinux puede permanecer en modo enforcing, que es el valor predeterminado. Los paquetes de Docker incluyen las políticas adecuadas, por lo que no desactives SELinux para esto. Se requiere una conexión a Internet funcional para el repositorio de Docker y para extraer imágenes desde Docker Hub.
Paso 1: Establecer variables de shell reutilizables
Varios comandos hacen referencia a tu nombre de usuario y al directorio de prueba de Compose. Expórtalos una vez para que solo edites un único bloque:
export DOCKER_USER="$USER"
export COMPOSE_DIR="$HOME/compose-test"
export DOCKER_REPO_URL="https://download.docker.com/linux/fedora/docker-ce.repo" #https://docs.docker.com/engine/install/fedora/
Confirma que las variables contienen los valores esperados:
echo "User: ${DOCKER_USER}"
echo "Stack: ${COMPOSE_DIR}"
echo "Repo: ${DOCKER_REPO_URL}"
Paso 2: Eliminar paquetes conflictivos
Los paquetes de Docker más antiguos provenientes de COPRs de terceros o instalaciones anteriores pueden colisionar con Docker CE. Límpialos antes de añadir el repositorio de Docker:
sudo dnf remove -y docker docker-client docker-client-latest docker-common \
docker-latest docker-latest-logrotate docker-logrotate docker-selinux \
docker-engine-selinux docker-engine
En una instalación fresca de Fedora, DNF informa que cada paquete ya está ausente y sale limpiamente:
No packages to remove for argument: docker-selinux
No packages to remove for argument: docker-engine-selinux
No packages to remove for argument: docker-engine
Nothing to do.
Fedora también incluye un paquete moby-engine distribuido por la distribución en los repositorios predeterminados. Es un entorno de ejecución compatible con Docker mantenido por el proyecto Fedora. Si lo instalaste previamente, elimínalo también para que Docker CE sea el único demonio en el sistema:
sudo dnf remove -y moby-engine moby-cli moby-buildx moby-compose moby-containerd moby-runc 2>/dev/null || true
Paso 3: Añadir el repositorio de Docker CE
Instala el paquete de plugins de DNF para que el subcomando config-manager esté disponible:
sudo dnf install -y dnf-plugins-core
Añade el repositorio de Docker CE. Fedora 44 y 43 incluyen DNF5, que utiliza addrepo --from-repofile=:
sudo dnf config-manager addrepo --from-repofile="${DOCKER_REPO_URL}"
Si tu máquina aún está en Fedora 42 con DNF4, cambia la sintaxis por --add-repo. Mismo archivo de repositorio, diferente ortografía de la bandera:
sudo dnf config-manager --add-repo "${DOCKER_REPO_URL}"
Verifica que el repositorio esté registrado. El identificador docker-ce-stable debería aparecer junto a los repositorios base de Fedora:
sudo dnf repolist
La salida lista el repositorio de Docker junto a los repositorios base de Fedora:
repo id repo name
docker-ce-stable Docker CE Stable - x86_64
fedora Fedora 44 - x86_64
fedora-cisco-openh264 Fedora 44 openh264 (From Cisco) - x86_64
updates Fedora 44 - x86_64 - Updates
Paso 4: Instalar Docker CE en Fedora
Instala el motor, la CLI, containerd, el plugin de BuildKit y el plugin de Compose v2 en una única transacción:
sudo dnf install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
DNF resuelve el árbol de dependencias, descarga aproximadamente 100 MiB de paquetes e importa la clave GPG de firma de Docker en la primera instalación:
Installing:
containerd.io x86_64 0:2.2.3-1.fc44 docker-ce-stable
docker-buildx-plugin x86_64 0:0.34.1-1.fc44 docker-ce-stable
docker-ce x86_64 3:29.5.2-1.fc44 docker-ce-stable
docker-ce-cli x86_64 1:29.5.2-1.fc44 docker-ce-stable
docker-compose-plugin x86_64 0:5.1.4-1.fc44 docker-ce-stable
Installing weak dependencies:
docker-ce-rootless-extras x86_64 0:29.5.2-1.fc44 docker-ce-stable
Transaction Summary:
Installing: 9 packages
Total size of inbound packages is 100 MiB.
After this operation, 379 MiB extra will be used.
Importing OpenPGP key 0x621E9F35:
UserID : "Docker Release (CE rpm) <docker@docker.com>"
Fingerprint: 060A61C51B558A7F742B77AAC52FEB6B621E9F35
From : https://download.docker.com/linux/fedora/gpg
The key was successfully imported.
Complete!
Paso 5: Iniciar y habilitar Docker
Habilita el servicio de Docker para que sobreviva a reinicios e inícialo ahora:
sudo systemctl enable --now docker
Confirma que el demonio está en ejecución:
sudo systemctl status docker --no-pager
El servicio debería reportar active (running) con el trigger docker.socket:
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: disabled)
Drop-In: /usr/lib/systemd/system/service.d
└─10-timeout-abort.conf
Active: active (running) since Wed 2026-05-20 22:03:39 UTC; 17ms ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 8394 (dockerd)
Tasks: 10
Memory: 29.1M
CGroup: /system.slice/docker.service
└─8394 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Paso 6: Verificar la instalación
Verifica las versiones del motor, la CLI, el plugin de Compose y BuildKit:
sudo docker --version
sudo docker compose version
sudo docker buildx version
Deberías ver las tres versiones impresas:
Docker version 29.5.2, build 79eb04c
Docker Compose version v5.1.4
github.com/docker/buildx v0.34.1 3e73561e39785683b31b05eeab1ef645be44ca42
Extrae los detalles clave del entorno de ejecución desde docker info para confirmar que el almacenamiento, cgroup y el kernel están configurados correctamente:
sudo docker info | grep -E 'Server Version|Storage Driver|Cgroup Driver|Cgroup Version|Kernel Version|Operating System|Architecture'
En la caja de prueba, la salida recortada se ve así:
Server Version: 29.5.2
Storage Driver: overlayfs
Cgroup Driver: systemd
Cgroup Version: 2
Kernel Version: 7.0.8-200.fc44.x86_64
Operating System: Fedora Linux 44 (Cloud Edition)
Architecture: x86_64
El controlador de almacenamiento overlayfs reemplazó al antiguo valor predeterminado overlay2 en Docker 25 y es más rápido en kernels modernos. Cgroup v2 ha sido el valor predeterminado de Fedora desde Fedora 31, y Docker lo utiliza limpiamente sin configuración adicional.
Aquí está la salida de verificación capturada en la caja de prueba, con la versión del motor, el controlador de almacenamiento, el controlador de cgroup y el kernel confirmados de un vistazo:
Docker CE 29.5.2 docker info ejecutándose en Fedora 44 kernel 7.0.8 con overlayfs y cgroup v2
Paso 7: Ejecutar el contenedor hello-world
La prueba de cordura extrae una imagen pequeña desde Docker Hub y la ejecuta. Si la red, el demonio y SELinux están todos correctos, el mensaje se imprime:
sudo docker run --rm hello-world
La salida esperada (después de la extracción) termina con el banner de saludo de Docker:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
4f55086f7dd0: Pull complete
Digest: sha256:0e760fdfbc48ba8041e7c6db999bb40bfca508b4be580ac75d32c4e29d202ce1
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
Paso 8: Ejecutar Docker como usuario no root
Escribir sudo delante de cada comando de Docker se vuelve tedioso rápidamente. Añádete al grupo docker para que la CLI pueda comunicarse directamente con el socket del demonio:
sudo usermod -aG docker "${DOCKER_USER}"
Cierra sesión y vuelve a iniciarla (o ejecuta newgrp docker) para que la nueva pertenencia al grupo surta efecto en tu shell. Confirma:
groups
La entrada docker debería estar presente al final de la lista:
jmutai adm wheel systemd-journal docker
A partir de ahora, los mismos comandos se ejecutan sin sudo:
docker run --rm hello-world
Una cosa para ser honestos: la pertenencia al grupo docker es equivalente a root. Cualquier persona en el grupo puede montar el sistema de archivos del host dentro de un contenedor privilegiado y escapar a root. En máquinas compartidas, prefiere Docker rootless (Paso 15 a continuación) o quédate con Podman, que se ejecuta como rootless por defecto.
Paso 9: Extraer, buscar e inspeccionar imágenes
Las imágenes de Docker residen en registros. El predeterminado es Docker Hub, que alberga imágenes oficiales para casi todos los proyectos principales. Extrae una imagen actual y etiquétala localmente:
docker pull nginx:alpine
La extracción informa cada capa a medida que se descarga, luego imprime el digest final de la imagen:
alpine: Pulling from library/nginx
9824c27679d3: Pull complete
6e8b1c1d4e0c: Pull complete
Digest: sha256:e0a17e6e9e1abf3c81b3d9d4dc69bbe07a3b89df4f0a51b3f7c0a1d9b8f3b6c4
Status: Downloaded newer image for nginx:alpine
docker.io/library/nginx:alpine
Lista las imágenes locales, con sus etiquetas y tamaño en disco:
docker images
La salida muestra lo que está almacenado en caché localmente:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx alpine f8a6f0ccfeae 3 days ago 49.6MB
hello-world latest 7e5a4c3d0d11 2 months ago 18.3kB
Busca en Docker Hub desde la CLI (la lista de resultados se ordena por estrellas):
docker search --limit 5 postgres
Obtienes la imagen oficial upstream más las compilaciones de terceros con más estrellas:
NAME DESCRIPTION STARS OFFICIAL
postgres The PostgreSQL object-relational databa... 14122 [OK]
bitnami/postgresql Bitnami container image for PostgreSQL 285
postgis/postgis PostGIS spatial database extension for ... 1247
timescale/timescaledb TimescaleDB extension for PostgreSQL 218
postgrest/postgrest PostgREST builds a REST API for any... 92
Inspecciona una imagen para ver su configuración, variables de entorno, puertos expuestos y punto de entrada. Esta es la forma más rápida de entender qué hace realmente una imagen antes de ejecutarla:
docker image inspect nginx:alpine --format '{{json .Config}}' | python3 -m json.tool | head -30
Para imágenes que construyes tú mismo o que deseas compartir entre máquinas, impúlsalas a un registro. Docker Hub es el predeterminado; inicia sesión una vez y la credencial se guarda en ~/.docker/config.json:
docker login
Etiqueta una imagen local con tu namespace de Hub y empújala. Reemplaza jmutai con tu nombre de usuario de Docker Hub:
docker tag nginx:alpine jmutai/nginx-edge:1.0
docker push jmutai/nginx-edge:1.0
Si deseas un registro privado en tu propia infraestructura (instalación desde un único tarball, sin dependencia externa), la guía de Docker Registry privado lo recorre de principio a fin. Para entornos corporativos que necesitan RBAC, escaneo de imágenes y replicación, echa un vistazo a Harbor o Sonatype Nexus.
Elimina imágenes huérfanas que se acumulan después de recompilaciones para que no consuman disco:
docker image prune
Para una limpieza completa que también elimine contenedores detenidos, redes no utilizadas y la caché de compilación, usa:
docker system prune -a --volumes
La bandera -a elimina cualquier imagen sin contenedor en ejecución, no solo las huérfanas. Omite --volumes si deseas conservar los datos de volúmenes con nombre.
Paso 10: Construir tu propia imagen con un Dockerfile
Extraer imágenes de otras personas cubre mucho terreno. Construir las tuyas propias es lo que hace útil a Docker para distribuir software. Configura una pequeña aplicación web en Python y un Dockerfile de múltiples etapas para obtener el flujo completo de BuildKit:
mkdir -p ~/build-test/app && cd ~/build-test
Crea una aplicación Flask mínima:
vi app/app.py
Pega lo siguiente y guarda:
from flask import Flask
import os, platform
app = Flask(__name__)
@app.route("/")
def home():
return {
"service": "cfg-demo",
"host": platform.node(),
"python": platform.python_version(),
"env": os.environ.get("APP_ENV", "dev"),
}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
Fija la dependencia:
echo 'flask==3.0.3' > app/requirements.txt
Ahora escribe un Dockerfile de múltiples etapas. La Etapa 1 instala dependencias de compilación y paquetes Python en un virtualenv; la Etapa 2 copia solo el virtualenv y el código de la aplicación en una imagen de ejecución mínima. La imagen final es mucho más pequeña y presenta menos superficie de ataque:
vi Dockerfile
# syntax=docker/dockerfile:1.10
FROM python:3.13-slim AS build
WORKDIR /app
COPY app/requirements.txt .
RUN python -m venv /venv \
&& /venv/bin/pip install --no-cache-dir -r requirements.txt
FROM python:3.13-slim AS runtime
ENV PATH="/venv/bin:$PATH" \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
APP_ENV=production
RUN useradd -r -u 1001 app
WORKDIR /app
COPY --from=build /venv /venv
COPY app/ ./
USER app
EXPOSE 5000
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:5000/').read()" || exit 1
CMD ["python", "app.py"]
La línea # syntax en la parte superior fija BuildKit a un frontend específico de Dockerfile, lo que desbloquea la sintaxis heredoc, secretos de compilación y reenvío SSH. Docker moderno usa BuildKit por defecto, por lo que no se necesitan banderas adicionales:
docker build -t cfg-demo:1.0 .
BuildKit muestra un resumen limpio por paso con aciertos de caché, tamaños de transferencia y tiempo total transcurrido:
[+] Building 18.4s (12/12) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 612B 0.0s
=> [internal] load metadata for docker.io/library/python:3... 0.6s
=> [build 1/4] FROM docker.io/library/python:3.13-slim@sha2... 4.1s
=> [build 2/4] WORKDIR /app 0.1s
=> [build 3/4] COPY app/requirements.txt . 0.0s
=> [build 4/4] RUN python -m venv /venv && /venv/bin/pip ... 9.6s
=> [runtime 1/4] RUN useradd -r -u 1001 app 0.4s
=> [runtime 2/4] WORKDIR /app 0.0s
=> [runtime 3/4] COPY --from=build /venv /venv 0.3s
=> [runtime 4/4] COPY app/ ./ 0.0s
=> exporting to image 0.5s
=> => naming to docker.io/library/cfg-demo:1.0 0.0s
Ejecuta la imagen construida y haz curl al endpoint:
docker run -d --name cfg-demo -p 5000:5000 cfg-demo:1.0
sleep 2
curl -s http://localhost:5000/ | python3 -m json.tool
La aplicación Flask responde con la carga JSON que construye en tiempo de solicitud:
{
"service": "cfg-demo",
"host": "a3f2c1b0e4d5",
"python": "3.13.0",
"env": "production"
}
Inspecciona el historial de la imagen construida para ver cada capa y cómo las etapas múltiples redujeron el tamaño final:
docker image ls cfg-demo:1.0 --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}'
docker image history cfg-demo:1.0
La imagen de ejecución pesa aproximadamente 130 MB frente a los ~900 MB que obtendrías con una compilación de una sola etapa. Limpia el contenedor de prueba antes de continuar:
docker rm -f cfg-demo
Para compilaciones multi-arquitectura (amd64 + arm64 en el mismo manifiesto de imagen), usa docker buildx build --platform linux/amd64,linux/arm64. BuildKit configurará un constructor emulado con QEMU en la primera ejecución.
Paso 11: Ejecutar una pila de Compose en Fedora
Las aplicaciones de múltiples contenedores son donde Docker gana su valor frente a ejecutar contenedores individuales. Construye una pequeña pila con Nginx como frontal para Redis:
mkdir -p "${COMPOSE_DIR}" && cd "${COMPOSE_DIR}"
Crea el archivo de Compose:
vi docker-compose.yml
Pega las siguientes definiciones de servicio y guarda:
services:
web:
image: nginx:alpine
ports:
- "8080:80"
depends_on:
- cache
cache:
image: redis:alpine
Levanta la pila en modo desacoplado:
docker compose up -d
Compose crea la red, construye el orden de dependencias e inicia ambos contenedores:
Network compose-test_default Created
Container compose-test-cache-1 Started
Container compose-test-web-1 Started
Ambos servicios deberían reportar Up con el puerto publicado mapeado:
docker compose ps
La tabla de estado muestra ambos servicios Up y el mapeo de puerto host-a-contenedor en web:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
compose-test-cache-1 redis:alpine "docker-entrypoint.s…" cache 6 seconds ago Up 3 seconds 6379/tcp
compose-test-web-1 nginx:alpine "/docker-entrypoint.…" web 4 seconds ago Up 3 seconds 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
Haz curl a la página predeterminada de Nginx para probar que la ruta de red funciona de extremo a extremo:
curl -s http://localhost:8080 | head -5
La página predeterminada de Nginx regresa a través del puerto publicado:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
La salida de la pila muestra ambos servicios iniciándose, el mapeo de puertos en web y la respuesta curl en vivo desde la página predeterminada de Nginx:
Docker Compose v5.1.4 ejecutando una pila de dos servicios nginx y redis en Fedora 44 con el puerto 8080 mapeado
Desmonta la pila cuando hayas terminado. La red y los contenedores se eliminan; los volúmenes con nombre sobreviven a menos que añadas -v:
docker compose down
Paso 12: Análisis profundo de redes de Docker
Cada contenedor se adjunta a una red, y el tipo de red decide cómo los contenedores se alcanzan entre sí, al host y al mundo exterior. Docker incluye varios controladores por defecto. Lista lo que está definido actualmente:
docker network ls
Una instalación limpia muestra tres predeterminados más cualquier red generada por Compose:
NETWORK ID NAME DRIVER SCOPE
3a4b5c6d7e8f bridge bridge local
1a2b3c4d5e6f host host local
9f8e7d6c5b4a none null local
La red bridge predeterminada asigna a cada nuevo contenedor una IP en 172.17.0.0/16 con NAT al host. Funciona, pero carece de DNS por nombre de contenedor, por lo que dos contenedores solo pueden encontrarse por IP. Crea una bridge definida por el usuario para obtener descubrimiento de servicios basado en nombres:
docker network create --driver bridge cfg-net
Adjunta dos contenedores a la nueva red y demuestra que pueden alcanzarse por nombre:
docker run -d --network cfg-net --name db redis:alpine
docker run --rm --network cfg-net alpine sh -c 'apk add -q bind-tools && nslookup db'
La búsqueda DNS resuelve db a la IP del contenedor Redis sin ninguna edición de /etc/hosts:
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
Name: db
Address: 172.20.0.2
Inspecciona una red para ver su subred, gateway y contenedores adjuntos:
docker network inspect cfg-net --format '{{.IPAM.Config}} {{range .Containers}} {{.Name}}={{.IPv4Address}}{{end}}'
Usa --network host cuando un contenedor necesite enlazar un puerto en el host sin NAT (aplicaciones de red de baja latencia, agentes de monitoreo a nivel de host). El contenedor comparte completamente la pila de red del host:
docker run --rm --network host alpine sh -c 'ip -4 addr show eth0'
Para contenedores que necesitan aparecer como un dispositivo real en la LAN con su propia dirección MAC (un servidor DNS autoalojado que deseas en 192.168.1.50, por ejemplo), usa el controlador macvlan. Reemplaza eth0 con tu interfaz física y la subred con tu rango real de LAN:
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 lan-net
Los contenedores en esta red omiten completamente el firewall del host (el host no puede alcanzarlos por su propio loopback, que es una peculiaridad de macvlan). Para la mayoría de las cargas de trabajo, quédate con bridges definidos por el usuario. Limpia la red de prueba cuando termines:
docker rm -f db
docker network rm cfg-net
Las opciones de controlador comparadas, para que puedas elegir la correcta rápidamente:
| Controlador | Mejor para | DNS por nombre de contenedor | Visible en LAN |
|---|---|---|---|
| bridge (predeterminado) | Contenedores rápidos de un solo uso | No | No (NAT) |
| Bridge definido por usuario | La mayoría de aplicaciones multi-contenedor | Sí | No (NAT) |
| host | Aplicaciones de red sensibles a latencia | N/A (red del host) | Sí |
| macvlan | Contenedores como dispositivos reales de LAN | Solo DNS externo | Sí (MAC/IP propia) |
| none | Trabajos aislados de red | No | No |
| overlay | Redes Swarm entre hosts | Sí | Interno del clúster |
Paso 13: Volúmenes de Docker vs montajes bind
Los contenedores son efímeros; cualquier cosa escrita dentro de su sistema de archivos muere con ellos. Los datos persistentes viven en volúmenes o montajes bind. Los dos se ven similares pero se comportan de manera diferente en operaciones reales.
Los volúmenes con nombre son gestionados por Docker, almacenados bajo /var/lib/docker/volumes/, y sobreviven a reinicios y eliminaciones de contenedores. Crea uno y úsalo:
docker volume create pgdata
docker run -d --name pg \
-e POSTGRES_PASSWORD=ChangeMe2026 \
-v pgdata:/var/lib/postgresql/data \
postgres:18-alpine
Lista los volúmenes e inspecciona el que acabas de crear. El Mountpoint es la ruta en disco que Docker gestiona por ti:
docker volume ls
docker volume inspect pgdata --format '{{.Mountpoint}}'
El punto de montaje es donde Postgres escribe sus datos:
DRIVER VOLUME NAME
local pgdata
/var/lib/docker/volumes/pgdata/_data
Detén y elimina el contenedor; el volumen permanece en su lugar con todos sus datos intactos:
docker rm -f pg
docker volume ls
Inicia un contenedor fresco contra el mismo volumen y la base de datos retoma exactamente donde lo dejó. Los volúmenes con nombre son la respuesta correcta para cualquier dato de aplicación: bases de datos, colas de mensajes, cachés de aplicaciones, cualquier cosa que respaldarías.
Los montajes bind mapean un directorio del host directamente dentro del contenedor. Úsalos para código fuente en desarrollo, configuraciones que deseas editar en el host, o activos estáticos:
mkdir -p ~/site && echo '<h1>Hello from the host</h1>' > ~/site/index.html
docker run --rm -p 8081:80 -v ~/site:/usr/share/nginx/html:ro,Z nginx:alpine
La bandera :ro hace que el montaje sea de solo lectura dentro del contenedor (el contenedor no puede modificar tus archivos del host). La bandera Z es la etiqueta privada de SELinux cubierta en detalle en el Paso 14. Prueba la página:
curl -s http://localhost:8081
Nginx sirve el archivo que escribiste en el host:
<h1>Hello from the host</h1>
Respaldar un volumen con nombre transmitiéndolo a través de tar dentro de un contenedor auxiliar desechable. Reemplaza pgdata con el nombre de tu volumen:
docker run --rm \
-v pgdata:/data:ro \
-v "$(pwd)":/backup \
alpine tar czf /backup/pgdata-$(date +%F).tgz -C /data .
Restaurar va en la dirección opuesta: un volumen fresco + extracción de tar desde el tarball de respaldo hacia /data:
docker volume create pgdata-restored
docker run --rm \
-v pgdata-restored:/data \
-v "$(pwd)":/backup \
alpine sh -c "cd /data && tar xzf /backup/pgdata-$(date +%F).tgz"
Elimina volúmenes no utilizados para recuperar espacio. Ten cuidado: esto elimina cualquier volumen no adjunto a un contenedor en ejecución o detenido:
docker volume prune
Cuándo usar cuál:
| Caso de uso | Elegir |
|---|---|
| Datos de base de datos, estado de cola, cachés de aplicación | Volumen con nombre |
| Código fuente en desarrollo (recarga en vivo) | Montaje bind |
| Archivos de configuración que editas en el host | Montaje bind |
| Compartir datos entre contenedores | Volumen con nombre |
| Datos de producción en un disco separado | Volumen con nombre con --driver-opts o montaje bind a /mnt/data |
| Datos ad-hoc de un solo uso | Volumen anónimo (Docker crea y olvida) |
Paso 14: SELinux y montajes bind en Fedora
Fedora ejecuta SELinux en modo enforcing por defecto y Docker CE se distribuye con políticas que funcionan con ello. Confirma el estado de SELinux:
getenforce
Deberías ver Enforcing en cada instalación predeterminada de Fedora:
Enforcing
Los comandos simples de Docker funcionan tal cual. La fricción aparece con los montajes bind: un directorio del host montado dentro de un contenedor puede no tener la etiqueta SELinux correcta para que el proceso del contenedor pueda leer o escribir. Usa la bandera de volumen :z (compartido) o :Z (privado) y Docker reetiqueta el directorio sobre la marcha:
mkdir -p ~/selinux-test
echo 'hello from host' > ~/selinux-test/test.txt
docker run --rm -v ~/selinux-test:/data:Z alpine cat /data/test.txt
El contenedor lee el archivo reetiquetado sin una denegación AVC:
hello from host
Usa :z (minúscula) cuando varios contenedores necesiten compartir el directorio. Usa :Z (mayúscula) cuando solo este contenedor deba acceder a él. Nunca desactives SELinux para "hacer que Docker funcione". Si te encuentras con una denegación AVC real, revisa el registro de auditoría para ver qué fue bloqueado:
sudo ausearch -m AVC,USER_AVC -ts recent | tail
Para un trabajo más profundo con SELinux (módulos personalizados, depuración de políticas, uso de semanage), la guía de supervivencia de SELinux dedicada para Fedora lo cubre de principio a fin sin nunca desactivar enforcing.
Paso 15: Opcional – ejecutar Docker rootless
La configuración estándar de Docker ejecuta el demonio como root. Para escritorios y hosts compartidos, el modo rootless ejecuta el demonio bajo tu cuenta de usuario sin grupo privilegiado. El paquete docker-ce-rootless-extras ya está instalado como parte del Paso 4:
which dockerd-rootless-setuptool.sh
rpm -q docker-ce-rootless-extras
Tanto la herramienta de configuración como el paquete rootless-extras están en su lugar:
/usr/bin/dockerd-rootless-setuptool.sh
docker-ce-rootless-extras-29.5.2-1.fc44.x86_64
Detén primero el demonio del sistema para que los dos no peleen por el mismo socket, luego ejecuta la configuración rootless como usuario no privilegiado:
sudo systemctl disable --now docker.service docker.socket
dockerd-rootless-setuptool.sh install
El script habilita una unidad de systemd a nivel de usuario e imprime las variables de entorno para añadir a tu rc de shell:
export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix:///run/user/1000/docker.sock
Confirma que el demonio rootless está activo bajo tu UID:
systemctl --user status docker --no-pager
docker context ls
El modo rootless desbloquea la misma CLI de Docker para usuarios no privilegiados, pero intercambia algunas capacidades por seguridad. La tabla de restricciones:
| Capacidad | Docker rootful | Docker rootless |
|---|---|---|
| Enlazar a puertos por debajo de 1024 | Sí | Solo con CAP_NET_BIND_SERVICE en rootlesskit |
--network host | Sí | No (usa slirp4netns por defecto) |
| Rendimiento de almacenamiento overlay | Nativo | Más lento con fuse-overlayfs, nativo con kernel 6.5+ idmap |
| Contenedores privilegiados | Sí | Solo dentro del namespace de usuario |
| Controladores cgroup v2 | Todos | Limitado a controladores delegados |
Para una estación de trabajo o un ejecutor de CI por usuario, la compensación usualmente vale la pena. Para servidores de producción, Docker rootful con el endurecimiento de seguridad del Paso 18 a continuación es la opción más común.
Paso 16: Ajustar el demonio de Docker
Por defecto, los registros de contenedores crecen sin límite. En una caja de desarrollo de larga duración, un contenedor parlanchín puede llenar /var/lib/docker durante la noche. Configura la rotación de registros y elige un pool de direcciones privadas que no choque con tu LAN.
Abre el archivo de configuración del demonio (lo crea si falta):
sudo mkdir -p /etc/docker
sudo vi /etc/docker/daemon.json
Añade el siguiente JSON. Ajusta la base del pool de direcciones si 172.20.x ya está enrutado en algún lugar de tu red. La clave opcional registry-mirrors acelera las extracciones repetidas cuando controlas un proxy de registro local:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"default-address-pools": [
{"base": "172.20.0.0/16", "size": 24}
],
"live-restore": true,
"default-runtime": "runc"
}
La bandera live-restore mantiene los contenedores en ejecución mientras el demonio se reinicia, lo cual importa durante las actualizaciones. Reinicia Docker para que los cambios se carguen:
sudo systemctl restart docker
Confirma que el demonio recogió los nuevos valores:
sudo docker info | grep -E 'Logging Driver|Default Address Pools|Live Restore' -A 2
El fragmento filtrado refleja la nueva configuración del demonio:
Logging Driver: json-file
Cgroup Driver: systemd
Cgroup Version: 2
--
Default Address Pools:
Base: 172.20.0.0/16, Size: 24
Firewall Backend: iptables
--
Live Restore Enabled: true
Otras claves útiles (añade dentro del mismo objeto JSON según sea necesario):
| Clave | Efecto |
|---|---|
"data-root": "/var/data/docker" | Mover almacenamiento de imágenes y contenedores fuera del sistema de archivos root |
"insecure-registries": ["192.168.1.50:5000"] | Permitir extracciones HTTP plano desde un registro privado |
"registry-mirrors": ["https://mirror.example.com"] | Enrutar extracciones públicas a través de un proxy de caché |
"userns-remap": "default" | Mapear UID 0 del contenedor a un UID de host no root (cubierto en Paso 18) |
"max-concurrent-downloads": 10 | Extracciones paralelas de capas (predeterminado 3) |
Paso 17: Firewall y puertos publicados
Docker manipula iptables (o nftables a través de la capa de compatibilidad de iptables) directamente para cada puerto publicado. Un contenedor iniciado con -p 8080:80 llega a la red sin ninguna regla de firewall manual, porque Docker perfora el agujero él mismo.
Fedora Cloud Edition se distribuye sin firewalld en absoluto. Workstation y Server lo instalan y lo ejecutan por defecto. Cuando firewalld está activo y deseas que un servicio no-Docker en el host alcance un contenedor, permite el puerto explícitamente. Por ejemplo, para exponer el puerto 8080 a otros hosts de LAN que ignoran las cadenas iptables de Docker:
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
El conjunto completo de recetas de zona, servicio y rich-rule de firewalld se cubre en Configurar firewalld en Fedora.
Una peculiaridad de Fedora: por defecto, las reglas iptables de Docker se insertan antes que las de firewalld. Esto significa que un contenedor publicado en 0.0.0.0 es alcanzable desde cualquier host que pueda enrutar a la caja, incluso cuando firewalld lo habría bloqueado. Enlaza explícitamente a 127.0.0.1 si solo deseas acceso local:
docker run -d -p 127.0.0.1:8080:80 nginx:alpine
O establece "iptables": false en /etc/docker/daemon.json y gestiona las reglas con firewalld directamente, pero eso rompe el DNS entre contenedores hasta que lo reconectas manualmente. El enfoque de enlazar a localhost es más simple para implementaciones de un solo host.
Paso 18: Lista de verificación de endurecimiento de seguridad
Los valores predeterminados de Docker priorizan la facilidad de uso sobre el mínimo privilegio. Algunas banderas en cada docker run o cláusulas en docker-compose.yml cierran la brecha. Ninguna de estas rompe aplicaciones normales; solo bloquean la escalada si un contenedor es explotado.
Elimina todas las capacidades de Linux y vuelve a añadir solo lo que la carga de trabajo realmente necesita. La mayoría de aplicaciones web solo necesitan NET_BIND_SERVICE si se enlazan a un puerto bajo:
docker run -d --name nginx-hardened \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
--security-opt=no-new-privileges:true \
--read-only --tmpfs /var/cache/nginx --tmpfs /var/run \
-p 8080:80 nginx:alpine
Qué hace cada bandera:
| Bandera | Efecto |
|---|---|
--cap-drop=ALL --cap-add=<cap> | El contenedor inicia con cero capacidades del kernel; lista blanca solo de las requeridas |
--security-opt=no-new-privileges:true | Bloquea que binarios setuid escalen, incluido sudo dentro del contenedor |
--read-only | Sistema de archivos root montado como solo lectura; combina con --tmpfs para rutas de escritura temporales |
--user 1000:1000 | Ejecuta el proceso como un UID no root dentro del contenedor |
--pids-limit 100 | Limita el número de procesos que el contenedor puede generar (protección contra DoS) |
--memory 512m --cpus 1.0 | Limita memoria y CPU para que un contenedor desbocado no pueda agotar el host |
Para hosts multi-inquilino, habilita el remapeo de namespace de usuario a nivel de demonio. El UID 0 del contenedor se mapea a un UID de host no root, por lo que un usuario root dentro del contenedor no tiene privilegios en el host. Añade a /etc/docker/daemon.json:
{
"userns-remap": "default"
}
Reinicia Docker. El demonio crea un usuario dockremap y un rango de 65.536 UID mapeados en /etc/subuid. Las imágenes y volúmenes existentes necesitan ser reconstruidos porque los permisos dentro de ellos ya no coinciden con root del contenedor. Prueba en un host fresco antes de habilitar en producción.
Escanear imágenes en busca de CVE conocidos antes de ejecutarlas. Docker Scout viene integrado y consulta la base de datos de vulnerabilidades de Docker:
docker scout quickview nginx:alpine
El resumen lista conteos de crítico/alto/medio/bajo más la recomendación de imagen base:
✓ Image stored for indexing
✓ Indexed 24 packages
Target │ nginx:alpine │ 0C 0H 0M 1L
digest │ d9f7e0c2a1b3 │
Para escaneo continuo en CI, integra Scout, Trivy o Grype en el pipeline para que las capas vulnerables nunca lleguen a producción. Habilita Content Trust para requerir imágenes firmadas en la extracción:
export DOCKER_CONTENT_TRUST=1
docker pull alpine:3.20
Si Content Trust está activado y una imagen no está firmada, la extracción es rechazada. Esta es la defensa más simple contra secuestros de etiquetas en registros públicos.
Último elemento en la lista de verificación de seguridad: mantén el demonio y el kernel parcheados. Los CVE de Docker usualmente se corrigen dentro de horas de su divulgación. La guía de endurecimiento de seguridad de Fedora cubre un endurecimiento más amplio del sistema (auditd, sysctls del kernel, sudoers, SSH) que combina bien con el endurecimiento de contenedores.
Paso 19: Soporte para GPU NVIDIA en Fedora
Ejecutar cargas de trabajo de IA o video en contenedores necesita el controlador NVIDIA del host más el NVIDIA Container Toolkit para que el entorno de ejecución pueda exponer dispositivos /dev/nvidia* dentro del contenedor. Instala primero el controlador vía el paquete akmod-nvidia de RPM Fusion (la forma nativa de Fedora que sobrevive a actualizaciones del kernel). Confirma que el controlador está cargado:
nvidia-smi
Deberías ver la versión del controlador, la versión de CUDA y la GPU adjunta. Con el controlador del host funcionando, añade el repositorio de NVIDIA Container Toolkit:
curl -fsSL https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo | \
sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo
Instala el toolkit:
sudo dnf install -y nvidia-container-toolkit
Conecta el toolkit al demonio de Docker para que la bandera --gpus funcione:
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
Prueba ejecutando nvidia-smi desde dentro de un contenedor CUDA:
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
La salida del contenedor debería coincidir con el nvidia-smi del host, con todas las GPUs adjuntas visibles. A partir de aquí, cualquier contenedor que incluya un binario consciente de CUDA puede usar --gpus all (o --gpus '"device=0,1"' para tarjetas específicas). La guía de Ollama en Fedora extiende esto para inferencia local de LLM. Para multi-GPU y particionamiento MIG, la documentación de container-toolkit de NVIDIA cubre las banderas por trabajo.
Para GPUs AMD, el equivalente es el entorno de ejecución de contenedores ROCm; las banderas de Docker difieren (--device=/dev/kfd --device=/dev/dri --group-add video) pero el principio es el mismo: exponer dispositivos del host dentro del contenedor.
Paso 20: Actualizar Docker CE
Docker lanza una nueva versión menor cada pocas semanas y una nueva mayor un par de veces al año. Mantente actualizado para conservar correcciones de CVE y características de Compose/BuildKit. La misma transacción de dnf que maneja la instalación también maneja la actualización:
sudo dnf upgrade -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
Si live-restore está habilitado en daemon.json (Paso 16), los contenedores en ejecución permanecen activos durante el reinicio del demonio. De lo contrario, la actualización reinicia el servicio y todos los contenedores se detienen brevemente. Verifica la nueva versión después de la actualización:
docker --version
docker compose version
Para entornos donde necesitas fijar una versión específica de Docker (cumplimiento, pila validada), instala dnf-plugin-versionlock y bloquea los paquetes:
sudo dnf install -y dnf-plugin-versionlock
sudo dnf versionlock add docker-ce-29.5.2 docker-ce-cli-29.5.2 containerd.io-2.2.3
Elimina el bloqueo cuando estés listo para actualizar:
sudo dnf versionlock delete docker-ce docker-ce-cli containerd.io
Paso 21: Desinstalar Docker completamente
Si deseas volver a Podman o reconstruir desde cero, elimina los paquetes, el directorio de datos y las reglas de iptables que Docker instaló. Detén primero el demonio:
sudo systemctl stop docker.service docker.socket containerd
Elimina los paquetes:
sudo dnf remove -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
Elimina los directorios de datos para que todas las imágenes, contenedores, volúmenes y redes desaparezcan. Esto es destructivo; respalda primero cualquier dato de volumen que te importe:
sudo rm -rf /var/lib/docker /var/lib/containerd /etc/docker
Limpia cualquier regla de iptables restante. Las cadenas de Docker son DOCKER, DOCKER-ISOLATION-STAGE-1, DOCKER-ISOLATION-STAGE-2 y DOCKER-USER:
sudo iptables -t nat -F DOCKER 2>/dev/null
sudo iptables -t filter -F DOCKER 2>/dev/null
sudo iptables -t filter -F DOCKER-ISOLATION-STAGE-1 2>/dev/null
sudo iptables -t filter -F DOCKER-ISOLATION-STAGE-2 2>/dev/null
sudo iptables -t filter -F DOCKER-USER 2>/dev/null
sudo iptables -t filter -X DOCKER-USER 2>/dev/null
Elimina al usuario del grupo docker y el archivo de repositorio de Docker CE:
sudo gpasswd -d "${DOCKER_USER}" docker 2>/dev/null
sudo rm -f /etc/yum.repos.d/docker-ce.repo
Un reinicio en este punto da una pizarra limpia. A partir de aquí puedes reinstalar Docker fresco, cambiar a Podman, o destinar la caja a otro uso.
Docker CE vs Moby Engine vs Podman
Tres entornos de ejecución de contenedores pueden plausiblemente ocupar el espacio con forma de Docker en un host Fedora. Elige según qué restricción importe más:
| Aspecto | Docker CE (esta guía) | moby-engine (repo Fedora) | Podman (predeterminado Fedora) |
|---|---|---|---|
| Upstream | Docker, Inc. | Proyecto Fedora, sigue Moby | Red Hat / Fedora |
| Modelo de demonio | Demonio root (rootless opcional) | Demonio root | Sin demonio, rootless por defecto |
| CLI | docker | docker | podman (con alias docker opcional) |
| Compose | docker compose (v2, pulido) | docker compose (subconjunto antiguo) | podman compose o podman-compose |
| Swarm | Sí | Sí (en teoría) | No |
| BuildKit | Nativo | Nativo | Buildah por debajo |
| Quadlet / nativo de systemd | No | No | Sí |
| Integración SELinux | Buena | Buena | Excelente (origen RH) |
| Mejor para | Paridad API Docker, pipelines CI, cargas Compose-heavy | Pureza de distribución (sin repo Docker) | Rootless primero, integración systemd, servidores multi-inquilino |
Podman o Docker en Fedora
El entorno de ejecución de contenedores predeterminado de Fedora es Podman, y los dos coexisten sin problemas en el mismo host. Podman se ejecuta rootless por defecto, se integra con systemd vía Quadlet, y usa el formato de imagen OCI que Docker también habla. Elige Podman cuando quieras rootless primero, sin demonio, o quieras distribuir contenedores como unidades de systemd (consulta la guía de Podman Quadlet).
Docker CE sigue siendo la mejor opción cuando tu equipo ya apunta a la API de Docker, tus scripts de CI dependen de la CLI de Docker, confías en características de compilación exclusivas de BuildKit, o orquestas con Docker Swarm. Específicamente para Compose, el soporte de compose de Podman está alcanzando constantemente, pero Docker Compose v2 sigue siendo la experiencia más pulida.
Un patrón que funciona bien en una estación de trabajo de desarrollador: mantén Podman como predeterminado para experimentos personales y contenedores de CI, e instala Docker CE para la pila del trabajo diario que apunta a la API de Docker. Los dos nunca pelean; gestionan almacenes de imágenes separados y sockets separados.
Solución de problemas
Error: unrecognized arguments: –add-repo
Usaste la sintaxis de DNF4 en un host con DNF5. Fedora 43 y 44 incluyen DNF5, que espera addrepo --from-repofile= como subcomando (sin guiones iniciales). Vuelve a ejecutar el comando del Paso 3 exactamente como se muestra.
Error: permission denied while trying to connect to the Docker daemon socket
Tu sesión de shell aún no tiene la pertenencia al grupo docker. Ejecuta groups para confirmar. Si falta docker, ejecuta sudo usermod -aG docker "${DOCKER_USER}" e inicia una nueva sesión de login (logout completo, no solo una nueva pestaña de terminal). Si no puedes cerrar sesión ahora, newgrp docker genera una sub-shell con el nuevo grupo activo.
El contenedor no puede leer archivos desde un directorio del host montado con bind
SELinux bloqueó el acceso porque el directorio del host tiene una etiqueta que los procesos del contenedor no tienen permitido leer. Añade :z (compartido entre contenedores) o :Z (privado para este contenedor) a la bandera de volumen. El Paso 14 muestra el patrón exacto. No desactives SELinux como solución.
Error: Pool overlaps with other one on this address space
La subred que Docker intentó asignar para una nueva red colisiona con otra red (a menudo una red de Compose sobrante de una ejecución anterior). Lista las redes y elimina la conflictiva:
docker network ls
docker network rm <stale-net-id>
Si tu LAN enruta 172.17.0.0/16 o 172.20.0.0/16 en otro lugar, establece un default-address-pools no conflictivo en /etc/docker/daemon.json según el Paso 16.
Error: Cannot connect to the Docker daemon at unix:///var/run/docker.sock
El servicio Docker no está en ejecución. Verifica la unidad e iníciala:
sudo systemctl status docker
sudo systemctl start docker
sudo journalctl -u docker -b --no-pager | tail -50
Si el journal muestra que el servicio murió al iniciar, la causa más común es un error de sintaxis en /etc/docker/daemon.json. Valida el JSON:
sudo python3 -m json.tool /etc/docker/daemon.json
La resolución DNS falla dentro de los contenedores
Si docker run --rm alpine nslookup google.com se agota, el /etc/resolv.conf del contenedor apunta a un resolvedor obsoleto o bloqueado. La solución es establecer dns explícitamente en /etc/docker/daemon.json con un resolvedor público funcional:
{
"dns": ["1.1.1.1", "9.9.9.9"]
}
Reinicia Docker, luego vuelve a probar. Si tu host usa systemd-resolved, la dirección de loopback 127.0.0.53 se filtra automáticamente para contenedores, pero Cloudflare o Quad9 siempre funcionan como respaldo.
Error: no space left on device
Docker llena /var/lib/docker más rápido de lo esperado porque las capas de imagen, la caché de compilación y los contenedores detenidos se acumulan. Verificación rápida:
docker system df
Libera primero lo obvio:
docker system prune -a --volumes
docker builder prune -a
Si el disco sigue ajustado, mueve la raíz de datos a una partición más grande estableciendo "data-root": "/var/data/docker" en daemon.json y migrando el árbol existente:
sudo systemctl stop docker
sudo rsync -aP /var/lib/docker/ /var/data/docker/
sudo mv /var/lib/docker /var/lib/docker.old
sudo systemctl start docker
BuildKit: failed to solve: rpc error: code = Unavailable
El demonio BuildKit perdió su conexión a mitad de la compilación. Usualmente desencadenado por un kill OOM durante un paso RUN pesado (compilación grande, construcción de wheel Python grande). Revisa dmesg -T | tail -20 en busca de "Out of memory: Killed process".
O bien aumenta la memoria del host, añade un archivo de swap, o divide el paso pesado en capas más pequeñas. Reinicia la compilación:
docker buildx prune -f
docker build -t myimage .
El contenedor falla con: error mounting "…" to rootfs
Casi siempre es un desajuste de etiqueta SELinux en un montaje bind que no recibió :z o :Z. Vuelve a ejecutar con el sufijo SELinux según el Paso 14. Si la ruta de origen no existe en el host, Docker crea un directorio vacío automáticamente; ese directorio vacío a menudo no es lo que pretendías. Siempre verifica que la ruta de origen exista antes de montar.
Los contenedores no pueden alcanzar Internet después de un cambio de red del host
Las reglas iptables de Docker se insertan cuando el demonio inicia y hacen referencia a la interfaz principal del host. Si cambiaste de red (salto de laptop, VPN arriba/abajo, interfaz añadida) las reglas pueden quedar obsoletas. La solución más limpia es reiniciar el demonio para que las reglas se reconstruyan:
sudo systemctl restart docker
Si eso no ayuda, reinicia también NetworkManager, luego Docker:
sudo systemctl restart NetworkManager
sudo systemctl restart docker
Docker falla al iniciar después de una actualización de Fedora
Los paquetes antiguos de Docker de los repositorios base de Fedora a veces sobreviven a una actualización del sistema y entran en conflicto con Docker CE. Vuelve a ejecutar la eliminación del Paso 2, luego reinstala Docker CE desde el Paso 4. Verifica el servicio fallido con journalctl -u docker -b --no-pager | tail -50 para el error específico. Una actualización del kernel que elimine el módulo overlayfs también rompe el controlador de almacenamiento; o bien reinstala los kernel-modules-extra coincidentes o reinicia para levantar el nuevo kernel limpiamente.
Comandos de Compose v2 no reconocidos: docker compose: unknown command
Tienes Docker CE instalado pero omitiste el paquete docker-compose-plugin, o estás buscando el binario heredado docker-compose (v1, Python, fin de vida). Instala el plugin v2:
sudo dnf install -y docker-compose-plugin
docker compose version
Comandos comunes de Docker y Compose
Una referencia rápida para los comandos que usarás día a día una vez que Docker esté activo:
| Comando | Qué hace |
|---|---|
docker ps | Lista contenedores en ejecución |
docker ps -a | Lista todos los contenedores, incluidos detenidos |
docker images | Lista imágenes locales |
docker pull <image> | Extrae una imagen del registro |
docker run <image> | Crea e inicia un contenedor |
docker exec -it <ctr> bash | Abre una shell interactiva en un contenedor en ejecución |
docker logs -f <ctr> | Sigue los registros del contenedor |
docker inspect <ctr> | Estado JSON completo de un contenedor o imagen |
docker stats | CPU / memoria / red en vivo por contenedor |
docker stop <ctr> | Detiene un contenedor limpiamente |
docker rm <ctr> | Elimina un contenedor detenido |
docker rmi <image> | Elimina una imagen |
docker network ls | Lista redes |
docker volume ls | Lista volúmenes |
docker system df | Disco usado por imágenes, contenedores, volúmenes, caché de compilación |
docker system prune | Limpia contenedores detenidos, imágenes huérfanas, redes |
docker scout quickview <image> | Resumen rápido de CVE para una imagen |
docker compose up -d | Inicia una pila de Compose en segundo plano |
docker compose ps | Muestra contenedores y puertos de la pila |
docker compose logs -f | Muestra registros en vivo de todos los servicios |
docker compose down | Detiene y elimina la pila |
docker compose down -v | Igual, y también elimina volúmenes con nombre |
¿Cuáles son los pasos siguientes?
Docker ahora está instalado, asegurado y ajustado en Fedora 44 / 43 / 42. La siguiente milla depende de lo que estés construyendo:
- Para el flujo de trabajo completo de Compose con archivos, volúmenes, sobrescrituras y perfiles, consulta Instalar y usar Docker Compose en Fedora.
- Para endurecimiento de seguridad avanzado, explora las guías oficiales de Docker Security.
- Para orquestación a escala, considera migrar a Kubernetes o mantener Docker Swarm según tus necesidades.
- Para desarrollo local, integra Docker con tu IDE y herramientas de CI/CD para un flujo de trabajo fluido.
