CI/CD24 min read

Jenkins for Azure and cloud delivery

Learn Jenkins pipelines, secure Azure authentication, App Service and AKS delivery, production operations, and systematic troubleshooting.

Production-aware guide

Review scope, permissions, impact, and rollback before applying changes.

Jenkins for Azure and cloud delivery

Jenkins is an automation server commonly used to build, test, scan, package, and deploy applications. The most maintainable approach is Pipeline as Code: store a Jenkinsfile beside the application so pipeline changes are versioned and reviewed with the code.

Who this guide is for

This guide is for developers, DevOps engineers, and cloud administrators who want to:

  • Understand Jenkins controllers, agents, jobs, and pipelines.
  • Build a declarative pipeline.
  • Handle credentials without exposing secrets.
  • Deploy an application to Azure App Service or Azure Kubernetes Service (AKS).
  • Diagnose common pipeline and agent failures.

Core architecture

Controller

The controller stores configuration, schedules work, manages plugins, exposes the web interface, and coordinates agents. Avoid running heavy builds directly on the controller in a production environment.

Agent

An agent provides the workspace and tools that execute pipeline stages. Agents may be permanent machines, virtual machines, containers, or short-lived Kubernetes pods.

Job and build

A job is a configured unit of automation. A build is one execution of that job. Pipeline jobs describe several related stages such as build, test, package, and deploy.

Jenkinsfile

A Jenkinsfile contains the pipeline definition. Jenkins supports Declarative and Scripted Pipeline syntax. Declarative syntax is usually easier to review and standardize.

Installation choices

Use one of these patterns:

  • Package installation for a small internal server.
  • Docker for local evaluation or a controlled single-host deployment.
  • Kubernetes for elastic, short-lived agents.
  • A hardened VM or managed platform pattern for long-running production use.

Before production deployment, plan persistent storage, HTTPS, backups, identity integration, plugin governance, monitoring, and upgrade procedures.

Local Docker example

This example creates a named volume so Jenkins data survives container replacement:

docker volume create jenkins_home

docker run --name jenkins \
  --detach \
  --restart unless-stopped \
  --publish 8080:8080 \
  --publish 50000:50000 \
  --volume jenkins_home:/var/jenkins_home \
  jenkins/jenkins:lts-jdk21

Verify the container:

docker ps --filter name=jenkins
docker logs jenkins

For public or shared environments, place Jenkins behind HTTPS and restrict network access. Do not expose an unconfigured Jenkins controller directly to the internet.

Your first declarative pipeline

Create a file named Jenkinsfile in the repository root:

pipeline {
    agent any

    options {
        timestamps()
        disableConcurrentBuilds()
        timeout(time: 30, unit: 'MINUTES')
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Install') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Lint') {
            steps {
                sh 'npm run lint'
            }
        }

        stage('Test') {
            steps {
                sh 'npm test -- --ci'
            }
        }

        stage('Build') {
            steps {
                sh 'npm run build'
            }
        }
    }

    post {
        always {
            deleteDir()
        }
    }
}

Replace the commands with those supported by the application. On Windows agents, use bat or powershell instead of sh.

Pipeline design recommendations

  • Keep the pipeline in source control.
  • Fail early on linting, validation, or unit-test failures.
  • Use immutable build artifacts. Build once, then promote the same artifact.
  • Separate build and deployment stages.
  • Require an approval before high-risk production changes when appropriate.
  • Add timeouts so stalled processes cannot occupy agents indefinitely.
  • Prevent overlapping deployments to the same environment.
  • Archive useful test reports and artifacts, but define a retention policy.
  • Put repeated logic in shared libraries rather than copying large Groovy blocks.

Credentials and secrets

Store credentials in Jenkins' credential store or use a supported external secret manager. Reference the credential by its Jenkins ID; never hard-code the secret in a Jenkinsfile.

pipeline {
    agent any

    stages {
        stage('Use secret safely') {
            steps {
                withCredentials([string(
                    credentialsId: 'example-api-token',
                    variable: 'API_TOKEN'
                )]) {
                    sh '''
                      set +x
                      ./deploy.sh
                    '''
                }
            }
        }
    }
}

Security rules:

  • Grant credentials only to the jobs and folders that require them.
  • Prefer short-lived workload identity or federated identity over long-lived client secrets.
  • Never print environment variables that may contain credentials.
  • Treat pull requests from forks as untrusted.
  • Rotate credentials and remove unused entries.
  • Do not allow unreviewed pipeline code to access production credentials.

