Integrando Ansible com Jenkins: Automatizando Seu Pipeline de CI/CD

Integre o Ansible com o Jenkins para executar playbooks a partir de pipelines CI/CD, gerenciar credenciais SSH e implantar de forma consistente.

Integrando Ansible com Jenkins: Automatizando seu Pipeline CI/CD

Integrar o Ansible com o Jenkins permite que seu pipeline CI/CD construa um artefato, execute testes e o implante com os mesmos playbooks que você usa fora do Jenkins. O principal desafio é conectar credenciais, inventário e execução de playbooks sem transformar o pipeline em uma pilha de comandos shell.

Este guia mostra uma configuração prática: o Jenkins orquestra o pipeline, enquanto o Ansible lida com a implantação e configuração nos hosts de destino. Os exemplos assumem implantações Linux baseadas em SSH, mas o mesmo padrão funciona com inventários e funções específicos do ambiente.

Como Jenkins e Ansible se Encaminham

Antes de escrever o pipeline, separe as responsabilidades:

  • Jenkins: Faz checkout do código, constrói artefatos, executa testes, coleta logs e decide quando os estágios de implantação são executados.
  • Ansible: Conecta-se aos hosts de destino, copia artefatos, escreve configuração, gerencia serviços e mantém as etapas de implantação idempotentes.

Por que Integrar Jenkins com Ansible?

Essa divisão dá à sua equipe um limite claro:

  1. O Jenkins armazena o fluxo de release em um Jenkinsfile.
  2. O Ansible armazena ações de infraestrutura em playbooks e funções.
  3. Os arquivos de inventário decidem quais hosts pertencem a staging, produção ou outros ambientes.
  4. As credenciais do Jenkins protegem chaves SSH, senhas do Vault e tokens.

Pré-requisitos para Integração

Antes de começar, certifique-se de ter:

  • Um controlador Jenkins funcional e pelo menos um agente que possa executar jobs de implantação.
  • Ansible instalado no agente Jenkins que executa ansible-playbook.
  • Máquinas de destino acessíveis a partir desse agente via SSH.
  • Um par de chaves SSH dedicado para automação.
  • Código da aplicação, inventário, playbooks e funções no controle de versão.

Configurando Jenkins para Ansible

Jenkins precisa de duas coisas antes de executar Ansible com segurança: o runtime do Ansible em um agente e credenciais para os hosts de destino.

1. Instalar o Plugin Ansible

Você pode chamar ansible-playbook diretamente de uma etapa shell, mas o plugin Ansible do Jenkins pode facilitar a configuração e a saída.

  1. Navegue até Manage Jenkins > Manage Plugins.
  2. Vá para a aba Available e pesquise por "Ansible".
  3. Selecione o plugin "Ansible" e clique em Install without restart ou Download now and install after restart.

2. Configurar Credenciais SSH

O Ansible usará SSH para se conectar aos servidores de destino. Armazene a chave privada nas credenciais do Jenkins, não no repositório.

  1. Vá para Manage Jenkins > Manage Credentials.
  2. Selecione o armazenamento de credenciais usado pelos seus jobs.
  3. Clique em Add Credentials.
  4. Escolha SSH Username with private key.
  5. Defina um ID estável, como ansible-ssh-key.
  6. Insira o nome de usuário SSH usado nas máquinas de destino.
  7. Adicione a chave privada e salve a credencial.

Dica: Melhores Práticas de Gerenciamento de Chaves

  • Nunca codifique chaves privadas SSH em um Jenkinsfile, inventário ou playbook.
  • Use chaves de automação dedicadas, não chaves pessoais.
  • Rotacione as chaves em um cronograma que corresponda à política de segurança da sua equipe.

Projetando seu Pipeline Jenkins com Ansible

Use um Pipeline Declarativo em um Jenkinsfile para que a lógica de implantação seja revisada junto com o código da aplicação.

Estrutura Básica do Pipeline

Aqui está um exemplo compacto para uma construção, implantação em staging e implantação em produção com gate:

// Jenkinsfile
pipeline {
    agent any

    environment {
        // Defina variáveis de ambiente se necessário
        ANSIBLE_HOST_KEY_CHECKING = 'False' // Cuidado em produção, prefira known_hosts
    }

    stages {
        stage('Checkout Source') {
            steps {
                git 'https://your-scm-url/your-repo.git'
            }
        }

        stage('Build Application') {
            // Este estágio pode construir um JAR, WAR, imagem Docker, etc.
            // Exemplo: construir um JAR Spring Boot
            steps {
                sh 'mvn clean package'
            }
        }

        stage('Run Unit Tests') {
            steps {
                sh 'mvn test'
            }
        }

        stage('Deploy to Staging') {
            steps {
                script {
                    // Use o agente SSH para disponibilizar a chave privada para o Ansible
                    sshagent(credentials: ['ansible-ssh-key']) {
                        // Executar playbook Ansible
                        sh 'ansible-playbook -i inventory/staging.ini playbooks/deploy_app.yml \n                            -e "app_version=$(cat target/VERSION)"'
                    }
                }
            }
        }

        stage('Deploy to Production') {
            // Este estágio pode exigir aprovação manual
            input {
                message "Prosseguir com a implantação para Produção?"
                ok "Implantar em Produção"
            }
            steps {
                script {
                    sshagent(credentials: ['ansible-ssh-key']) {
                        sh 'ansible-playbook -i inventory/production.ini playbooks/deploy_app.yml \n                            -e "app_version=$(cat target/VERSION)"'
                    }
                }
            }
        }
    }

    post {
        always {
            echo 'Pipeline finalizado.'
        }
        success {
            echo 'Pipeline bem-sucedido!'
            // slackSend channel: '#deployments', message: "Implantação bem-sucedida: ${env.BUILD_URL}"
        }
        failure {
            echo 'Pipeline falhou!'
            // slackSend channel: '#deployments', message: "Implantação falhou: ${env.BUILD_URL}"
        }
    }
}

