viernes, 14 de mayo de 2010

OpenSolaris y sus servicios



En este artículo se aborda la forma que tiene OpenSolaris de manejar sus servicios.
Veremos que ha cambiado bastante desde la época de Solaris 8 ó 9, e inclusive respecto de la forma en la cual se trabajaba con Solaris 10.
Tenemos, en el caso de OpenSolaris, varias herramientas que nos permitirán armar el árbol de precedencia de procesos a la hora de lanzar un servicio en particular, así como la forma en la cual se paralelizará éste con otros.
Aprendamos a utilizarlos, serán nuestros amigos en la automatización de tareas de arranque, y su diagnóstico nos hará muy sencilla la vida cuando aparezca algún problema.
Para los que creyeron que los artículos anteriores eran light, acá va un desafío a sus neuronas.

Todo es historia

Ya hace un buen tiempo atrás aparecieron tecnologías de hardware que permitieron contar con herramientas de monitoreo y detección de fallas en forma automática. Elementos tales como el termómetro interno nos permiten conocer la temperatura de nuestro procesador, y en base a ello decidir qué hacer en caso que se eleve demasiado. No es raro que alguien esté escribiendo un documento larguísimo, y que antes de salvarlo descubra que su máquina se apaga por tener un ventilador tapado con pelos del perro Caniche Toy que le recomendaron comprar para cuidar la casa.

image
En el caso de servidores de mayor porte, hasta tenemos indicadores que nos dicen cuándo alguna pieza debe ser reemplazada. Así, por ejemplo, tenemos discos, memorias y otras piezas de hardware que tienen como característica ser “hot swap”, es decir, que se pueden reemplazar aún con el sistema funcionando, sin generar ningún tipo de inconveniente. La redundancia es muy común en este tipo de sistemas.
Ahora bien, a nivel de hardware pareciera que nuestra vida está simplificada. ¿Qué pasa a nivel de software? Hasta hace un tiempo atrás, los diferentes sabores de Unix, tanto originales como clónicos, sólo contaban con la posibilidad de lanzar servicios en forma secuencial, y en el mejor de los casos con algún grado de paralelismo.
La forma de monitorear servicios, así como de lograr su lanzamiento considerando dependencias se basaba casi de forma exclusiva en infinidad de scripts no estandarizados que cada sysadmin armaba. Y que debuggeaba cada vez que un servicio se caía.
No era extraño poder casi adivinar la cantidad de versiones de scripts creados, y su fecha de release sólo con mirar el CV de un sysadmin. Los cambios de empresa coincidían con una “prueba productiva” que generalmente terminaba con un botellazo y algunas palabras irreproducibles por parte de sus superiores.

image
Antes configurábamos un script en el directorio /etc/init.d, que luego linkeábamos simbólicamente ("ln -s") hacia los directorios /etc/rcX.d con un nombre que comanzaba con “S” si queríamos que se ejecuten con el argumento “start”, o con “K” si el argumento debía ser “stop”. Pero si necesitábamos verificar la existencia de un servicio previo al lanzamiento de otro, todo volvía a depender de scripts. Y si algo fallaba, lo más común era buscar con comandos como “grep” algún tipo de pista en los logs del sistema.
Teniendo esto en cuenta, OpenSolaris modificó este subsistema al punto de crear un framework completo de gestión de servicios. Así logramos identificar procesos correspondientes a servicios en un único log por cada uno de ellos, separándolos de cualquier otro proceso lanzado por un usuario.
También se generó un subsistema que permite saber en qué momento debe ser ejecutado cada servicio, sus dependencias, las reglas que implican su relanzamiento, la cantidad de relanzamientos antes de considerar que hay una falla que requiere intervención humana, y un formato estandarizado de configuración para todos y cada uno de ellos.
Y si tenemos algún sysadmin enamorado de los scripts, le permitimos que los siga usando como hasta ahora, sin tener que modificar nada.

Conceptos previos

Bueno, creo que todos ya sabemos lo que es un servicio. ¿Lo sabemos? Está bien, para los que no lo tienen muy claro, acá van algunas definiciones de “servicio”:

- En *nix, lo que se ejecuta en forma no-interactiva, por lo que no debe ser lanzado por un usuario humanamente logueado en nuestro sistema.
- En España, es un sinónimo de “baño”.
- Para el ciudadano común, aquello que le permite tener luz, agua, y gas, y que le es cortado cuando no paga, y a veces cuando paga también.

Por ejemplo, cuando ingresamos a un sistema mediante SSH o Telnet, lo hacemos gracias a un servicio que “escucha” en un determinado puerto esperando a que algo, como nuestro pedido de ingreso, ocurra. Sin caer en lo obvio, entendemos ahora por qué se llama a los sistemas que nos proveen algún servicio (suenen trompetas), "servidores".
El framework que en OpenSolaris se creó para poder manejar estos servicios recibió el nombre de SMF (Service Management Framework). Él permite estandarizar, por ejemplo, el modelo de estados y la convención de nombres. Asigna dependencias y describe cada uno de los métodos utilizados para rearrancar un servicio en caso de fallas o caídas. Todo esto se encuentra controlado por un proceso demonio llamado “svc.startd”. Es él quien se ocupa de recibir los avisos de procesos o servicios caídos, siendo quien los levanta o notifica en base a las especificaciones que se hayan asignado.
El proceso svc.startd es invocado en forma automática cuando el sistema operativo arranca, de allí que veamos en una de las líneas del archivo "/etc/inittab":
smf::sysinit:/lib/svc/bin/svc.startd >/dev/msglog 2<>/dev/msglog El nombre de la rosa

De la misma forma en la cual si queremos referirnos a alguien lo hacemos por su nombre y apellido, cuando querramos referirnos a un servicio lo debemos hacer por medio de su nombre.
Entonces, lo primero será saber cómo se nombran los servicios.
En OpenSolaris el nombre de un servicio se denomina FMRI, siglas de “Fault Management Resource Identifier” (más adelante extenderemos la explicación sobre por qué se ha asignado este nombre).
Veamos primero cuáles son los campos que existen en su nombre, para luego llegar a un ejemplo práctico que pueden seguir en sus propias máquinas. Los campos existentes en un nombre de servicio son:

- scheme: Indica el tipo de servicio que se está invocando. Puede ser “svc” si se trata de un servicio manejado por SMF, o “rc” si mantiene el viejo esquema de scripts. ¡Sí, desde esta facilidad también podemos administrar los viejos scripts localizados en /etc/init.d!
- location: Este campo indicará el servidor o sistema donde el servicio esté declarado, o en ejecución. Normalmente estaremos declarando “localhost” en este campo.
- functional category: Este campo indicará el tipo de servicio que se está invocando, desde un punto de vista funcional. Según esta característica puede ser:
- application: Se está haciendo referencia, por medio de este campo, a un programa o demonio en particular. El que se nombre de esta forma implicará que no tiene nada que ver con alguna de las categorías anteriores. Ejemplos de “application” son “graphical-login”, que nos mostrará la ventana gráfica por medio de la cual ingresar nuestro usuario y contraseña, o “net-snmp”, que nos permitirá manejar la gestión de servicios SNMP (simple Network Management Protocol).
- system: Se está invocando un servicio independiente de la plataforma. Ejemplos de esta categoría son “cron” (el gestor de tareas agendadas en forma repetitiva en OpenSolaris o cualquier *nix), o “rbac” (Role Based Access Control).
- device: Se nombra un servicio que ayuda a cubrir las dependencias originadas en el hardware, como ser algún dispositivo del cual se requiera una entrada o salida para funcionar.
- network: Refiere servicios de red que ya han sido convertidos de “inetd”. Ejemplos de esta categoría son “nfs” (Network File System), o “ssh”.
- milestone: Tal como en los viejos sistemas SVR4 teníamos “run levels”, en OpenSolaris tenemos “milestones”. Por lo tanto, esta categoría hará referencia al nivel de ejecución que el sistema operativo tendrá, y a los servicios dependientes que deberán encontrarse en estado de ejecución para considerar que ese “milestone” se ha alcanzado. Para verlo más claramente, un “milestone” podría ser “multi-user”, o “single-user”, por sólo citar un par de ejemplos.
- platform: Esta categoría hace referencia a servicios que sean específicos al hardware con el cual se está trabajando.
- site: Hacen referencia a la organización del sitio en el cual se esté trabajando. Esta categoría tiene toda la pinta de ser un placeholder, dado que al menos al día d ela fecha no encuentro ninguno que se lance desde ella.
- description: Tal como se podrán imaginar, es una descripción del servicio. Ni más ni menos.
- instance: Existen en OpenSolaris (así como en cualquier sistema operativo) servicios que podrán encontrarse en ejecución más de una vez, por ejemplo para entregar algo a más de un cliente. En casos como éste podremos encontrar diferentes instancias de un servicio ejecutándose al mismo tiempo.

