15%

Ahorra 15%<\/span> en todos los servicios de hosting

Pon a prueba tus habilidades y obtén Descuento<\/span> en cualquier plan de hosting

Usa el código:

Skills
Comenzar
08.10.2024

Docker en Ubuntu: Guía Completa de Instalación y Uso

Docker es una plataforma de contenedorización de código abierto que empaqueta aplicaciones y sus dependencias en unidades aisladas y portátiles llamadas contenedores. A diferencia de las máquinas virtuales, los contenedores comparten el kernel del sistema operativo del host, lo que los hace significativamente más ligeros, más rápidos de iniciar y más eficientes en el uso de recursos — una distinción crítica para cualquiera que ejecute cargas de trabajo en un entorno de VPS Hosting donde los recursos de cómputo afectan directamente el costo y el rendimiento.

Esta guía cubre el proceso completo de instalación de Docker en Ubuntu 20.04, 22.04 y 24.04 LTS, incluyendo el fortalecimiento posterior a la instalación, flujos de trabajo de Docker Compose y patrones de comandos relevantes para producción que la mayoría de los tutoriales omiten.

Requisitos previos y requisitos del sistema

Antes de ejecutar un solo comando, verifique lo siguiente:

  • Versión de Ubuntu: 20.04 LTS (Focal), 22.04 LTS (Jammy) o 24.04 LTS (Noble). El comando `lsb_release -cs` utilizado durante la configuración del repositorio detectará automáticamente su nombre en clave.
  • Arquitectura: `amd64`, `arm64` o `armhf` son compatibles con el repositorio oficial de Docker.
  • Versión del kernel: Docker requiere el kernel de Linux 3.10 o superior. Ejecute `uname -r` para confirmarlo.
  • Privilegios de usuario: `sudo` o acceso root es obligatorio para la instalación y la gestión del daemon.
  • Espacio en disco: Como mínimo 2 GB libres en la partición que aloja `/var/lib/docker`, que es donde Docker almacena imágenes, contenedores, volúmenes y caché de compilación. En sistemas de producción, monte este directorio en una partición o volumen dedicado.

Paso crítico previo a la instalación: Si anteriormente instaló Docker desde el repositorio `apt` predeterminado de Ubuntu (el paquete `docker.io`), elimínelo primero para evitar conflictos con los paquetes oficiales de Docker CE:

“`bash

sudo apt remove docker docker-engine docker.io containerd runc

“`

Paso 1: Actualizar los paquetes del sistema

Actualice el índice de paquetes y los paquetes instalados a sus últimas versiones antes de agregar cualquier repositorio nuevo:

“`bash

sudo apt update

sudo apt upgrade -y

“`

Esto garantiza que el resolvedor de dependencias de `apt` trabaje con los metadatos de paquetes actuales y que las bibliotecas base del sistema no estén desactualizadas — una fuente común de errores sutiles en tiempo de ejecución con aplicaciones en contenedores.

Paso 2: Instalar Docker Engine desde el repositorio oficial

Los repositorios `apt` predeterminados de Ubuntu incluyen un paquete llamado `docker.io`, que es mantenido por Canonical y generalmente va varias versiones por detrás de la versión oficial de Docker. Para uso en producción, instale siempre desde el repositorio propio de Docker.

2.1 Instalar dependencias de transporte y verificación

“`bash

sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release -y

“`

¿Por qué `gnupg`? A partir de Ubuntu 22.04, `gpg` no siempre está presente de forma predeterminada. Incluirlo explícitamente evita que la importación de la clave GPG falle silenciosamente.

2.2 Agregar la clave GPG oficial de Docker

“`bash

sudo install -m 0755 -d /usr/share/keyrings

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg –dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg

“`

El paso `chmod a+r` se omite con frecuencia en los tutoriales, pero es necesario en sistemas donde `apt` se ejecuta bajo un contexto de usuario restringido — sin él, el gestor de paquetes no puede leer el llavero y generará un error `NO_PUBKEY` durante `apt update`.

2.3 Agregar el repositorio estable de Docker

“`bash

echo

"deb [arch=$(dpkg –print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg]

https://download.docker.com/linux/ubuntu

$(lsb_release -cs) stable" |

sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

“`

La sustitución `arch=$(dpkg –print-architecture)` es esencial en servidores basados en ARM. Codificar `amd64` aquí es un error común que provoca fallos silenciosos en la resolución de paquetes en instancias ARM.

2.4 Instalar Docker Engine, CLI y plugins

“`bash

sudo apt update

sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

“`

Desglose de paquetes:

