🧠FFVAcademy
🏛️

Jenkins Pipelines: o CI/CD da era enterprise

19 min de leitura·+85 XP
Pré-requisitos (0/1)0%

Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.

Jenkins é o avô do CI/CD e continua rodando metade da indústria. Nasceu em 2004 como Hudson, virou Jenkins em 2011, tem ~2.000 plugins e uma comunidade enorme. GitHub Actions e GitLab CI vieram depois, com sintaxe mais limpa e integração SaaS. Mas Jenkins sobrevive porque: roda on-prem em rede isolada, integra com qualquer coisa (SVN, Perforce, Bitbucket, sistemas legados), tem governança fina de permissões, e uma empresa de 20 anos provavelmente já tem 300 jobs investidos nele. Saber Jenkins é diferencial real em empresas de porte. Este guia cobre arquitetura moderna, Jenkinsfile declarativo, agents Kubernetes, shared libraries e migração de freestyle para pipeline-as-code.

Por que Jenkins ainda existe em 2026

Self-hosted sérioRoda em sua rede, sem depender de SaaS, sem dados saindo. Banco, saúde, governo exigem isso.
Plugin ecosystemIntegra com SVN, CVS, Perforce, TFS, Mercurial, sistemas SAP, mainframe. Coisas que GH Actions nem lista.
NeutralidadeFunciona igual com Bitbucket Server, GitLab self-hosted, GitHub Enterprise, Azure Repos.
Pipeline-as-codeJenkinsfile versionado com o projeto — code review no pipeline, rollback via git revert.
Shared librariesPadrão comum entre centenas de repos: função buildImage() igual em todos, mudança em um lugar.
CustoBinário é grátis. Custo real é operação (VM + pessoa cuidando). Para grandes, diluído rápido.
💡
Se você está começando hoje num stack 100% GitHub/cloud, provavelmente não deveria montar Jenkins. Mas se você trabalha em empresa com Jenkins legado, ou precisa de on-prem, esta é a plataforma — e dominar significa modernizar legado, não construir do zero.

Arquitetura: controller + agents

🧑‍💻Devpush
Commit no repo (GitHub, Bitbucket, GitLab).
webhook
🏛️Jenkins Controllerorquestra
Recebe trigger, carrega Jenkinsfile, decide em qual agent rodar. NÃO deve executar builds pesados.
agent protocol (JNLP/SSH)
🧩Agents (workers)executam
VMs, containers ou Pods K8s efêmeros. Cada stage pode rodar em um agent diferente.
shell/powershell
📦Stagesbuild/test/deploy
Passos declarados no Jenkinsfile. Post actions cuidam de notificação e cleanup.
⚠️
Erro clássico: usar o controller como agent (agent any apontando pro master). O controller carrega UI, schedule, gerencia estado — se o build consumir CPU/disco dele, a plataforma inteira engasga. Regra: controller não roda build. Nunca.

Declarative vs Scripted Pipeline

