La cultura DevOps ha transformado radicalmente la forma en que las organizaciones desarrollan, despliegan y mantienen software. En el corazón de esta revolución se encuentra Linux, el sistema operativo que ejecuta más del 90% de los servidores en la nube y constituye la base de casi todas las herramientas del ecosistema DevOps moderno. Esta guía te lleva desde los fundamentos conceptuales hasta la práctica real con las herramientas que utilizan los equipos de ingeniería más avanzados del mundo.
🔄 ¿Qué es DevOps? Origen, principios y filosofía
DevOps es un movimiento cultural y un conjunto de prácticas que busca eliminar la barrera histórica entre los equipos de desarrollo (Dev) y operaciones (Ops). El término fue acuñado en 2009 por Patrick Debois tras organizar los primeros DevOpsDays en Gante, Bélgica, aunque las ideas que lo sustentan venían gestándose desde años antes en comunidades como Agile Infrastructure y el movimiento de Continuous Delivery.
Tradicionalmente, los desarrolladores escribían código y lo «lanzaban por encima del muro» al equipo de operaciones, que debía desplegarlo y mantenerlo en producción sin haber participado en su diseño. Este modelo generaba fricciones constantes: los desarrolladores querían cambios rápidos y los operadores querían estabilidad. DevOps propone que ambos objetivos no son incompatibles — al contrario, la estabilidad se logra precisamente mediante despliegues frecuentes, automatización exhaustiva y retroalimentación continua.
Los principios CALMS resumen la filosofía DevOps:
Automation — Automatizar todo lo que sea repetible: builds, tests, despliegues, infraestructura.
Lean — Eliminar desperdicios, limitar el trabajo en progreso, optimizar el flujo.
Measurement — Medir todo: tiempo de despliegue, tasa de fallos, tiempo de recuperación.
Sharing — Compartir conocimiento, herramientas, responsabilidades y aprendizajes.
Es importante entender que DevOps no es una herramienta, no es un puesto de trabajo específico y no es simplemente «automatizar cosas». Es un cambio de mentalidad que afecta a toda la organización. Las herramientas son medios para implementar esa mentalidad, no fines en sí mismos.
Foto: Pexels · Licencia libre
🐧 ¿Por qué Linux es el corazón del ecosistema DevOps?
No es casualidad que Linux domine el panorama DevOps. Hay razones técnicas, económicas y filosóficas profundas que explican esta hegemonía:
Dominio absoluto en servidores y nube: más del 90% de las cargas de trabajo en AWS, Google Cloud y Azure se ejecutan sobre Linux. Cuando un equipo DevOps automatiza infraestructura, está automatizando Linux. Los servicios administrados (Kubernetes, Lambda, Cloud Functions) también corren sobre kernels Linux internamente.
Naturaleza scriptable: Linux fue diseñado desde sus orígenes como un sistema operativo programable. Cada componente del sistema es un archivo de texto o un proceso que puede controlarse mediante líneas de comando. Esta filosofía Unix — «hacer una cosa bien y combinar herramientas mediante pipes» — es exactamente lo que necesita la automatización DevOps.
Contenedores nativos: Docker, Podman, containerd y todas las tecnologías de contenedores se basan en primitivas del kernel Linux: cgroups para limitar recursos, namespaces para aislar procesos, y overlay filesystems para gestionar capas de imágenes. Los contenedores en Windows son posibles gracias a WSL2, que ejecuta un kernel Linux real.
Ecosistema de herramientas nativo: la inmensa mayoría de herramientas DevOps (Ansible, Terraform, Jenkins, GitLab CI, Prometheus, Grafana, Kubernetes) fueron desarrolladas para Linux primero. Muchas ni siquiera tienen versión nativa para otros sistemas operativos.
Código abierto: la filosofía open source permite inspeccionar, modificar y auditar cada componente del stack. En un entorno donde la seguridad y la reproducibilidad son críticas, poder leer el código fuente de tu infraestructura no es un lujo — es una necesidad.
🤖 Automatización con scripts en Linux
La automatización es el primer pilar práctico de DevOps. En Linux, todo comienza con scripts de shell — secuencias de comandos que automatizan tareas repetitivas. Un ingeniero DevOps competente domina Bash como herramienta fundamental antes de pasar a herramientas de automatización más sofisticadas.
Los casos de uso más comunes para la automatización con scripts incluyen:
Backups: copias de seguridad de bases de datos, rotación de logs, sincronización con almacenamiento remoto.
Monitorización ligera: verificar uso de disco, comprobar que servicios están activos, alertar si un proceso consume demasiada memoria.
Despliegues simples: clonar repositorio, instalar dependencias, reiniciar servicio.
Limpieza: purgar imágenes Docker antiguas, eliminar archivos temporales, rotar certificados.
Veamos un ejemplo práctico de un script de despliegue real:
#!/bin/bash
set -euo pipefail # Salir ante errores, variables no definidas, fallos en pipes
# ══════════════════════════════════════════════════════
# Script de despliegue para aplicación web
# Uso: ./deploy.sh [entorno] (staging|production)
# ══════════════════════════════════════════════════════
ENTORNO="${1:-staging}"
APP_DIR="/opt/webapp"
REPO="git@github.com:empresa/webapp.git"
BRANCH="main"
LOG="/var/log/deploy-$(date +%Y%m%d-%H%M%S).log"
log() { echo "[$(date '+%H:%M:%S')] $1" | tee -a "$LOG"; }
log "🚀 Iniciando despliegue en $ENTORNO"
# 1. Verificar que estamos en el servidor correcto
if [[ "$ENTORNO" == "production" ]] && [[ "$(hostname)" != "prod-server" ]]; then
log "❌ Error: Este no es el servidor de producción"
exit 1
fi
# 2. Crear backup del estado actual
log "📦 Creando backup..."
tar czf "/backups/webapp-$(date +%Y%m%d%H%M).tar.gz" "$APP_DIR" 2>/dev/null || true
# 3. Actualizar código
log "📥 Actualizando código desde $BRANCH..."
cd "$APP_DIR"
git fetch origin
git checkout "$BRANCH"
git pull origin "$BRANCH"
# 4. Instalar dependencias
log "📚 Instalando dependencias..."
pip install -r requirements.txt --quiet
# 5. Ejecutar migraciones de base de datos
log "🗄️ Ejecutando migraciones..."
python manage.py migrate --noinput
# 6. Reiniciar servicio
log "🔄 Reiniciando servicio..."
sudo systemctl restart webapp
sleep 3
# 7. Health check
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health)
if [[ "$HTTP_CODE" == "200" ]]; then
log "✅ Despliegue exitoso — Health check OK ($HTTP_CODE)"
else
log "❌ Health check falló ($HTTP_CODE) — Iniciando rollback"
tar xzf "/backups/webapp-*.tar.gz" -C / 2>/dev/null
sudo systemctl restart webapp
exit 1
fi
Este script ilustra varias buenas prácticas DevOps: set -euo pipefail para fallar rápido, logging con timestamps, backups antes de cambios, y un health check automático con rollback si algo falla. Si necesitas profundizar en Bash, consulta nuestra guía completa de Bash scripting.
📦 Gestión de configuración: Ansible, Puppet y Chef
Cuando la automatización con scripts crece más allá de un puñado de servidores, necesitas herramientas de gestión de configuración. Estas herramientas permiten definir el estado deseado de tus servidores de forma declarativa y asegurar que todos los nodos converjan a ese estado, independientemente de su situación inicial.
Ansible es la herramienta más popular por su simplicidad: no requiere agente en los servidores remotos (usa SSH), se configura con archivos YAML legibles por humanos y tiene una curva de aprendizaje suave para cualquiera que ya domine Linux.
# playbook.yml — Configurar servidor web con Nginx
---
- name: Configurar servidor web
hosts: webservers
become: yes # Ejecutar como root
vars:
dominio: "ejemplo.com"
puerto: 443
tasks:
- name: Actualizar caché de paquetes
apt:
update_cache: yes
cache_valid_time: 3600
- name: Instalar Nginx
apt:
name: nginx
state: present
- name: Copiar configuración personalizada
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/{{ dominio }}
notify: Recargar Nginx
- name: Activar sitio
file:
src: /etc/nginx/sites-available/{{ dominio }}
dest: /etc/nginx/sites-enabled/{{ dominio }}
state: link
notify: Recargar Nginx
- name: Asegurar que Nginx está activo
systemd:
name: nginx
state: started
enabled: yes
handlers:
- name: Recargar Nginx
systemd:
name: nginx
state: reloaded
La diferencia clave entre Ansible y un script Bash es la idempotencia: puedes ejecutar este playbook 100 veces y el resultado será siempre el mismo. Si Nginx ya está instalado, Ansible no lo reinstala; si la configuración no ha cambiado, no recarga el servicio. Esta propiedad es fundamental para la automatización fiable.
Puppet: Con agente, DSL propio, muy maduro. Preferido en grandes empresas con miles de servidores.
Chef: Con agente, Ruby, muy flexible. Popular en entornos que ya usan Ruby extensivamente.
En 2026, Ansible domina el mercado con diferencia. Si estás empezando, es la elección recomendada.
⚡ CI/CD: Integración y entrega continua
CI/CD (Continuous Integration / Continuous Delivery) es quizá la práctica más transformadora de DevOps. La integración continua significa que cada cambio de código se integra al menos una vez al día en la rama principal, ejecutando automáticamente tests para detectar errores temprano. La entrega continua extiende este concepto: cada cambio que pasa los tests está listo para desplegarse en producción con un solo click (o automáticamente, en el caso de continuous deployment).
Las plataformas CI/CD más utilizadas en el ecosistema Linux son:
GitHub Actions: integrado nativamente en GitHub. Define workflows en archivos YAML que se ejecutan en runners Ubuntu. Es la opción más popular para proyectos open source y equipos que ya usan GitHub.
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: test_password
POSTGRES_DB: test_db
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Configurar Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- name: Instalar dependencias
run: |
pip install -r requirements.txt
pip install pytest coverage
- name: Ejecutar tests con cobertura
env:
DATABASE_URL: postgresql://postgres:test_password@localhost:5432/test_db
run: |
coverage run -m pytest tests/ -v
coverage report --fail-under=80
- name: Análisis estático
run: |
pip install flake8 mypy
flake8 src/ --max-line-length=120
mypy src/ --ignore-missing-imports
build-and-push:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t app:${{ github.sha }} .
- name: Push to registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login -u "${{ secrets.REGISTRY_USER }}" --password-stdin
docker tag app:${{ github.sha }} registry.example.com/app:latest
docker push registry.example.com/app:latest
GitLab CI/CD: integrado en GitLab, define pipelines en .gitlab-ci.yml. Muy popular en empresas que prefieren alojar su propia instancia de GitLab.
Jenkins: el veterano del CI/CD, extensible mediante plugins. Requiere más configuración inicial pero ofrece flexibilidad absoluta. Ideal para pipelines complejos con requisitos específicos.
🐳 Contenedores en producción
Los contenedores han revolucionado la forma en que empaquetamos y desplegamos aplicaciones. A diferencia de las máquinas virtuales, un contenedor comparte el kernel del host y solo aísla el espacio de usuario, lo que resulta en tiempos de arranque de milisegundos y una eficiencia de recursos drásticamente superior.
En un entorno DevOps real, no basta con saber construir un Dockerfile — necesitas entender cómo orquestar múltiples contenedores, gestionar su ciclo de vida y mantenerlos seguros en producción.
# Dockerfile multi-stage — Best practices para producción
# Stage 1: Build
FROM python:3.12-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# Stage 2: Runtime (imagen mínima)
FROM python:3.12-slim
WORKDIR /app
# Crear usuario no-root (seguridad)
RUN groupadd -r appuser && useradd -r -g appuser appuser
# Copiar solo las dependencias compiladas
COPY --from=builder /install /usr/local
COPY src/ ./src/
# Metadata
LABEL maintainer="devops@empresa.com"
LABEL version="1.0"
# Health check
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# Ejecutar como no-root
USER appuser
EXPOSE 8080
CMD ["python", "-m", "src.main"]
Este Dockerfile aplica varias buenas prácticas de producción: multi-stage build para reducir el tamaño de la imagen final, usuario no-root por seguridad, health check integrado, y separación clara entre compilación y ejecución.
Para gestionar múltiples contenedores, Docker Compose es la herramienta estándar en entornos de desarrollo y staging. Para producción a escala, Kubernetes (K8s) es el orquestador dominante. Puedes profundizar en estos temas en nuestra guía de Docker y contenedores en Linux.
Foto: Pexels · Licencia libre
📊 Monitorización y observabilidad
La monitorización es el sistema nervioso de una infraestructura DevOps. Sin visibilidad sobre lo que ocurre en producción, cualquier automatización es un acto de fe. La tendencia moderna va más allá de la simple monitorización y abraza el concepto de observabilidad, que se sustenta en tres pilares: métricas, logs y trazas.
Métricas con Prometheus y Grafana: Prometheus es un sistema de monitorización de código abierto diseñado para entornos dinámicos y contenerizados. Recopila métricas mediante un modelo pull (consulta periódicamente a los servicios) y las almacena en una base de datos de series temporales.
# prometheus.yml — Configuración básica
global:
scrape_interval: 15s # Cada 15 segundos
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
rule_files:
- "alerts/*.yml"
scrape_configs:
# Monitorizar Prometheus a sí mismo
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# Monitorizar servidores Linux con node_exporter
- job_name: 'linux-servers'
static_configs:
- targets:
- 'web-01:9100'
- 'web-02:9100'
- 'db-01:9100'
relabel_configs:
- source_labels: [__address__]
regex: '(.+):9100'
target_label: instance
# Monitorizar contenedores Docker
- job_name: 'docker'
static_configs:
- targets: ['cadvisor:8080']
Grafana se conecta a Prometheus como fuente de datos y permite crear dashboards visuales con gráficos en tiempo real, tablas, alertas y paneles personalizados. La combinación Prometheus + Grafana es el estándar de facto para monitorización en entornos Linux.
Herramientas de línea de comandos de Linux que todo DevOps debe dominar:
# Monitorización en tiempo real con herramientas nativas de Linux
# htop — Monitor de procesos interactivo (mejor que top)
htop --sort-key=PERCENT_CPU
# iostat — Estadísticas de I/O de disco
iostat -xz 1 5 # Extendido, cada 1s, 5 veces
# vmstat — Estadísticas de memoria virtual
vmstat 1 10 # Cada 1 segundo, 10 muestras
# ss — Conexiones de red (reemplaza a netstat)
ss -tlnp # TCP listening, numérico, con PID
# sar — System Activity Reporter (datos históricos)
sar -u 1 5 # CPU usage
sar -r 1 5 # Memory usage
sar -n DEV 1 5 # Network interfaces
# journalctl — Logs del sistema con systemd
journalctl -u nginx --since "1 hour ago" --no-pager
journalctl -p err -b # Solo errores desde el último boot
# dmesg — Mensajes del kernel
dmesg -T --level=err,warn | tail -20
Tráfico: Cantidad de demanda sobre el sistema (requests/segundo, transacciones).
Errores: Tasa de peticiones que fallan (HTTP 5xx, excepciones, timeouts).
Saturación: Qué tan «lleno» está el servicio (CPU, memoria, disco, cola de peticiones).
Monitorizar estas cuatro señales cubre el 90% de los problemas de producción.
📝 Gestión centralizada de logs
En un entorno con múltiples servidores y contenedores, revisar logs manualmente en cada máquina es inviable. La gestión centralizada de logs es una práctica DevOps esencial que consiste en recopilar todos los logs en un sistema centralizado donde pueden buscarse, filtrarse y correlacionarse.
El stack más popular para centralización de logs en Linux es el ELK Stack (Elasticsearch + Logstash + Kibana), aunque alternativas más ligeras como Loki + Grafana (de los creadores de Grafana) están ganando terreno rápidamente por su menor consumo de recursos.
# Configurar rsyslog para enviar logs a un servidor central
# /etc/rsyslog.d/50-remote.conf
# Formato JSON para facilitar el parseo
template(name="json-template"
type="list") {
constant(value="{")
constant(value="\"timestamp\":\"") property(name="timereported" dateFormat="rfc3339")
constant(value="\",\"host\":\"") property(name="hostname")
constant(value="\",\"severity\":\"") property(name="syslogseverity-text")
constant(value="\",\"facility\":\"") property(name="syslogfacility-text")
constant(value="\",\"message\":\"") property(name="msg" format="json")
constant(value="\"}\n")
}
# Enviar todos los logs al servidor central por TCP
*.* action(type="omfwd"
target="logserver.empresa.internal"
port="514"
protocol="tcp"
template="json-template"
queue.type="LinkedList"
queue.filename="remote_fwd"
queue.maxdiskspace="1g"
queue.saveonshutdown="on"
action.resumeRetryCount="-1")
La configuración anterior usa una cola persistente (queue.type="LinkedList") que garantiza que no se pierden logs aunque el servidor central esté temporalmente inaccesible. Este tipo de resiliencia es lo que distingue una configuración profesional de una amateur.
Para análisis de logs en línea de comandos, combinaciones como grep | awk | sort | uniq -c | sort -rn siguen siendo herramientas invaluables que todo profesional DevOps debe dominar.
🏗️ Infraestructura como código (IaC)
La Infraestructura como Código (Infrastructure as Code, IaC) es el principio de que toda la infraestructura — servidores, redes, balanceadores de carga, bases de datos, reglas de firewall — debe definirse y gestionarse mediante archivos de código versionados, no mediante clicks manuales en consolas web.
Terraform de HashiCorp es la herramienta IaC más utilizada. Permite definir infraestructura en un lenguaje declarativo (HCL) y gestionar su ciclo de vida completo: creación, modificación y destrucción.
# main.tf — Infraestructura completa de una aplicación web
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "empresa-terraform-state"
key = "webapp/terraform.tfstate"
region = "eu-west-1"
}
}
provider "aws" {
region = var.region
}
# VPC con subredes públicas y privadas
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.5.0"
name = "${var.proyecto}-vpc"
cidr = "10.0.0.0/16"
azs = ["${var.region}a", "${var.region}b"]
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.10.0/24", "10.0.20.0/24"]
enable_nat_gateway = true
single_nat_gateway = var.entorno == "staging" ? true : false
}
# Cluster ECS para contenedores
resource "aws_ecs_cluster" "main" {
name = "${var.proyecto}-${var.entorno}"
setting {
name = "containerInsights"
value = "enabled"
}
}
# Base de datos RDS
resource "aws_db_instance" "postgres" {
identifier = "${var.proyecto}-db-${var.entorno}"
engine = "postgres"
engine_version = "16.1"
instance_class = var.entorno == "production" ? "db.r6g.large" : "db.t3.medium"
allocated_storage = 100
max_allocated_storage = 500
storage_encrypted = true
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.db.id]
backup_retention_period = var.entorno == "production" ? 30 : 7
deletion_protection = var.entorno == "production" ? true : false
}
El beneficio fundamental de IaC es la reproducibilidad: puedes destruir y recrear tu infraestructura completa en minutos, lo que permite tener entornos de staging idénticos a producción. Además, al estar versionado en Git, cada cambio de infraestructura queda registrado con su autor, fecha y razón.
☸️ Kubernetes: orquestación de contenedores a escala
Kubernetes (K8s) es el sistema de orquestación de contenedores estándar de la industria. Desarrollado originalmente por Google y liberado como open source en 2014, gestiona el despliegue, escalado y operación de aplicaciones contenerizadas en clusters de servidores Linux.
Los conceptos fundamentales de Kubernetes que todo profesional DevOps debe conocer:
Pod: la unidad mínima de despliegue. Un pod contiene uno o más contenedores que comparten red y almacenamiento. Nunca se despliega un contenedor «suelto» en Kubernetes.
Deployment: define el estado deseado de tu aplicación (cuántas réplicas, qué imagen, qué recursos). Kubernetes trabaja continuamente para mantener ese estado.
Service: expone un conjunto de pods como un servicio de red estable. Los pods son efímeros (se crean y destruyen constantemente); el Service proporciona una IP y DNS fijos.
# deployment.yml — Despliegue de aplicación en Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
labels:
app: webapp
env: production
spec:
replicas: 3
selector:
matchLabels:
app: webapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # Zero downtime
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: registry.example.com/webapp:v2.1.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: webapp-svc
spec:
selector:
app: webapp
ports:
- port: 80
targetPort: 8080
type: ClusterIP
La configuración de RollingUpdate con maxUnavailable: 0 garantiza que siempre hay al menos 3 réplicas disponibles durante un despliegue, logrando zero downtime deployments. Las probes de liveness y readiness permiten a Kubernetes reiniciar automáticamente pods que fallen y dirigir tráfico solo a pods que estén listos para servir.
🔒 Seguridad DevOps (DevSecOps)
DevSecOps integra la seguridad como parte natural del ciclo DevOps, en lugar de tratarla como una fase separada al final del desarrollo. En Linux, esto implica endurecer los sistemas base, escanear imágenes de contenedores, gestionar secretos de forma segura y auditar continuamente la infraestructura.
Prácticas esenciales de seguridad en un entorno DevOps:
# Hardening básico de un servidor Linux para DevOps
# 1. Actualizar sistema
sudo apt update && sudo apt upgrade -y
# 2. Configurar firewall UFW
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
# 3. Desactivar login con contraseña SSH (solo claves)
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# 4. Configurar fail2ban
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
cat > /etc/fail2ban/jail.local << EOF
[sshd]
enabled = true
port = ssh
maxretry = 3
bantime = 3600
findtime = 600
EOF
sudo systemctl restart fail2ban
# 5. Escanear imagen Docker con Trivy
trivy image --severity HIGH,CRITICAL registry.example.com/webapp:latest
# 6. Audit de configuración con Lynis
sudo lynis audit system --quick
La gestión de secretos (contraseñas, API keys, certificados) es otro aspecto crítico. Nunca almacenes secretos en el código fuente o en variables de entorno sin cifrar. Herramientas como HashiCorp Vault, AWS Secrets Manager o los Sealed Secrets de Kubernetes proporcionan almacenamiento seguro y rotación automática de credenciales.
Para una guía detallada sobre seguridad en Linux, consulta nuestro artículo de seguridad básica en Linux.
🎯 Ejercicios prácticos progresivos
Objetivo: Crear un script Bash que monitorice el uso de CPU, memoria y disco de un servidor Linux, y envíe una alerta si algún recurso supera un umbral configurable.
Requisitos:
— El script debe aceptar umbrales como parámetros (ej:
./monitor.sh --cpu 80 --mem 90 --disk 85)— Debe generar un log con timestamp de cada check
— Si se supera un umbral, escribir una línea de alerta en un fichero de alertas
— Incluir opción
--cron que genere la línea de crontab necesaria para ejecutarlo cada 5 minutos
Ver solución del Ejercicio 1
#!/bin/bash
set -euo pipefail
# Defaults
CPU_THRESH=80
MEM_THRESH=90
DISK_THRESH=85
LOG_FILE="/var/log/sysmon.log"
ALERT_FILE="/var/log/sysmon-alerts.log"
CRON_MODE=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--cpu) CPU_THRESH="$2"; shift 2 ;;
--mem) MEM_THRESH="$2"; shift 2 ;;
--disk) DISK_THRESH="$2"; shift 2 ;;
--cron) CRON_MODE=true; shift ;;
*) echo "Uso: $0 [--cpu N] [--mem N] [--disk N] [--cron]"; exit 1 ;;
esac
done
if $CRON_MODE; then
echo "*/5 * * * * $(readlink -f "$0") --cpu $CPU_THRESH --mem $MEM_THRESH --disk $DISK_THRESH >> $LOG_FILE 2>&1"
exit 0
fi
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# CPU usage (promedio 1 segundo)
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print int($2 + $4)}')
# Memory usage
MEM_USAGE=$(free | awk '/Mem:/ {printf "%d", $3/$2 * 100}')
# Disk usage (partición raíz)
DISK_USAGE=$(df / | awk 'NR==2 {print int($5)}')
# Log
echo "[$TIMESTAMP] CPU=${CPU_USAGE}% MEM=${MEM_USAGE}% DISK=${DISK_USAGE}%" >> "$LOG_FILE"
# Alertas
ALERT=false
if [ "$CPU_USAGE" -ge "$CPU_THRESH" ]; then
echo "[$TIMESTAMP] ⚠️ ALERTA CPU: ${CPU_USAGE}% >= ${CPU_THRESH}%" >> "$ALERT_FILE"
ALERT=true
fi
if [ "$MEM_USAGE" -ge "$MEM_THRESH" ]; then
echo "[$TIMESTAMP] ⚠️ ALERTA MEM: ${MEM_USAGE}% >= ${MEM_THRESH}%" >> "$ALERT_FILE"
ALERT=true
fi
if [ "$DISK_USAGE" -ge "$DISK_THRESH" ]; then
echo "[$TIMESTAMP] ⚠️ ALERTA DISK: ${DISK_USAGE}% >= ${DISK_THRESH}%" >> "$ALERT_FILE"
ALERT=true
fi
$ALERT && echo "[$TIMESTAMP] Alertas generadas → $ALERT_FILE" || echo "[$TIMESTAMP] Todo OK"
Objetivo: Crear un Dockerfile multi-stage para una aplicación Python Flask que incluya: stage de build con instalación de dependencias, stage de producción con usuario no-root, health check integrado, y tamaño final inferior a 150MB.
Requisitos:
— La aplicación Flask debe tener un endpoint
/health que devuelva {"status": "ok"}— El Dockerfile debe usar
python:3.12-slim como imagen base— Incluir un
.dockerignore adecuado— Documentar los comandos para build y run
Ver solución del Ejercicio 2
# Dockerfile
FROM python:3.12-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
FROM python:3.12-slim
RUN groupadd -r flask && useradd -r -g flask flask
WORKDIR /app
COPY --from=builder /install /usr/local
COPY app.py .
RUN apt-get update && apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
USER flask
EXPOSE 5000
CMD ["python", "app.py"]
# app.py
# from flask import Flask, jsonify
# app = Flask(__name__)
# @app.route('/health')
# def health(): return jsonify(status='ok')
# app.run(host='0.0.0.0', port=5000)
# Build: docker build -t flask-app .
# Run: docker run -d -p 5000:5000 flask-app
# Check: docker inspect --format='{{.State.Health.Status}}' CONTAINER_ID
Objetivo: Diseñar un workflow de GitHub Actions que ejecute: lint (flake8), tests unitarios (pytest con cobertura mínima del 80%), build de imagen Docker, push a un registry, y deploy automático a staging cuando se hace merge a
develop.Pista: Usa
jobs con needs para crear dependencias entre stages, y if: github.ref == 'refs/heads/develop' para condicionar el deploy.
Ver solución del Ejercicio 3
# .github/workflows/full-pipeline.yml
name: Full CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.12' }
- run: pip install flake8
- run: flake8 src/ --max-line-length=120
test:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.12', cache: 'pip' }
- run: pip install -r requirements.txt pytest coverage
- run: |
coverage run -m pytest tests/ -v
coverage report --fail-under=80
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: docker build -t app:${{ github.sha }} .
- run: |
echo "${{ secrets.REGISTRY_PASS }}" | docker login -u "${{ secrets.REGISTRY_USER }}" --password-stdin
docker tag app:${{ github.sha }} registry.example.com/app:${{ github.sha }}
docker push registry.example.com/app:${{ github.sha }}
deploy-staging:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
steps:
- run: |
ssh deploy@staging "docker pull registry.example.com/app:${{ github.sha }} && \
docker-compose -f /opt/app/docker-compose.yml up -d"
🎓 Ruta profesional DevOps: del junior al senior
La carrera DevOps es una de las más demandadas y mejor remuneradas en el sector tecnológico. El perfil combina habilidades de administración de sistemas Linux, desarrollo de software, y gestión de infraestructura cloud. Aquí te presentamos una hoja de ruta realista:
Fase 1 — Fundamentos Linux (3-6 meses): Dominar la línea de comandos, scripting Bash, gestión de procesos, redes, permisos y administración de servicios con systemd. Sin una base sólida en Linux, todo lo demás se construye sobre arena.
Fase 2 — Control de versiones y CI/CD (2-3 meses): Dominar Git a nivel profesional (rebasing, cherry-pick, bisect). Implementar pipelines CI/CD con GitHub Actions o GitLab CI. Entender el concepto de trunk-based development.
Fase 3 — Contenedores y orquestación (3-4 meses): Docker a nivel profesional (multi-stage, networking, volumes, security scanning). Kubernetes básico: deployments, services, configmaps, secrets, ingress. Consulta nuestra guía de Docker y contenedores en Linux.
Fase 4 — Cloud e IaC (3-6 meses): Uno o dos proveedores cloud (AWS, GCP, Azure). Terraform para gestionar infraestructura. Ansible para configuración de servidores.
Fase 5 — Observabilidad y seguridad (2-3 meses): Stack de monitorización (Prometheus + Grafana). Gestión de logs (ELK o Loki). Principios de seguridad y hardening.
CKA (Certified Kubernetes Administrator): El estándar para demostrar competencia en Kubernetes.
Terraform Associate: Certificación oficial de HashiCorp para infraestructura como código.
RHCSA / RHCE: Las certificaciones Red Hat siguen siendo referencia para administración Linux.
LFCS (Linux Foundation): Certificación práctica de administración de sistemas Linux.
Consulta nuestra guía detallada de certificaciones Linux profesionales.
El salario de un ingeniero DevOps junior en España oscila entre 30.000-40.000€ anuales, mientras que un senior con experiencia en Kubernetes y cloud puede superar los 70.000-90.000€. En mercados internacionales (remoto), estas cifras se multiplican significativamente.
📚 Recursos y comunidades para seguir aprendiendo
El ecosistema DevOps evoluciona constantemente. Estos son los recursos más valiosos para mantenerse actualizado:
Libros fundamentales: The Phoenix Project (Gene Kim) — una novela que explica DevOps de forma práctica; Site Reliability Engineering (Google) — cómo Google gestiona sus sistemas a escala; The DevOps Handbook — la guía práctica definitiva con casos de estudio reales.
Plataformas de práctica: KodeKloud y A Cloud Guru ofrecen laboratorios interactivos de Kubernetes, Terraform y Docker. KillerCoda proporciona entornos de práctica gratuitos para Kubernetes. Play with Docker permite experimentar con contenedores directamente en el navegador.
Comunidades: r/devops y r/sysadmin en Reddit son comunidades activas con discusiones de calidad. DevOps Roadmap (roadmap.sh) ofrece una hoja de ruta visual actualizada. La CNCF (Cloud Native Computing Foundation) mantiene el CNCF Landscape, un mapa exhaustivo de todas las herramientas del ecosistema cloud native.
Si estás dando tus primeros pasos con Linux, te recomendamos empezar por nuestra guía de qué es Linux y seguir con la instalación de Ubuntu paso a paso antes de profundizar en temas DevOps.
⚠️ Errores frecuentes y buenas prácticas
Después de años trabajando con equipos DevOps, estos son los errores más comunes que se repiten y las prácticas que los previenen:
2. No tener rollback: Todo despliegue debe poder revertirse en minutos. Si tu pipeline no tiene rollback automático, no está listo para producción.
3. Ignorar los logs: Los logs son tu seguro de vida en producción. No rotar logs, no centralizarlos, o no monitorizarlos es negligencia profesional.
4. Secretos en el código: Contraseñas, API keys, certificados en repositorios Git — incluso en repos privados — es un fallo de seguridad gravísimo.
5. Servidores «snowflake»: Servidores configurados manualmente que nadie sabe reproducir. Si pierdes el servidor, pierdes el servicio.
6. No limitar recursos: Contenedores sin límites de CPU/memoria pueden consumir todo el host y causar cascadas de fallos.
7. Saltarse staging: Desplegar directamente en producción sin pasar por un entorno de staging idéntico es una ruleta rusa.
8. Herramientas antes que cultura: Comprar herramientas DevOps sin cambiar la cultura del equipo es como comprar un gimnasio sin intención de hacer ejercicio.
Las buenas prácticas que distinguen a un equipo DevOps maduro incluyen: documentar todo (especialmente el proceso de rollback), practicar chaos engineering (probar qué pasa cuando algo falla), mantener el principio de least privilege en accesos, y realizar retrospectivas después de cada incidente sin buscar culpables (blameless post-mortems).
❓ Preguntas frecuentes sobre Linux para DevOps: guía completa para dominar la infraestructura moderna
Las dudas más comunes respondidas de forma clara y directa.
💬 Foro de discusión
¿Tienes dudas sobre Linux para DevOps: guía completa para dominar la infraestructura moderna? Comparte tu pregunta con la comunidad.
Todavía no hay mensajes. ¡Sé el primero en participar!