PaqueteFunción
`docker-ce`Daemon de Docker Engine (`dockerd`)
`docker-ce-cli`CLI del cliente (comando `docker`)
`containerd.io`Runtime de contenedores de bajo nivel (compatible con OCI)
`docker-buildx-plugin`Capacidades de compilación extendidas (multiplataforma, BuildKit)
`docker-compose-plugin`Compose V2 integrado como plugin de CLI de Docker

Nota sobre `containerd.io`: No es lo mismo que el paquete `containerd` en el repositorio predeterminado de Ubuntu. El `containerd.io` de Docker es una versión específica y probada del runtime containerd. Mezclar ambos es una causa conocida de fallos al iniciar el daemon.

Paso 3: Verificar la instalación

Confirme que el daemon está activo y habilitado para iniciarse al arrancar:

“`bash

sudo systemctl status docker

sudo systemctl enable docker

“`

Verifique la versión instalada:

“`bash

sudo docker –version

sudo docker info

“`

`docker info` es más informativo que `–version` solo — revela el controlador de almacenamiento en uso (generalmente `overlay2`), el controlador cgroup (`systemd` vs `cgroupfs`), y el número de CPUs y memoria a los que Docker puede acceder.

Ejecute la prueba de humo canónica:

“`bash

sudo docker run hello-world

“`

Una ejecución exitosa imprime un mensaje “Hello from Docker!” y confirma que el daemon de Docker, la descarga de imágenes desde Docker Hub y la ejecución de contenedores funcionan correctamente.

Paso 4: Configurar Docker para acceso sin root

De forma predeterminada, el socket de Docker (`/var/run/docker.sock`) es propiedad de `root` y del grupo `docker`. Cualquier usuario que no esté en el grupo `docker` debe usar `sudo` para cada comando de Docker.

“`bash

sudo usermod -aG docker $USER

“`

Aplique la membresía de grupo sin cerrar sesión:

“`bash

newgrp docker

“`

Verifique:

“`bash

docker run hello-world

“`

Advertencia de seguridad: La membresía en el grupo `docker` es efectivamente equivalente a `sudo` sin contraseña. Un usuario en el grupo `docker` puede montar trivialmente el sistema de archivos del host en un contenedor y eludir todos los controles de acceso a nivel de sistema de archivos. En sistemas multiusuario o servidores compartidos, considere usar Docker rootless en su lugar:

“`bash

dockerd-rootless-setuptool.sh install

“`

El modo rootless ejecuta el daemon de Docker y los contenedores bajo un espacio de nombres de usuario sin privilegios, reduciendo drásticamente la superficie de ataque. Es la configuración recomendada para cualquier entorno donde múltiples usuarios comparten el mismo host.

Paso 5: Referencia de comandos esenciales de Docker

Gestión de imágenes

“`bash

Pull a specific image version from Docker Hub

docker pull nginx:1.27-alpine

List locally cached images

docker images

Remove a specific image

docker rmi nginx:1.27-alpine

Remove all dangling (untagged) images to reclaim disk space

docker image prune

Remove all unused images (not just dangling)

docker image prune -a

“`

Consejo para producción: Siempre descargue etiquetas con versión (p. ej., `nginx:1.27-alpine`) en lugar de `latest` en cualquier flujo de trabajo automatizado o de producción. La etiqueta `latest` es mutable — puede apuntar a una imagen diferente después de un push al registro, rompiendo la reproducibilidad.

Ciclo de vida de los contenedores

“`bash

Run a container interactively with a pseudo-TTY

docker run -it ubuntu:22.04 /bin/bash

Run a container in detached mode with port mapping and a name

docker run -d -p 8080:80 –name my-nginx nginx:1.27-alpine

List running containers

docker ps

List all containers (including stopped)

docker ps -a

Stop a running container gracefully (SIGTERM, then SIGKILL after timeout)

docker stop my-nginx

Start a stopped container

docker start my-nginx

Remove a stopped container

docker rm my-nginx

Force-remove a running container (sends SIGKILL immediately)

docker rm -f my-nginx

View real-time logs

docker logs -f my-nginx

Execute a command inside a running container

docker exec -it my-nginx /bin/sh

“`

Inspección de recursos y del sistema

“`bash

Display real-time resource usage statistics

docker stats

Inspect detailed container metadata (JSON)

docker inspect my-nginx

Display disk usage by Docker objects

docker system df

Remove all stopped containers, unused networks, dangling images, and build cache

docker system prune

“`

`docker system prune` es uno de los comandos de mantenimiento más importantes para servidores de larga duración. Sin una limpieza periódica, la caché de compilación de Docker y los contenedores detenidos pueden consumir decenas de gigabytes en un host de desarrollo o CI activo.

