Saltar a contenido

Fase 0 — Preparación

Objetivo

Tener el repo clonado, Ansible operativo, inventario validado y (opcional) un informe de hardware medido antes de tocar red o clústeres.

Qué aprendes

Cómo Ansible usa un inventario como fuente de verdad de hosts, y por qué un discovery opcional evita suposiciones sobre RAM, disco y arquitectura al elegir roles (control-plane, Longhorn, etc.).

Stack de esta fase

flowchart LR
  Op[Operador] --> Repo[Repo_homelab]
  Op --> Ansible[Ansible]
  Ansible --> Inv[inventory.ini]
  Ansible --> Disc[playbook_discovery]
  Disc --> Reports[reports_md]
  • Ansible — Orquestador de bootstrap; Fase 0–3.
  • Debian — SO en invincible, oliver y deborah.

Profundización: Discovery de hardware · Inventario

Antes de empezar

  • Tres nodos accesibles por SSH (aunque aún con DHCP está bien).
  • Python 3.11+ en tu estación.
  • Clave SSH (Secure Shell) configurada hacia los nodos.
  • GitHub: la organización symintel creada, con un team devops (sus miembros son quienes pueden entrar a ArgoCD) y una cuenta que sea owner de la organización para crear las Apps. Detalle en Plataforma symintel — GitHub.
  • 1Password: la app de escritorio instalada, con una bóveda llamada HomeLab y Settings → Developer → Integrate with other apps activado. Ahí se guardan las credenciales que usan los playbooks (qué items y campos).

Ejecutar

Clonar repo y entorno Ansible

git clone https://github.com/symintel/homelab.git
cd homelab
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt   # Ansible, mkdocs, ansible-lint, etc.
ansible-galaxy collection install -r ansible/requirements.yml

Ruta del requirements.txt

requirements.txt vive en la raíz del repo, no en ansible/ — es un error común confundirlo con ansible/requirements.yml (ese es el manifiesto de collections de Galaxy, un archivo YAML distinto, no algo que pip install -r pueda instalar).

Día 0 — nodos recién instalados (solo la primera vez por nodo)

Un nodo recién flasheado (Debian netinst) todavía no tiene python3 ni sudo listos, y el usuario admin no está en el grupo sudo — el ping de más abajo (usa el módulo ansible.builtin.ping, que sí necesita Python en el destino) va a fallar sin este paso primero:

cd ansible
ansible-playbook -i bootstrap/inventory.ini bootstrap/setup_sudo.yml --ask-pass
cd ..

Detalle completo (por qué conecta como root y dónde encaja en el resto del bootstrap) en ansible/bootstrap/README.md. Si tus 3 nodos ya tienen un usuario admin con sudo funcionando, salteá este paso.

Validar inventario

Revisa ansible/inventory.ini: ansible_host, static_ip, bridge_iface por nodo.

ansible -i ansible/inventory.ini incus_cluster -m ping

Discovery opcional (recomendado la primera vez)

cd ansible
ansible-playbook -i inventory.ini playbook-discovery.yml

Salida en ansible/reports/ (gitignored): ficha por nodo + summary.md.

Recopila CPU, RAM, disco y red con lscpu, free -h, lsblk, ip -br link y compara con Inventario de hardware.

GitHub y 1Password — org symintel (manual, una sola vez)

Aquí se preparan, una sola vez, las cuentas y credenciales de GitHub que el HomeLab necesita: las Apps con las que el clúster habla con GitHub (entre ellas la que usa ArgoCD para leer el repo privado symintel/gitops) y los repos base (gitops, core-pipelines e infra). Todo se crea a mano, y las credenciales se guardan en 1Password para que después los playbooks las lean desde ahí. El detalle de cada una (permisos, dónde encontrar cada dato en GitHub y cómo cargarlo en 1Password) está en Plataforma symintel — GitHub.

Los items de 1Password van en la bóveda HomeLab, casi todos como Nota segura con campos propios. El título del item y el nombre de cada campo tienen que ser exactos, porque el playbook los busca por nombre: cómo crear el item.

