Docker para principiantes: concepto, instalación y primeros comandos en Windows, Mac y Linux
Docker para principiantes: concepto, instalación y primeros comandos en Windows, Mac y Linux
Introducción
Si alguna vez te encontraste con el problema de "en mi máquina funciona, pero en el servidor no", Docker es la solución que estabas buscando. En este tutorial vas a aprender qué es Docker, para qué sirve y cómo instalarlo en los tres sistemas operativos más usados: Windows, macOS y Linux. Además, verás ejemplos de comandos ejecutados en terminal con su salida esperada, para que puedas seguir paso a paso y comenzar a trabajar con contenedores de inmediato.
Este artículo está dirigido a desarrolladores, administradores de sistemas y cualquier persona interesada en empaquetar aplicaciones de forma portátil y reproducible. No se requieren conocimientos previos de virtualización, solo familiaridad básica con la línea de comandos.
Al finalizar, sabrás:
- Qué es un contenedor y cómo se diferencia de una máquina virtual.
- Cuál es la arquitectura de Docker (daemon, cliente, imágenes, registros).
- Cómo instalar Docker Desktop en Windows y macOS, y el motor Docker en las principales distribuciones Linux.
- Cómo ejecutar tus primeros contenedores, crear imágenes con Dockerfile y usar Docker Compose para aplicaciones multi‑contenedor.
- Buenas prácticas y errores comunes que debes evitar.
¿Qué es Docker?
Docker es una plataforma de código abierto que permite crear, desplegar y ejecutar aplicaciones dentro de contenedores ligeros. Un contenedor es un paquete estándar que incluye todo lo necesario para que un software se ejecute: código, runtime, bibliotecas, variables de entorno y archivos de configuración.
A diferencia de las máquinas virtuales, que emulan un hardware completo y requieren un sistema operativo invitado completo, los contenedores comparten el kernel del sistema operativo anfitrión y solo aíslan el espacio de usuario. Esto los hace mucho más rápidos de iniciar, más ligeros en consumo de recursos y más fáciles de mover entre entornos.
Ventajas principales
- Portabilidad: la misma imagen funciona en cualquier máquina con Docker instalado.
- Consistencia: elimina el problema de "funciona en mi máquina" porque el entorno es idéntico.
- Escalabilidad: puedes lanzar cientos de réplicas de un contenedor en segundos.
- Eficiencia: aprovecha mejor el hardware, ya que no hay overhead de un hipervisor completo.
- Integración con CI/CD: las imágenes se pueden almacenar en registros y desplegar automáticamente en pipelines.
Arquitectura básica
- Docker Daemon (dockerd): servicio que gestiona la creación, ejecución y monitoreo de contenedores.
- Docker Client (docker): la interfaz de línea de comandos que tú usas para comunicarte con el daemon.
- Imagen: plantilla de solo lectura que contiene el sistema de archivos y la configuración para lanzar un contenedor.
- Contenedor: instancia ejecutable de una imagen. Puede estar en ejecución o detenido.
- Registro (Registry): servidor donde se almacenan y distribuyen imágenes (por ejemplo, Docker Hub).
Cuando ejecutas docker run, el cliente le indica al daemon que descargue (si es necesario) la imagen desde el registro, cree un contenedor a partir de ella y lo ponga en marcha.
Instalación de Docker
En Windows
Docker Desktop for Windows incluye el daemon, la CLI y una interfaz gráfica. Requiere Windows 10 versión 1903 o superior con WSL 2 habilitado.
Habilitar WSL 2
Abre PowerShell como administrador y ejecuta:dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestartLuego reinicia el equipo.
Instalar un kernel de Linux actualizado
Descarga el paquete desde https://aka.ms/wsl2kernel y ejecútalo.Establecer WSL 2 como versión predeterminada
wsl --set-default-version 2Descargar e instalar Docker Desktop
Ve a https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe, ejecuta el instalador y sigue el asistente.Verificar la instalación
Abre PowerShell o CMD y ejecuta:docker versionSalida esperada (algo similar):
Client: Docker Engine - Community Version: 24.0.7 API version: 1.43 Go version: go1.22.5 Git commit: 1d8f0b3 Built: Thu Apr 25 20:12:34 2024 OS/Arch: windows/amd64 Context: default Server: Docker Engine - Community Version: 24.0.7 API version: 1.43 Go version: go1.22.5 Git commit: 1d8f0b3 Built: Thu Apr 25 20:12:34 2024 OS/Arch: linux/amd64
En macOS
Docker Desktop for macOS también usa una máquina ligera Linux basada en HyperKit.
- Requisitos: macOS 10.15 (Catalina) o superior, al menos 4 GB de RAM.
- Descargar: https://desktop.docker.com/mac/main/amd64/Docker.dmg
- Instalar: arrastra el ícono de Docker a la carpeta de Aplicaciones.
- Iniciar: abre Docker desde Launchpad; el daemon se inicia en segundo plano.
- Verificar: abre Terminal y ejecuta:Salida esperada (similar a la de Windows, pero con OS/Arch: darwin/amd64 o darwin/arm64 según tu CPU).
docker version
En Linux
En Linux puedes instalar el motor Docker (dockerd) directamente desde los repositorios de tu distribución o usar el script de conveniencia oficial.
Ubuntu/Debian
# 1. Actualizar el índice de paquetes
sudo apt-get update
# 2. Instalar paquetes necesarios para permitir el uso de repositorios HTTPS
sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release
# 3. Añadir la clave GPG oficial de Docker
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 4. Configurar el repositorio
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 5. Actualizar nuevamente e instalar Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 6. Verificar que el daemon está activo
sudo systemctl status dockerSalida esperada del último comando (activo):
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2024-06-01 10:15:00 CEST; 5min agoPara usar Docker sin sudo, agrega tu usuario al grupo docker:
sudo usermod -aG docker $USER
newgrp docker # o cierra y vuelve a abrir la sesiónLuego prueba:
docker run hello-worldSalida esperada:
Hello from Docker!
This message shows that your installation appears to be working correctly.
...Fedora
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl start docker
sudo systemctl enable dockerArch Linux
sudo pacman -Syu
sudo pacman -S docker
sudo systemctl start docker
sudo systemctl enable dockerPrimeros pasos con Docker
Una vez que Docker está instalado, lo primero es probar la imagen oficial hello-world.
docker run hello-worldSalida esperada (resumida):
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bashEjecutar un contenedor interactivo
docker run -it ubuntu bashLa opción -it combina -i (interactiva) y -t (TTY). Verás el prompt cambiar a algo como root@<container-id>:/#. Dentro puedes ejecutar comandos de Linux normalmente.
Ejemplo dentro del contenedor:
apt-get update && apt-get install -y cowsay
cowsay "¡Hola desde Docker!"Salida esperada:
_________________
< ¡Hola desde Docker! >
-----------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||Para salir del contenedor sin detenerlo, usa Ctrl+P Ctrl+Q. Para terminar y eliminar el contenedor, escribe exit o ejecuta desde otra terminal:
docker stop <container-id>
docker rm <container-id>Listar imágenes y contenedores
- Ver imágenes locales:
docker images
Salida esperada (ejemplo): REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 5 weeks ago 13.3kB
ubuntu latest 9c7d5f6a1b2c 3 days ago 77.8MB
- Ver contenedores en ejecución:
```run:bash
docker psSalida esperada (si ninguno está corriendo):
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES- Ver todos los contenedores (incluidos los detenidos):
docker ps -a
---
## Crear tu propia imagen con Dockerfile
Un `Dockerfile` es un archivo de texto que contiene instrucciones para construir una imagen. Vamos a crear una imagen simple que sirva una aplicación Flask.
### Paso 1: Crear el directorio del proyecto
```run:bash
mkdir -p ~/docker-flask && cd ~/docker-flaskPaso 2: Escribir la aplicación (app.py)
cat > app.py << 'EOF'
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello from Dockerized Flask!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
EOFPaso 3: Crear el Dockerfile
cat > Dockerfile << 'EOF'
# Usa la imagen oficial de Python como base
FROM python:3.12-slim
# Establece el directorio de trabajo dentro del contenedor
WORKDIR /app
# Copia solo el archivo de requerimientos primero para aprovechar caché
COPY requirements.txt .
# Instala dependencias
RUN pip install --no-cache-dir -r requirements.txt
# Copia el resto del código
COPY . .
# Expone el puerto que usará la aplicación
EXPOSE 5000
# Define el comando por defecto al iniciar el contenedor
CMD ["python", "app.py
]
EOFNota: las comillas simples dentro del
here-docevitan expansión de variables.
Paso 4: Crear el archivo de requerimientos
echo "flask" > requirements.txtPaso 5: Construir la imagen
docker build -t mi-flask-app .Salida esperada (fragmento):
Sending build context to Docker daemon 5.632kB
Step 1/7 : FROM python:3.12-slim
---> 8a69b636b6e5
Step 2/7 : WORKDIR /app
---> Using cache
---> 9d9b9b2f2b1c
Step 3/7 : COPY requirements.txt .
---> Using cache
---> e3b0c44298fc1c809afbfc41e140f5e4f21b2b3c5d6e7f8a9b0c1d2e3f4a5b6c
Step 4/7 : RUN pip install --no-cache-dir -r requirements.txt
---> Running in 9f8d7c6b5a4e
Collecting flask
Downloading Flask-3.0.3-py3-none-any.whl (101 kB)
...
Successfully installed Flask-3.0.3 Werkzeug-3.0.2 ...
Removing intermediate container 9f8d7c6b5a4e
---> 2b1a0c9d8e7f6g5h4i3j2k1l0m9n8o7p
Step 5/7 : COPY . .
---> Using cache
---> a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
Step 6/7 : EXPOSE 5000
---> Using cache
---> 7a8b9c0d1e2f3g4h5i6j7k8l9m0n1o2p
Step 7/7 : CMD ["python", "app.py
t]" ]
---> Using cache
---> 3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r
Successfully built 3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r
Successfully tagged mi-flask-app:latestPaso 6: Ejecutar el contenedor
docker run -d -p 5000:5000 --name flask-app mi-flask-app-dejecuta en modo detached (en segundo plano).-p 5000:5000mapea el puerto 5000 del contenedor al mismo puerto del host.--name flask-appasigna un nombre legible.
Salida esperada (ID del contenedor):
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6Probar la aplicación
Abre tu navegador y visita http://localhost:5000 o usa curl:
curl http://localhost:5000Salida esperada:
Hello from Dockerized Flask!"` (sin comillas).
### Detener y eliminar
```run:bash
docker stop flask-app
docker rm flask-appDocker Compose: orquestar múltiples contenedores
Cuando tu aplicación necesita más de un servicio (por ejemplo, una web y una base de datos), Docker Compose simplifica la definición y ejecución.
Instalación del plugin
En la mayoría de las instalaciones recientes, el plugin docker compose ya viene incluido. Verifica con:
docker compose versionSalida esperada:
Docker Compose version v2.24.5Ejemplo: Flask + Redis
Crearemos un proyecto que tenga una aplicación Flask que incremente un contador almacenado en Redis.
Estructura de archivos
myproject/
├── docker-compose.yml
├── app.py
└── requirements.txtapp.py
cat > app.py << 'EOF'
from flask import Flask
import redis
import os
app = Flask(__name__)
# Conexión a Redis usando el nombre del servicio definido en compose
r = redis.Redis(host=os.getenv('REDIS_HOST', 'redis'), port=6379, db=0)
@app.route('/')
def hello():
count = r.incr('hits')
return f'Hello! This page has been viewed {count} times.
'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
EOFrequirements.txt
echo -e "flask
redis" > requirements.txtdocker-compose.yml
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
environment:
- REDIS_HOST=redis
depends_on:
- redis
redis:
image: "redis:7-alpine"
ports:
- "6379:6379"
EOFConstruir y levantar
docker compose up --buildSalida esperada (fragmento):
[+] Building 0.3s (5/5) FINISHED
=> [internal] load build definition from Dockerfile
=> => transferring dockerfile: 32B
=> [internal] load .dockerignore
=> => transferring context: 2B
=> [internal] load metadata for docker.io/library/python:3.12-slim
=> [1/4] FROM docker.io/library/python:3.12-slim
=> [2/4] WORKDIR /app
=> [3/4] COPY requirements.txt .
=> [4/4] RUN pip install --no-cache-dir -r requirements.txt
=> exporting to image
=> => exporting layers
=> => writing image sha256:9f8d7c6b5a4e...
=> => naming to docker.io/library/myproject_web
[+] Running 2/2
✔ Container myproject-web-1 Started
✔ Container myproject-redis-1 StartedAhora visita http://localhost:5000 y verás el contador incrementarse en cada recarga.
Para detener y eliminar todo:
docker compose downBuenas prácticas y errores comunes
Buenas prácticas
- Usa imágenes oficiales y mantenidas siempre que sea posible (por ejemplo,
python:3.12-slimen lugar depython:latest). - Aprovecha la capa de caché: copia primero los archivos que cambian menos (como
requirements.txt) antes del código fuente. - Etiqueta tus imágenes con versiones semánticas (
mi-app:1.0.0) además delatest. - Mantén los contenedores efímeros: no guardes estado dentro del sistema de archivos del contenedor; usa volúmenes o bases de datos externas.
- Limita los privilegios: evita ejecutar procesos como
rootdentro del contenedor cuando no sea necesario (USERen Dockerfile). - Usa
.dockerignorepara excluir archivos innecesarios (como.git,node_modules, archivos de log) del contexto de construcción. - Monitoriza el tamaño: imágenes más pequeñas se descargan más rápido y reducen la superficie de ataque.
Errores comunes
- Olvidar exponer puertos: si no usas
-poEXPOSE, la aplicación no será accesible desde el host. - Usar rutas absolutas dentro del contenedor sin crear el directorio: siempre asegúrate de que el
WORKDIRexista o créalo conRUN mkdir -p /ruta. - Confundir
docker runcondocker start:runcrea un nuevo contenedor cada vez;startsolo reanuda uno detenido. - No limpiar imágenes y contenedores sin uso: ejecuta periódicamente
docker system prunepara liberar espacio. - Ejecutar bases de datos en modo de producción sin persistencia: recuerda montar un volumen (
-v ./data:/var/lib/postgresql/data) para que los datos sobrevivan a reinicios. - Usar
latesten producción: puede traer cambios inesperados; prefiera tags específicos.
Conclusión
Docker ha revolucionado la forma en que desarrollamos, probamos y desplegamos aplicaciones. En este tutorial aprendiste:
- Qué es Docker y por qué los contenedores son más ligeros y portátiles que las máquinas virtuales.
- Cómo instalar Docker en Windows, macOS y las distribuciones Linux más populares.
- Cómo ejecutar tu primer contenedor, trabajar con imágenes y contenedores mediante la CLI.
- Cómo crear una imagen personalizada usando un
Dockerfiley publicar un servicio web simple. - Cómo orquestar múltiples contenedores con Docker Compose, ilustrado con una aplicación Flask que usa Redis.
- Buenas prácticas para mantener tus imágenes seguras, pequeñas y eficientes, y los errores que más suelen aparecer al comenzar.
Con estas bases ya estás listo para empaquetar tus propios proyectos, crear entornos de desarrollo reproducibles y desplegar a escala en la nube o en tus propios servidores. El próximo paso podría ser explorar registros privados, integrar Docker en tus pipelines de CI/CD o aprender sobre orquestadores como Kubernetes para gestionar clústeres de contenedores a gran escala.
¡Así que manos a la obra y comienza a contenedorizar!
¿Te quedó alguna duda? Déjala en los comentarios y con gusto te ayudamos.
DUGLAS MORENO
Comentarios (0)
Sé el primero en comentar.