Saltar al contenido principal
Version: 0.54.0-rc.8

Sistema de Compilación

Lana utiliza Nix Flakes para compilaciones reproducibles y Cachix para almacenamiento en caché binario. Si no estás familiarizado con Nix, la versión corta es: es un sistema de compilación que garantiza que las mismas entradas siempre produzcan la misma salida, sin importar en qué máquina estés compilando. Esto elimina el problema de "funciona en mi máquina" tanto para desarrollo como para CI.

Esta página cubre cómo funcionan las compilaciones localmente, cómo CI utiliza la caché de Nix y cómo se producen las imágenes de Docker para los lanzamientos.

Estructura del Nix Flake

Todo comienza con el archivo flake.nix en la raíz del repositorio. Define todos los objetivos de compilación, entornos de desarrollo y puntos de entrada de CI:

flake.nix
├── packages
│ ├── lana-cli # El binario principal del servidor/CLI (compilación de lanzamiento, optimizada)
│ ├── lana-cli-debug # Una compilación de depuración (más rápida de compilar, útil en desarrollo)
│ └── lana-deps # Solo el árbol de dependencias de Rust, precompilado (usado para almacenamiento en caché)
├── devShells
│ └── default # El entorno de desarrollo con todas las herramientas
├── checks
│ └── flake-check # Valida el flake mismo
└── apps
├── nextest # Ejecuta la suite de pruebas de Rust mediante cargo nextest
├── bats # Ejecuta las pruebas de extremo a extremo de BATS
└── simulation # Ejecuta simulaciones de escenarios de instalaciones

La sección packages es lo que compila CI. La sección apps proporciona puntos de entrada convenientes para ejecutar pruebas — CI llama a nix run .#nextest en lugar de manipular cargo nextest manualmente, porque la aplicación Nix asegura que todas las variables de entorno y dependencias correctas estén configuradas.

El paquete lana-deps merece mención especial: precompila solo el árbol de dependencias de Rust (todos los crates en Cargo.lock) sin ningún código propio de lana. Esta es una optimización de almacenamiento en caché — dado que las dependencias cambian con mucha menos frecuencia que el código de la aplicación, compilarlas por separado significa que pueden almacenarse en caché y reutilizarse en muchas compilaciones.

Entorno de Desarrollo

Cuando ejecutas nix develop, Nix configura un entorno con todas las herramientas que necesitas para el desarrollo:

nix develop

Esto te proporciona: el toolchain estable de Rust, Node 20, pnpm 10, Python 3.13, un cliente de PostgreSQL, sqlx-cli y todas las demás utilidades que usa el proyecto. No necesitas instalar ninguna de estas herramientas globalmente en tu máquina — Nix las gestiona por ti y no interfieren con otros proyectos.

Si has configurado Cachix (ver más abajo), este comando es casi instantáneo porque el entorno precompilado se descarga desde la caché en lugar de compilarse en tu máquina.

Compilar el Binario de Producción

Hay dos formas de compilar el binario lana-cli:


# Compilación de producción — optimizada, usada en CI para imágenes Docker

nix build --impure .#lana-cli-release

# Compilación de depuración — más rápida de compilar, incluye símbolos de depuración

nix build .#lana-cli-debug

La compilación de producción usa el flag --impure porque lee variables de entorno (VERSION, COMMITHASH, BUILDTIME) que se integran en el binario. Estas son establecidas por el pipeline de CI para que la aplicación en ejecución sepa qué versión es y cuándo fue compilada. En desarrollo local normalmente usarías la compilación de depuración, que omite esto y compila mucho más rápido.

Imágenes Docker

Las imágenes Docker se compilan durante el pipeline de lanzamiento de Concourse (consulta CI/CD e Ingeniería de Lanzamientos para ver el panorama completo). Lo importante es entender que hay dos Dockerfiles diferentes dependiendo de si estamos compilando un candidato de lanzamiento o un lanzamiento final:

  • Dockerfile.rc se usa para candidatos de lanzamiento. El paso de compilación de Nix compila el binario, y este Dockerfile simplemente lo copia en una imagen base mínima. Esto es rápido porque el binario ya está compilado.

  • Dockerfile.release se usa para el lanzamiento final. En lugar de copiar un binario local, descarga el binario publicado desde el Release de GitHub. Esto hace que la compilación de la imagen sea completamente reproducible — cualquiera puede reconstruir exactamente la misma imagen a partir de los artefactos del Release de GitHub.

Ambos Dockerfiles usan una imagen base distroless, que contiene solo lo mínimo necesario para ejecutar un binario (sin shell, sin gestor de paquetes, sin utilidades). Esto minimiza la superficie de ataque y mantiene la imagen pequeña.

Las cuatro imágenes

Cada lanzamiento produce cuatro imágenes Docker, enviadas a Google Artifact Registry:

ImagenQué contieneRegistro
lana-bankEl binario principal del servidor lana-cligcr.io/galoyorg/lana-bank
lana-bank-admin-panelLa aplicación Next.js del panel de administracióngcr.io/galoyorg/lana-bank-admin-panel
lana-bank-customer-portalLa aplicación Next.js del portal de clientesgcr.io/galoyorg/lana-bank-customer-portal
dagster-code-location-lana-dwEl código del pipeline de datos Dagsterus.gcr.io/galoyorg/dagster-code-location-lana-dw

