...
consigli-software Development

Cosa abbiamo imparato gestendo applicazioni containerizzate su macchine virtuali, perché gli strumenti che utilizzavamo hanno iniziato a frammentare il nostro lavoro e come siamo arrivati a costruire un control plane.

Per molto tempo, in Brokenice, la nostra infrastruttura di deployment è stata relativamente semplice. Il codice viveva nei repository Git, Jenkins eseguiva le pipeline, le immagini venivano pubblicate su un Docker Registry e le applicazioni giravano su macchine virtuali utilizzando Docker Compose. Traefik si occupava di instradare il traffico verso i container corretti, mentre Portainer ci forniva una vista centralizzata sul runtime e ci permetteva di intervenire sui container quando necessario.

Concettualmente, il flusso era questo:

Repository Git
      ↓
Jenkins
      ↓
Docker Registry
      ↓
Virtual Machine
      ↓
Docker Compose
      ↓
Traefik

Portainer → gestione e ispezione dei container

Non c’era nulla di particolarmente sbagliato in questa architettura. Anzi, per molte delle applicazioni che sviluppiamo, utilizzare una o più VM con Docker continua a essere una scelta perfettamente ragionevole.

Non tutte le applicazioni hanno bisogno di un cluster, non tutti i workload devono essere schedulati dinamicamente e non sempre esiste un vantaggio reale nell’introdurre un orchestratore.

Il nostro problema è iniziato altrove.

Con il tempo, i progetti sono aumentati, così come le VM e gli ambienti di staging e produzione. Le pipeline Jenkins hanno iniziato a presentare piccole differenze tra un’applicazione e l’altra. Sono aumentati i registry, le credenziali, le configurazioni di Traefik, le variabili d’ambiente e le procedure specifiche di deployment.

Portainer continuava a mostrarci i container. Jenkins continuava a eseguire le pipeline. Traefik continuava a gestire l’ingress. GitHub e Bitbucket ospitavano correttamente il codice. Altri strumenti conservavano password e segreti.

Nel frattempo, però, le richieste di assistenza dei clienti arrivavano via email, le attività di sviluppo venivano gestite su altri sistemi e la pianificazione delle milestone viveva ancora in un contesto differente.

Ogni strumento, preso singolarmente, faceva bene il proprio lavoro.

Il problema era la somma.

La nostra infrastruttura era ancora relativamente semplice. Era il modello operativo a essere diventato complesso.

Con il tempo ci siamo accorti che non stavamo realmente cercando un modo migliore per eseguire docker compose up. Quello sapevamo già farlo.

Stavamo cercando un modo migliore per gestire tutto il contesto operativo di un’applicazione e, più in generale, del progetto a cui quell’applicazione apparteneva.

È da questa esigenza che nasce Snowflake.


Il container raramente è la parte difficile

Avviare un container è semplice. Anche descrivere un’applicazione composta da più container è ormai un problema largamente risolto.

Una configurazione Compose può essere molto lineare:

services:
  app:
    image: registry.example.com/my-app:42

  worker:
    image: registry.example.com/my-app:42

  redis:
    image: redis:alpine

Il ciclo di vita più semplice richiede pochi comandi:

docker compose pull
docker compose up -d

Il problema è che il ciclo di vita operativo di un’applicazione non finisce con l’avvio dei container.

Quando si gestiscono molti progetti, iniziano rapidamente a emergere domande differenti. Quale versione dell’applicazione è attualmente in produzione? Quale deployment l’ha portata lì e chi lo ha eseguito? Qual era la release precedente? Quali componenti appartengono all’ambiente di produzione? Da quale repository arriva il codice e quali immagini Docker fanno parte del progetto?

A queste si aggiungono le domande relative alla sicurezza e all’operatività. Quali variabili d’ambiente devono essere fornite al runtime? Chi può avviare un deployment? Chi può accedere al terminale di un container in produzione? Cosa succede se la nuova release non supera l’health check? Come viene eseguito un rollback?