Luego de haber enloquecido con toda esta nomenclatura, vamos a las arenas, y nos ponemos a ver en un simple gráfico cada uno de estos campos:

image
En muchos casos veremos que la “location” se obvia, por lo que el servicio presentado podría ser listado sencillamente como “svc:/network/dns/client:default”.

Isla de los Estados

Como era de esperarse, los servicios podrán tener diferentes estados, dependiendo de si se han lanzado, si están bajos, si han fallado, etc.
A continuación, un resumen de los estados posibles de un servicio:

- uninitialized: Este estado aparece cuando el proceso “svc.startd” aún no ha realizado ninguna acción sobre él. Cuando el sistema está booteando, por ejemplo, se podrían ver servicios en este estado.
- disabled: El administrador del sistema ha deshabilitado este servicio por algún motivo. Mientras que el estado sea éste, aún con un rebooteo continuará sin levantar.
- offline: El servicio se encuentra habilitado por el administrador del sistema, pero aún no se ha lanzado, de seguro por estar a la espera de una dependencia que debe ser satisfecha para su correcto funcionamiento. Más adelante veremos cómo se pueden declarar las dependencias para que sean revisadas por un servicio previo a su lanzamiento.
- online: Éste es el estado de felicidad absoluta del administrador de sistemas. Su salario ha quedado justificado por el resto del año. El servicio se ha lanzado, así como todas sus dependencias, y está funcionando. La casa está en orden, y…
- degraded: El servicio se encuentra online, y funcionando, pero con un nivel de performance degradado. Es el momento de tomar el toro por las astas, leer el log de ese servicio en particular, o ejecutar, como veremos más adelante “svcs –xv” para comprender el motivo por el cual ese servicio se encuentra en ese estado.
- maintenance: Es éste y no otro el estado por el cual se consume café entre los sysadmines. Algo ha logrado bajar nuestro servicio, y es nuestra misión como mega-plus-super-expertos en el área analizarlo y repararlo en forma adecuada. Pensabas que todo iba a ser mágico…pobre iluso…

Cuando un servicio aparece con el estado “maintenance”, debemos hurgar en sus fosas nasales hasta encontrar qué causa su malfuncionamiento. Para eso, encontraremos los correspondientes logs en “/var/svc/log”. Cada archivo se corresponde con un servicio en particular. Cada nombre de archivo comenzará con su “functional category” (por ejemplo, “network”), continuará con su “description” (por ejemplo, “ssh”), y finalizará con su “instance”, seguido de la palabra “log” (por ejemplo, “default.log”). El archivo de log correspondiente al servicio de ssh sería, entonces, “/var/svc/log/network-ssh:default.log”. No dolió tanto, ¿o sí?


Comandos azules

OpenSolaris nos entrega una nueva serie de comandos para gestionar los servicios del sistema. Y ellos, como en los casos anteriores, siguen los mismos estándares de las demás novedades de este sistema operativo: son pocos, y muy sencillos de aprender y utilizar.
En este caso, utilizaremos en general, y salvo grandes problemas, sólo cuatro comandos: svcs, svcprop, svcadm y svccfg. Sencillo, ¿no?
Veamos para qué sirve cada uno de estos comandos:

