DevOpsCI/CDKubernetesInfrastructureSecurity
De ce CI/CD-ul tău arată corect, dar tot se strică vinerea: 3 greșeli ascunse în Kubernetes
Trei greșeli reale de configurare CI/CD și Kubernetes care arată corect dar provoacă incidente în producție. Soluții practice cu exemple de cod pentru companii din Moldova și România.
W
WebDirect TeamAi un pipeline CI/CD configurat. Testele trec. Lintere-le tac. Deployment-ul e automat. Și totuși — vinerea seara ceva pică, clienții scriu, iar tu rezolvi un incident în loc să cinezi. Sună familiar? Nu e vorba că DevOps-ul tău e «prost». E vorba de câteva greșeli neevidente de configurare care arată corect pe hârtie, dar distrug stabilitatea în producție.Dacă vinerea e mai periculoasă decât marțea — ai o problemă sistemică, nu un timing prost. Un pipeline fiabil nu știe ce zi a săptămânii este. În acest articol analizăm trei greșeli reale pe care le întâlnim frecvent la auditul infrastructurii companiilor din Moldova, România și UE — cu cod, explicații și soluții concrete.Greșeala #1 — Resource limits nesetate: pod-urile tale consumă totulCând un dezvoltator creează un deployment Kubernetes fără
resources.requests și resources.limits, scheduler-ul nu știe de câte resurse are nevoie pod-ul. Îl plasează «unde încape». Sub sarcină maximă, un serviciu poate consuma toată memoria disponibilă de pe nod — apare efectul «vecin zgomotos»: alte pod-uri primesc OOMKill sau throttling fără nicio cauză vizibilă. Costul greșelii: cascading failure → mai multe servicii indisponibile simultan.Configurație greșită arată așa: deployment fără resources specificate, scheduler ghicește. Abordarea corectă — să setezi explicit requests (minim garantat) și limits (maxim permis). De exemplu: 256Mi memorie și 250m CPU ca requests, 512Mi memorie și 500m CPU ca limits.Soluție practică: rulează kubectl top pods în staging sub sarcină reală. Folosește consumul p95 ca requests, p99 + 30% ca limits. Configurează LimitRange pe namespace — pod-urile fără limits explicite vor primi valori implicite sensate, nu «tot ce e disponibil».Greșeala #2 — RollingUpdate fără readinessProbe: deployment «reușit», serviciu indisponibilImplicit, Kubernetes consideră un pod «pregătit» imediat ce containerul pornește. Pentru Hello World simplu — e OK. Pentru o aplicație reală care are nevoie de 20–60 de secunde pentru inițializare — e o catastrofă. RollingUpdate trimite trafic către noul pod înainte ca acesta să fie pregătit să-l primească. Utilizatorii primesc erori. CI/CD raportează «deployment reușit» — pentru că tehnic pod-urile au pornit. Costul greșelii: 2–10 minute de downtime la fiecare deployment × N deployments pe zi.Endpoint-ul /health/ready ar trebui să returneze 200 doar când aplicația este cu adevărat pregătită: conectată la DB, cache-ul încălzit, configurațiile încărcate. livenessProbe verifică dacă procesul mai rulează și repornește containerul dacă e necesar. Greșeală frecventă — folosirea aceluiași endpoint pentru ambele probe. Aceasta duce la repornirea pod-urilor sănătoase care pur și simplu se inițializează lent.Soluție practică: adaugă rollback automat în CI — dacă pod-urile nu devin Ready în N secunde, deployment-ul se revine. Configurează probe-uri separate cu întârzieri corespunzătoare. Majoritatea aplicațiilor beneficiază de un initialDelaySeconds de 10–30 de secunde înainte de a începe verifica ready-ness.Greșeala #3 — `image:latest` în producție: fiecare deployment e imprevizibilTag-ul latest nu este o versiune. Înseamnă «dă-mi ce e curent în momentul pull-ului». De fiecare dată când Kubernetes recreează un pod, poate descărca o imagine diferită față de cea folosită la ultimul deployment. Când upstream-ul actualizează imaginea de bază și dependența ta nu mai funcționează cu noua versiune de OpenSSL — primești incidente din cod pe care nu l-ai schimbat. Costul greșelii: regresii imprevizibile + vulnerabilități de securitate din imagini de bază necontrolate.Comparația e clară: image: myapp:latest — pod-uri diferite rulează cod diferit (periculos). Tag semver cum ar fi image: myapp:v1.4 poate fi suprascris (riscant). Dar image: myapp:1.4.2-abc1234 cu Git SHA + semver — reproductibil și trasabil (bine). Pentru garantia maximă, folosește digest: image: myapp@sha256:a1b2c3... — asigură aceeași imagine de fiecare dată.Soluție practică: în pipeline-ul CI, etichetează imaginile cu Git SHA (TAG=$(git rev-parse --short HEAD)). În deployment.yaml pinstează versiunea exactă. Setează imagePullPolicy: IfNotPresent. Configurează o politică în Admission Controller sau OPA care să respingă automat deployment-urile cu tag-ul latest. Durează o oră, elimină permanent o întreagă clasă de incidente.Dincolo de marele trei: ucigași tăcuți ai infrastructuriiInfrastructura ta mai suferă și de: lipsa PodDisruptionBudget (actualizările nodurilor opresc toate replicile simultan), secrete în ConfigMap în loc de Kubernetes Secrets (expuse prin kubectl describe), lipsa HorizontalPodAutoscaler (plătești pentru resurse inactive sau pici sub vârf de trafic), fără cache pentru layer-ele Docker în CI (build-uri de 15 minute în loc de 3 minute), și lipsa network policies (orice pod compromis poate comunica cu orice serviciu din cluster).Checklist: diagnostichează-ți clusterul în 30 de minuteRulează aceste comenzi: kubectl get pods -A -o json | jq '.items[] | select(.spec.containers[].resources.limits == null) | .metadata.name' pentru a găsi pod-uri fără resource limits. Verifică pod-urile fără readinessProbe. Caută imagini cu tag-ul :latest cu grep ':latest'. Asigură-te: toate pod-urile au resources.requests și resources.limits, configurate probe-uri separate, niciun tag latest în producție, PodDisruptionBudget pentru serviciile critice, și rollback automat dacă pod-urile nu devin Ready.FAQ: întrebări frecventePot seta aceleași valori pentru requests și limits? Tehnic da — asta acordă clasa QoS Guaranteed. Dar dacă aplicația are vârfuri legitime de consum, va fi throttled chiar și când clusterul are resurse suficiente. Folosește valori diferite. Cât de des trebuie revizuite resource limits? După fiecare schimbare semnificativă a aplicației și trimestrial pentru întreaga infrastructură. Folosește Vertical Pod Autoscaler în modul recommend pentru sugestii automate. Ce fac dacă un serviciu legacy nu are endpoint de health? Folosește un probe de tip exec pentru verificare printr-o comandă în interiorul containerului, sau un probe tcpSocket pentru verificarea disponibilității portului. Oricare e mai bine decât nimic. Este relevant pentru companiile mici din Moldova și România? Da. Aceste greșeli sunt critice chiar și pentru clustere cu 3–5 servicii. Costul unei ore de downtime pentru un business e-commerce din Moldova sau România depășește semnificativ costul configurării corecte de la început.ConcluzieAceste trei greșeli nu sunt cazuri exotice. Le întâlnim regulat la auditul infrastructurii companiilor din Moldova, România și UE, indiferent de dimensiunea echipei sau de stack-ul folosit. Vestea bună: fiecare poate fi remediată în câteva ore. Dacă dorești un audit al infrastructurii și pipeline-ului CI/CD — la WebDirect oferim un IT Health Check gratuit cu un raport concret despre sistemul tău specific. Echipa noastră va analiza mediul tău și va oferi o evaluare clară și onestă a situației actuale — împreună cu un plan concret de îmbunătățire.Aveți nevoie de ajutor expert?
Echipa noastră este gata să vă ajute să implementați strategiile discutate în articolele noastre.
