Railshot
AI deployment & operations platform
Wdrożenie lokalnie zbudowanej aplikacji webowej w przygotowanych środowiskach chmurowych i lokalnych, a potem jej utrzymanie.
Platforma AI do wdrażania i utrzymania, która przenosi lokalnie zbudowaną aplikację webową do przygotowanych środowisk chmurowych lub lokalnych (on-premises) i dalej ją utrzymuje.
Klaster operacyjny i klastry aplikacji klientów są oddzielone, a ścieżka publiczna jest odseparowana od sterowania wdrożeniem.
W operacyjnym K3s panel, API produktu i build controller są umieszczone na węzłach w roli platform, a Joby runnerów na węźle w roli build, natomiast wdrożeniem zajmuje się Argo CD. Aplikacje klientów działają w wyznaczonej przestrzeni nazw osobnego, jednowęzłowego klastra K3s + Cilium dla każdego zarejestrowanego celu.
Build → publikacja obrazu
API produktu zleca przebieg GitHub Actions, a runner na węźle build pobiera i sprawdza zadanie. Tylko bundle, który przeszedł te same kontrole, jest publikowany w GHCR przez zadanie wydania hostowane przez GitHub.
API produktu · cd.js → bridge.py
railshot-systemuruchomienie · zastosowanie: workflow_dispatchloop job · self-hosted runnerrailshot-deploy.ymlAPI produktu zleca przebieg GitHub Actions z tenantem, aplikacją, commitem źródłowym i celem. API nigdy nie wywołuje Joba runnera bezpośrednio.
build controller · CronJob
railshot-systemuruchomienie · zastosowanie: uzupełnianie Jobów runnerarunner Job · hostNetwork · Docker socketrailshot-buildCronJob build controllera (co minutę, na węźle platform) tworzy Joby runnerów w przestrzeni nazw railshot-build. Jego Role pozwala tylko na get, list i create dla Jobów oraz get, update i patch dla jednego Secretu rejestracji runnera; nie może tworzyć przestrzeni nazw ani innych Secretów.
runner Job · hostNetwork · Docker socket
railshot-builduruchomienie · zastosowanie: pobranie zadanialoop job · self-hosted runnerrailshot-deploy.ymlRunner na węźle w roli build (dokładna nazwa hosta, toleracja NoSchedule) pobiera zadanie loop według etykiet self-hosted i je wykonuje. Kod źródłowy klienta działa w istniejących, ograniczonych kontenerach budowania i kontroli Docker.
runner Job · hostNetwork · Docker socket
railshot-builddane: przetestowany bundlerelease job · GitHub-hostedrailshot-deploy.ymlZadanie loop pozostawia bundle, który przeszedł te same kontrole, a zadanie wydania przyjmuje tylko ten bundle.
release job · GitHub-hosted
railshot-deploy.ymldane: publikacja według digestGHCRZadanie wydania hostowane przez GitHub (ubuntu-24.04) publikuje obraz z przetestowanego bundla w GHCR bez przebudowy. Publikacja obrazów nigdy nie odbywa się wewnątrz klastra aplikacji klienta.
Config Git → Argo → przestrzeń nazw klienta
Config Git przenosi pożądane zasoby, a GHCR bajty obrazu. Argo CD stosuje zmiany tylko w zarejestrowanej przestrzeni nazw klienta.
API produktu · cd.js → bridge.py
railshot-systemdane: workload commit · pushRepozytorium config Gitcd.js uruchamia bridge.py, który commituje i wypycha workload.json tylko wtedy, gdy zapis publikacji i zarejestrowany cel są zgodne, a następnie odczytuje zdalną rewizję. Git przenosi pożądane zasoby; GHCR przenosi bajty obrazu.
Repozytorium config Gitdane: revisionArgo CD · Application
argocdApplication odczytuje tylko swoje ograniczone repozytorium konfiguracji, ścieżkę i rewizję.
API produktu · cd.js → bridge.py
railshot-systemuruchomienie · zastosowanie: Application syncArgo CD · ApplicationargocdWskazana Application jest ustawiana przez server-side apply, a synchronizacja jednej dokładnej rewizji jest zlecana bez prune. ServiceAccount railshot-product API produktu ma zarówno zainstalowany przez operatora bootstrap rejestracji (create dla Secretów, AppProjectów i Applications w argocd; get, update i escalate dla wskazanych Roles), jak i uprawnienia get i patch dopisywane dokładną nazwą dla każdego zweryfikowanego celu. Kubernetesowego create nie da się ograniczyć nazwą, więc nazw w zakresie pilnuje też walidacja wejścia w produkcie.
Argo CD · Application
argocduruchomienie · zastosowanie: zastosowanie w przestrzeni nazw<app namespace>Argo CD stosuje zmiany w wyznaczonej przestrzeni nazw w klastrze klienta z poświadczeniem z zarejestrowanego Secretu klastra. AppProject dopuszcza tylko rodzaje w zakresie przestrzeni nazw i żadnych zasobów o zakresie klastra.
Deployment · Pod · obraz według digest
<app namespace>dane: pobranie według digestGHCROpublikowany obraz według digest jest pobierany z użyciem pull Secretu wskazanego nazwą w tej samej przestrzeni nazw. Wartości Secretów nigdy nie trafiają do artefaktu ani do config Git.
Publiczna ścieżka żądań
Żądania aplikacji idą: wejście L7 dostawcy → NodePort węzła → Service → pod aplikacji. Egzekwowanie polityki przez Cilium to osobna kontrola, a nie etap przenoszący żądanie. Wejście do panelu operacyjnego to osobna ścieżka.
Użytkownik aplikacjidane: HTTPS 443Wejście L7 dostawcy
Użytkownicy aplikacji docierają do wejścia L7 dostawcy pod zarejestrowaną nazwą hosta. Każdy dostawca implementuje własne wejście.
Wejście L7 dostawcydane: NodePortNodePort Service · Local
<app namespace>Wejście przekazuje ruch na prywatny adres węzła i NodePort. NodePort to ten przydzielony przy rejestracji celu.
NodePort Service · Local
<app namespace>dane: do podaDeployment · Pod · obraz według digest<app namespace>Service wysyła żądanie do poda aplikacji (Deployment) na tym samym węźle. Przy externalTrafficPolicy Local adres źródłowy dociera bez zmian do kontroli zarejestrowanych CIDR w NetworkPolicy.
Cilium · Helm · VXLAN
kube-systemuruchomienie · zastosowanie: egzekwowanie politykiNetworkPolicy · wymienione CIDR<app namespace>Cilium egzekwuje NetworkPolicy: ruch przychodzący tylko z zarejestrowanych CIDR na port aplikacji; domyślnie brak ruchu wychodzącego, z wyjątkiem zatwierdzonego adresu bazy danych. Zapory chmurowe i reguły hosta nadal mają znaczenie.
Użytkownik Railshotdane: panel · APIdashboard · nginx
railshot-systemUżytkownicy przechodzą przez wejście operacyjne do panelu nginx, a nginx stoi przed API produktu. Service panelu jest typu NodePort tylko wtedy, gdy podano zatwierdzony port węzła; API pozostaje ClusterIP.
Weryfikacja · obserwacja
Werdykt wdrożenia opiera się wyłącznie na stanie Argo i kontroli publicznego URL. Diagnostyka podów, bieżące logi i metryki operacyjne to osobne sygnały, które nigdy go nie zmieniają.
API produktu · cd.js → bridge.py
railshot-systemobserwacja: rewizja · health · obrazyArgo CD · ApplicationargocdStan deployed wymaga rewizji synchronizacji Application, Synced i Healthy, operacji Succeeded oraz zgodności odwołań do obrazów zapisanych w stanie Application w Argo z obrazami według digest z przejrzanego Deploymentu. To nie jest bramka bezpośrednio na imageID poda, a sam zielony stan Argo nie potwierdza tej zgodności.
API produktu · cd.js → bridge.py
railshot-systemobserwacja: publiczna kontrola HTTPSWejście L7 dostawcyZarejestrowany publiczny URL jest sprawdzany bez przekierowań. Succeeded jest zapisywane tylko przy werdykcie Argo i tej kontroli łącznie.
API produktu · cd.js → bridge.py
railshot-systemobserwacja: diagnostyka poda · nie werdyktDeployment · Pod · obraz według digest<app namespace>Po werdykcie Argo i kontroli publicznej Deployment, ReplicaSety i pody są odczytywane osobno z zarejestrowanym poświadczeniem, a imageID i gotowość są dołączane jako diagnostyka ready, progressing lub unavailable. Nieudana lub odmienna diagnostyka nigdy nie zmienia werdyktu deployed ani succeeded.
API produktu · cd.js → bridge.py
railshot-systemobserwacja: tail logów · 100 wierszy na podDeployment · Pod · obraz według digest<app namespace>Tylko dla obecnie wdrożonej operacji, z zaufaną konfiguracją i zarejestrowanym poświadczeniem. Dla każdego bieżącego poda (najwyżej trzech) digest uruchomionego obrazu musi być równy oczekiwanemu; wtedy odczytywane jest do 100 zamaskowanych wierszy na pod w limicie bajtów. Starsza próba odpowiada superseded; bez konfiguracji not_configured. To nie jest agregacja logów.
VM obserwacyjnaobserwacja: scrape · NodePortyrailshot-observability
Prometheus na VM obserwacyjnej zbiera dane z node-exporter i kube-state-metrics przez dwa NodePorty ograniczone zaporą. Brakujące lub nieaktualne wartości są nieznane, a nie zerowe.
VM obserwacyjnaobserwacja: Blackbox probeWejście L7 dostawcy
probe_success=1 oznacza odpowiedź 2xx w miejscu tej sondy. Nie dowodzi dostępu każdego użytkownika ani wdrożonej wersji i nigdy nie podnosi published do deployed.
Instalacja · rejestracja przez operatora
Instalacja klastra, bootstrap rejestracji i dane celów, Secrety oraz konfiguracja odnawiania poświadczeń to dane wejściowe operatora, nigdy część ładunku aplikacji tenanta.
Bootstrap operatorauruchomienie · zastosowanie: renderowanie platform · Secretrailshot-system
Operator renderuje deklarację platformy za pomocą render-platform.py i dostarcza prywatną konfigurację operacyjną i Secrety. Zdalny MCP jest dołączany tylko wtedy, gdy dostarczono jego obraz, a osobista bramka (WireGuard) tylko z --personal.
Bootstrap operatorauruchomienie · zastosowanie: bootstrap rejestracjiAppProject · cluster Secret
argocdOperator instaluje w argocd Role bootstrapu rejestracji i pustą Role registrations oraz przygotowuje dane celu. Następnie helpery rejestracji uruchamiane przez API produktu (environment.py, applications.py) zapisują Secret railshot-<target> z poświadczeniem o ograniczonym zakresie (clusterResources false, wymienione dozwolone przestrzenie nazw) i dopisują zweryfikowane dokładne nazwy do Role registrations. Rejestracja dla aplikacji wiąże przestrzeń nazw app-<id> z AppProject o tej samej nazwie.
Bootstrap operatorauruchomienie · zastosowanie: instalacja K3s · CiliumCilium · Helm · VXLAN
kube-systeminstall-k3s.sh instaluje jednowęzłowy serwer K3s (flannel, network policy, traefik i servicelb wyłączone; kube-proxy zachowany), a Cilium jest instalowany jako wydanie Helm (kubeProxyReplacement false, VXLAN, Hubble wyłączony).
CronJob odnowienia · co 2 h
argocduruchomienie · zastosowanie: TokenRequest · 6 hSA railshot-argocd · token<app namespace>CronJob railshot-credentials co dwie godziny żąda nowego sześciogodzinnego tokenu dla SA klienta. Role po stronie klienta pozwala tylko na token create dla własnego SA. Sześć godzin to TTL jednego tokenu, a nie moment, w którym kończy się dostęp operatora.
Każde połączenie z tą samą wagą. Wybór przepływu wyróżnia tylko jego ścieżkę z ponumerowanymi krokami.
- Linia ciągła · kierunek przepływu żądań, bundli, obrazów i deklaracji
- Linia przerywana · żądania uruchomienia, zastosowanie, instalacja, poświadczenia
- Długa kreska z kropką · odczyt stanu, logów, sond, metryk; oddzielnie od werdyktu
- Gruba czarna linia · wybrany przepływ; liczby podają kolejność
- Ramka · przestrzeń nazw, nazwa w nagłówku (nie węzeł)
- Wewnętrzny element · komponent w tej przestrzeni nazw
- Przerywana ramka · poza klastrami
- railshot-system · produkt
- argocd · uprawnienia wdrożeniowe
- railshot-build · uprawnienia Docker hosta
- GitHub · klaster klienta
Decyzja o rozmieszczeniu z October 2 w docs/architecture (dwa węzły ról) i diagram w publicznym README to historia; ta mapa odpowiada deklaracjom i kodowi w 645e28a. Strzałki pokazują przyczynę i kierunek, a nie dowód, że każda ścieżka dostawcy działa teraz.
- Przestrzenie nazw i węzły
- Przestrzeń nazw to zakres nazewnictwa: ani sprzęt, ani sama w sobie granica bezpieczeństwa. Role platform i build to rozmieszczenie w planowaniu przez nodeSelector i taint; ta mapa nie ustala liczby węzłów klastra operacyjnego. Rozmieszczenie Argo CD na węzłach to również osobna kontrola.
- Uprawnienia węzła build
- Joby runnerów działają z hostNetwork, gniazdem Docker hosta, NET_ADMIN i jako root. Przestrzeń nazw, taint ani RBAC nie usuwają uprawnień Docker hosta, więc nie jest to ani izolacja od administratora VM, ani piaskownica dla dowolnego kodu.
- Przestrzeń nazw klienta
- Każdy zarejestrowany cel używa niedomyślnej przestrzeni nazw i AppProject (na przykład tenant-demo lub app-<id> dla każdej aplikacji). Tworzone są tylko Deployment jednej usługi (automount tokenu ServiceAccount wyłączony), Service NodePort i NetworkPolicy oraz opcjonalnie PVC lub Job migracji; Secrety są tylko wskazywane nazwą (pull Secret i zatwierdzony DATABASE_URL), nigdy tworzone.
- Wejście AWS
- Route 53 Alias → współdzielony ALB HTTPS 443 → prywatny adres węzła klienta i NodePort. Wiele aplikacji korzysta z jednego węzła, każda z własną przestrzenią nazw, Application i NodePort.
- Wejście GCP
- Globalny EXTERNAL_MANAGED HTTPS LB → strefowy GCE_VM_IP_PORT NEG → prywatny NodePort istniejącej VM. Certyfikaty pochodzą z Certificate Manager z autoryzacją DNS. Moduł nie jest właścicielem ani VM, ani VPC, a jedna VM pozostaje pojedynczym punktem awarii.
- Wejście OpenStack
- Listener TLS Amphora 443 z politykami L7 dla Host i ścieżki → HTTP NodePort. Domyślny adres to prywatny VIP; Octavia, K3s, baza danych i DNS są poza modułem. Publiczna osiągalność i gotowość Amphory na miejscu wymagają osobnego odbioru, a żadnego wdrożenia na miejscu nie zweryfikowano jeszcze tym modułem.
- Między dostawcami
- Trzy wejścia to osobne implementacje, bez automatycznego failoveru ani replikacji między dostawcami. Klaster aplikacji klienta to przykład zarejestrowanego celu, a nie twierdzenie, że to samo wdrożenie działa jednocześnie w każdej chmurze.
- Opcje operatora
- Osobista bramka (WireGuard) dołącza do platformy tylko wtedy, gdy operator włączy --personal; nie jest wymaganą ścieżką dla chmur klientów. W obsługiwanym trybie direct VM obserwacyjna może współdzielić operacyjną VM sterującą.