Instalación automática de Shiny y RStudio server en Raspberry Pi con Ansible
Tengo una publicación relacionada sobre la instalación manual de Shiny y RStudio Server en una Raspberry Pi, pero incluso con los últimos avances en el soporte de software para la arquitectura ARM, este proceso aún consume mucho tiempo y requiere mucho copiar/pegar y observar la terminal esperando que se complete una tarea para poder comenzar con la siguiente, así que decidí idear una mejor solución, y es automatizar el proceso para que pueda dejarse desatendido y regresar más tarde cuando haya terminado.
Para automatizar el proceso de instalación y configuración, decidí usar Ansible, aquellos en DevOps deben estar familiarizados con el poder de Ansible, pero incluso si nunca has escuchado de ello, no te preocupes, no necesitas conocer Ansible para aprovechar sus capacidades de automatización, yo mismo no soy un experto en Ansible y he sido capaz de realizar este proyecto con solo conocimientos básicos de la herramienta, así que si yo puedo hacerlo, tú también puedes. Te guiaré a través del proceso asumiendo que no tienes experiencia previa con esta herramienta y solo algunas habilidades básicas de terminal de Linux.
Ansible es una herramienta de implementación de aplicaciones, administración de configuración y aprovisionamiento de software de código abierto que habilita la infraestructura como código. Se ejecuta en muchos sistemas de tipo Unix y puede configurar tanto sistemas tipo Unix como Microsoft Windows. En términos simples, te permite automatizar tareas en tu infraestructura (una, o muchas Raspberry Pi a la vez en nuestro caso) definiendo un conjunto de pasos para ejecutar en archivos YAML llamados “playbooks”. Me sacrifique por el equipo y escribí algunos playbooks de Ansible para automatizar la mayor parte del proceso de instalación, pero dejando algo de espacio para que configures la instalación a tu gusto a través de un archivo de configuración, por lo que no necesitas modificar los playbooks (lo que requerirá que sepas cómo funcionan). Aunque, si deseas tener una comprensión básica de cómo funciona esta herramienta, hay una buena serie de Ansible para principiantes en el canal de YouTube de Jeff Geerling y si eres el tipo de personas que prefiere leer en lugar de ver cosas, aquí hay un Tutorial de Ansible para principiantes bastante agradable pero lamentablemente, está sólo en inglés.
✏️ Ten en cuenta que esto solo se ha probado con las versiones de software especificadas en el archivo
config_vars.yml
, es muy probable que funcione aún con las versiones de software más nuevas, pero en algunos casos, podría requerir algunas modificaciones a los playbooks, las que haré tan pronto como note el problema.
Prepara la Raspberry Pi
Incluso si la mayor parte del proceso se puede automatizar con Ansible, aún necesitamos al menos una Raspberry Pi en funcionamiento para configurar, por lo tanto, debemos comenzar cargando un sistema operativo (SO) en una tarjeta SD (recomiendo al menos 32 GB clase 10 HC1). Ten en cuenta que RStudio Server es compatible solo con los sistemas operativos arm64, por lo que si deseas poder instalarlo, deberás elegir un sistema operativo de 64 bits, los playbooks funcionan tanto con Raspberry Pi OS como con Ubuntu.
Descarga “Raspberry Pi Imager” del sitio oficial e instálalo en tu sistema, ejecuta “Raspberry Pi Imager”, selecciona un sistema operativo adecuado, elije tu “Tarjeta SD” y presiona “Escribir”.
Una vez finalizado el proceso, tendras una instalación limpia de un sistema operativo en tu tarjeta micro SD, inserta la tarjeta en tu Raspberry Pi, conecta un teclado y una pantalla y enciéndela.
Inicia sesión en el sistema (el usuario y la contraseña predeterminados son pi
y raspberry
para Raspberry Pi OS, y en Ubuntu es ubuntu
tanto para el usuario como para la contraseña) y ejecuta una actualización inicial del sistema con estos comandos:
A continuación, debes configurar una IP estática para que puedas encontrar tu Pi fácilmente en tu red más adelante.
Para configurar una IP estática en Raspberry Pi OS, ejecuta estos comandos. Esta es una configuración de IP de muestra para una conexión por cable, modificala de acuerdo a tus propias necesidades:
# Configuración IP de muestra:
sudo nmcli c mod 'Wired connection 1' ipv4.addresses 192.168.3.101/24 ipv4.method manual
sudo nmcli con mod 'Wired connection 1' ipv4.gateway 192.168.3.1
sudo nmcli con mod 'Wired connection 1' ipv4.dns "192.168.3.1"
sudo nmcli c down 'Wired connection 1' && sudo nmcli c up 'Wired connection 1'
Luego debes volver a establecer una nueva conexión SSH con tu Pi ya que el IP ha cambiado.
Y para configurar la IP en Ubuntu, debes crear este archivo, sudo nano /etc/netplan/01-netcfg.yaml
, agregar el siguiente contenido (edita según sea necesario) y aplicar la configuración con sudo netplan apply
.
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: false
addresses:
- 192.168.3.101/24
nameservers:
addresses: [8.8.8.8, 8.8.4.4, 192.168.3.1]
routes:
- to: default
via: 192.168.3.1
Luego necesitamos establecer algunas configuraciones básicas con raspi-config
. Ejecuta sudo raspi-config
y realiza las siguientes tareas (en Ubuntu debes instalarlo primero con sudo apt install raspi-config
):
- Opcionalmente, cambia la contraseña del usuario “pi” (System Options –> Password)
- Habilita el servidor SSH (Interface Options –> SSH)
- Establece tu configuración regional (Localization Options)
- Expande el sistema de archivos para utilizar la capacidad total de tu tarjeta SD (Advanced Options –> Expand Filesystem)
- Deshabilita los nombres de interfaz de red predecibles (Advanced Options –> Network Interface Names)
Cuando hayas terminado, sal de la herramienta raspi-config
y reinicia tu Pi.
Si no tienes una, debes crear una clave SSH, incluso si es posible usar Ansible proporcionando una contraseña para tus hosts de forma interactiva, una forma más conveniente y segura de hacerlo es usando un par de claves SSH. Para crear una, ejecuta los siguientes comandos en la terminal:
# Crea la carpeta .ssh
cd ~
mkdir .ssh
cd .ssh
# Crea el archivo authorized_keys
touch authorized_keys
# Establece permisos de acceso adecuados
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
# Crea el par de claves
ssh-keygen
# Agregua la nueva clave al archivo authorized_keys
cat id_rsa.pub >> authorized_keys
# Si usas Putty como tu cliente SSH (Windows), genera una clave ppk; de lo contrario, ignora estos pasos
sudo apt install putty-tools
puttygen id_rsa -o id_rsa.ppk
Copia los archivos id_rsa e id_rsa.pub (id_rsa.ppk si corresponde) a la máquina que va a usar para ejecutar los playbooks, a mí me gusta usar sftp
pero puedes hacerlo de la manera que prefieras (por ejemplo, con una memoria USB). Después de haber copiado los archivos de clave, elimínalos de tu Pi con rm ~/.ssh/id_rsa*
. Si ya tienes una clave SSH, confío en que sabes cómo agregarla a tu sistema operativo en el momento de cargarlo con Raspberry Pi Imager.
Ahora tu Pi está lista, desconecta el teclado y el monitor, conecta la Raspberry Pi a tu red (recomiendo usar una conexión por cable).
Instala Ansible
En teoría, podrías instalar Ansible en la propia Raspberry Pi y ejecutar los playbooks directamente en ella con connection: local
pero no sería práctico, es mejor ejecutar los playbooks desde una computadora que no sea tu Raspberry Pi.
Para instalar Ansible, si tienes un sistema basado en Unix (es decir, Linux, macOS) a tu disposición, tienes suerte, instalar Ansible es muy simple.
# Instala python3
sudo apt install python3 # En macOS usa `brew install python3`
# Instala pip3
sudo apt install python3-pip
# Instala la versión 9.5.1 de Ansible con pip3 (Por reproducibilidad)
sudo pip3 install ansible==9.5.1 --break-system-packages
Si estás en Windows, lamentablemente, no hay forma de ejecutar Ansible de forma nativa, tu mejor opción es habilitar WSL (Subsistema de Windows para Linux), instalar una distribución de Linux del Microsoft Store (recomiendo Ubuntu) y ejecutar los pasos anteriores en tu máquina virtual Linux.
Puedes encontrar una guía detallada para instalar WSL aquí y puede encontrar más información sobre la instalación de Ansible en el sitio de documentación oficial.
Además, dado que vamos a estar instalando varios paquetes desde la fuente en una SBC de baja potencia, algunas de estas tareas van a tomar bastante tiempo y la conexión SSH
podría cerrarse automáticamente por inactividad, para evitar esta situación, activa el envío de paquetes “keep-alive” al servidor editando el archivo ssh_config
con sudo nano /etc/ssh/ssh_config
en la computadora que está ejecuntado Ansible y agregando estas dos líneas debajo de Host *
:
⚠️ Es muy importante no saltarse el paso anterior, de lo contrario, la conexión SSH podría fallar silenciosamente mientras se ejecutan tareas largas en Ansible y vas a estar esperando inútilmente con tu Raspberry Pi sin hacer nada en realidad.
Descarga y configura los Playbooks
Los playbooks están en un repositorio público en GitHub, puedes clonar el repositorio con estos comandos:
# Instala git si aún no lo tienes
sudo apt install git
# Clonar el último commit del repositorio
git clone https://github.com/andresrcs/raspberry_pi_server.git --depth 1
Ansible no ejecuta playbooks en “carpetas de escritura global”, por lo que debes configurar los permisos de la carpeta raspberry_pi_server
en 755
.
Ten en cuenta que en WSL es necesario volver a montar la unidad C
para poder cambiar los permisos de los archivos, por lo que debes hacer esto antes de cambiar los permisos:
Para configurar los playbooks, primero debes definir tu “inventario”, esta es una lista de los hosts a los que te vas a conectar, edita el archivo raspberry_pi_server/inventory.ini
y agrega la IP de tu(s) Raspberry Pi(s):
[raspberries] # Esto representa un grupo de Raspberries
raspberry_01 ansible_host=192.168.3.101 # Este es el nombre de host y la IP de una Raspberry Pi individual
# Puedes agregar tantas Raspberries como necesites
Luego, configura las variables comunes para el grupo [raspberries]
editando el archivo raspberry_pi_server/group_vars/raspberries.yml
, lo más importante para verificar aquí es la ruta a tu clave ssh y el usuario predeterminado para el sistema operativo que estes usando.
---
ansible_user: pi # Este es el usuario predeterminado para el sistema operativo
ansible_become_method: sudo
ansible_python_interpreter: /usr/bin/python3
ansible_ssh_private_key_file: ~/.ssh/raspberrypi_key # La ubicación de la clave ssh en la computadora que está ejecuntando Ansible.
Ahora, puedes configurar las opciones de instalación editando las variables en el archivo raspberry_pi_server/vars/config_vars.yml
, las opciones ya configuradas están bien para la mayoría de los casos de uso, incluidas configuraciones de seguridad razonables, pero como mínimo, debes configurar tu contraseña personal para el usuario principal de PostgreSQL. También puedes elegir tu método preferido para instalar R, si no deseas usar la opción predeterminada, ten en cuenta que usar la opción R4Pi solo es posible con Raspberry Pi OS y siempre instalará la última versión de R disponible.
---
# Configuraciones del sistema ##################################################
# Parametros Swap
swap_file_path: '/var/swap.1'
# Utiliza cualquiera de los siguientes sufijos
# c=1
# w=2
# b=512
# kB=1000
# K=1024
# MB=1000*1000
# M=1024*1024
# xM=M
# GB=1000*1000*1000
# G=1024*1024*1024
swap_file_size: '3GB'
swappiness: '10'
# Instalar Nginx?
install_nginx: true
# Instalar PostgreSQL?
install_postgresql: true
# Configuraciones de seguridad #################################################
# Puertos para abrir
exposed_ports:
- { rule: 'allow', port: 22, proto: 'tcp' } # ssh
- { rule: 'allow', port: 22, proto: 'udp' } # ssh
- { rule: 'allow', port: 80, proto: 'tcp' } # http
- { rule: 'allow', port: 5432, proto: 'tcp' } # Postgresql (omitir si Postgresql no está instalado)
- { rule: 'allow', port: 5432, proto: 'udp' } # Postgresql (omitir si Postgresql no está instalado)
# - { rule: 'allow', port: 8787, proto: 'tcp' } # RStudio Server (descomentar si Nginx no está instalado)
# - { rule: 'allow', port: 3838, proto: 'tcp' } # Shiny Server (descomentar si Nginx no está instalado)
# Contraseña para el usuario principal de PostgreSQL
postgres_password: 'very_secure_password'
# Reglas de acceso para PostgreSQL
postgresql_rules:
postgresql_rules:
- { contype: local, users: postgres, address: samehost, method: trust }
- { contype: local, users: all, address: samehost, method: trust }
- { contype: hostssl, users: all, address: 0.0.0.0/0, method: scram-sha-256 }
- { contype: host, users: all, address: 0.0.0.0/0, method: scram-sha-256 }
- { contype: hostssl, users: all, address: '::0/0', method: scram-sha-256 }
- { contype: host, users: all, address: '::0/0', method: scram-sha-256 }
- { contype: host, users: all, address: 127.0.0.1/32, method: scram-sha-256 }
- { contype: host, users: all, address: '::1/128', method: scram-sha-256 }
# Versiones principales de software ############################################
# Versión de R a instalar
use_r4pi: true # Si se establece en verdadero, se instalará la última versión de R, esto solo es compatible con
# Raspberry Pi OS.
use_rig: false # Si se establece en verdadero, no olvide especificar una versión R en la siguiente línea
r_version: '' # (e.g. '4.3.3') Actualmente, solo puede elegir la versión R si va a ser
# instalado con rig o compilado (con 'use_r4pi' y 'use_rig' establecidos como false).
# Versión de shiny-server a instalar
shiny_server_version: 'v1.5.21.1012'
# Versión del servidor rstudio-server a instalar
rstudio_version: '2024.04.0-daily+651'
Ejecuta los Playbooks
En condiciones ideales, como usando el último modelo de Raspberry Pi, con 8 GB de RAM, booteando desde un SSD, y conectado a una red estable, puedes simplemente acceder a la carpeta raspberry_pi_server
y ejecutar el libro de jugadas site.yml
para instalar todo de una sóla vez:
Pero en condiciones menos que ideales, es muy probable que encuentres algunos errores aleatorios causados por la sobrecarga de la Pi o conexiones de red inestables, por lo que, para mitigar este problema y hacer que el proceso de instalación sea más flexible, he dividido el proceso en tres playbooks individuales:
cd raspberry_pi_server
ansible-playbook install_basic_services.yml
ansible-playbook install_shiny_server.yml
ansible-playbook install_rstudio_server.yml
Si decides que solo necesitas el servidor Shiny o el servidor RStudio pero no el otro, o si ya has instalado los servicios de soporte que deseas, puedes ejecutar solo los playbooks que necesitas.
Si deseas actualizar algo en el futuro, como R, RStudio o Shiny server (no puedo garantizar que siempre funcionará sin necesidad de cambios), puedes simplemente cambiar la versión en el archivo de configuración y ejecutar la parte específica del playbook aprovechando las “etiquetas” definidas.
Por ejemplo, esto solo instalará la versión R definida en el archivo de configuración y nada más:
Las etiquetas disponibles son:
- install_basic_services.yml
secure
: Establecer la configuración de seguridad en el servidorswap
: Agregar memoria swap al servidornginx
: Instalar y configurar Nginx + PHPpostgresql
: Instalar y configurar PostgreSQLr
: Instalar R desde la fuentedisable_wifi
: Desactivar el módulo Wifi y Bluetooth
- install_shiny_server.yml
shiny-server
: Instalar shiny-server desde la fuenteconfigure_shiny
: Configurar shiny-server
- install_rstudio_server.yml
rstudio
: Instalar RStudio server desde la fuenteconfigure_rstudio
: Configurar RStudio server
También puedes hacer lo contrario y omitir partes específicas de los playbooks usando la opción --skip-tags
, por ejemplo, si no necesitas PostgreSQL, puedes evitar instalarlo ejecutando el playbook de esta manera:
Después de ejecutar con éxito todos los playbooks, tendrás una instalación completamente funcional lista para ser utilizada, por lo que podras simplemente abrir una sesión de RStudio en http://ip_de_tu_servidor/rstudio
y/o publicar tus aplicaciones Shiny en la carpeta /srv/shiny-server
y acceder a ellas en http://ip_de_tu_servidor/shiny/nombre_de_tu_app
.
⚠️ Si la configuración de Nginx no ha sido establecida por el playbook
install_basic_services.yml
porque lo has omitido, debes configurar el proxy inverso manualmente o acceder a los servicios con su puerto específico, por ejemplohttp://your_server_ip/3838/your_app_name
, esto también requiere que abras el puerto correspondiente en el firewall.
Notas Finales
Incluso con la automatización, la instalación de forma nativa llevará mucho más tiempo que, por ejemplo, con el uso de contenedores, especialmente si usas una Raspberry Pi con poca memoria RAM (< 4GB) pero como está automatizado, simplemente puedes dejar que se ejecute y volver más tarde, y disfrutarás de la facilidad de gestión de una instalación nativa.
Además, ten en cuenta que el proceso de instalación llevará tu Raspberry Pi a sus límites, por lo que puedes esperar algunos errores aleatorios, pero eso no significa que no va ha funcionar, simplemente reinicia tu Pi, vuelve a ejecutar el playbook problemático y ve si funciona la segunda vez. He hecho todo lo posible para que esto sea funcional a largo plazo estableciendo versiones de software específicas, pero aún es posible que una actualización de librerias del sistema inutilice los playbooks. Si encuentras algún problema, ve al repositorio de GitHub para los playbooks y registra un “issue”, o mejor aún, si sabes cómo solucionarlo, haz un “pull request”.
Como nota final, quiero señalar que este enfoque se puede extender aún más de acuerdo con tus propias necesidades, por ejemplo, puedes implementar la restauración automática de tu servidor, incluido el contenido desplegado. Por ejemplo, yo tengo un playbook adicional para restaurar las aplicaciones, servicios y bases de datos que normalmente ejecuto en mi Raspberry Pi, por lo que, en caso de una falla catastrófica, puedo volver a un estado operativo en un período corto de tiempo y con poco esfuerzo, comparado con hacer una restauración manual de mi sistema.