E poi esistono questioni che, almeno inizialmente, sembrano completamente separate dal mondo DevOps: ci sono ticket di assistenza aperti per il progetto? Quali attività sono in corso? Qual è la prossima milestone? Una richiesta ricevuta dal cliente è già diventata un’attività per il team?

Deployment, container management, package management, supporto e project management vengono normalmente trattati come domini differenti. Dal punto di vista di chi deve gestire il progetto ogni giorno, però, rappresentano spesso parti dello stesso contesto.

Il progetto.


Il nostro stack funzionava. Ed era proprio questo il problema

È relativamente semplice riconoscere un problema quando qualcosa smette di funzionare. È molto più difficile farlo quando tutti i sistemi continuano a svolgere correttamente il proprio lavoro.

Jenkins continuava a eseguire le pipeline. Traefik continuava a instradare il traffico. Portainer continuava a mostrarci i container. Docker Compose continuava ad avviare le applicazioni.

Ma, progressivamente, iniziavano a comparire differenze.

Il progetto A aveva una determinata pipeline Jenkins. Il progetto B utilizzava una pipeline simile, ma con un passaggio aggiuntivo. Il progetto C richiedeva una procedura particolare durante il deployment. Un’applicazione eseguiva le migrazioni prima dell’avvio, un’altra aveva esigenze differenti. Alcuni progetti dovevano riavviare processi worker, altri utilizzavano immagini provenienti da registry diversi.

Le configurazioni di Traefik dipendevano dal progetto. Le variabili d’ambiente dovevano essere recuperate da un altro sistema. Per capire quale versione fosse realmente in produzione poteva essere necessario controllare Jenkins, il registry, Portainer e infine il server.

Il problema non era nel singolo comando.

Era nelle convenzioni accumulate attorno ai comandi.

Una procedura funzionante può nascondere un modello operativo sempre più complesso per molto più tempo di quanto immaginiamo.

Questa è probabilmente una delle prime lezioni che abbiamo tratto dalla nostra esperienza.

La complessità operativa non nasce necessariamente da un’infrastruttura sofisticata. Può essere il risultato del numero di decisioni, eccezioni e convenzioni necessarie per gestire un’infrastruttura che, osservata esclusivamente dal punto di vista tecnico, continua a sembrare semplice.


“DevOps tooling” significa in realtà molte cose diverse

Spesso utilizziamo l’espressione “stack DevOps” per indicare strumenti che, in realtà, risolvono problemi appartenenti a livelli molto differenti.

Il primo livello è quello del provisioning dell’infrastruttura. Bisogna creare una macchina virtuale, configurare una rete, collegare uno storage o gestire il DNS. È il dominio dell’Infrastructure as Code e di strumenti come Terraform.

Una volta creata, la macchina deve essere preparata. Docker deve essere installato, il firewall configurato, i package di sistema aggiornati e le policy di sicurezza applicate. Strumenti come Ansible sono estremamente potenti in questo ambito e possono essere utilizzati anche per costruire workflow di deployment molto sofisticati.

Tecnicamente avremmo potuto modellare una parte importante delle nostre procedure attraverso inventory, ruoli e playbook.

A un certo punto, però, ci siamo posti una domanda:

Stiamo utilizzando primitive di automazione oppure stiamo costruendo una piattaforma interna utilizzando primitive di automazione?

Non c’è nulla di sbagliato nella seconda possibilità. Probabilmente molte internal developer platform sono nate proprio dall’accumulo e dalla standardizzazione di procedure interne.

Il punto è riconoscere il momento in cui il problema non consiste più soltanto nell’automatizzare una serie di comandi.

Docker Compose, ad esempio, ci fornisce un ottimo modello per descrivere servizi, network, volumi e dipendenze. Per molte applicazioni assegnate esplicitamente a una VM, è esattamente il livello di astrazione necessario. Ed è ancora oggi il modello applicativo su cui abbiamo scelto di lavorare.

Gli orchestratori, invece, affrontano domande differenti: su quale nodo deve essere eseguito un workload, quante repliche devono esistere, cosa deve accadere quando un nodo scompare e come deve essere ripristinato automaticamente lo stato desiderato.

