Zademy

Guía Completa de Docker y Docker Compose: Comandos y Mejores Prácticas

Docker; DevOps; Contenedores; Guía; CLI
words palabras

Guía Completa de Docker y Docker Compose: Comandos y Mejores Prácticas

Conceptos Fundamentales de Docker

Docker empaqueta tu aplicación y sus dependencias en contenedores: unidades autónomas que corren igual en tu laptop, en CI y en producción. Se acabó el "en mi máquina sí funciona". Esa es toda la idea, y funciona bien.

Tres conceptos que necesitas tener claros antes de tocar la terminal:

Una imagen es una plantilla de solo lectura con todo lo necesario para ejecutar tu app: código, runtime, librerías, configuración. No se ejecuta, se construye. Un contenedor es una instancia viva de una imagen, corriendo en memoria. Puedes tener docenas de contenedores basados en la misma imagen. Docker Hub es el registro público donde encuentras y publicas imágenes.

Comandos CLI de Docker (Básico)

Esta es la chuleta que tengo pegada en mi monitor. La comparto porque me cansé de buscar lo mismo cinco veces al día.

TareaComandoQué hace
Imágenes
Construirdocker build -t <nombre> .Construye desde el Dockerfile del directorio actual
Sin cachédocker build -t <nombre> . --no-cacheReconstruye desde cero, ignora capas cacheadas
Listardocker imagesMuestra imágenes locales
Eliminardocker rmi <nombre>Borra una imagen
Limpiar sin usodocker image pruneElimina imágenes no referenciadas
Publicardocker push <usuario>/<nombre>Sube a Docker Hub
Contenedores
Crear y correrdocker run --name <nombre> <imagen>Crea un contenedor con nombre
En backgrounddocker run -d <imagen>Detached, libera la terminal
Con puertosdocker run -p <host>:<cont> <imagen>Mapea un puerto del contenedor al host
Listar activosdocker psContenedores corriendo
Listar todosdocker ps --allIncluye detenidos
start/stop/restartdocker start|stop|restart <nombre>stop manda SIGTERM para apagado limpio
Eliminardocker rm <nombre>Borra un contenedor detenido
Entrar con shelldocker exec -it <nombre> shShell interactivo dentro del contenedor
Ver logsdocker logs -f <nombre>Sigue los logs en tiempo real
Inspeccionardocker inspect <nombre>Detalles del contenedor en JSON
Recursos en vivodocker statsCPU, memoria y red en tiempo real

Docker Avanzado: Buenas Prácticas en Imágenes y Seguridad

Construcciones Multi-Etapa (Multi-stage Builds)

Los multi-stage builds son de las cosas que cuando las aprendes no vuelves atrás. La idea: usas una etapa con todo el toolchain de build, compiladores, Maven, npm, lo que sea, y luego copias solo el binario o artefacto resultante a una imagen mínima de producción. Tu imagen final pasa de 1.2 GB a 80 MB sin perder funcionalidad.

Se define con varios FROM, cada uno arrancando una etapa nueva. Nombralas con FROM <imagen> AS <nombre> para que el COPY --from=<nombre> no se rompa si reordenas instrucciones. Si solo quieres construir hasta una etapa para depurar, docker build --target <etapa> -t app . hace exactly eso. BuildKit, que es el builder por defecto en versiones modernas, solo procesa las etapas necesarias, a diferencia del legacy builder que compilaba todo.

Seguridad en Imágenes y Contenedores

PrácticaQué hacer
Imágenes baseUsa imágenes oficiales mínimas. Menos paquetes instalados, menos superficie de ataque
EscaneoPasa Trivy o Docker Scout antes de pushear. Habitual
UsuarioNunca corras como root. Crea un usuario sin privilegios en el Dockerfile
FilesystemMonta como read-only cuando puedas: --read-only
FirmaActiva Docker Content Trust para verificar que las imágenes vienen de quien dicen venir

Docker Compose (Gestión de Aplicaciones Multi-Contenedor)

Docker maneja contenedores individuales. Compose orquesta varios que trabajan juntos. Lo defines todo en un YAML y levantas la aplicación entera con un comando. Para desarrollo local no hay nada mejor.

Si vienes de la V1, cambia el guion por espacio: docker compose en vez de docker-compose. La V1 dejó de recibir actualizaciones.

Estructura y Comandos Básicos de Compose

El archivo docker-compose.yml tiene tres bloques: servicios, redes y volúmenes.