Azure authentication

Interactive az login is unsuitable for an unattended agent. For production automation, prefer workload identity federation or a managed identity when the agent runs in Azure. If a service principal secret is temporarily required, store it in the Jenkins credential store and limit its Azure RBAC scope.

Example using credential bindings:

stage('Azure login') {
    steps {
        withCredentials([
            string(credentialsId: 'azure-client-id', variable: 'AZURE_CLIENT_ID'),
            string(credentialsId: 'azure-client-secret', variable: 'AZURE_CLIENT_SECRET'),
            string(credentialsId: 'azure-tenant-id', variable: 'AZURE_TENANT_ID'),
            string(credentialsId: 'azure-subscription-id', variable: 'AZURE_SUBSCRIPTION_ID')
        ]) {
            sh '''
              set +x
              az login --service-principal \
                --username "$AZURE_CLIENT_ID" \
                --password "$AZURE_CLIENT_SECRET" \
                --tenant "$AZURE_TENANT_ID" \
                --output none
              az account set --subscription "$AZURE_SUBSCRIPTION_ID"
              az account show --query '{name:name,id:id}' --output table
            '''
        }
    }
}

Do not copy this secret-based pattern into a new production platform without first evaluating federation or managed identity.

Deploy to Azure App Service

A safe pipeline packages an artifact, deploys it to a staging slot, validates the slot, and then swaps it into production.

stage('Deploy staging slot') {
    steps {
        sh '''
          az webapp deploy \
            --resource-group "$AZURE_RESOURCE_GROUP" \
            --name "$AZURE_WEBAPP_NAME" \
            --slot staging \
            --src-path dist/app.zip \
            --type zip
        '''
    }
}

stage('Verify staging') {
    steps {
        sh './scripts/verify-staging.sh'
    }
}

stage('Swap to production') {
    input {
        message 'Promote the verified staging slot to production?'
    }
    steps {
        sh '''
          az webapp deployment slot swap \
            --resource-group "$AZURE_RESOURCE_GROUP" \
            --name "$AZURE_WEBAPP_NAME" \
            --slot staging \
            --target-slot production
        '''
    }
}

The verification script should check the health endpoint, expected version, dependency availability, and any critical smoke tests.

Deploy to AKS

The agent needs kubectl, access to the cluster, and only the permissions required for its target namespace.

stage('Deploy to AKS') {
    steps {
        sh '''
          az aks get-credentials \
            --resource-group "$AKS_RESOURCE_GROUP" \
            --name "$AKS_CLUSTER" \
            --overwrite-existing

          kubectl apply -f k8s/ --namespace "$K8S_NAMESPACE"
          kubectl rollout status deployment/cloudforge \
            --namespace "$K8S_NAMESPACE" \
            --timeout=180s
        '''
    }
}

Avoid using cluster-admin credentials for routine deployment. Prefer Azure RBAC or Kubernetes RBAC scoped to the deployment namespace.

Testing and validation

At minimum, validate:

  • Pipeline syntax before merge.
  • Application lint and unit tests.
  • Dependency and container vulnerability results.
  • Infrastructure templates with their native validation tools.
  • The deployment health endpoint.
  • Rollout status and actual running image version.
  • Rollback readiness.

Freestyle jobs, pipelines, and multibranch pipelines

A Freestyle job can run simple commands, but much of its behavior lives in the Jenkins user interface. That makes review, reuse, and migration harder. Prefer a Pipeline job when the workflow has several stages or must be treated as code.

A Multibranch Pipeline discovers branches containing a Jenkinsfile. It can create separate branch jobs and integrate with pull requests. This is valuable when teams need the same validation workflow across feature branches.

Before enabling automatic branch discovery, decide:

  • Which repositories Jenkins is allowed to scan.
  • Whether pull requests from forks are trusted.
  • Which branches may request production credentials.
  • How long old branch jobs and artifacts remain.
  • Which webhook events should trigger builds.
  • Whether duplicate webhook and polling triggers can run the same commit twice.

Webhooks and source-control integration

Webhooks provide timely builds without constant repository polling. A reliable integration has four parts:

  1. The source-control platform can reach the Jenkins webhook endpoint.
  2. Jenkins validates the webhook secret or signature where supported.
  3. The job is configured for the correct repository and event types.
  4. Branch and environment rules prevent untrusted code from reaching privileged stages.

