all systems operational +48 697 610 212
Techniczne · [2026-06-17]

Optymalizacja kosztów Kubernetes z GitLab CI: gdzie ucieka budżet

Pięć dźwigni, które realnie obniżają rachunek za CI/CD na Kubernetes: right-sizing zasobów, autoskalowanie runnerów do zera, węzły spot i cache.

KUBERNETES · GITLAB · CI-CD · FINOPS · DEVOPS

Pipeline'y działają, klaster się skaluje, deploye wchodzą same. A potem przychodzi faktura za chmurę i ktoś pyta, dlaczego samo CI kosztuje tyle co połowa produkcji.

Kubernetes nie jest drogi z natury. Drogie jest CI, którego nikt nie mierzy: runnery stojące na zawołanie 24/7, joby proszące o 8 GB RAM „na wszelki wypadek”, obrazy ważące po dwa giga i buildy bez cache. Poniżej pięć dźwigni, które stosujemy, żeby ten rachunek zbić — bez spowalniania zespołu.

TL;DR

  • Right-sizing: requesty ustawione pod realne zużycie, nie pod „a nuż zabraknie” — najszybsza wygrana
  • Autoskalowanie do zera: runnery na Kubernetes executor + cluster autoscaler, zero płacenia za bezczynność
  • Węzły spot: efemeryczne CI świetnie pasuje do tanich maszyn spot/preemptible
  • Cache i mniejsze obrazy: krótszy build to mniej zużytych minut — a więc mniej pieniędzy
  • Pomiar per projekt: bez kosztu rozbitego na zespoły optymalizujesz po omacku

Gdzie naprawdę ucieka budżet

Zanim zaczniesz ciąć, warto wiedzieć, na co idą pieniądze. W środowiskach CI/CD, które przejmowaliśmy, koszt prawie zawsze rozkładał się tak samo:

Źródło kosztuTypowy objaw
Przewymiarowane requestyJob rezerwuje 8 vCPU, zużywa 1,5 — reszta węzła leży odłogiem
Runnery 24/7Stała pula maszyn płaci za noce i weekendy, gdy nikt nie commituje
Brak cacheKażdy build ściąga zależności od zera — minuty, za które płacisz
Grube obrazyPull obrazu trwa dłużej niż sam build; mnożone przez setki jobów

Klasyczny przypadek: 200 vCPU rozłożone na stałej puli hostów, z których w nocy realnie pracuje kilka procent. Płacisz za szczyt, korzystasz ze średniej.

Dźwignia 1: right-sizing zasobów

Najczęstsze marnotrawstwo to requesty ustawione „na oko, z zapasem”. Kubernetes rezerwuje dokładnie tyle, ile poprosisz — niezależnie od tego, ile job faktycznie zużyje. Przewymiarowany request to pojemność, za którą płacisz i której nikt nie używa.

Co robimy w praktyce:

  • Mierzymy realne zużycie jobów (Prometheus / metrics-server) zamiast zgadywać
  • Ustawiamy request blisko mediany zużycia, limit z rozsądnym zapasem
  • Egzekwujemy to per projekt przez ResourceQuota i LimitRange — opisaliśmy ten mechanizm w osobnym wpisie: twarde limity zasobów per projekt w GitLab CI

To zwykle najszybsza wygrana: nie zmienia infrastruktury, a uwalnia pojemność, którą do tej pory blokowały rezerwacje na wyrost.

Dźwignia 2: autoskalowanie runnerów do zera

Docker runnery na stałych hostach płacą rachunek niezależnie od tego, czy ktoś commituje. GitLab na Kubernetes executor tworzy pody jobów na żądanie — a w połączeniu z cluster autoscalerem dokłada i zdejmuje węzły zależnie od kolejki.

  • Brak jobów → pula schodzi do zera (albo do małego minimum na ciepłe godziny)
  • Skok commitów → autoscaler dokłada węzły na czas pracy, potem je zwalnia
  • Płacisz za realnie wykonane joby, nie za gotowość maszyn w nocy

Kosztem jest cold start — pierwszy job po ciszy czeka kilkadziesiąt sekund na węzeł. Dla zdecydowanej większości zespołów to opłacalna wymiana.

Dźwignia 3: węzły spot dla CI

CI to obciążenie efemeryczne: job albo się uda, albo zostanie ponowiony. To idealny kandydat na węzły spot / preemptible, które bywają kilkukrotnie tańsze od on-demand.

Warunek jest jeden — pipeline musi znosić wywłaszczenie węzła. W praktyce oznacza to idempotentne joby i włączone retry. Produkcji na spotach nie stawiamy, ale buildy i testy przenosimy tam bez obaw. Pula on-demand zostaje jako bufor na wypadek braku spotów.

Dźwignia 4: cache i mniejsze obrazy

Tu koszt i czas to ta sama rzecz: każda minuta builda to minuta, za którą płacisz. Dwie zmiany dają najwięcej:

  • Cache zależności — Maven, npm, pip czy warstwy Dockera nie muszą lecieć od zera przy każdym buildzie
  • Mniejsze obrazy — multi-stage build i chude bazy skracają pull i przyspieszają start joba

W jednej z naszych migracji multi-stage build i porządki w warstwach ścięły rozmiar obrazów o 87%, a czas builda spadł z około 6 minut do ~30 sekund. Krótszy build to nie tylko wygoda — to wprost mniej zużytych minut runnera. Opisaliśmy to w case study migracji 60 aplikacji na Kubernetes.

Dźwignia 5: mierz koszt per projekt

Nie zoptymalizujesz czegoś, czego nie widzisz. Dopóki rachunek za CI jest jedną liczbą, nie wiadomo, który zespół generuje gros kosztu i gdzie cięcie ma sens.

  • Namespace i ResourceQuota per projekt dają naturalny punkt rozliczenia zużycia
  • Prometheus + Grafana pokazują CPU/RAM i czas jobów w rozbiciu na zespoły
  • Z tym obrazem optymalizujesz tam, gdzie boli — a nie tam, gdzie akurat patrzysz

Od czego zacząć

Kolejność, którą rekomendujemy: najpierw zmierz (dźwignia 5 i right-sizing), bo to nic nie kosztuje i od razu pokazuje skalę marnotrawstwa. Potem autoskalowanie i spot — tam są największe oszczędności strukturalne. Cache i obrazy domykają temat i przy okazji przyspieszają pracę zespołu.

Prowadzimy CI/CD na Kubernetes w produkcji i regularnie przejmujemy środowiska, w których rachunek wymknął się spod kontroli. Jeśli Twoje CI kosztuje więcej, niż powinno, zobacz, jak budujemy i optymalizujemy pipeline'y albo umów bezpłatną konsultację — zaczynamy od audytu i konkretnych liczb.

Chcesz to samo u siebie?

Napisz do nas — pierwsza konsultacja jest bezpłatna.

Darmowa konsultacja