- svcs: Entrega información relativa al estado, dependencia, instancias y diagnóstico de procesos. Si nos encontramos que un determinado servicio no parece estar funcionando, utilizaríamos este comando para verificarlo. Veamos algunos ejemplos:
Este comando sólo nos muestra los servicios que se encuentran en ejecución:

root@server:~# svcs more
STATE STIME FMRI
legacy_run 17:44:25 lrc:/etc/rc2_d/S20sysetup
legacy_run 17:44:25 lrc:/etc/rc2_d/S47pppd
legacy_run 17:44:25 lrc:/etc/rc2_d/S72autoinstall
legacy_run 17:44:25 lrc:/etc/rc2_d/S73cachefs_daemon
legacy_run 17:44:25 lrc:/etc/rc2_d/S81dodatadm_udaplt
legacy_run 17:44:25 lrc:/etc/rc2_d/S89PRESERVE
legacy_run 17:44:26 lrc:/etc/rc2_d/S98deallocate
online 17:43:35 svc:/system/svc/restarter:default
online 17:43:37 svc:/network/loopback:default


El siguiente nos mostrará todos los servicios declarados, estén o no en ejecución:

root@server:~# svcs -a more
STATE STIME FMRI
legacy_run 17:44:25 lrc:/etc/rc2_d/S20sysetup
legacy_run 17:44:25 lrc:/etc/rc2_d/S47pppd
legacy_run 17:44:25 lrc:/etc/rc2_d/S72autoinstall
legacy_run 17:44:25 lrc:/etc/rc2_d/S73cachefs_daemon
legacy_run 17:44:25 lrc:/etc/rc2_d/S81dodatadm_udaplt
legacy_run 17:44:25 lrc:/etc/rc2_d/S89PRESERVE
legacy_run 17:44:26 lrc:/etc/rc2_d/S98deallocate
disabled 17:43:35 svc:/network/physical:default
disabled 17:43:35 svc:/system/device/mpxio-upgrade:default
disabled 17:43:36 svc:/system/svc/global:default


Y este último, los servicios que están marcados con problemas:

root@server:~# svcs –xv

- svcadm: Habilita, deshabilita, relanza y administra diferentes instancias de servicios. Si por ejemplo queremos bajar un servicio, o relanzarlo en forma manual, sería éste el comando que podríamos utilizar. Este comando posee varios argumentos que manejarán su comportamiento, dentro de los cuales encontramos:
- enable: Habilita la instancia del servicio especificado. Esto pondrá al servicio como “online”, lo lanzará, y mantendrá su estado entre booteos.
- disable: Ídem caso anterior, pero lo deshabilita.
- restart: Relanza un servicio siempre y cuando el mismo se encuentre en estado “online” o “degraded”.
- refresh: Verifica la nueva configuración del servicio, y solicita a “svc.startd” que la modifique, mientras se encuentra en ejecución.
- clear: Cuando un servicio se fue a estado “maintenance” por algún motivo, y habiendo solucionado la causa raíz del problema, ejecutaremos “svcadm” con este argumento para que limpie dicho estado, y lo relance.
- mark: Si una instancia de un servicio se encuentra en estado “maintenance”, este argumento pone en el mismo modo a todos los servicios e instancias especificados. Si la instancia se encuentra en modo “degraded”, hace lo mismo pero colocándolos en modo “degraded”.

Analicemos un ejemplo con el servidor web Apache:
Primero, verificamos si Apache se encuentra en funcionamiento:

root@server:~# svcs apache22
STATE STIME FMRI
online 17:44:27 svc:/network/http:apache22

Viendo que su estado es “online”, procederemos a bajarlo con el comando:

root@server:~# svcadm disable apache22
root@server:~# svcs apache22
STATE STIME FMRI
disabled 0:20:36 svc:/network/http:apache22

Ahora, procederemos a subirlo con el comando:

