No soy un buen administrador de sistemas.
Por muchos años, mi estrategia para administrar mis máquinas en casa ha sido una de negligencia máxima:
-
Evitar actualizar la distro o reinstalarla lo más posible, porque las cosas se rompen o pierden su configuración.
-
Mantener mi $HOME intacto entre cada actualización, para conservar mi configuración personal aunque se acumule la basura vieja.
-
Llorar cuando instalo un servicio en mi servidorcito casero, como directorios compartidos con SMB o un servicio de música, porque sé que se va a romper cuando tenga que reinstalar.
Hace unos dos años escribí unos scripts para automatizar al menos la parte de instalar los paquetes que necesito, y configurar lo más indispensable como el firewall. Esos scripts me ayudaron a perder parte del miedo a reinstalar o poner actualizaciones; al correrlos, ya sólo tenía que hacer un poco de trabajo manual para dejar todo funcionando. También, el tener esos scripts me hizo pensar en qué cosas puedo dejar como defaults en la distro, y qué necesito cambiar de deveras.
Salt
En mi cabeza pienso que existe un universo tenebroso de herramientas para administración de sistemas a gran escala. Por supuesto que querrías automatización para manejar una granja de servidores. Por supuesto que nadie administraría 3000 estaciones de trabajo a mano. Pero para mi redecita minúscula en casa, con un servidor y dos estaciones de trabajo, ¿no es como matar hormigas con aplanadora? ¿No es demasiado usar esas herramientas gigantescas?
¡Por fortuna no es así!
Mi colega Richard Brown ha estado hablando sobre el Proyecto Salt por varios años. Es un sistema similar a Ansible o Puppet, para instalar y configurar compus de forma automática.
Lo que me gusta de Salt hasta ahora es que su documentación es excelente, y me ha permitido traducir mi modesta configuración casera a un sistema automático, mientras que aprendo algunas buenas prácticas.
Comencé con el Salt walkthrough, que es bastante sencillo.
Resumen: el salt-master es la máquina central que mantiene y distribuye la configuración a otras máquinas. Esas otras máquinas se llaman salt-minions. Escribes YAML más o menos declarativo en el salt-master, y propagas esa configuración a los minions. Salt tiene operaciones de alto nivel como "crear un usuario" o "instalar un paquete" o "reiniciar un servicio cuando cambian archivos de configuración" sin que tengas que saber cómo lo hace tu distro en específico.
Mi red casera y cómo quiero que sea
pambazo
- Tiene un RAID con música y películas y almacena respaldos
de datos. Este es mi servidor casero.
tlacoyo
- Compu de escritorio; es mi estación de trabajo principal.
torta
- Mi laptop, que he usado muy poco durante la pandemia. En
principio debería tener una configuración idéntica a mi estación de
trabajo.
Tengo abierto el puerto de MDNS en esas tres máquinas para que pueda
usar nombre-de-host.local
para accesarlas, sin tener que configurar
un servicio de DNS. Tal vez debería aprender a hacer esto último.
Todas las compus necesitan mis archivos básicos de configuración (Emacs, prompt del shell), y unos cuantos programas indispensables (Emacs, Midnight Commander, git, podman).
Mis estaciones de trabajo necesitan tener mis llaves de SSH para gitlab/github, mis llaves de la VPN de Suse, y algo de infraestructura básica para desarrollo. Necesito poder reinstalar y reconstruir esas máquinas rápidamente.
Todas las compus deben tener la misma configuración para las dos impresoras que hay en casa (una laser que imprime por dos lados, y una de inyección de tinta para fotos).
Mi servidor casero por supuesto que necesita la configuración para todos sus servicios.
También tengo unas cuantas máquinas virtuales más bien efímeras, para probar imágenes de distros. En esas sólo necesito algunos paquetes y configuración básica.
Instalar el salt-master
Mi servidor casero funciona como el "salt master", que es la máquina
que mantiene la configuración que se va a distribuir a las demás.
Allí uso el paquete de salt-master
que viene con openSUSE. Lo único
que le moví a la configuración por default son las rutas a los
archivos de configuración para los minions, para poder tenerlos en un
árbol de git en mi directorio personal en vez de bajo /etc/salt
. Lo
siguiente va en /etc/salt/master
:
# configuración para los minions
file_roots:
base:
- /home/federico/src/salt-states
# datos privados para distribuir a los minions
pillar_roots:
base:
- /home/federico/src/salt-pillar
Instalar los minions
Es fácil instalar el paquete por default de salt-minion
y
configurarlo para que sepa ubicar al salt-master, pero quería una
forma más directa de haerlo en un solo paso
Salt-bootstrap permite hacer eso. Puedo correr esto
en una máquina recién instalada:
curl -o bootstrap-salt.sh -L https://bootstrap.saltproject.io
sudo sh bootstrap-salt.sh -w -A 192.168.1.10 -i mi-hostname stable
La primera línea descarga el script de bootstrap-salt.sh
.
La segunta línea:
-
-w
- usar el paquete de la distro desalt-minion
, no el oficial. -
-A 192.168.1.10
la dirección IP del salt-master. En este punto la máquina que se va a convertir en minion todavía no tiene abierto el puerto de DNS en el firewall, entonces no puede encontrar apambazo.local
. Entonces, el ponemos su IP. -
-i mi-hostname
- Nombre para el minion. Salt te permite tener un nombre diferente para el minion y para el host, pero yo quiero que sean iguales. Es decir, quiero que el hosttlacoyo.local
sea un minion llamadotlacoyo
. -
stable
- Usar la versión estable de salt-minion, no la desarrollo.
Cuando se ejecuta ese script, éste crea un par de llaves y le pide al salt-master que registre la llave pública del minion. Luego, en el salt-master hago esto:
salt-key -a mi-hostname
Esto hace que el master acepte la llave pública del minion, y ya está listo para configurarse.
Lo primero: poner el nombre del host, abrir el puerto de MDNS en el firewall
Quiero que el nombre del host sea igual al nombre del minion:
'poner el nombre del host igual al nombre del minion:
network.system:
- hostname: {{ grains['id'] }}
- apply_hostname: True
- retain_settings: True
Salt usa plantillas de Jinja para pre-procesar sus archivos
de configuración. Una de las variables disponibles es grains
, que
contiene información específica a cada minion: su arquitectura de CPU,
memoria, distribución, y el identificador del minion. Aquí uso {{
grains['id'] }}
para sacar el identificador del minion y ponerlo como
el hostname.
Para configurar el firewall de las estaciones de trabajo, usé YaST y luego copié la configuración resultante a Salt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
file.managed
es lo que se usa en Salt para copiar archivos a las
máquinas de destino. En las líneas 1 a 6, se copia
salt://opensuse/desktop-firewalld.conf
a
/etc/firewalld/firewalld.conf
. El prefijo salt://
se refiere a
una ruta bajo el lugar donde tienes los salt-states; este es el árbol
de git que mencioné más arriba.
Las líneas 15 a 20 le dicen a salt que habilite el servicio
firewalld
service, y que lo reinicien cuando cambie cualquiera de
esos archivos de configuración.
Paquetes indispensables
No puedo vivir sin estos:
'paquetes indispensables:
pkg.installed:
- pkgs:
- emacs
- git
- mc
- ripgrep
pkg.installed
toma un arreglo de nombres de paquetes. Aquí pongo
los nombres que se usan en openSUSE. Salt te permite hacer mucha
magia con Jinja y el salt-pillar para tener nombres de paquetes
específicos para cada distribución de Linux, si es que tienes un
entorno con distros diferentes. Como aquí tengo todo con openSUSE, no
necesito hacer eso.
Mi usuario, y archivos de configuración personales
Esto crea mi usuario:
federico:
user.present:
- fullname: Federico Mena Quintero
- home: /home/federico
- shell: /bin/bash
- usergroup: False
- groups:
- users
Esto copia algunos archivos de configuración:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Aquí uso un arreglo de Jinja para definir una lista de archivos y sus
rutas de destino, y un ciclo for
para reducir la duplicación de
código en el YAML.
Instalar algunos flatpaks
Instalar los flatpaks que necesito:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Poner uno de los archivos de configuración de esas aplicaciones:
/home/federico/.var/app/org.freac.freac/config/.freac/freac.xml:
file.managed:
- source: salt://opensuse/federico-config-files/freac.xml
- user: federico
- group: users
- mode: 644
- makedirs: True
Este último es el archivo de configuración para fre:ac, una
aplicación para ripear CDs de audio. Los Flatpaks guardan su
configuración bajo ~/.var/app/nombre-del-flatpak
. Para ésta,
configuré la aplicación una vez desde su interfaz gráfica y luego
copié el archivo de configuración a los salt-states.
Etcétera
Esto de arriba no es mi configuración completa; por supuesto que las cosas como el servidor casero necesitan muchos más paquetes y archivos. Sin embargo, esos patrones de arriba son casi todo lo que necesito para configurar lo demás.
Cómo funciona en la práctica
Tengo un árbol de git con mis salt-states. Cuando hago cambios y
quiero distribuirlos a mis compus, hago un git push
al repositorio
en mi servidor casero y luego corro este script:
#!/bin/sh
set -e
cd /home/federico/src/salt-states
git pull
sudo salt '*' state.apply
La línea con salt '*' state.apply
hace que todas las compus obtengan
una configuración actualizada. Salt te dice qué cambió en cada
máquina y qué se quedó igual. La parte más lenta parece ser cuando
zypper
actualiza la información sobre sus repositorios de paquetes;
fuera de eso, Salt es suficientemente rápido para mis propósitos.
Cómo jugar con esto por primera vez
Después de instalar el salt-master nuevo en mi servidor casero, me hice una máquina virtual, la configuré como minion e inmediatamente le hice un snapshot a la VM. Así quería poder regresar al estado "recién instalado, nada configurado" para probar mis salt-states como si fuera una compu nuevecita. Ya que tuve la confianza de que las cosas funcionaban, instalé salt-minion en mi máquina de escritorio y en mi laptop de la misma manera. Esto me fue muy útil para no romperlas desde el principio.
Un proceso de actualización personal
Poco a poco he estado mudando mi configuración acumulada de mi $HOME
histórico a Salt. Esto me hizo darme cuenta de toda la basura que
seguía cargando ahí; todavía tenía archivos como ~/.red-carpet
y
~/.realplayerrc
para software que no existe desde hace muchos años.
¡Mis archivos de configuración están mucho más limpios ahora!
También pude quitar mi scripts viejos y que ya no uso de ~/bin
(todavía tenía el que usaba para conectarme al túnel SSH de Ximian,
y el script para conetarse a los modems con PPP de la universidad),
darme cuenta de cuáles aun necesitaba, moverlos a ~/.local/bin
y
manejarlos bajo Salt.
Para limpiar archivos viejos en varias máquinas al mismo tiempo, tengo algo así:
/home/federico/.dotfile-que-ya-no-se-usa:
file.absent
Eso borra el archivo.
Al final de cuentas, sí pude alcanzar mi meta inicial: puedo reinstalar una compu, y luego dejarla bien configurada con un solo comando.
Esto me ha dado más confianza para instalar juguetes lindos en mi servidor casero... como un servidor de música, que me llena de felicidad. ¡Mira todo esto!
Algo que sería lindo en Flatpak
Salt te permite saber qué cambió al aplicar una configuración, o también puedes hacer una ejecución simulada donde te dice qué va a cambiar sin que modifique nada. Por ejemplo, Salt sabe cómo revisar la base de datos de paquetes en cada distribución, para avisarte si un paquete tiene actualizaciones, o si un archivo de configuración existente difiere de uno que vas a propagar.
Sería lindo si el comando flatpak
regresara esa
información. En los ejemplos de arriba, utilizo flatpak
remote-add --if-not-exists
y flatpak install --or-update
para que
sean idempotentes, pero Salt no se entera de lo que Flatpak hizo
realmente; nada más ejecuta los comandos y regresa si fueron exitosos
o no.
Cosillas pendientes
Algunos programas mezclan información de estado con información de configuración en el mismo archivo controlado por el usuario, y este estado se pierde cada vez que Salt sobreescribe el archivo:
-
fre:ac, un programa para ripear CDs de audio, tiene uno de esos "consejos del día" al iniciarlo. Cada vez que lo ejecutas, se actualiza el "número del último consejo visto", pero lo hace en el mismo archivo donde se guarda la información de las rutas a donde va a escribir los archivos de audio y la configuración que le pusiste para los codecs. Cada vez que Salt reescribe este archivo, se resetea el "número del último consejo" al inicial.
-
Cuando cargas un tema en Emacs, digamos, con
custom-enabled-theme
encustom.el
, Emacs guarda un checksum del tema después de preguntarte si quieres ejecutar el código del tema — para prevenir temas maliciosos o algo así. Sin embargo, ese checksum también se guarda encustom.el
. Si Salt sobreescribe ese archivo, Emacs te vuelve a preguntar sobre el tema la vez siguiente.
En términos de Salt, tal vez necesito usar una forma más detallada de cambiar un archivo que copiarlo enterito. Salt permite cambiar líneas individuales y cosas así. ¿Copiar todo el archivo si no existe, o sólo cambiar unas líneas si ya está?
Necesito destilar la información de dconf para los programas de GNOME instalados en el sistema, a diferencia de los flatpaks, para poder restaurarla después.
Estoy seguro que todavía tengo detritus bajo ~/.config
que debería
manejarse con Salt... tal vez tengo que hacer otra pasada de
actualización personal y limpiar eso.
En casa tenemos algunas máquinas Windows para cosas de la escuela. Salt también funciona en Windows, y me encataría configurarlo para que los respaldos al servidor casero se configuren automáticamente.