# Nota: En las versiones más recientes de Docker Compose, la versión ya no es necesaria
# version: '3.8'  # Opcional en versiones modernas
services:
  service1: # Definición de contenedores/servicios
    # Configuración del servicio
networks:
  network1: # Configuración de redes personalizadas
    # Configuración de red
volumes:
  volume1: # Definición de volúmenes nombrados
    # Configuración de volumen
TareaComandoQué hace
Levantar tododocker compose upConstruye y ejecuta los contenedores del YAML
En backgrounddocker compose up -dIgual pero detached
Detenerdocker compose stopPara los contenedores sin borrarlos
Detener y borrardocker compose downElimina servicios y redes. No toca volúmenes
Borrar volúmenes tambiéndocker compose down -vTodo lo anterior más volúmenes nombrados
Escalardocker compose up --scale <svc>=nLevanta n réplicas de un servicio
Estadodocker compose psQué está corriendo
Logsdocker compose logsOutput de todos los servicios

Gestión de Datos Persistentes (Volúmenes)

Si no usas volúmenes, pierdes los datos cada vez que un contenedor se recrea. Esto incluye bases de datos, uploads de usuarios, lo que sea. No es opcional.

Los volúmenes nombrados se declaran en la sección volumes del YAML y se montan en cada servicio. Los bind mounts montan un directorio del host directamente: /ruta/host:/ruta/contenedor. Útiles en desarrollo para que los cambios en tu código se vean al instante.

TareaComando
Listar volúmenesdocker volume ls
Inspeccionardocker volume inspect <nombre>
Eliminardocker volume rm <nombre>
Limpiar sin usodocker volume prune

Buenas Prácticas Avanzadas de Producción con Compose

Gestión de Secretos y Variables de Entorno

Nunca, bajo ninguna circunstancia, pongas contraseñas o tokens en el Dockerfile o en el docker-compose.yml. Las capas de la imagen se guardan en el registro y cualquiera con acceso las puede leer.

Guarda todo en un archivo .env, referéncialo con env_file: .env en el YAML, y mete .env en .gitignore. Los secretos se cargan en runtime, no quedan en git.

Redes y Seguridad de Acceso

Los contenedores de un mismo Compose se ven entre sí por defecto. La base de datos puede hablar con la app sin exponer puertos al host.

Aquí va una práctica que me ahorró más de un susto: no publiques el puerto de la base de datos. Quita el ports: del servicio de Postgres. El contenedor seguirá escuchando en su puerto, pero no estará vinculado al host. Para acceder, haz un túnel SSH. Si el puerto no está mapeado, no está expuesto. Simple.

Límites de Recursos y Reinicios

En un servidor compartido, un contenedor sin límites puede comerse toda la RAM y tirar el resto de servicios. Define límites con deploy: resources:

Dentro de limits pones el techo: cpus: 1 y memory: 1GB, por ejemplo. En reservations pones lo mínimo garantizado. Para reinicios, restart: always asegura que todo vuelva si el servidor se cae o se reinicia. Si necesitas más control, puedes especificar condiciones como on-failure, retardos entre intentos y un máximo de reintentos.

Health Checks (Comprobaciones de Salud)

Un healthcheck le dice a Docker si tu contenedor realmente está sirviendo tráfico, no solo si el proceso está vivo. Si falla, Compose lo reinicia. Puedes configurar interval (frecuencia), retries (fallos antes de declararlo caído), timeout (tiempo máximo de espera) y start_period (margen inicial para que arranque).

Seguridad del Host y Buenas Prácticas Generales

El host donde corre Docker Engine también hay que endurecerlo:

Desactiva el login root por SSH. Es lo primero que hago en cualquier servidor nuevo. Usa claves RSA en vez de contraseñas: ssh-keygen para generar, ssh-copy-id usuario@servidor para copiar la pública. Instala Fail2Ban (apt install fail2ban) para que bloquee IPs con demasiados intentos fallidos contra el puerto SSH. Mantiene Docker Engine actualizado. Y monitoriza: registra logs, alerta cuando algo se cae, usa docker stats para vigilar recursos en tiempo real.

Conclusión

Docker y Compose son de esas herramientas que una vez que las dominas no las sueltas. Los comandos se aprenden con el uso. Lo que de verdad importa son las buenas prácticas: imágenes pequeñas, usuarios sin privilegios, secretos fuera del código, volúmenes para lo que importa.


Si ya te sientes cómodo con todo esto, el siguiente paso natural es Kubernetes. Pero eso es otra bestia totalmente distinta.