Con una cuenta owner de la organización symintel:

  1. GitHub App symintel-terraform → item symintel-terraform (Nota segura) con los campos app_id (Texto), installation_id (Texto) y private_key (Contraseña, el .pem completo). Permisos y dónde está cada dato.
  2. GitHub App symintel-arc-runners → item symintel-arc-runners, con los mismos tres campos pero con los datos de esta App. Permisos y pasos.
  3. OAuth App Symintel Dex → campos GITHUB_CLIENT_ID (Texto) y GITHUB_CLIENT_SECRET (Contraseña) en el item symintel-dex (Nota segura). Pasos.
  4. Repos privados, con su contenido subido con git:
    • gitops.
    • core-pipelines: en Settings → Actions → General → Access, elige "Accessible from repositories in the 'symintel' organization". No hace falta crear tags: mientras pruebas, los demás repos lo usan con @main.
    • infra.
  5. GitHub App symintel-argocd (solo lectura, instalada solo en gitops) → item symintel-argocd con los mismos tres campos. Va después de los repos porque se instala en gitops. Permisos y pasos.
  6. Llave de Sealed Secrets (opcional hasta la Fase 6): un par de llaves generado con openssl, en el item sealed-secrets (certificate y private_key), para que sobreviva si reinstalas K3s. Comando y pasos.
  7. Credenciales FTP (File Transfer Protocol) del repo api: api es el primer proyecto del mapa de repos y despliega por FTP, así que necesita su item ftp-api (Nota segura) desde el primer pipeline. Cada repo que agregues después sigue el procedimiento de rutina — Agregar un repo. El item lleva 8 campos: dev_host, dev_user, dev_password, dev_remote_dir y los mismos cuatro con prod_. Los *_password van como Contraseña y el resto como Texto. Tabla con ejemplos.

Comprueba que todas las credenciales se pueden leer de 1Password. Son dos comandos, y ninguno toca un clúster ni muestra valores secretos:

  • --check: revisa cada item esperado y marca con ✓ los campos que están bien y con ✗ los que faltan, tienen otro nombre o están dentro de una sección. Córrelo primero: si algo está mal, dice exactamente qué.
  • --dry-run: lee todos los valores y lista los Secrets que se van a crear en el clúster, con los valores ocultos (<redacted>). Confirma que las llaves se pueden interpretar.

El script lee 1Password a través de la app de escritorio, así que la app tiene que estar desbloqueada y con Settings → Developer → Integrate with other apps activado. Además hay que decirle qué cuenta usar con la variable ONEPASSWORD_ACCOUNT_NAME: es el nombre de tu cuenta tal como aparece arriba a la izquierda en la barra lateral de la app (por ejemplo MCO Family). Si no la defines, usa Personal.

export ONEPASSWORD_ACCOUNT_NAME="MCO Family"  # tu cuenta
.venv/bin/python ansible/scripts/apply_platform_secrets.py --check
.venv/bin/python ansible/scripts/apply_platform_secrets.py --dry-run

--check termina bien cuando todos los items tienen ✓ (el aviso de que no hay items ftp-<repo> es solo informativo si ningún repo despliega).

Opciones

Opción Cuándo
Saltar discovery Re-despliegue y hardware ya conocido
Actualizar inventario Tras cambiar IPs en Fase 1
Análisis de trade-offs
Discovery Ansible
RAM/disco/I/O medidos → reports/
Requiere SSH y unos minutos por nodo
Discovery manual
Sin playbook
Valores desactualizados; errores de planificación
Saltar discovery
Más rápido en re-despliegues
Presupuesto RAM/disco puede no coincidir con la realidad

Verificar

ansible -i ansible/inventory.ini incus_cluster -m ping
# todos → SUCCESS

export ONEPASSWORD_ACCOUNT_NAME="MCO Family"  # tu cuenta
.venv/bin/python ansible/scripts/apply_platform_secrets.py --check
# todos los items con ✓
.venv/bin/python ansible/scripts/apply_platform_secrets.py --dry-run
# lista los Secrets de plataforma (valores <redacted>), sin errores de 1Password

Si falla

Síntoma Revisar
UNREACHABLE ansible_host, firewall, clave SSH
ping falla por Python ausente Nodo recién instalado — correr setup_sudo.yml (paso "Día 0" arriba)
Discovery sin reports Ejecutar desde ansible/; permisos de escritura
--check o --dry-run no leen 1Password App desbloqueada con Integrate with other apps y ONEPASSWORD_ACCOUNT_NAME con el nombre de tu cuenta. Si dice field cannot be found o Bóveda no encontrada, mira la salida de --check: marca qué item o campo no coincide (nombres esperados)

Siguiente

→ Fase 1 — Red