Paso 6: Docker Compose — Orquestación de aplicaciones multicontenedor

Docker Compose V2 (el `docker-compose-plugin` instalado anteriormente) se invoca como `docker compose` (con un espacio), no el legado `docker-compose` (con un guion). Ambas sintaxis funcionan si tiene el plugin instalado, pero V2 es el estándar actual.

6.1 Comprensión de la estructura del archivo Compose

Cree un directorio de proyecto y un archivo `compose.yml` (el nombre de archivo preferido en Compose V2; `docker-compose.yml` sigue siendo compatible por retrocompatibilidad):

“`bash

mkdir ~/my-web-app && cd ~/my-web-app

nano compose.yml

“`

Un ejemplo realista para producción con Nginx y un servicio backend:

“`yaml

services:

web:

image: nginx:1.27-alpine

ports:

  • "8080:80"

volumes:

  • ./nginx.conf:/etc/nginx/nginx.conf:ro
  • ./html:/usr/share/nginx/html:ro

depends_on:

  • app

restart: unless-stopped

app:

image: node:20-alpine

working_dir: /usr/src/app

volumes:

  • ./app:/usr/src/app

command: node server.js

environment:

  • NODE_ENV=production

restart: unless-stopped

“`

Explicación de las directivas clave de Compose:

  • `restart: unless-stopped` — El contenedor se reinicia automáticamente después de un fallo o reinicio del sistema, a menos que el operador lo haya detenido explícitamente. Esta es la política correcta para servicios de larga duración; `always` reiniciará incluso los contenedores detenidos intencionalmente.
  • `depends_on` — Controla el orden de inicio pero no espera a que el servicio esté *listo* (p. ej., una base de datos aceptando conexiones). Para el control de disponibilidad, use `healthcheck` combinado con `condition: service_healthy`.
  • `volumes` con `:ro` — Montar archivos de configuración como solo lectura evita que un proceso de contenedor comprometido modifique su propia configuración.

6.2 Comandos del flujo de trabajo de Compose

“`bash

Start all services in detached mode

docker compose up -d

View logs for all services

docker compose logs -f

View logs for a specific service

docker compose logs -f web

List running Compose services

docker compose ps

Scale a specific service to multiple replicas

docker compose up -d –scale app=3

Stop services without removing containers

docker compose stop

Stop and remove containers, networks, and volumes

docker compose down –volumes

Rebuild images before starting (useful after code changes)

docker compose up -d –build

“`

6.3 Verificar el servicio en ejecución

“`bash

curl -I http://localhost:8080

“`

Una respuesta `200 OK` confirma que Nginx está sirviendo correctamente. Para servicios que se ejecutan en una instancia remota de VPS Hosting, reemplace `localhost` con la dirección IP pública de su servidor y asegúrese de que el puerto correspondiente esté abierto en su firewall (`ufw allow 8080/tcp`).

Paso 7: Fundamentos de redes en Docker

Comprender el modelo de redes de Docker es esencial para construir aplicaciones multicontenedor que se comuniquen de forma segura.

Controladores de red predeterminados:

ControladorCaso de uso
`bridge`Predeterminado para contenedores independientes; espacio de nombres de red aislado en el host
`host`El contenedor comparte la pila de red del host; máximo rendimiento, cero aislamiento
`none`Sin acceso a la red; útil para procesamiento por lotes o cargas de trabajo sensibles a la seguridad
`overlay`Redes multihost para clústeres Docker Swarm
`macvlan`Asigna una dirección MAC al contenedor; aparece como un dispositivo físico en la red

Creación y uso de una red bridge personalizada:

“`bash

Create an isolated network

docker network create my-app-network

Run containers attached to the custom network

docker run -d –name db –network my-app-network postgres:16-alpine

docker run -d –name api –network my-app-network my-api-image

Containers on the same custom bridge network can resolve each other by name

Inside 'api', you can connect to 'db' using the hostname 'db'

“`

Las redes bridge personalizadas proporcionan resolución DNS automática entre contenedores por nombre de contenedor. La red `bridge` predeterminada no lo hace — esta es una distinción crítica que provoca fallos de conexión cuando los desarrolladores asumen que los contenedores en la red predeterminada pueden comunicarse entre sí por nombre.

Paso 8: Datos persistentes con volúmenes de Docker

Los contenedores son efímeros por diseño. Cualquier dato escrito dentro del sistema de archivos de un contenedor se pierde cuando el contenedor es eliminado. Para almacenamiento persistente, use volúmenes o bind mounts.