Kubernetes, Nomad e gli altri strumenti di orchestrazione risolvono problemi reali. Quando quelle proprietà sono necessarie, adottare un orchestratore è una scelta ingegneristica assolutamente sensata.

La nostra situazione, semplicemente, era differente.


Non volevamo astrarre i server. Volevamo gestirli meglio

In molti dei nostri progetti, l’assegnazione di un’applicazione all’infrastruttura è intenzionale.

Applicazione A → VM A
Applicazione B → VM B
Applicazione C → VM C

La VM non è necessariamente un dettaglio implementativo che vogliamo nascondere dietro uno scheduler. Può essere parte integrante del design dell’infrastruttura.

In alcuni casi la separazione dipende dai clienti. In altri dalla topologia di rete o da specifici requisiti infrastrutturali. In altri ancora è una semplice valutazione economica.

Molto spesso, banalmente, l’applicazione non ha alcun bisogno concreto di un cluster.

Non avevamo bisogno di un sistema che rispondesse alla domanda: “Su quale nodo devo schedulare questo workload?”. La risposta era già stata definita nella progettazione dell’infrastruttura.

Il nostro problema era un altro:

Come possiamo gestire in modo coerente tutte le applicazioni assegnate alle nostre VM?

Da qui nasce una delle frasi che, secondo noi, descrive meglio il problema:

Non volevamo astrarre i server. Volevamo gestirli meglio.

È un problema più circoscritto rispetto alla container orchestration. Ma un problema più circoscritto non è necessariamente un problema banale.


Potevamo utilizzare piattaforme già esistenti?

Ovviamente sì.

Sarebbe scorretto raccontare Snowflake come se nessuno avesse mai affrontato problemi simili.

Portainer permette di centralizzare la gestione degli ambienti Docker ed è stato, infatti, uno degli strumenti che utilizzavamo. Coolify affronta il deployment di applicazioni su server propri attraverso un modello PaaS self-hosted. Dokploy integra Docker Compose, Git e deployment applicativo.

Esistono registry dedicati, piattaforme CI/CD, secret manager e decine di ottimi prodotti specializzati nei singoli problemi che stavamo affrontando.

Quindi, perché costruire qualcosa di nuovo?

La risposta è che, a quel punto, non stavamo più cercando semplicemente di sostituire Jenkins o Portainer con un altro deployment tool.

Volevamo costruire un modello comune attorno a package Composer e npm privati, immagini Docker, repository Git, applicazioni, VM, ambienti, componenti e deployment. Allo stesso tempo volevamo riportare nello stesso contesto i ticket di assistenza, le attività interne e le milestone del progetto.

Non perché credessimo che un singolo prodotto dovesse sostituire ogni possibile strumento aziendale.

Il motivo era molto più specifico: nel nostro modello operativo tutte queste informazioni erano collegate dallo stesso elemento.

Il progetto che stavamo gestendo.

Una richiesta di assistenza ricevuta via email poteva generare un’attività. L’attività poteva essere inserita in una milestone. La milestone apparteneva a un progetto. Quel progetto possedeva ambienti di staging e produzione, costituiti da componenti applicativi. I componenti avevano uno storico di deployment e quei deployment utilizzavano immagini, repository e credenziali.

Il valore che stavamo cercando non era “avere più funzionalità dentro una dashboard”.

Era evitare di perdere continuamente il contesto passando da uno strumento all’altro.


L’applicazione e il progetto come oggetti principali

Il modello che abbiamo iniziato a costruire era quindi differente da quello di un semplice Docker manager.

Al centro esiste l’organizzazione. All’organizzazione appartengono i progetti e, all’interno di ogni progetto, esistono le VM e gli ambienti applicativi. Un ambiente, come staging o production, contiene componenti deployabili e ogni componente possiede il proprio storico di deployment.

Concettualmente:

Organizzazione
    ↓
Progetto
    ↓
VM
    ↓