If a webhook appears successful but no build starts, inspect the delivery response, Jenkins system logs, job branch filters, repository credentials, and whether the commit contains a discoverable Jenkinsfile.

Do not expose the complete Jenkins web interface merely to receive a webhook. Use network controls, a reverse proxy, or an approved integration architecture.

Parameters and environment promotion

Parameters can make a pipeline reusable, but a free-form production target is risky. Constrain inputs:

pipeline {
    agent any

    parameters {
        choice(
            name: 'TARGET_ENVIRONMENT',
            choices: ['dev', 'test', 'prod'],
            description: 'Approved deployment environment'
        )
        booleanParam(
            name: 'RUN_SMOKE_TESTS',
            defaultValue: true,
            description: 'Run post-deployment health checks'
        )
    }

    stages {
        stage('Validate target') {
            steps {
                script {
                    if (params.TARGET_ENVIRONMENT == 'prod' && env.BRANCH_NAME != 'main') {
                        error('Production deployment is allowed only from main.')
                    }
                }
            }
        }
    }
}

Pipeline checks complement—not replace—protected branches, environment permissions, credential scope, and human approval.

Parallel stages

Independent tests can run concurrently:

stage('Quality gates') {
    parallel {
        stage('Unit tests') {
            steps {
                sh 'npm test -- --ci'
            }
        }
        stage('Lint') {
            steps {
                sh 'npm run lint'
            }
        }
        stage('Dependency scan') {
            steps {
                sh './scripts/dependency-scan.sh'
            }
        }
    }
}

Do not parallelize operations that mutate the same environment, workspace, database, state file, or deployment slot unless the tools provide safe locking.

Artifacts, test reports, and retention

An artifact is a file produced by a build, such as a package, test report, or infrastructure plan. Archive only what is needed for deployment, diagnosis, compliance, or traceability.

post {
    always {
        junit testResults: 'reports/junit/*.xml', allowEmptyResults: true
        archiveArtifacts artifacts: 'dist/**', fingerprint: true, onlyIfSuccessful: true
    }
}

Production delivery should promote the same immutable artifact tested earlier. Rebuilding at every environment can introduce dependency or source differences.

Define retention by business and audit requirements. Unlimited builds, logs, workspaces, and artifacts eventually exhaust storage.

Shared libraries

Shared libraries centralize approved pipeline functions. They are appropriate for stable capabilities such as standardized build stages, security scans, notifications, and deployment wrappers.

Govern shared libraries carefully:

  • Version the library and release changes predictably.
  • Pin critical pipelines to reviewed versions.
  • Test library changes against representative consumers.
  • Keep the public interface small.
  • Avoid hiding important production behavior behind undocumented helpers.
  • Restrict who can modify trusted libraries because their code may run with broad permissions.

Agent strategy

Static agents

Static agents are simple to understand but accumulate tools, credentials, and configuration drift. Patch them, monitor capacity, and rebuild them regularly from a documented baseline.

Container agents

Container images make tool versions reproducible. Use minimal trusted images, scan them, pin immutable versions, and avoid privileged container execution.

Kubernetes agents

Kubernetes plugins can create short-lived agent pods. Define resource requests, pod security settings, service accounts, workspace behavior, network access, and cleanup. A dynamic agent should disappear after the build without taking the only copy of required artifacts or diagnostics with it.

Complete delivery flow

A mature delivery pipeline normally follows this order:

  1. Discover the source revision and record its commit ID.
  2. Restore or install locked dependencies.
  3. Lint and run fast tests.
  4. Run security and policy checks.
  5. Build one immutable artifact.
  6. Publish it to an approved artifact or container registry.
  7. Deploy to a non-production environment.
  8. Run smoke, integration, and health checks.
  9. Require production approval when policy demands it.
  10. Promote the exact tested artifact.
  11. Verify service health, version, logs, and key user paths.
  12. Record deployment evidence and notify the responsible team.

If verification fails, stop promotion and execute a documented rollback or recovery path. Do not allow a failed health check to be hidden by a successful deployment command.

Backup and disaster recovery

Back up the Jenkins home data required to recover jobs, configuration, credentials, plugins, and build history according to policy. Encryption keys and credential material require particularly careful protection.