CritérioDeclarativeScripted
SintaxeEstrutura fixa: pipeline { }, agent, stages, steps, postGroovy livre: node { } + steps imperativos
ValidaçãoLinter oficial: jenkins-cli declarative-linterSó roda no Jenkins pra saber se passa
LegibilidadeAlta — shape consistente entre projetosDepende do autor
PoderSuficiente pra 95% dos casos + escape hatch via script { }Full Groovy — loops arbitrários, classes
Blue OceanRenderiza bem (grid de stages)Renderização limitada
Uso recomendadoDefault em 2026Só quando lógica for realmente dinâmica
groovy
// Jenkinsfile — declarativo, 100 linhas cobrem um pipeline real
pipeline {
  agent none                              // cada stage escolhe seu agent

  options {
    timeout(time: 30, unit: 'MINUTES')
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(numToKeepStr: '20'))
  }

  environment {
    IMAGE = "ghcr.io/me/api"
    SHA   = "${GIT_COMMIT.take(7)}"
  }

  stages {
    stage('Checkout') {
      agent { label 'linux' }
      steps { checkout scm }
    }

    stage('Quality') {
      parallel {
        stage('Lint') {
          agent { docker 'node:20-alpine' }
          steps { sh 'npm ci && npm run lint' }
        }
        stage('Test') {
          agent { docker 'node:20-alpine' }
          steps { sh 'npm ci && npm test -- --ci' }
          post { always { junit 'junit.xml' } }
        }
      }
    }

    stage('Build & push image') {
      agent { label 'linux' }
      when { branch 'main' }
      steps {
        withCredentials([usernamePassword(
          credentialsId: 'ghcr',
          usernameVariable: 'USER', passwordVariable: 'TOKEN')]) {
          sh '''
            echo "$TOKEN" | docker login ghcr.io -u "$USER" --password-stdin
            docker buildx build --push --platform linux/amd64,linux/arm64 \
              -t $IMAGE:$SHA -t $IMAGE:latest .
          '''
        }
      }
    }

    stage('Deploy staging') {
      agent { label 'kubectl' }
      when { branch 'main' }
      steps {
        sh '''
          kubectl set image deploy/api api=$IMAGE:$SHA -n staging
          kubectl rollout status deploy/api -n staging --timeout=5m
        '''
      }
    }

    stage('Deploy prod') {
      agent { label 'kubectl' }
      when { branch 'main' }
      input {
        message 'Promote to production?'
        ok 'Deploy'
        submitter 'sre,tech-lead'
      }
      steps {
        sh '''
          kubectl set image deploy/api api=$IMAGE:$SHA -n prod
          kubectl rollout status deploy/api -n prod --timeout=5m
        '''
      }
    }
  }

  post {
    success { slackSend channel: '#deploys', color: 'good',   message: "✅ ${env.JOB_NAME} ${env.BUILD_NUMBER} deployed" }
    failure { slackSend channel: '#deploys', color: 'danger', message: "❌ ${env.JOB_NAME} ${env.BUILD_NUMBER} failed" }
    always  { cleanWs() }
  }
}

Agents Kubernetes — o padrão moderno

Plugin kubernetes permite que o Jenkins agende agents como Pods efêmeros em um cluster K8s. Cada pipeline declara qual imagem quer; o Pod sobe, roda, morre. Escala automática, zero drift, custo sob demanda.

