Jenkins¶
Purpose¶
The full build → scan → image → deploy pipeline - the only path that ever pushes an image to a registry or deploys to dev/staging/production.
File¶
Jenkinsfile (declarative pipeline, one agent labeled docker).
Prerequisites for the Jenkins agent¶
Docker, .NET 8 SDK, Node 20+, Helm, kubectl.
Configuration (environment block)¶
REGISTRY = 'ghcr.io'
REGISTRY_NAMESPACE = 'thirunk'
BACKEND_IMAGE = 'ghcr.io/thirunk/akshayabazaar-backend'
FRONTEND_IMAGE = 'ghcr.io/thirunk/akshayabazaar-frontend'
HELM_RELEASE = 'akshayabazaar'
HELM_CHART_PATH = 'helm/akshayabazaar'
SCAN_FAIL_SEVERITY = 'CRITICAL'
No secret value ever appears in this file - every credential is a Jenkins Credentials-store
ID, resolved only at runtime via withCredentials:
| Credentials ID | What it is |
|---|---|
container-registry-creds |
Registry username/token (GHCR) |
k3s-kubeconfig-dev |
kubeconfig for the dev deploy |
k3s-kubeconfig-staging |
kubeconfig for the staging deploy |
k3s-kubeconfig-production |
kubeconfig for the production deploy |
Pipeline parameters¶
| Parameter | Choices | Purpose |
|---|---|---|
ACTION |
Deploy (default) / Rollback |
Deploy the current commit, or roll an already-deployed environment back |
ROLLBACK_ENV |
staging / production / dev |
ACTION=Rollback only |
ROLLBACK_REVISION |
(blank = previous revision) | ACTION=Rollback only - helm history <release> -n <namespace> shows what's available |
Stages (Deploy path)¶
Checkout → resolves IMAGE_TAG (immutable short commit SHA), BUILD_VERSION, branch/tag flags
Backend → restore, build, test (xUnit, non-zero exit stops here), dependency scan
(dotnet list package --vulnerable - fails only on SCAN_FAIL_SEVERITY findings)
Frontend → npm ci, test (vitest), dependency scan (npm audit --audit-level), production build
Docker image build → both images, VCS_REF/BUILD_VERSION/BUILD_DATE/VCS_URL build args
Security/image scan → Trivy, fails on CRITICAL (fixable) findings; full HIGH+ report always archived
Tag images → immutable commit-SHA tag (always) + a floating <env>-latest pointer
(human browsing only, never what Helm deploys with) + semver tag on a release
Push images → only if SHOULD_DEPLOY (master or a release tag)
Deploy to dev → only on master - helm upgrade --install ... values-dev.yaml --atomic
Helm deploy to staging → only on a release tag - helm upgrade --install ... values-staging.yaml --atomic
Smoke tests → scripts/smoke-test.sh against staging - failure stops here, before promotion
Promote to production → manual approval gate (submitter: release-managers, 24h timeout),
then helm upgrade --install ... values-production.yaml --atomic
Production smoke tests → scripts/smoke-test.sh against production
"Promote, don't rebuild": the exact same image tag that passed staging's smoke test is what gets deployed to production - never a second build. This is what makes the manual approval gate meaningful (approving this specific, already-tested artifact, not a promise to rebuild it correctly later).
Rollback path (ACTION=Rollback)¶
Short-circuits the rest of the pipeline entirely:
helm history akshayabazaar -n akshayabazaar-<env>
helm rollback akshayabazaar <revision> -n akshayabazaar-<env> --wait --timeout 5m
--atomic: the first line of rollback defense¶
Every helm upgrade --install in this pipeline passes --atomic - if the rollout doesn't reach
Ready within --timeout, Helm automatically rolls the release back to its previous revision
before the pipeline stage even returns. The explicit ACTION=Rollback path above is for a
deploy that succeeded but is behaviorally wrong, not for a deploy that simply timed out.
Security/dependency/image scanning¶
- Backend:
dotnet list package --vulnerable --include-transitive- fails the build only on aCRITICALfinding (text-matched, since this command always exits 0 regardless of findings); High/Moderate findings are logged, archived, and do not block. - Frontend:
npm audit --omit=dev --audit-level=critical- uses npm's own severity-threshold exit code natively. - Images: Trivy (
aquasec/trivy image),--severity CRITICAL --exit-code 1 --ignore-unfixed- fails only on a fixable CRITICAL vulnerability; a full HIGH+CRITICAL report is always archived regardless of pass/fail.
Validation¶
# Linux/Bash - the exact commands this pipeline runs, for local reproduction
cd backend && dotnet restore ECommerce.sln && dotnet build ECommerce.sln --configuration Release --no-restore
dotnet test tests/ECommerce.Tests/ECommerce.Tests.csproj --configuration Release --no-build
cd ../frontend && npm ci && npm test && VITE_API_URL=/api npm run build
Troubleshooting¶
- Pipeline failed at a gated stage - nothing later ran; the
post { failure }block always points at which check stopped it (tests / scan / smoke test / rollout timeout) - check that specific stage's log, not the overall job summary. - Smoke test failure blocking promotion -
scripts/smoke-test.shis intentionally environment-agnostic HTTP-only checks; see Operations → Verification for the fuller Kubernetes-aware equivalent (verify-staging.ps1) to narrow down why. Promote to productiontimed out (24h) - re-running the job re-enters the same approval gate; nothing was deployed while it waited.
Rollback / recovery¶
See "Rollback path" above, and Operations → Rollback for the Helm-level detail of what a rollback does and does not undo.
Security considerations¶
- Images are promoted, never rebuilt per environment - eliminates "it worked in staging because it was a different build" as a failure mode.
- Production deploys require a named-group human approval (
submitter: release-managers) - never automatic, regardless of how green every earlier stage was. - No secret is ever written to a log, an archived artifact, or this file - only Credentials-store
IDs, resolved at runtime and scoped to the single stage that needs them (
withCredentialsblocks).