root@server:~# svcadm enable apache22
root@server:~# svcs apache22
STATE STIME FMRI
online 0:41:09 svc:/network/http:apache22

Lo pondremos en modo “maintenance”:

root@server:~# svcadm mark maintenance apache22
root@server:~# svcs apache22
STATE STIME FMRI
maintenance 0:52:57 svc:/network/http:apache22

Y finalmente lo pondremos nuevamente en modo online:

root@server:~# svcadm clear apache22
root@server:~# svcs apache22
STATE STIME FMRI
online 0:54:18 svc:/network/http:apache22

Nótese que en todos los casos anteriores, no se ha utilizado el FMRI completo para invocar al servicio, sino sólo una parte significativa de su nombre. Esto es posible siempre que no haya más de una instancia de ese servicio´y que no exista otro servicio con la misma “description”, pero con alguno de los demás componentes de su FMRI diferentes. Algo tenía que ser simple, después de todo…


- svccfg: Configura los parámetros necesarios en cada servicio. También permite importar y exportar configuraciones de servicios. Si es invocado sin ningún FMRI, abre un prompt propio, para trabajar con los diferentes servicios del sistema. Por ejemplo, si se tiene un servicio web basado en Apache, y se desea cambiar el puerto 80 por otro, sería éste el comando a utilizar.
- svcprop: Entrega un detalle de los permisos y propiedades de un servicio. Si un determinado usuario no puede lanzar un servicio, podríamos comenzar analizando si tiene los permisos necesarios a través de este comando.




Hablemos de milestones

Cuando obtuvimos el listado de servicios, encontramos varios que tenían entre sus functional categories la palabra "milestone". Un servicio tipo "milestone" forma parte de un grupo que permite, tal como antes ocurría con los niveles de ejecución de un sistema operativo *nix, llevar el sistema a un determinado nivel de ejecución.
Por lo tanto, y como es lógico, encontraremos una determinada analogía entre los niveles de ejecución de los sistemas *nix basados en scripts rc*, y OpenSolaris.
Veamos cuáles son estas correspondencias:

- : En SMF existe un nivel de ejecución que no existe en otros sistemas operativos, donde sólo el kernel se encuentra en funcionamiento. El nombre de este milestone será "none".
s ó S: Lo que en otros sistemas operativos se consideraba el nivel "single-user", en OpenSolaris recibe, justamente, este nombre: milestone "single-user". Si ejecutamos:

root@server:/etc# svcs -a grep milestone grep single-user

...la salida será:

online 23:48:29 svc:/milestone/single-user:default

2: El nivel "2" es considerado como el multiusuario sin recursos compartidos. Si bien se permite el ingreso por telnet, o ssh, no debieran existir, en este nivel, filesystems exportados mediante NFS, o cualquier otro sistema. En OpenSolaris, este milestone se denomina "multiuser". Tal como en el caso anterior, ejecutaremos:

root@server:/etc# svcs -a grep milestone grep multi-user

...y la salida será:

online 23:48:49 svc:/milestone/multi-user:default

3: El nivel "3" es el multiuser pero a diferencia del anterior, con recursos compartidos. El equivalente en OpenSolaris es el milestone "multi-user-server".
5: Es el equivalente a mencionar todos los niveles anteriores.

Por lo tanto, si debiéramos dejar nuestro sistema operativo en un nivel diferente al que actualmente posee, debemos utilizar, como en todos los casos anteriores, el comando svcadm:

root@server:/etc# svcadm milestone single-user

El comando anterior lo llevaría a nivel single user.
El conjunto de programas que se ejecutarán en cada nivel se puede explorar de una manera muy sencilla, por ejemplo, revisando el archivo /var/svc/manifest/milestone/single-user.xml.

Conclusión

Hemos analizado cómo funcionan los servicios en OpenSolaris, ahora es momento de crear los nuestros propios para los sistemas que implementemos.
Al principio puede ser medio complicado, pero con el tiempo veremos que estos extraños comandos nuevos se nos volverán parte de nuestro día a día.

Publicar un comentario en la entrada