Ambiente
    ↓
Componente
    ↓
Deployment

Un componente può rappresentare l’applicazione web, i queue worker, lo scheduler o altri processi che costituiscono il runtime applicativo.

Il deployment, invece, non viene considerato semplicemente come l’esecuzione di un comando. È una revisione numerata dello stato desiderato del componente.

rev 41
rev 42
rev 43

Lo storico diventa quindi parte del modello. Un rollback non consiste più nel cercare di ricordare quale immagine fosse in esecuzione prima dell’ultimo aggiornamento: può essere rappresentato da una nuova revisione costruita utilizzando lo snapshot di uno stato precedente.

Attorno allo stesso progetto esiste poi il lavoro operativo. Ticket, task e milestone non sono oggetti completamente isolati dall’applicazione. Appartengono allo stesso contesto.

La domanda che volevamo porre al sistema non era più semplicemente:

“Quali container stanno girando su questo host?”

La domanda era diventata:

“Cosa sta succedendo sul progetto X?”

Quale versione è in produzione? Ci sono deployment falliti? Quali VM appartengono al progetto? Quali componenti sono attivi? Ci sono ticket aperti? Su quali attività sta lavorando il team e qual è la prossima milestone?

Questo cambio di prospettiva ha influenzato quasi tutte le scelte successive.


Da qui nasce Snowflake

A un certo punto abbiamo dato un nome alla piattaforma: Snowflake.

Oggi il modo più semplice in cui riusciamo a descriverla è questo:

Snowflake è un control plane per gestire applicazioni e progetti su infrastrutture VM che controlliamo direttamente.

È una piattaforma privata e self-hosted. Non introduce un runtime proprietario: le VM rimangono normali macchine Linux, Docker rimane Docker e Docker Compose continua a essere il modello applicativo sottostante. Traefik gestisce l’ingress sulle macchine.

Snowflake costruisce un control plane sopra questi elementi.

                     Snowflake
                    Control Plane
                         │
        ┌────────────────┼────────────────┐
        │                │                │
      Agent            Agent            Agent
        │                │                │
      VM A             VM B             VM C
        │                │                │
     Docker           Docker           Docker

Dalla stessa installazione vengono gestiti registry Composer e npm privati, Docker Registry e accesso Git tramite gateway. Lo stesso modello comprende organizzazioni, progetti, VM, ambienti, componenti, deployment, rollback, container management, monitoring e accesso al terminale dei container.

Sul lato operativo del progetto, Snowflake integra anche ticket di assistenza, task Kanban e milestone.

Uno degli obiettivi è stato inoltre ridurre la frammentazione degli endpoint e dei modelli di autenticazione. Composer, npm, Docker e Git possono essere raggiunti attraverso lo stesso hostname, utilizzando token organizzativi o token limitati al singolo progetto.

Il Git gateway permette, inoltre, di lavorare con repository upstream senza dover necessariamente distribuire le relative credenziali su ogni laptop degli sviluppatori.

Non pensiamo che “avere tutto in un unico prodotto” rappresenti automaticamente un vantaggio. Un monolite di funzionalità scollegate sarebbe probabilmente peggiore degli strumenti specializzati che vuole sostituire.

Nel nostro caso, il collante è il modello condiviso.

Organizzazioni, progetti, utenti, ruoli e ambienti sono gli stessi sia quando parliamo di software delivery sia quando parliamo del lavoro operativo attorno al progetto.


Dal controllo remoto a un modello agent-first

Una delle decisioni architetturali più importanti riguarda il rapporto tra Snowflake e le VM.

La soluzione apparentemente più semplice sarebbe stata controllare le macchine da remoto via SSH. È un protocollo disponibile praticamente su ogni server Linux ed è utilizzato da moltissimi strumenti di automazione.

Eppure, evolvendo Snowflake, abbiamo preferito un modello agent-first.

Il control plane non accede via SSH alle VM per eseguire i deployment. Su ogni macchina gestita gira un agent, snowflaked, che rappresenta il data plane locale.

