Railshot
AI deployment & operations platform
Implementarea unei aplicații web construite local în medii cloud și on-premises pregătite, apoi operarea ei.
O platformă AI de implementare și operare care duce o aplicație web construită local în medii cloud sau on-premises pregătite și o ține în funcțiune.
Clusterele de operare și cele pentru aplicațiile clienților sunt separate, iar calea publică este ținută separat de controlul implementării.
În K3s-ul de operare, dashboardul, API-ul produsului și build controller-ul sunt plasate pe noduri cu rol platform, iar Job-urile runner pe un nod cu rol build, în timp ce Argo CD se ocupă de implementare. Aplicațiile clienților rulează într-un namespace desemnat al unui cluster separat K3s + Cilium cu un singur nod, câte unul pentru fiecare țintă înregistrată.
Build → publicarea imaginii
API-ul produsului cere o rulare GitHub Actions, iar runnerul de pe nodul build preia și verifică jobul. Doar un pachet care a trecut aceleași verificări este publicat în GHCR de un job de release găzduit de GitHub.
API-ul produsului · cd.js → bridge.py
railshot-systemrulare · aplicare: workflow_dispatchloop job · self-hosted runnerrailshot-deploy.ymlAPI-ul produsului cere o rulare GitHub Actions cu tenant, app, source commit și țintă. API-ul nu apelează niciodată direct un Job runner.
build controller · CronJob
railshot-systemrulare · aplicare: completarea Job-urilor runnerrunner Job · hostNetwork · Docker socketrailshot-buildCronJob-ul build controller (la fiecare minut, pe un nod platform) creează Job-uri runner în namespace-ul railshot-build. Role-ul său permite doar get, list și create pentru Job-uri, plus get, update și patch pe singurul Secret de înregistrare a runnerului; nu poate crea namespace-uri sau alte Secret-uri.
runner Job · hostNetwork · Docker socket
railshot-buildrulare · aplicare: preluarea jobuluiloop job · self-hosted runnerrailshot-deploy.ymlRunnerul de pe nodul cu rol build (hostname exact, toleration NoSchedule) preia jobul loop după etichetele self-hosted și îl rulează. Sursa clientului rulează în containerele restricționate existente de build și verificare Docker.
runner Job · hostNetwork · Docker socket
railshot-builddate: pachet testatrelease job · GitHub-hostedrailshot-deploy.ymlJobul loop lasă pachetul care a trecut aceleași verificări, iar jobul de release preia doar acel pachet.
release job · GitHub-hosted
railshot-deploy.ymldate: publicare prin digestGHCRUn job de release găzduit de GitHub (ubuntu-24.04) publică imaginea pachetului testat în GHCR fără a o reconstrui. Publicarea imaginilor nu are loc niciodată în clusterul aplicațiilor clientului.
Config Git → Argo → namespace-ul clientului
Config Git transportă resursele dorite, iar GHCR octeții imaginii. Argo CD aplică doar în namespace-ul înregistrat al clientului.
API-ul produsului · cd.js → bridge.py
railshot-systemdate: workload commit · pushdepozitul config Gitcd.js rulează bridge.py, care face commit și push pentru workload.json doar când înregistrarea de publicare și ținta înregistrată corespund, apoi recitește revizia de pe remote. Git transportă resursele dorite; GHCR transportă octeții imaginii.
depozitul config Gitdate: revisionArgo CD · Application
argocdApplication citește doar depozitul de configurație, calea și revizia restricționate.
API-ul produsului · cd.js → bridge.py
railshot-systemrulare · aplicare: Application syncArgo CD · ApplicationargocdApplication numită este setată prin server-side apply, iar sincronizarea unei singure revizii exacte este cerută fără prune. ServiceAccount-ul railshot-product al API-ului produsului deține atât bootstrap-ul de înregistrare instalat de operator (create pentru Secret-uri, AppProject-uri și Application-uri în argocd; get, update și escalate pe Role-uri numite), cât și permisiunile get și patch adăugate cu numele exact pentru fiecare țintă validată. create din Kubernetes nu poate fi limitat după nume, așa că validarea intrărilor din produs menține și ea numele în domeniu.
Argo CD · Application
argocdrulare · aplicare: aplicare în namespace<app namespace>Argo CD aplică în namespace-ul desemnat din clusterul clientului cu credențiala Secret-ului de cluster înregistrat. AppProject permite doar tipuri cu namespace și nicio resursă la nivel de cluster.
Deployment · Pod · imagine prin digest
<app namespace>date: pull prin digestGHCRImaginea publicată prin digest este descărcată cu un Secret de pull referit după nume în același namespace. Valorile Secret nu intră niciodată în artefact sau în config Git.
Calea publică a cererilor
Cererile către aplicație merg pe ruta punct de intrare L7 al furnizorului → NodePort-ul nodului → Service → Pod-ul aplicației. Aplicarea politicilor de către Cilium este un control separat, nu un pas care transportă cererea. Accesul la dashboardul de operare urmează o cale separată.
Utilizatorul aplicațieidate: HTTPS 443Punctul de intrare L7 al furnizorului
Utilizatorii aplicației ajung la punctul de intrare L7 al furnizorului prin hostname-ul înregistrat. Fiecare furnizor își implementează propriul punct de intrare.
Punctul de intrare L7 al furnizoruluidate: NodePortNodePort Service · Local
<app namespace>Punctul de intrare redirecționează către adresa privată și NodePort-ul nodului. NodePort-ul este cel alocat la înregistrarea țintei.
NodePort Service · Local
<app namespace>date: către PodDeployment · Pod · imagine prin digest<app namespace>Service trimite cererea către Pod-ul aplicației (Deployment) de pe același nod. Cu externalTrafficPolicy Local, adresa sursă ajunge neschimbată la verificarea CIDR-urilor înregistrate din NetworkPolicy.
Cilium · Helm · VXLAN
kube-systemrulare · aplicare: aplicarea politiciiNetworkPolicy · doar CIDR-urile listate<app namespace>Cilium aplică NetworkPolicy: trafic de intrare doar din CIDR-urile înregistrate către portul aplicației; implicit niciun trafic de ieșire, cu excepția unei adrese de bază de date aprobate. Firewallurile din cloud și regulile gazdei contează în continuare.
Utilizator Railshotdate: dashboard · APIdashboard · nginx
railshot-systemUtilizatorii vin prin punctul de intrare de operare către dashboardul nginx, iar nginx stă în fața API-ului produsului. Service-ul dashboardului este NodePort doar când este dat un port de nod aprobat; API-ul rămâne ClusterIP.
Verificare · observare
Verdictul implementării se bazează doar pe starea Argo și pe verificarea URL-ului public. Diagnosticul Pod, jurnalele curente și metricile de operare sunt semnale separate, care nu îl schimbă niciodată.
API-ul produsului · cd.js → bridge.py
railshot-systemobservare: revizie · health · imaginiArgo CD · ApplicationargocdStarea deployed cere revizia de sincronizare a Application, Synced și Healthy, operation Succeeded și ca referințele de imagine înregistrate în starea Argo Application să fie egale cu imaginile prin digest ale Deployment-ului revizuit. Nu este o poartă directă pe imageID-ul Pod-ului, iar o stare Argo verde nu stabilește singură potrivirea.
API-ul produsului · cd.js → bridge.py
railshot-systemobservare: verificare HTTPS publicăPunctul de intrare L7 al furnizoruluiURL-ul public înregistrat este verificat fără redirecționări. Succeeded este înregistrat doar cu verdictul Argo și cu această verificare.
API-ul produsului · cd.js → bridge.py
railshot-systemobservare: Diagnostic Pod · nu verdictulDeployment · Pod · imagine prin digest<app namespace>După verdictul Argo și verificarea publică, Deployment-ul, ReplicaSet-urile și Pod-urile sunt citite separat cu credențiala înregistrată, iar imageID și starea de pregătire sunt adăugate ca diagnostic ready, progressing sau unavailable. Un diagnostic eșuat sau diferit nu schimbă niciodată verdictul deployed sau succeeded.
API-ul produsului · cd.js → bridge.py
railshot-systemobservare: coada jurnalului · 100 de rânduri per PodDeployment · Pod · imagine prin digest<app namespace>Doar pentru operația implementată în prezent, cu configurația de încredere și credențiala înregistrată. Pentru fiecare Pod curent (cel mult trei), digest-ul imaginii care rulează trebuie să fie egal cu digest-ul așteptat; apoi sunt citite cel mult 100 de rânduri mascate per Pod, într-o limită de octeți. O încercare mai veche primește răspunsul superseded; fără configurație, not_configured. Nu este agregare de jurnale.
VM de observareobservare: scrape · NodePort-urirailshot-observability
Prometheus de pe VM-ul de observare colectează node-exporter și kube-state-metrics prin două NodePort-uri restricționate de firewall. Valorile lipsă sau învechite sunt necunoscute, nu zero.
VM de observareobservare: Blackbox probePunctul de intrare L7 al furnizorului
probe_success=1 înseamnă un 2xx în acel punct de sondare. Nu dovedește nici accesul fiecărui utilizator, nici versiunea implementată și nu promovează niciodată published la deployed.
Instalare · înregistrare de către operator
Instalarea clusterului, bootstrap-ul de înregistrare și intrările țintei, Secret-urile și configurarea reînnoirii credențialelor sunt intrări ale operatorului, niciodată parte din payloadul aplicației tenantului.
Bootstrap-ul operatoruluirulare · aplicare: randarea platformei · Secretrailshot-system
Operatorul randează declarația platformei cu render-platform.py și furnizează configurația de operare privată și Secret-urile. MCP-ul la distanță este inclus doar când imaginea lui este furnizată, iar gateway-ul personal (WireGuard) doar cu --personal.
Bootstrap-ul operatoruluirulare · aplicare: bootstrap de înregistrareAppProject · cluster Secret
argocdOperatorul instalează în argocd Role-ul de bootstrap pentru înregistrare și un Role registrations gol și pregătește intrările țintei. Apoi helperii de înregistrare rulați de API-ul produsului (environment.py, applications.py) scriu Secret-ul railshot-<target> cu o credențială limitată (clusterResources false, namespace-uri permise listate) și adaugă numele exacte validate în Role-ul registrations. Înregistrarea per aplicație leagă un namespace app-<id> de un AppProject cu același nume.
Bootstrap-ul operatoruluirulare · aplicare: instalare K3s · CiliumCilium · Helm · VXLAN
kube-systeminstall-k3s.sh instalează un server K3s cu un singur nod (flannel, network policy, traefik și servicelb dezactivate; kube-proxy păstrat), iar Cilium este instalat ca release Helm (kubeProxyReplacement false, VXLAN, Hubble dezactivat).
CronJob de reînnoire · la fiecare 2 h
argocdrulare · aplicare: TokenRequest · 6 hSA railshot-argocd · token<app namespace>CronJob-ul railshot-credentials cere la fiecare două ore un token nou de șase ore pentru SA-ul clientului. Role-ul din partea clientului permite doar token create pentru propriul SA. Șase ore este TTL-ul unui token, nu momentul în care se încheie accesul operatorului.
Fiecare conexiune cu aceeași grosime. Alegeți un flux pentru a evidenția doar traseul lui, cu pași numerotați.
- Continuă · direcția în care circulă cererile, pachetele, imaginile și declarațiile
- Întreruptă · cereri de rulare, aplicare, instalare, credențiale
- Linie-punct lungă · citirea stării, jurnalelor, sondelor, metricilor; separată de verdict
- Linie neagră groasă · fluxul selectat; numerele dau ordinea
- Casetă · un namespace, cu numele în antet (nu un nod)
- Etichetă interioară · o componentă din acel namespace
- Casetă întreruptă · în afara clusterelor
- railshot-system · produs
- argocd · dreptul de implementare
- railshot-build · drept asupra Docker-ului gazdei
- GitHub · clusterul clientului
Decizia de plasare din 2 octombrie din docs/architecture (două noduri cu roluri) și diagrama din README-ul public sunt istoric; această hartă urmează declarațiile și codul de la 645e28a. Săgețile arată cauza și direcția, nu o dovadă că fiecare cale de furnizor este activă acum.
- Namespace-uri și noduri
- Un namespace este un domeniu de nume: nici hardware, nici, prin el însuși, o graniță de securitate. Rolurile platform și build sunt plasări de planificare prin nodeSelector și taint; această hartă nu fixează numărul de noduri al clusterului de operare. Plasarea pe noduri a Argo CD este, de asemenea, o verificare separată.
- Drepturile nodului build
- Job-urile runner rulează cu hostNetwork, socketul Docker al gazdei, NET_ADMIN și root. Un namespace, un taint sau RBAC nu elimină dreptul asupra Docker-ului gazdei, așa că nu este nici izolare de administratorul VM, nici un sandbox pentru cod arbitrar.
- Namespace-ul clientului
- Fiecare țintă înregistrată folosește un namespace și un AppProject care nu sunt implicite (de exemplu tenant-demo sau app-<id> pentru fiecare aplicație). Sunt create doar Deployment-ul unui singur serviciu (cu montarea automată a tokenului ServiceAccount dezactivată), un NodePort Service și o NetworkPolicy, plus opțional un PVC sau un Job de migrare; Secret-urile sunt doar referite după nume (Secret-ul de pull și un DATABASE_URL aprobat), niciodată create.
- Punctul de intrare AWS
- Route 53 Alias → ALB partajat HTTPS 443 → adresa privată și NodePort-ul nodului clientului. Multe aplicații refolosesc un singur nod, fiecare cu propriul namespace, propria Application și propriul NodePort.
- Punctul de intrare GCP
- LB HTTPS global EXTERNAL_MANAGED → NEG zonal GCE_VM_IP_PORT → NodePort-ul privat al VM-ului existent. Certificatele vin din Certificate Manager cu autorizare DNS. Modulul nu deține nici VM-ul, nici VPC-ul, iar un singur VM rămâne un punct unic de eșec.
- Punctul de intrare OpenStack
- Listener TLS Amphora 443 cu politici L7 pe Host și cale → HTTP NodePort. Adresa implicită este un VIP privat; Octavia, K3s, baza de date și DNS sunt în afara modulului. Accesibilitatea publică și pregătirea Amphora la fața locului necesită o recepție separată, iar nicio aplicare la fața locului nu a fost încă verificată cu acest modul.
- Între furnizori
- Cele trei puncte de intrare sunt implementări separate, fără failover sau replicare automată între furnizori. Clusterul aplicațiilor clientului este un exemplu de țintă înregistrată, nu o afirmație că aceeași implementare rulează simultan în fiecare cloud.
- Opțiuni ale operatorului
- Gateway-ul personal (WireGuard) se alătură platformei doar când operatorul activează --personal; nu este o cale obligatorie pentru cloud-urile clienților. În modul direct acceptat, VM-ul de observare poate împărți VM-ul de control al operării.