Detalhes Chave do Pipeline

  • agent any funciona para uma demonstração. Em produção, use um rótulo de agente que garanta que o Ansible esteja instalado.
  • sshagent(credentials: ['ansible-ssh-key']) expõe a chave privada apenas dentro desse bloco.
  • ansible-playbook -i inventory/staging.ini playbooks/deploy_app.yml mantém o ambiente de destino explícito.
  • O bloco input de produção adiciona um gate manual antes de uma implantação sensível.
  • Evite desabilitar a verificação de chave do host em produção. Gerencie known_hosts no agente Jenkins.

Exemplo de Playbook Ansible: Implantando uma Aplicação Web

Aqui está um inventory/staging.ini e playbooks/deploy_app.yml simplificados para uma aplicação web Java. O nome do artefato, gerenciador de serviços e caminhos podem diferir.

inventory/staging.ini

[web_servers]
web1.example.com
web2.example.com

[database_servers]
db1.example.com

[all:vars]
ansible_user=ubuntu

playbooks/deploy_app.yml

---
- name: Implantar Aplicação Web
  hosts: web_servers
  become: yes
  vars:
    app_name: my-webapp
    app_path: /opt/{{ app_name }}
    app_port: 8080
    app_version: "{{ app_version | default('1.0.0') }}"

  tasks:
    - name: Garantir que o diretório da aplicação exista
      ansible.builtin.file:
        path: "{{ app_path }}"
        state: directory
        owner: "{{ ansible_user }}"
        group: "{{ ansible_user }}"
        mode: '0755'

    - name: Copiar JAR da aplicação para o destino
      ansible.builtin.copy:
        src: "target/{{ app_name }}-{{ app_version }}.jar"
        dest: "{{ app_path }}/{{ app_name }}.jar"
        owner: "{{ ansible_user }}"
        group: "{{ ansible_user }}"
        mode: '0644'
      notify: reiniciar serviço da aplicação

    - name: Garantir que o arquivo de serviço systemd exista
      ansible.builtin.template:
        src: templates/my-webapp.service.j2
        dest: /etc/systemd/system/{{ app_name }}.service
        owner: root
        group: root
        mode: '0644'
      notify: reiniciar serviço da aplicação

    - name: Garantir que o serviço da aplicação esteja iniciado e habilitado
      ansible.builtin.systemd:
        name: "{{ app_name }}"
        state: started
        enabled: yes

  handlers:
    - name: reiniciar serviço da aplicação
      ansible.builtin.systemd:
        name: "{{ app_name }}"
        state: restarted
        daemon_reload: yes

templates/my-webapp.service.j2 (Template de serviço Systemd)

[Unit]
Description={{ app_name }} Application
After=network.target

[Service]
User={{ ansible_user }}
ExecStart=/usr/bin/java -jar {{ app_path }}/{{ app_name }}.jar --server.port={{ app_port }}
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

Este playbook cria o diretório da aplicação, copia o JAR construído, escreve uma unit systemd e inicia o serviço. O handler reinicia o serviço apenas quando o artefato ou arquivo de unidade muda.

Melhores Práticas e Dicas

  • Mantenha os playbooks idempotentes para que reexecutar um pipeline com falha não cause danos extras.
  • Armazene senhas do Vault nas credenciais do Jenkins e passe-as através de um arquivo de senha temporário ou vinculação de credencial aprovada.
  • Organize a lógica de implantação em funções, como webserver, database e app_deploy.
  • Use inventários separados ou group_vars para staging e produção.
  • Execute Ansible em agentes Jenkins dedicados, não no controlador.
  • Use -v ou -vv apenas quando precisar de mais detalhes; evite vazar segredos nos logs.
  • Teste os playbooks antes de o Jenkins executá-los, especialmente para funções de produção.

Quando Consultar um Profissional

Traga um administrador Jenkins ou de plataforma quando o pipeline implantar em produção, gerenciar credenciais compartilhadas, escrever em muitos hosts ou precisar de controles de auditoria. O manuseio de credenciais, verificação de chave do host e comportamento de rollback merecem uma segunda revisão antes da primeira execução em produção.

Conclusão

Use Jenkins para orquestração e Ansible para estado de implantação. Mantenha as credenciais no Jenkins, os playbooks no controle de versão, torne o inventário explícito e teste os mesmos comandos Ansible fora do pipeline antes de automatizar a implantação em produção.