Il bootstrap avviene direttamente sulla VM. Dalla UI viene generato un comando che l’operatore copia ed esegue sulla macchina. Il runtime registra la VM sul control plane, installa l’agent e avvia le fasi di provisioning.

Da quel momento, la relazione è concettualmente questa:

Snowflake Control Plane
          │
          │ API / eventi
          ↓
      snowflaked
          │
          ↓
     Docker Compose
          │
          ↓
       Container

Il control plane decide quale operazione deve essere eseguita. L’agent la applica localmente sulla macchina.

snowflaked mantiene lo stato della VM, esegue i deployment, gestisce le build quando la sorgente è un repository Git, interagisce con Docker Compose e permette di stabilire sessioni verso il terminale dei container o il file browser.

Questa architettura evita al control plane di conservare una chiave SSH con cui entrare in ogni server e rende più esplicita la separazione tra il sistema che coordina e quello che esegue.


La CLI dello sviluppatore e l’agent sono due cose differenti

Snowflake dispone anche di una CLI destinata agli sviluppatori e alle pipeline CI.

Dal proprio laptop, uno sviluppatore può autenticarsi, selezionare l’organizzazione e il progetto su cui sta lavorando, configurare gli accessi ai registry e avviare un deployment.

Ad esempio:

snowflake auth login
snowflake config set organization acme
snowflake config set project my-app
snowflake init
snowflake auth configure-docker
snowflake auth configure-composer
snowflake deploy create

Questa CLI è un’interfaccia da terminale verso il control plane. Lo stesso modello può essere utilizzato all’interno di una pipeline CI.

snowflaked, invece, è l’agent che gira sulla VM e appartiene al data plane.

La distinzione è intenzionale:

Developer / CI
      │
      │ Snowflake CLI
      ↓
Control Plane
      │
      │ orchestration
      ↓
snowflaked
      │
      ↓
VM Runtime

Lo sviluppatore dichiara l’operazione. Il control plane la coordina. L’agent la applica localmente sull’infrastruttura.


Il deployment come revisione

Uno dei concetti su cui abbiamo lavorato maggiormente è proprio il deployment.

Non volevamo trattarlo semplicemente come “esegui una serie di comandi sulla VM”. In Snowflake, ogni deployment rappresenta una revisione dello stato desiderato di un componente.

Una revisione contiene le informazioni necessarie a descrivere ciò che deve essere eseguito: la sorgente, i processi, l’ingress e la configurazione runtime.

La piattaforma crea la revisione e l’agent la applica sulla VM. Durante l’esecuzione, eventi e log vengono inviati al control plane.

Nel caso di una sorgente Git, il processo può includere una build direttamente sulla macchina. Il workflow può fermarsi al termine della build, lasciando la release in attesa di deployment, oppure proseguire automaticamente.

Anche il rollback segue lo stesso modello.

Immaginiamo questa cronologia:

rev 41 → deployed
rev 42 → deployed
rev 43 → failed

Ripristinare lo stato della rev 42 non significa modificare manualmente il runtime corrente. Snowflake può creare una nuova revisione utilizzando lo snapshot della configurazione precedente:

rev 44 → snapshot rev 42

La cronologia del deployment diventa parte del sistema e non dipende più dalla memoria di chi ha eseguito l’ultima operazione.


Zero-downtime su una VM rimane un problema interessante

Il deployment più semplice consiste nel fermare la vecchia applicazione e avviare la nuova.

Questa procedura funziona finché il nuovo container non impiega quaranta secondi per diventare disponibile o finché la nuova release non presenta un problema durante l’avvio.

Il ciclo di vita che volevamo era differente: preparare la nuova release, avviarla come candidata, attendere il superamento dell’health check e soltanto a quel punto completare la transizione del traffico e rimuovere la release precedente.

Concettualmente:

            ┌──── app-v41 ✓
Traefik ────┤
            └──── app-v42 starting

Quando la nuova release è pronta:

            ┌──── app-v41 ✓
Traefik ────┤
            └──── app-v42 ✓