“`bash

Create a named volume

docker volume create pgdata

Use the volume with a container

docker run -d

–name postgres-db

-e POSTGRES_PASSWORD=securepassword

-v pgdata:/var/lib/postgresql/data

postgres:16-alpine

List volumes

docker volume ls

Inspect a volume (shows mount point on host)

docker volume inspect pgdata

Remove unused volumes

docker volume prune

“`

Volúmenes vs. bind mounts:

CaracterísticaVolumen con nombreBind Mount
Gestionado por DockerNo
Requiere ruta del hostNo
Portable entre hostsSí (con controladores de volumen)No
Ideal paraDatos de bases de datos, estado de aplicacionesCódigo de desarrollo, archivos de configuración
Mecanismo de respaldo`docker run –volumes-from`Herramientas estándar del sistema de archivos

Paso 9: Mantener Docker actualizado

El repositorio oficial de Docker gestiona las actualizaciones a través del mecanismo estándar `apt`:

“`bash

sudo apt update

sudo apt upgrade -y

“`

Para actualizar solo los paquetes relacionados con Docker sin actualizar todo el sistema:

“`bash

sudo apt install –only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

“`

Consulte las notas de la versión de Docker antes de actualizaciones de versiones principales, especialmente para cambios en el controlador de almacenamiento, el manejo de versiones de cgroup o versiones de API obsoletas que puedan afectar los archivos `compose.yml` existentes.

Docker vs. enfoques alternativos de contenedorización

CaracterísticaDocker EnginePodmanLXC/LXDcontainerd (independiente)
Arquitectura del daemonDaemon centralizadoSin daemonBasado en daemonBasado en daemon
Soporte rootlessSí (v20+)NativoLimitado
Soporte de Docker ComposeNativoMediante `podman-compose`NoNo
Cumplimiento OCINo (formato LXC)
Integración con KubernetesMediante shim CRI-dockerdCRI nativoNoCRI nativo
Soporte Windows/macOSDocker DesktopLimitadoNoNo
Mejor opción paraDesarrollo general y producciónEnfocado en seguridad, rootlessContenedores de sistema, VMsNodos de Kubernetes

Para equipos que ejecutan cargas de trabajo en contenedores a escala en bare metal, un entorno de Servidores Dedicados le brinda control total sobre los parámetros del kernel, la programación de I/O de almacenamiento y la configuración de red — todo lo cual afecta directamente la densidad de contenedores y el rendimiento.

Lista de verificación de fortalecimiento para producción

Antes de ejecutar Docker en un entorno de producción, aborde lo siguiente:

Configuración del daemon (`/etc/docker/daemon.json`):

“`json

{

"log-driver": "json-file",

"log-opts": {

"max-size": "10m",

"max-file": "3"

},

"storage-driver": "overlay2",

"userns-remap": "default",

"live-restore": true,

"no-new-privileges": true

}

“`

  • `log-opts` con `max-size` y `max-file`: Sin rotación de registros, los archivos de registro JSON de Docker llenarán su disco. Esta es una de las causas más comunes de interrupciones inesperadas del servidor en hosts con contenedores.
  • `userns-remap: "default"`: Habilita la reasignación de espacios de nombres de usuario, de modo que el root del contenedor (UID 0) se mapea a un UID sin privilegios en el host.
  • `live-restore: true`: Permite que los contenedores sigan ejecutándose si el daemon de Docker falla o se reinicia durante una actualización — crítico para el mantenimiento sin tiempo de inactividad.
  • `no-new-privileges: true`: Evita que los procesos del contenedor obtengan privilegios adicionales mediante binarios `setuid` o `setgid`.

Consideraciones de red y firewall:

Docker manipula `iptables` directamente y omite las reglas de `ufw` de forma predeterminada. Un contenedor con un puerto publicado (`-p 8080:80`) será accesible desde internet incluso si `ufw deny 8080` está configurado. Para aplicar las reglas de `ufw` sobre la manipulación de `iptables` de Docker, agregue `"iptables": false` a `daemon.json` y gestione el enrutamiento manualmente, o use `–network host` de Docker con reglas `ufw` explícitas.

Para proyectos que requieren terminación HTTPS, combine su aplicación en contenedor con un proxy inverso correctamente configurado (Nginx o Traefik) y un certificado válido. Los Certificados SSL son un requisito previo para cualquier servicio web en producción que se ejecute detrás de una pila en contenedores.

Si su carga de trabajo implica inferencia de aprendizaje automático, servicio de modelos o procesamiento de datos acelerado por GPU dentro de contenedores, el NVIDIA Container Toolkit se integra directamente con Docker Engine. El GPU Hosting proporciona el hardware subyacente necesario para estas cargas de trabajo.