groovy
pipeline {
  agent {
    kubernetes {
      yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: node
      image: node:20-alpine
      command: [cat]
      tty: true
    - name: docker
      image: docker:26-dind
      securityContext: { privileged: true }
    - name: kubectl
      image: bitnami/kubectl:1.30
      command: [cat]
      tty: true
      '''
      defaultContainer 'node'
    }
  }
  stages {
    stage('Install') { steps { sh 'npm ci' } }
    stage('Test')    { steps { sh 'npm test' } }
    stage('Build')   {
      steps {
        container('docker') {
          sh 'docker build -t me/api:$GIT_COMMIT .'
        }
      }
    }
    stage('Deploy') {
      steps {
        container('kubectl') {
          sh 'kubectl apply -f k8s/'
        }
      }
    }
  }
}
Ganho real:um agent sai de “VM Linux com toda ferramenta pré-instalada” para “Pod com só o que esse pipeline precisa”. Sem conflito entre Java 11 e Java 21. Sem disco enchendo com cache. Quando não há build, zero recurso consumido.

Credentials — como não vazar segredo

Credential StoreManage Jenkins → Credentials. Tipos: Username/Password, Secret Text, SSH Key, Certificate, AWS, Vault.
withCredentialsInjeta credencial como env variable só durante o bloco. Jenkins masca em logs automaticamente.
Credential Binding pluginPermite montar credencial como arquivo temporário (file()) — útil pra kubeconfig, service account key.
IAM Role via OIDCJenkins 2.400+ + plugin OIDC Token plugin permite federar STS sem static keys. É o estado da arte.
HashiCorp VaultPlugin vault-plugin busca segredos em runtime do Vault, com lease curto. Melhor modelo de rotação.
MaskingJenkins masca valores declarados. Segredo derivado (base64, JSON) pode escapar — evite print ou use maskPasswords plugin.
groovy
stage('Deploy to AWS') {
  steps {
    withCredentials([[
      $class: 'AmazonWebServicesCredentialsBinding',
      credentialsId: 'aws-prod',
      accessKeyVariable: 'AWS_ACCESS_KEY_ID',
      secretKeyVariable: 'AWS_SECRET_ACCESS_KEY'
    ]]) {
      sh 'aws s3 sync ./dist s3://meu-bucket --delete'
    }
  }
}

Shared Libraries — DRY real na plataforma

Shared Library é um repo Git com estrutura convencional:

bash
jenkins-shared-lib/
├── vars/
│   ├── buildDockerImage.groovy     # usado como: buildDockerImage(name: 'api', tag: env.GIT_COMMIT)
│   └── deployToK8s.groovy
├── src/
│   └── com/minhaorg/jenkins/
│       └── K8sClient.groovy        # classes Groovy reutilizáveis
└── resources/
    └── k8s/
        └── deployment.yaml.tpl
groovy
// vars/buildDockerImage.groovy
def call(Map config) {
  def image = "${config.registry}/${config.name}:${config.tag}"
  sh """
    docker build -t ${image} .
    docker push ${image}
  """
  return image
}
groovy
// Jenkinsfile consome assim
@Library('jenkins-shared-lib@v2') _

pipeline {
  agent { label 'linux' }
  stages {
    stage('Build') {
      steps {
        script {
          def img = buildDockerImage(
            registry: 'ghcr.io/minha-org',
            name: 'api',
            tag: env.GIT_COMMIT.take(7)
          )
          echo "Built ${img}"
        }
      }
    }
  }
}
💡
Versione a library: tag v1, v2. Pipelines pinam versão. Mudança breaking? Novo major. Library sem versão é bomba-relógio — uma linha mudada quebra 200 pipelines em produção ao mesmo tempo.

Triggers e multibranch pipeline

Tipo de jobO que criaQuando usar
Pipeline (single)Um job que lê Jenkinsfile de um branchRaramente — só se repo tem 1 branch
Multibranch PipelineDescobre branches e PRs automaticamente, cria sub-job por branchDefault moderno
Organization FolderDescobre TODOS os repos de uma org/user com JenkinsfileEmpresas com 50+ repos
FreestyleUI clicada, sem JenkinsfileLegado — não usar em projetos novos
Webhook do GitHubConfigura no GitHub: Settings → Webhooks → https://jenkins/github-webhook/. Push/PR notifica Jenkins em segundos.
Poll SCMPlano B quando webhook não pode ser feito (rede fechada). Cron pegando mudanças — poluente e lento.
Triggers crontriggers { cron("H 2 * * *") } — H é hash por job (não sobrecarrega Jenkins todo mundo às 2h em ponto).
Evento upstreamtriggers { upstream(upstreamProjects: "libA", threshold: SUCCESS) } — job B roda após A.

Blue Ocean + Pipeline Editor

Blue Ocean é a UI moderna do Jenkins: grid visual de stages, logs limpos, trace de falha direto. É um plugin (um pouco desatualizado em 2026 mas ainda útil). Alternativa: UI oficial nova do Jenkins 2.4xx também tem visual de pipeline.

⚠️
Blue Ocean não é onde você edita Jenkinsfile em produção. O editor visual é ótimo pra descobrir sintaxe, mas o artefato canônico é sempre Jenkinsfile no repo, commitado, revisado.

Migração freestyle → pipeline

📋1. Documentar freestyleinventário
Captura triggers, build steps, post actions e plugins usados em cada job.
mapeia
🧪2. Prototipar Jenkinsfileem branch
Cria pipeline equivalente num branch, roda multibranch em paralelo ao freestyle.
valida
🔁3. Shadow runparalelo
Por 1-2 semanas, freestyle e pipeline rodam lado a lado. Compare resultados.
promove
🏁4. Cutover + disablego live
Desabilita freestyle (sem deletar) e vira oficial. Deleta após 1 mês sem reclamação.

Performance e produção

Controller high-availableEm escala, use CloudBees CI ou roda controller em K8s com persistent volume + backup do $JENKINS_HOME. Sem HA nativo no OSS.
Plugins: menos é maisPlugin sem manutenção = CVE aberto. Audite bimestralmente. CloudBees Plugin Catalog ajuda a filtrar.
Job DSL / JCasCConfiguration-as-Code: jenkins.yaml descreve plugins, credentials (referência), agents, views. Reprovisão em 5 min.
Disco do controllerLogs e workspaces enchem rápido. Workspace em agent, não no controller. buildDiscarder mantém só N builds.
Upgrade disciplinePula LTS → LTS (não weekly). Teste em controller de staging. Plugins atualizam junto.
SegurançaMatrix-based Authorization, Role-Based Strategy plugin, CSRF on, Script Approval fechado para não-admins.

Decisões

📋 Empresa nova, green field, tudo no GitHub

GitHub Actions

Jenkins é força desnecessária pra quem não tem drag de legado. GH Actions já resolve 95% dos casos com 10% do esforço operacional.

Alt: Jenkinsvire pra cá se crescer e precisar on-prem ou integração com sistemas exóticos.

📋 Banco/Seguradora com 500 jobs Jenkins, proibido SaaS, auditoria rigorosa

Jenkins modernizado — K8s agents + JCasC + shared libraries

Migrar 500 jobs é projeto de meses. Modernizar sem trocar a plataforma dá retorno mais rápido: libraries padronizam, K8s agents resolvem escala, JCasC vira infra-as-code.

Alt: GH Actions Enterprise Serverse a empresa aceita investir na migração. Horizonte de 1-2 anos.

📋 Time pequeno, repo híbrido (GitHub + SVN legado), precisa CI dos dois

Jenkins com multibranch + SVN plugin

GH Actions nem enxerga SVN. Jenkins orquestra os dois, centraliza resultado, permite shared library comum.

Alt: Dois CIs separadosduplica overhead, fragmenta cultura.

Perguntas típicas

Posso testar Jenkinsfile sem commitar 10 vezes?

Sim. jenkins-cli declarative-linter valida sintaxe. Replay na UI roda a mesma build com um Jenkinsfile editado sem commit. E JenkinsPipelineUnit permite teste unitário Groovy de shared library.

Como versionar a shared library?

Dois caminhos: (1) tag Git — @Library('lib@v1.2.0'); (2) branch — usa @Library('lib@main') para dev, tag em prod. Em ambiente regulado, pin por SHA é superior: @Library('lib@abc123def').

Jenkins em containers Docker no próprio Docker (DinD) — faz sentido?

Sim pra desenvolvimento/testes locais. Em prod, prefira Jenkins controller em Kubernetes (sem DinD), e agents com docker: socket mount (dood) ou buildkit daemon. Docker-in-Docker tem custos de performance e problemas de cache.

Como deploy de infra (Terraform) no Jenkins é diferente?

Estágios: init → validate → plan → (approval) → apply. O plan vira artefato; apply usa exatamente esse plan com -lock-timeout. Credenciais via OIDC/STS, estado no S3 com DynamoDB lock. Um webhook por repo de infra.

Como cuidar de flakiness em testes E2E no Jenkins?

Três camadas: (1) retry(2) em stages sabidamente flaky; (2) dashboard de flaky tests via Allure/Test Analytics; (3) quarentena — testes instáveis vão pra um stage que não falha o build, mas gera alerta. Corrigir a raiz é melhor que retry, mas retry salva deploy de sexta.
Take-aways. (1) Jenkins é plataforma — vale o investimento em empresa grande/regulada; overkill pra startup nova. (2) Declarative pipeline como padrão; scripted só pra dinâmica real. (3) Controller NÃO roda builds — agents (Kubernetes de preferência) sim. (4) Credenciais sempre via Credential Store + withCredentials; OIDC/STS é o estado da arte. (5) Shared Library versionada é o que mantém sanidade em 50+ repos. (6) Multibranch Pipeline + webhook é o default moderno — freestyle é legado. (7) JCasC + Job DSL transformam Jenkins em infra-as-code. (8) Upgrade LTS a LTS com cluster de staging — plugins são o ponto fraco.
🧩

Quiz rápido

4 perguntas · Acerte tudo e ganhe o badge 🎯 Gabarito

Continue lendo