Infine:

Traefik ───────── app-v42 ✓

                 app-v41 stopped

Non abbiamo inventato una nuova strategia di deployment. Gli orchestratori implementano da anni meccanismi di rolling update molto più sofisticati.

Il nostro requisito era più ristretto: volevamo una transizione controllata tra release per un’applicazione assegnata esplicitamente a una VM.

Esiste però un confine importante.

Zero-downtime dei container non significa automaticamente zero-downtime dell’applicazione.

Una migrazione database non retrocompatibile può comunque interrompere il servizio. Due versioni differenti dei queue worker possono elaborare job contemporaneamente e un task schedulato potrebbe essere eseguito due volte.

Una piattaforma può coordinare il runtime. Non può trasformare magicamente un’applicazione in un sistema deployment-safe.

È una distinzione che riteniamo importante mantenere esplicita.


Le credenziali sono diventate un problema architetturale

Centralizzare il controllo delle applicazioni crea inevitabilmente un nuovo problema: i deployment hanno bisogno di segreti e le applicazioni utilizzano variabili d’ambiente contenenti credenziali.

Non volevamo costruire un sistema in cui, alla domanda “Snowflake può leggere tutte le password delle nostre applicazioni?”, la risposta fosse: “Sì, tecnicamente, ma le colonne del database sono cifrate”.

Se l’applicazione possiede automaticamente tutto ciò che serve per decifrare il dato, un processo sufficientemente privilegiato può potenzialmente accedere alle credenziali.

Per questo il vault organizzativo è stato progettato seguendo un modello zero-knowledge.

La password del vault e la data encryption key non risiedono nell’API. Il browser deriva il materiale crittografico dal segreto del team e il server conserva il ciphertext.

La difficoltà diventa evidente durante un deployment. L’agent deve ricostruire le variabili d’ambiente sulla VM, ma il control plane non dovrebbe ottenere il contenuto in chiaro dei segreti che sta coordinando.

Nel modello che abbiamo implementato, il materiale necessario allo sblocco viene sigillato per la chiave Ed25519 dell’agent. È quindi l’agent a ricevere ciò che serve per ricostruire localmente l’environment sulla VM.

Il control plane coordina l’operazione senza dover leggere in chiaro le credenziali custodite dal vault.

Naturalmente esiste un compromesso: se il team perde la password del vault, Snowflake non può recuperarla.

È una conseguenza intenzionale del confine di sicurezza scelto.


Poi ci siamo accorti che mancava ancora il progetto

A questo punto avevamo iniziato a risolvere una parte importante del problema di software delivery.

Avevamo registry, Git, VM, ambienti, componenti, deployment, container e segreti.

Eppure, durante il lavoro quotidiano, continuavamo a uscire dalla piattaforma.

Un cliente inviava una richiesta via email. Qualcuno la leggeva e la classificava. In molti casi la richiesta diventava un’attività tecnica. L’attività veniva assegnata a uno sviluppatore e poteva appartenere a una milestone. Al termine dello sviluppo veniva eseguito un deployment e, infine, bisognava rispondere al cliente.

Il flusso era:

Email cliente
      ↓
Ticket
      ↓
Analisi
      ↓
Task
      ↓
Milestone
      ↓
Sviluppo
      ↓
Deployment
      ↓
Produzione
      ↓
Risposta cliente

Il deployment era soltanto una parte del ciclo.

Da qui è nata la decisione di integrare anche il supporto clienti e una forma volutamente leggera di gestione delle attività.

Una mailbox IMAP può trasformare le email in ticket. Le regole di routing permettono di collegare le richieste ai progetti e agli assegnatari. Un ticket può essere collegato a un’attività interna, mentre task e milestone vivono nello stesso contesto del progetto.

Non stiamo cercando di costruire un sostituto completo di Jira o un sistema universale di project management.

L’obiettivo è molto più specifico: mantenere il filo operativo del progetto.

Perché, alla fine, la domanda che continuiamo a voler fare a Snowflake è sempre la stessa:

Cosa sta succedendo sul progetto X?


Il vero problema era la frammentazione del contesto

Guardando indietro, Snowflake non nasce da un singolo problema tecnico particolarmente difficile.

Jenkins funzionava. Portainer funzionava. Traefik funzionava. I nostri registry funzionavano. GitHub e Bitbucket funzionavano. Anche email, Kanban e gli altri strumenti che utilizzavamo svolgevano il proprio compito.

Il problema era ricostruire continuamente le relazioni tra questi sistemi.

La complessità operativa spesso non nasce dalla complessità dell’infrastruttura. Nasce dalla frammentazione del contesto necessario per gestirla.

Dieci VM semplici possono diventare difficili da gestire non perché Docker sia complesso o perché Traefik sia complesso, ma perché capire lo stato reale di dieci progetti richiede di aprire sei strumenti differenti e ricostruire mentalmente le relazioni tra ciò che mostrano.

Il valore di un control plane, almeno per noi, non è la capacità di eseguire un comando Docker.

È la capacità di collegare in modo coerente il progetto, l’ambiente, il componente, la versione, la VM, il deployment e il risultato dell’operazione con i problemi aperti, le attività in corso e le milestone che il team sta portando avanti.

Quando abbiamo iniziato a osservare il problema in questo modo, Jenkins, Portainer e i nostri script non sembravano più una piattaforma.

Erano strumenti e primitive di una piattaforma che, di fatto, stavamo già cercando di ricostruire ogni giorno nella nostra testa.

Snowflake è il tentativo di rendere quel modello esplicito.


Esiste davvero un mercato per questo modello?

È una domanda a cui non abbiamo ancora una risposta definitiva.

La maggior parte dei team, probabilmente, sceglie di mantenere la propria toolchain, standardizzare l’automazione, adottare una PaaS self-hosted, costruire una internal developer platform oppure passare a un orchestratore.

Sono tutte opzioni valide.

Forse lo spazio in cui si colloca Snowflake è troppo stretto.

Oppure esiste una categoria di team che si trova esattamente nel punto in cui ci siamo trovati noi: software house che gestiscono molti progetti, organizzazioni che separano l’infrastruttura per cliente, aziende con decine di applicazioni distribuite su VM o team che non hanno bisogno di scheduling dinamico dei workload ma vogliono comunque deployment standardizzati e una visione più coerente del lavoro operativo.

È questo il contesto in cui abbiamo costruito Snowflake.

Non come sostituto di Kubernetes, Terraform o Ansible. E nemmeno semplicemente come alternativa a Portainer o Jenkins.

Lo abbiamo costruito perché la nostra infrastruttura era ancora comprensibile, ma il lavoro necessario per gestirla in maniera coerente si stava frammentando sempre di più.

Oggi Snowflake riunisce registry Composer e npm privati, Docker Registry, Git gateway, gestione delle VM tramite agent, ambienti, componenti, deployment revisionati, rollback, workflow zero-downtime, gestione e monitoring dei container, terminale dal browser, ticket di assistenza, Kanban, milestone e un vault zero-knowledge per i segreti di runtime.

Stiamo iniziando ad aprire il progetto a una prima fase beta.

Ma la domanda che ci interessa maggiormente non è se l’elenco delle funzionalità sia abbastanza lungo.

È molto più semplice:

Se gestite molte applicazioni Docker su VM, quanto è frammentato oggi il vostro modello operativo?

Usate Jenkins, GitHub Actions, Portainer, Ansible, Coolify o Dokploy? Avete deciso di utilizzare comunque Kubernetes? Oppure avete costruito strumenti interni?

E, soprattutto, supporto, software delivery e infrastruttura vivono per voi in mondi completamente separati oppure avete trovato un modo efficace per mantenere il contesto del progetto?

Noi abbiamo costruito Snowflake perché avevamo questo problema.

Ora stiamo cercando di capire chi altro ce l’ha.

Seraphinite AcceleratorOptimized by Seraphinite Accelerator
Turns on site high speed to be attractive for people and search engines.