Metadatos de compilación

Cada compilación de imagen inyecta tres piezas de información a través de un archivo .env para que la aplicación en ejecución pueda reportar qué versión es:

  • VERSION — la versión semántica (ej., 0.42.0)
  • COMMITHASH — el SHA corto de git desde el cual se compiló
  • BUILDTIME — una marca de tiempo UTC de cuándo ocurrió la compilación

Almacenamiento en Caché Binario de Cachix

Este es el problema que Cachix resuelve: Las compilaciones de Nix son perfectamente reproducibles, pero son lentas cuando estás compilando desde cero. Compilar la cadena de herramientas de Rust, todas las dependencias y el binario de la aplicación puede llevar mucho tiempo. Si cada ejecución de CI y cada desarrollador tuviera que hacer esto desde cero, sería doloroso.

Cachix es una caché binaria para Nix. Cuando alguien compila una derivación de Nix y la envía a Cachix, todos los demás que necesiten la misma derivación pueden descargar el resultado precompilado en lugar de compilarlo ellos mismos. Dado que las derivaciones de Nix están direccionadas por contenido (la salida está determinada completamente por las entradas), esto es seguro — siempre obtendrás exactamente el mismo resultado ya sea que compiles localmente o descargues desde la caché.

Detalles de la caché

Nombre de cachégaloymoney
URLhttps://galoymoney.cachix.org
Quién escribe en ellaTrabajos de CI configurados con un token de escritura de Cachix
Quién lee de ellaFlujos de trabajo de GitHub Actions, trabajos de Concourse y cualquier desarrollador que ejecute cachix use galoymoney

El diseño de almacenamiento en caché de dos sistemas

Existe una separación intencional entre quién escribe en la caché y quién lee de ella:

  • Los constructores de CI realizan el trabajo pesado. Trabajos de CI seleccionados construyen derivaciones de Nix relevantes y las envían a Cachix.

  • GitHub Actions es el consumidor. Cada flujo de trabajo configura Cachix con skipPush: true, lo que significa que descargará binarios preconstruidos de la caché pero nunca cargará nada. Los ejecutores de GitHub Actions son efímeros, y tener muchos ejecutores paralelos enviando a la caché crearía cargas redundantes y posibles condiciones de carrera.

Este diseño mantiene la caché limpia y garantiza que las compilaciones sean rápidas en ambos sistemas de CI.

Cómo funciona el llenado de caché

Los pasos de compilación de CI que usan cachix watch-exec cargan derivaciones a medida que se construyen, por lo que trabajos posteriores pueden obtener esos artefactos en lugar de recompilar. Esto mantiene el calentamiento de caché incremental y reduce la compilación repetida entre pipelines y desarrollo local.

Usando Cachix como desarrollador

Puedes acelerar tus comandos locales nix develop y nix build configurando Cachix:


# Configuración única — añade galoymoney como caché binaria

cachix use galoymoney

# Ahora esto descarga herramientas precompiladas en lugar de compilarlas

nix develop

Después de esto, Nix verificará la caché galoymoney antes de compilar cualquier cosa. Si la derivación que necesitas ya está allí, se descarga en segundos en lugar de compilarse en minutos.

Qué sucede cuando la caché está vacía

Si la caché no tiene lo que necesitas (un "fallo de caché"), Nix simplemente lo compila localmente. Esto es más lento pero siempre funciona — la caché es una optimización de rendimiento, no un requisito. El script de utilidad wait-cachix-paths está disponible en CI para casos donde un trabajo necesita esperar a que la caché sea poblada por un pipeline paralelo antes de continuar.


Modo Offline de SQLx

Lana utiliza SQLx para consultas de base de datos, que proporciona verificación SQL en tiempo de compilación — el compilador de Rust verifica tus consultas SQL contra el esquema real de la base de datos durante la compilación. Esto es excelente para detectar errores, pero significa que necesitas una base de datos en ejecución para compilar el código.

Eso es un problema en CI, donde no hay ninguna base de datos disponible durante el paso de compilación. La solución es el modo offline de SQLx: guardas los metadatos de las consultas en un directorio .sqlx/ (incluido en git), y las compilaciones de CI usan esos metadatos en caché en lugar de conectarse a una base de datos real.


# Cuando tengas una base de datos ejecutándose localmente, regenera los metadatos

make sqlx-prepare

# En CI o al compilar sin una base de datos

SQLX_OFFLINE=true cargo build

Si cambias una consulta SQL y olvidas ejecutar make sqlx-prepare, la compilación en CI fallará porque los metadatos sin conexión no coincidirán con la consulta real. Esto es intencional: mantiene los metadatos sincronizados con el código.

Objetivos Comunes del Makefile

ObjetivoQué hace
make check-code-rustCompila todo el código Rust con SQLX_OFFLINE=true para verificar que se compile
make check-code-appsAnaliza, verifica tipos y compila las aplicaciones frontend de Next.js
make sqlx-prepareRegenera los metadatos de consultas sin conexión .sqlx (requiere una base de datos en ejecución)
make sdlRegenera los archivos de esquema GraphQL a partir del código Rust
make start-depsInicia las dependencias de desarrollo locales (PostgreSQL, Keycloak, etc.)
make reset-depsDetiene las dependencias, limpia las bases de datos y reinicia todo desde cero