RO EN

CI/CD profesionist cu GitHub Actions (2): environments și approval gates

CI/CD profesionist cu GitHub Actions (2): environments și approval gates ✨ Imagine generată cu AI
Doru Bulubasa
02 septembrie 2026
42 vizualizări

În prima parte a seriei am construit fundația: un pipeline care face build o singură dată, rulează testele și produce un artifact versionat. Am stabilit și principiul-cheie – build once, deploy many.

Acum vine partea în care acel artifact chiar ajunge undeva. Dar nu direct în producție. Îl trecem controlat prin medii separate – dev, staging, producție – cu o aprobare umană înainte de pasul final.

Întrebarea nu e doar cum ajunge codul în producție, ci cine apasă butonul și când.

🎯 Ce sunt GitHub Environments

Un environment în GitHub e o țintă logică de deploy – dev, staging, production – care are propriile reguli de protecție, propriile secrete și propriile variabile.

Practic, un environment îți dă trei lucruri:

  • Reguli de protecție – cine trebuie să aprobe, cât se așteaptă, de pe ce branch se poate face deploy.

  • Secrete și variabile per-mediu – connection string-ul de staging e altul decât cel de prod, iar fiecare stă doar în environment-ul lui.

  • Istoric de deploy-uri – vezi ce versiune e în fiecare mediu și cine a promovat-o.


🛠️ Cum creezi environments

În repo, mergi la Settings → Environments → New environment. Creează trei: dev, staging și production.

Pentru dev nu pui nicio restricție – vrei feedback rapid. Pentru staging poți pune restricții ușoare. Pentru production pui toate garanțiile: reviewers și branch restrictions. Asta e ideea – cu cât mediul e mai aproape de clienți, cu atât poarta e mai strictă.


🚦 Regulile de protecție (approval gates)

Aici stă toată valoarea. Pe environment-ul production activezi:

Required reviewers

Alegând până la 6 persoane (sau echipe) care trebuie să aprobe înainte ca deploy-ul să pornească. Asta e approval gate-ul: când pipeline-ul ajunge la job-ul de producție, se oprește și așteaptă ca cineva să apese Approve. Până atunci, nu se întâmplă nimic.

Wait timer

O întârziere obligatorie (de la câteva minute până la 30 de zile) înainte ca deploy-ul să continue. Util când vrei o fereastră de siguranță în care cineva poate anula.

Deployment branches

Restrângi din ce branch-uri se poate face deploy în acest mediu. Tipic: doar main ajunge în production. Așa, nimeni nu promovează accidental un branch de feature direct la clienți.


🔐 Secrete și variabile per-mediu

Fiecare environment își ține propriile secrete și variabile. Un secret definit pe production e vizibil doar unui job care rulează în environment-ul production – și doar după ce a trecut de approval gate.

Asta rezolvă elegant o problemă reală: nu mai ai un singur set global de secrete la care are acces orice job. Connection string-ul de producție e izolat în environment-ul lui.

Ce diferă între medii e configurația – secrete, connection strings, feature flags – nu artifactul. Binarul rămâne același.

🧩 Cum referi un environment în workflow

Legi un job de un environment cu proprietatea environment. Când job-ul pornește, GitHub aplică automat regulile de protecție ale acelui mediu:

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    needs: build-test
    environment:
      name: staging
      url: https://staging.example.com
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: app
          path: ./publish
      # ... pasul de deploy

Observă actions/download-artifact – nu reconstruim nimic. Luăm exact artifactul produs de job-ul de build și îl punem în staging. Asta e build once, deploy many în practică.


🏗️ Pipeline-ul complet: build → staging → producție

Punem totul cap la cap. Un job de build care produce artifactul, un deploy în staging, apoi un deploy în producție care așteaptă aprobare:

name: CI/CD

on:
  push:
    branches: [ main ]

jobs:
  build-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'
      - run: dotnet build --configuration Release
      - run: dotnet test --configuration Release --no-build
      - run: dotnet publish ./src/Api/Api.csproj -c Release -o ./publish
      - uses: actions/upload-artifact@v4
        with:
          name: app
          path: ./publish

  deploy-staging:
    runs-on: ubuntu-latest
    needs: build-test
    environment:
      name: staging
      url: https://staging.example.com
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: app
          path: ./publish
      - name: Deploy to Azure (staging)
        uses: azure/webapps-deploy@v3
        with:
          app-name: my-app-staging
          package: ./publish

  deploy-production:
    runs-on: ubuntu-latest
    needs: deploy-staging
    environment:
      name: production
      url: https://example.com
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: app
          path: ./publish
      - name: Deploy to Azure (production)
        uses: azure/webapps-deploy@v3
        with:
          app-name: my-app-prod
          package: ./publish

Fluxul e liniar și controlat: build-test produce artifactul, deploy-staging îl pune în staging (needs: build-test), iar deploy-production îl așteaptă pe staging (needs: deploy-staging). Pentru că production are required reviewers, ultimul job se oprește și așteaptă aprobare.

Notă: pasul de autentificare la Azure (login-ul propriu-zis) l-am lăsat deoparte intenționat – în partea 5 vedem cum ne conectăm complet fără parole, cu Managed Identity și OIDC. Aici ne concentrăm pe mecanica mediilor.


👀 Cum arată aprobarea în practică

Când pipeline-ul ajunge la job-ul de producție, în tab-ul Actions apare butonul Review deployments. Reviewer-ul vede ce urmează să fie promovat, poate lăsa un comentariu și apasă Approve and deploy sau Reject.

Până la aprobare, artifactul stă cuminte – testat, gata, dar neinstalat în prod. Exact controlul pe care îl vrei înainte de un release.


✅ Câteva reguli sănătoase

  • dev fără restricții, production cu reviewers și branch restrictions – strictețea crește spre clienți.

  • Ține secretele în environment, nu global – fiecare mediu vede doar ce îi trebuie.

  • Niciodată rebuild per mediu – promovezi mereu același artifact.

  • Folosește url în environment ca să ai link direct către mediul deployat în istoricul rulărilor.


Concluzie

Environments transformă un simplu deploy într-un proces controlat: același artifact urcă prin dev → staging → producție, fiecare mediu cu secretele lui, iar înainte de prod stă un approval gate real. Nu mai ajunge nimic la clienți fără ca cineva să apese conștient butonul.

În partea 3 coborâm un nivel: în loc să creăm resursele Azure manual din portal, le definim în cod cu Bicep – ca deploy-ul să includă și infrastructura, nu doar aplicația.