Para equipos que gestionan múltiples proyectos con administración de contenedores basada en web, el VPS con cPanel ofrece un entorno de panel de control administrado que puede complementar las implementaciones basadas en Docker para pilas de aplicaciones más simples.

Conclusiones técnicas clave y matriz de decisión

Cuándo usar Docker en un VPS vs. un servidor dedicado:

  • Use un VPS para entornos de desarrollo, staging y cargas de trabajo de producción de tráfico bajo a medio donde la densidad de contenedores es de 10 a 50 contenedores.
  • Use un servidor dedicado cuando la densidad de contenedores supere las 50 instancias, cuando necesite un rendimiento de I/O predecible (sin efecto de vecino ruidoso), o cuando se requiera ajuste de parámetros del kernel (`sysctl`) para su carga de trabajo.

Lista de verificación operativa antes de entrar en producción:

  • Configure la rotación de registros en `daemon.json` (`max-size`, `max-file`)
  • Habilite `live-restore` para sobrevivir a reinicios del daemon sin tiempo de inactividad de los contenedores
  • Use volúmenes con nombre, no bind mounts, para datos de servicios con estado
  • Fije versiones de imágenes en todos los archivos `compose.yml` — nunca use `latest` en producción
  • Habilite `userns-remap` o ejecute Docker rootless en hosts multiusuario
  • Audite las reglas `iptables` después de la instalación de Docker para confirmar que la política del firewall no está siendo eludida
  • Establezca `restart: unless-stopped` en todos los servicios de larga duración
  • Ejecute `docker system prune` en un trabajo cron programado para prevenir el agotamiento del disco
  • Use redes bridge personalizadas para toda la comunicación entre contenedores — nunca dependa del bridge predeterminado para el descubrimiento de servicios

Preguntas frecuentes

¿Docker en Ubuntu usa `systemd` o `cgroupfs` como controlador cgroup de forma predeterminada?

Desde Docker Engine 20.10, el controlador cgroup predeterminado en sistemas basados en `systemd` (incluidas todas las versiones modernas de Ubuntu LTS) es `systemd`. Esto se alinea con los requisitos de Kubernetes y evita la inestabilidad causada por ejecutar dos gestores de cgroup simultáneamente. Puede verificarlo con `docker info | grep -i cgroup`.

¿Cuál es la diferencia entre `docker compose down` y `docker compose stop`?

`docker compose stop` detiene los contenedores en ejecución pero los conserva junto con sus redes asociadas. `docker compose down` detiene los contenedores y luego los elimina junto con las redes creadas por Compose. Agregar `–volumes` a `down` también elimina los volúmenes con nombre definidos en el archivo Compose — use este indicador con precaución en producción, ya que elimina permanentemente los datos persistentes.

¿Por qué Docker omite las reglas del firewall `ufw` en Ubuntu?

Docker inserta sus propias reglas `iptables` en las cadenas `DOCKER` y `DOCKER-USER`, que se evalúan antes que las reglas de la cadena `INPUT` de `ufw`. Esto significa que un puerto publicado con `-p` es accesible desde internet independientemente de la política de `ufw`. La mitigación correcta es agregar reglas directamente a la cadena `DOCKER-USER`, o vincular los puertos publicados a una interfaz específica (p. ej., `-p 127.0.0.1:8080:80`) cuando no se requiere acceso externo.

¿Cómo limito la CPU y la memoria que puede consumir un contenedor Docker?

Use indicadores de restricción de recursos en tiempo de ejecución: `docker run –memory="512m" –cpus="1.5" my-image`. En Compose, configúrelos bajo la clave `deploy.resources` (Compose V2) o las claves de nivel superior `mem_limit` y `cpus`. Sin límites, un solo contenedor descontrolado puede agotar los recursos del host y derribar todos los demás contenedores en el mismo host.

¿Puedo ejecutar Docker dentro de un contenedor Docker (Docker-in-Docker)?

Sí, pero está fuertemente desaconsejado para uso en producción. El patrón común para pipelines de CI es montar el socket Docker del host (`-v /var/run/docker.sock:/var/run/docker.sock`) en el contenedor de CI, lo que le da al contenedor control total sobre el daemon Docker del host — un riesgo de seguridad significativo. Una alternativa más segura es usar el indicador `–allow security.insecure` de BuildKit o herramientas diseñadas específicamente como Kaniko o Buildah, que construyen imágenes OCI sin requerir un daemon Docker.

15%

Ahorra 15%<\/span> en todos los servicios de hosting

Pon a prueba tus habilidades y obtén Descuento<\/span> en cualquier plan de hosting

Usa el código:

Skills
Comenzar