A backup is not sufficient until restoration has been tested. Document:

  • Backup frequency and retention.
  • Storage encryption and access.
  • Jenkins and plugin versions needed for recovery.
  • Recovery time and recovery point objectives.
  • The process for restoring into an isolated environment.
  • DNS, certificates, reverse proxy, agents, and external integrations.

Do not assume that source-controlled Jenkinsfile files alone can reconstruct the controller.

Monitoring Jenkins

Monitor at least:

  • Controller availability and response time.
  • Queue length and oldest queued item.
  • Online/offline agents and executor utilization.
  • Build duration, success rate, and failure trends.
  • Disk space and workspace growth.
  • Java memory, garbage collection, and process restarts.
  • Webhook delivery failures.
  • Authentication and administrative changes.
  • Plugin and core security advisories.

Alert on symptoms that require action. A dashboard with no operational ownership does not improve reliability.

Troubleshooting decision table

SymptomFirst evidenceLikely areasSafe next step
Build never startsQueue reasonLabels, executors, locksConfirm a matching online agent
Checkout failsSCM error and agent networkCredentials, URL, DNS, proxyTest repository access from the same agent
Tool missingConsole path and agent labelWrong image or PATHCorrect the agent image or label
Deployment unauthorizedCloud identity and scopeExpired secret, federation, RBACVerify identity and exact required action
Build suddenly slowsStage timingAgent capacity, dependency sourceCompare per-stage duration and agent load
Controller disk fillsDisk and artifact usageRetention, workspaces, logsPreserve evidence, then apply retention safely
Pipeline changed unexpectedlyCommit and library versionUnpinned library or branchReproduce using the recorded versions
Duplicate deploymentsBuild causes and concurrencyWebhook plus polling, retriesIdentify trigger IDs and add concurrency control

Troubleshooting

A build remains queued

Check:

  1. Whether an online agent matches the job label.
  2. Whether all matching executors are busy.
  3. Whether the node is temporarily offline.
  4. Whether resource quotas prevent a dynamic agent from starting.
  5. Whether a previous build holds a lock.

script returned exit code 1

This is a generic wrapper around a failed command. Find the first meaningful error above it in the console log. Reproduce that exact command inside the same agent image or workspace configuration.

command not found

The selected agent lacks the tool or its executable is not in PATH. Confirm the agent label, container image, tool installation, and environment variables.

Azure authentication fails

Verify:

az account show
az account list --output table

Then check credential expiry, tenant, subscription selection, federated credential configuration, and RBAC scope. Authentication success does not prove authorization to the target resource.

AKS rollout times out

Run:

kubectl get pods -n <namespace>
kubectl describe deployment <deployment> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp
kubectl logs deployment/<deployment> -n <namespace> --all-containers

Investigate image pulls, readiness probes, missing configuration, insufficient capacity, and application startup failures before increasing the timeout.

Workspace or disk usage grows continuously

Define build retention, delete unnecessary workspaces, archive only required artifacts, and monitor controller and agent storage. Never delete the Jenkins home directory as a cleanup shortcut.

A plugin update breaks a job

Record plugin versions, back up Jenkins before upgrades, test changes in a non-production controller, review compatibility notes, and update in controlled batches.

Operational checklist

  • HTTPS is enforced.
  • Anonymous access is disabled unless explicitly required.
  • Least-privilege authorization is configured.
  • The controller is backed up and restoration is tested.
  • Plugin installation is governed.
  • Controller and agents are patched.
  • Credentials are scoped and rotated.
  • Build retention is configured.
  • Logs, disk, queue length, and agent health are monitored.
  • Production deployments include verification and rollback procedures.

Frequently asked questions

Should Jenkins run application builds on the controller?

For production, use dedicated agents. This reduces contention and limits the tools and untrusted code executed on the controller.

Declarative or Scripted Pipeline?

Start with Declarative Pipeline for readability and policy consistency. Use Scripted Pipeline only where the additional flexibility is genuinely required.

Should Azure credentials be placed in environment files?

No. Use the Jenkins credential store, a secret manager, managed identity, or workload identity federation. Keep secrets out of source control and build artifacts.

How should failed production deployments be handled?

Stop further promotion, preserve diagnostic evidence, run documented health checks, and execute a tested rollback or slot swap. Do not improvise destructive changes during an incident.

Official references