Si quieres ser capaz de gestionar eficazmente las aplicaciones web en desarrollo y en producción, tienes que entender las variables de entorno.

Este no fue siempre el caso. Hace sólo unos años, casi nadie configuraba sus aplicaciones Rails con variables de entorno. Pero entonces apareció Heroku.

Heroku introdujo a los desarrolladores el enfoque de las aplicaciones de 12 factores. En su manifiesto de aplicaciones de 12 factores exponen muchas de sus mejores prácticas para crear aplicaciones que sean fáciles de desplegar. La sección sobre las variables de entorno ha sido particularmente influyente.

La aplicación de doce factores almacena la configuración en variables de entorno (a menudo abreviado como env vars o env). Las env vars son fáciles de cambiar entre los despliegues sin cambiar ningún código; a diferencia de los archivos de configuración, hay pocas posibilidades de que se comprueben en el repositorio de código accidentalmente; y a diferencia de los archivos de configuración personalizados, u otros mecanismos de configuración como las propiedades del sistema de Java, son un estándar agnóstico para el lenguaje y el sistema operativo.

Más Rubyistas están utilizando variables de entorno que nunca. Pero a menudo es en una forma de carga de la facultad. Estamos usando estas cosas sin entender realmente cómo funcionan.

Este post te mostrará cómo funcionan realmente las variables de entorno – y quizás más importante, cómo NO funcionan. También exploraremos algunas de las formas más comunes de gestionar las variables de entorno en tus aplicaciones Rails. Comencemos.

NOTA: Puedes leer sobre la seguridad de las variables de entorno aquí.

Cada proceso tiene su propio conjunto de variables de entorno

Cada programa que ejecutas en tu servidor tiene al menos un proceso. Ese proceso obtiene su propio conjunto de variables de entorno. Una vez que las tiene, nada fuera de ese proceso puede cambiarlas.

Un error comprensible que cometen los principiantes es pensar que las variables de entorno son de alguna manera en todo el servidor. Servicios como Heroku seguro que hacen parecer que establecer las variables de entorno es el equivalente a editar un archivo de configuración en el disco. Pero las variables de entorno no se parecen en nada a los archivos de configuración.

Cada programa que ejecutas en tu servidor obtiene su propio conjunto de variables de entorno en el momento en que lo lanzas.

Cada proceso tiene su propio entorno. Cada proceso tiene su propio entorno.

Las variables de entorno mueren con su proceso

¿Alguna vez has configurado una variable de entorno, has reiniciado y te has encontrado con que ha desaparecido? Dado que las variables de entorno pertenecen a los procesos, eso significa que cada vez que el proceso se cierra, su variable de entorno desaparece.

Puedes ver esto estableciendo una variable de entorno en una sesión IRB, cerrándola, y tratando de acceder a la variable en una segunda sesión irb.

Cuando un proceso se cierra, sus variables de entorno se pierden Cuando un proceso se cierra, sus variables de entorno se pierden

Este es el mismo principio que hace que se pierdan las variables de entorno cuando el servidor se reinicia, o cuando se sale del shell. Si quiere que persistan a través de las sesiones, tiene que almacenarlas en algún tipo de archivo de configuración como .bashrc .

Un proceso obtiene sus variables de entorno de su padre

Cada proceso tiene un padre. Eso es porque cada programa tiene que ser iniciado por algún otro programa.

Si usas tu shell bash para lanzar vim, entonces el padre de vim es el shell. Si tu aplicación Rails utiliza imagemagick para identificar una imagen, entonces el padre del programa identify será tu aplicación Rails.

Los procesos hijos heredan las variables de entorno de sus padres Los procesos hijos heredan las variables de entorno de sus padres

En el siguiente ejemplo, estoy estableciendo el valor de la variable de entorno $MARCO en mi proceso IRB. Luego utilizo back-ticks para hacer un shell out y hacer eco del valor de esa variable.

Como IRB es el proceso padre del shell que acabo de crear, obtiene una copia de la variable de entorno $MARCO.

Las variables de entorno establecidas en Ruby son heredadas por los procesos hijosLas variables de entorno establecidas en Ruby son heredadas por los procesos hijos

Los padres pueden personalizar las variables de entorno enviadas a sus hijos

Por defecto, un hijo obtendrá copias de cada variable de entorno que tenga su padre. Pero el padre tiene control sobre esto.

Desde la línea de comandos, puedes usar el programa env. Y en bash hay una sintaxis especial para establecer variables de entorno en el hijo sin establecerlas en el padre.

Usa el comando env para establecer variables de entorno para un hijo sin establecerlas en el padre Usa el comando env para establecer variables de entorno para un hijo sin establecerlas en el padre

Si estás haciendo shelling desde dentro de Ruby también puedes proporcionar variables de entorno personalizadas al proceso hijo sin ensuciar tu hash ENV. Simplemente usa la siguiente sintaxis con el método system:

Cómo pasar variables de entorno personalizadas al método del sistema de Ruby Cómo pasar variables de entorno personalizadas al método del sistema de Ruby

