Módulo 1 · Fundamentos que sostienen todo

Lección 05 — Linux y terminal

Procesos, permisos, logs, variables de entorno, SSH y scripting para operar tu backend.

Publicada
En esta lección
  1. Ejercicio 1 — Anatomía de tus procesos
  2. Ejercicio 2 — Puertos y carga
  3. Ejercicio 3 — El pipeline de logs
  4. Ejercicio 4 — Permisos de verdad
  5. Ejercicio 5 — El.env bien hecho
  6. Ejercicio 6 — SSH local
  7. Ejercicio 7 — El script de operación
  8. Resumen del profesor

La terminal es la herramienta de diagnóstico definitiva: estos ejercicios son músculo, no teoría.


Ejercicio 1 — Anatomía de tus procesos

  1. El padre (arbiter) muestra el comando base gunicorn config.wsgi --bind 127.0.0.1:8000; los workers muestran [1]/[2] (o similar) tras el comando. El RSS del padre es pequeño; los workers cargan tu app (más memoria).
  2. Con SIGTERM el worker termina educadamente (acaba la petición en curso) y el arbiter lo reemplaza con un PID nuevo: el servicio no deja de responder ni un instante. Es el mecanismo del reload sin downtime.
  3. Con SIGKILL el worker muere sin limpiar: la petición en curso se corta (el cliente ve conexión cerrada) y el arbiter detecta al muerto y levanta otro. Diferencia clave: SIGTERM respeta lo que estaba haciendo; SIGKILL ni pregunta. Por eso los despliegues usan TERM y los orquestadores (systemd, Docker) esperan un graceful timeout antes de mandar KILL.

Ejercicio 2 — Puertos y carga

  1. Gunicorn (o runserver) en 8000; PostgreSQL en 5432; Redis en 6379. Si algo no aparece, ese es tu primer diagnóstico real.
  2. El consumo se reparte entre los 2 workers (y el runserver si no usaste Gunicorn: nota fina, runserver es de desarrollo y monohilo; los números no trasladan a producción). Los curl compiten entre sí; con 200 lanzados en paralelo verás contención en CPU o en la cola de aceptación del socket.
  3. Los tres números son carga en 1, 5 y 15 min. En una máquina de n núcleos, carga > n significa trabajo en espera. Tendencia: si 1min > 15min, el sistema va a peor ahora; la lectura en tendencia importa más que el valor puntual.

Ejercicio 3 — El pipeline de logs

  1. $9 es el noveno campo del log de acceso combinado: el código de estado HTTP. El pipeline responde "¿cuántas respuestas de cada código tengo?" — en un incidente, la primera pregunta: ¿200s dominan (todo bien) o 500s se disparan (bug nuestro)?
  2. Si el formato tiene la duración en el último campo (configurable en Nginx/Gunicorn):
bash
awk '{print $NF, $7}' access.log | sort -rn | head -5

(duración + ruta, ordenado descendente, top 5). Si tu log no tiene duración, añadirla es la mitad del ejercicio: sin dato no hay análisis — la misma idea que reaparece en la Lección 37 (perfilado).

Ejercicio 4 — Permisos de verdad

  1. Sí pudo: 644 da lectura a "otros", y app_test es "otro". Cualquier usuario del sistema lee tus secretos.
  2. Con 640 y grupo de la app: el dueño y ese grupo leen; el resto nada. Con 600: solo el dueño (más estricto: úsalo cuando no haya otra app del mismo grupo). La jerarquía que recordarás: cada bit que abres es un usuario del servidor que puede leer.
  3. chmod 600.env y dueño = usuario que corre la app (no root). Y en el service de systemd: User=ticketflow, así solo ese usuario (y root) puede leer el fichero.

Ejercicio 5 — El.env bien hecho

  1. Un env.example completo: los nombres son contratos; los valores, secretos. Si settings.py pide una variable que no está en el example, el onboarding de un compañero se rompe sin motivo.
  2. git check-ignore -v.env debe imprimir la regla que lo ignora (p. ej. .gitignore:6:.env). Si no imprime nada, tu .env es un accidente esperando commit.
  3. Si aparecieron secretos en el historial: rotar (cambiar la credencial en el proveedor) — borrar el commit no basta, el historial queda clonado. La rotación es la única reparación real. (Las herramientas para reescribir historia las verás en la Lección 06; la rotación sigue siendo imprescindible.)

Ejercicio 6 — SSH local

  1. Sí entró sin contraseña: tu pública quedó en ~/.ssh/authorized_keys y la privada demostró identidad. La contraseña dejan de pedirla (y puedes desactivar PasswordAuthentication en el servidor: la puerta de fuerza bruta se cierra).
  2. ssh localtest hostname funciona igual: el config mapea apodos a host/usuario/clave. Con 3 servidores ya no vives sin él.
  3. En el puerto 5433 escucha tu cliente ssh (proceso local), que reenvía lo que reciba por el túnel cifrado hasta el 5432 del servidor. Con una BD real remota: conectas tu psql/DBeaver a localhost:5433 y el tráfico viaja cifrado por SSH aunque la BD no esté expuesta a Internet — el patrón de depuración que usarás siempre.

Ejercicio 7 — El script de operación

  1. Con Gunicorn caído, el curl devuelve 000/refused → el script imprime FALLO y sale con exit 1 (que es lo que un monitor interpreta como alerta). Levantado: OK.
  2. Redis caído avisa pero no falla porque no tumba la web (la API sigue sirviendo; pierdes caché/cola, degradación no indisponibilidad). La API caída sí es fallo. Distinguir severidades es la diferencia entre un script y un instrumento de monitorización: el exit code es tu API con los sistemas de alerta.
  3. En producción: systemd timer (o cron) que ejecuta el script cada minuto y, si falla, un mecanismo de alerta (email, Slack, Prometheus — Lección 46). watch es el juguete; el timer es el juguete con logs, alerta y reinicio tras caída.

Resumen del profesor

  • Los procesos se operan con señales: TERM educado, KILL último recurso; el arbiter de Gunicorn es tu primer ejemplo de resiliencia.
  • Mínimo privilegio: usuario de sistema, 600 para secretos, y cada bit abierto es una puerta más.
  • El pipeline de logs responde "¿qué está pasando y cuántas veces?" en una línea de shell.
  • El entorno vive fuera del código; los secretos jamás en Git ni en logs; SSH con claves y túneles para depurar.
  • Si lo hiciste tres veces a mano, ya es un script. Si corre solo, ya es operación.

Cuando entregues, cerramos la 05 y pasamos a la Lección 06 — Git profesional: rebase, conflictos y el flujo de equipo que sostiene todo lo demás.