Contenedores de aplicación con Docker

Introducción

Docker es la plataforma de contenedores de aplicación más extendida. Permite empaquetar una aplicación y todas sus dependencias en una imagen portable que se ejecuta de forma idéntica en cualquier sistema con Docker instalado.

Instalación

Debian/Ubuntu


# Instalar desde el repositorio oficial de Docker
apt install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
  > /etc/apt/sources.list.d/docker.list

apt update
apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Añadir el usuario al grupo docker para no necesitar sudo
usermod -aG docker $USER
          

RHEL / Rocky Linux


dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
dnf install docker-ce docker-ce-cli containerd.io docker-compose-plugin
systemctl enable --now docker
          

Verificar instalación


docker version
docker info
docker run hello-world
          

Pasos recomendados tras la instalación

1. Ejecutar Docker sin sudo

Por defecto Docker requiere sudo. Para poder usarlo como usuario normal hay que añadirse al grupo docker:


sudo groupadd docker                  # crear el grupo si no existe
sudo usermod -aG docker $USER         # añadir el usuario actual

# Activar sin cerrar sesión:
newgrp docker

# Verificar que funciona sin sudo:
docker run hello-world
          

El grupo docker da privilegios equivalentes a root sobre el daemon. No añadir usuarios no confiables a este grupo.

2. Arranque automático con el sistema


sudo systemctl enable docker.service
sudo systemctl enable containerd.service

# Verificar que están habilitados
systemctl is-enabled docker
systemctl is-enabled containerd
          

3. Configurar el driver de logging

Por defecto Docker usa el driver json-file sin límite de tamaño, lo que puede llenar el disco. Se recomienda configurar rotación en /etc/docker/daemon.json:


{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
          

sudo systemctl reload docker
          

4. Configurar el almacenamiento de datos

Por defecto Docker almacena imágenes, contenedores y volúmenes en /var/lib/docker. Si el disco raíz es pequeño, se puede cambiar en /etc/docker/daemon.json:


{
  "data-root": "/mnt/disco-grande/docker"
}
          

sudo systemctl restart docker
docker info | grep "Docker Root Dir"
          

5. Limpiar recursos sin usar

Docker acumula imágenes, contenedores parados y volúmenes huérfanos. Conviene limpiar periódicamente:


docker system prune            # elimina contenedores parados, redes sin uso e imágenes colgantes
docker system prune -a         # también elimina imágenes sin contenedores asociados
docker system prune -a --volumes  # incluye volúmenes huérfanos (¡cuidado con datos!)
docker system df               # ver uso de espacio por Docker
          

Conceptos clave

  • Imagen: plantilla de solo lectura con el sistema de ficheros y metadatos del contenedor
  • Contenedor: instancia en ejecución de una imagen (con su capa de escritura)
  • Dockerfile: fichero de instrucciones para construir una imagen
  • Registry: repositorio de imágenes (Docker Hub, ghcr.io, registry privado)
  • Volumen: almacenamiento persistente fuera del ciclo de vida del contenedor
  • Red: red virtual que conecta contenedores entre sí o con el host

Comandos básicos

Imágenes


docker images                          # listar imágenes locales
docker pull nginx:latest               # descargar imagen de Docker Hub
docker rmi nginx:latest                # eliminar imagen
docker image prune                     # eliminar imágenes sin usar
docker image inspect nginx             # info detallada de una imagen
          

Contenedores


docker run nginx                       # crear y arrancar contenedor (primer plano)
docker run -d nginx                    # en segundo plano (detached)
docker run -d -p 8080:80 nginx         # mapear puerto host:contenedor
docker run -d --name mi-nginx nginx    # con nombre personalizado
docker run -it ubuntu bash             # interactivo con shell

docker ps                              # contenedores en ejecución
docker ps -a                           # todos (incluidos parados)
docker stop mi-nginx                   # parar contenedor
docker start mi-nginx                  # arrancar contenedor parado
docker restart mi-nginx                # reiniciar
docker rm mi-nginx                     # eliminar contenedor parado
docker rm -f mi-nginx                  # forzar eliminación
docker container prune                 # eliminar todos los parados

docker logs mi-nginx                   # ver logs
docker logs -f mi-nginx                # seguir logs en tiempo real
docker exec -it mi-nginx bash          # abrir shell en contenedor en ejecución
docker inspect mi-nginx                # info detallada del contenedor
docker stats                           # uso de recursos en tiempo real
          

Dockerfile

El Dockerfile define cómo se construye una imagen. Ejemplo para una app Node.js:


FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
          

Instrucciones más usadas:

  • FROM: imagen base
  • WORKDIR: directorio de trabajo dentro del contenedor
  • COPY / ADD: copiar ficheros al contenedor
  • RUN: ejecutar comandos durante la construcción
  • EXPOSE: documentar el puerto que usa la aplicación
  • ENV: variables de entorno
  • CMD / ENTRYPOINT: comando al arrancar el contenedor

docker build -t mi-app:1.0 .           # construir imagen
docker build -t mi-app:1.0 -f Dockerfile.prod .  # Dockerfile alternativo
docker push mi-usuario/mi-app:1.0     # publicar en Docker Hub
          

Volúmenes y bind mounts


# Volumen gestionado por Docker (persistente entre contenedores)
docker volume create mis-datos
docker run -d -v mis-datos:/var/lib/mysql mysql
docker volume ls
docker volume inspect mis-datos
docker volume rm mis-datos

# Bind mount (directorio del host montado en el contenedor)
docker run -d -v /home/user/datos:/app/datos nginx

# Montar solo lectura
docker run -d -v /etc/nginx/nginx.conf:/etc/nginx/nginx.conf:ro nginx
          

Redes


docker network ls                              # listar redes
docker network create mi-red                   # crear red bridge
docker run -d --network mi-red --name app nginx
docker run -d --network mi-red --name db postgres
# Los contenedores en la misma red se resuelven por nombre

docker network inspect mi-red
docker network connect mi-red otro-contenedor
docker network disconnect mi-red contenedor
          

Docker Compose

Docker Compose permite definir y gestionar aplicaciones multi-contenedor mediante un fichero YAML (compose.yaml).


# compose.yaml
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
    depends_on:
      - db

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secreto
    volumes:
      - datos-db:/var/lib/postgresql/data

volumes:
  datos-db:
          

docker compose up -d        # arrancar en segundo plano
docker compose down         # parar y eliminar contenedores
docker compose down -v      # también eliminar volúmenes
docker compose logs -f      # ver logs de todos los servicios
docker compose ps           # estado de los servicios
docker compose exec web sh  # shell en el contenedor web
          

Docker es la herramienta fundamental para el desarrollo y despliegue de aplicaciones modernas. Para entornos de producción a gran escala, se combina con orquestadores como Kubernetes o Docker Swarm.

Contenedores de sistema con LXC

Índice de la sección

Índice del curso