Los hijos no pueden establecer las variables de entorno de sus padres

Dado que los hijos sólo obtienen copias de las variables de entorno de sus padres, los cambios hechos por el hijo no tienen efecto en el padre.

Las variables de entorno se "pasan por valor", no "por referencia"Las variables de entorno se «pasan por valor», no «por referencia»

Aquí, utilizamos la sintaxis back-tick para desgranar e intentar establecer una variable de entorno. Mientras que la variable se establecerá para el hijo, el nuevo valor no se traslada al padre.

Los procesos hijos no pueden cambiar las variables de entorno de sus padres Los procesos hijos no pueden cambiar las variables de entorno de sus padres

Los cambios en el entorno no se sincronizan entre los procesos en ejecución

En el ejemplo de abajo estoy ejecutando dos copias de IRB una al lado de la otra. Añadir una variable al entorno de una sesión IRB no tiene ningún efecto en la otra sesión IRB.

Añadir una variable de entorno a un proceso no lo cambia para otros procesosAñadir una variable de entorno a un proceso no lo cambia para otros procesos

Tu shell es sólo una interfaz de usuario para el sistema de variables de entorno.

El sistema en sí es parte del núcleo del sistema operativo. Eso significa que el shell no tiene ningún poder mágico sobre las variables de entorno. Tiene que seguir las mismas reglas que cualquier otro programa que se ejecute.

Las variables de entorno NO son lo mismo que las variables del shell

Uno de los mayores malentendidos ocurre porque los shells proporcionan sus propios sistemas de variables «locales» del shell. La sintaxis para usar variables locales es a menudo la misma que para las variables de entorno. Y los principiantes a menudo confunden los dos.

Pero las variables locales no se copian a los hijos.

Las variables de entorno no son lo mismo que las variables de shellLas variables de entorno no son lo mismo que las variables de shell

Veamos un ejemplo. Primero establezco una variable local del shell llamada MARCO. Como es una variable local, no se copia a ningún proceso hijo. En consecuencia, cuando intento imprimirla a través de Ruby, no funciona.

A continuación, uso el comando export para convertir la variable local en una variable de entorno. Ahora se copia en cada nuevo proceso que crea este shell. Ahora la variable de entorno está disponible para Ruby.

Las variables locales no están disponibles para los procesos hijos. Exportar convierte la variable local en una variable de entorno. Las variables locales no están disponibles para los procesos hijos. Exportar convierte la variable local en una variable de entorno.

La gestión de las variables de entorno en la práctica

¿Cómo funciona todo esto en el mundo real? Hagamos un ejemplo:

Supongamos que tienes dos aplicaciones Rails ejecutándose en un mismo ordenador. Estás utilizando Honeybadger para monitorizar estas aplicaciones en busca de excepciones. Pero te encuentras con un problema.

Te gustaría almacenar tu clave de API de Honeybadger en la variable de entorno $HONEYBADGER_API_KEY. Pero tus dos aplicaciones tienen dos claves de API diferentes.

¿Cómo puede una variable de entorno tener dos valores diferentes?

Ahora espero que sepas la respuesta. Dado que las env vars son por proceso, y mis dos aplicaciones de rails se ejecutan en diferentes procesos no hay ninguna razón por la que no puedan tener cada una su propio valor para $HONEYBADGER_API_KEY.

Ahora la única pregunta es cómo configurarlo. Afortunadamente hay algunas gemas que hacen que esto sea realmente fácil.

Figaro

Cuando instalas la gema Figaro en tu aplicación Rails, cualquier valor que introduzcas en config/application.yml se cargará en el hash ENV de ruby al iniciarse.

Sólo tienes que instalar la gema:

# Gemfilegem "figaro"

Y empezar a añadir elementos a application.yml. Es muy importante que añadas este archivo a tu .gitignore, para que no confirmes accidentalmente tus secretos.

# config/application.ymlHONEYBADGER_API_KEY: 12345

Dotenv

La gema dotenv es muy similar a Figaro, excepto que carga las variables de entorno desde .env, y no utiliza YAML.

Sólo tienes que instalar la gema:

# Gemfilegem 'dotenv-rails'

Y añadir tus valores de configuración a .env – y asegúrate de ignorar en git el archivo para no publicarlo accidentalmente en github.

HONEYBADGER_API_KEY=12345

Entonces puedes acceder a los valores en tu hash de Ruby ENV

ENV

También puedes ejecutar comandos en el shell con tu conjunto predefinido de env vars así:

dotenv ./my_script.sh

¿Secrets.yml?

Lo siento. Secrets.yml – aunque genial – no establece variables de entorno. Así que no es realmente un reemplazo para gemas como Figaro y dotenv.

Plain old Linux

También es posible mantener conjuntos únicos de variables de entorno por aplicación utilizando comandos básicos de linux. Un enfoque es hacer que cada aplicación que se ejecuta en su servidor sea propiedad de un usuario diferente. A continuación, puede utilizar el .bashrc del usuario para almacenar los valores específicos de la aplicación.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.