Salta el contingut

Integració amb CI/CD

8. Integració amb CI/CD

L'automatització d'infraestructures amb Ansible o Puppet cobra tot el seu sentit quan s'integra amb pipelines de CI/CD. Vegem com fer-ho efectivament.

Per què Integrar Configuration Management amb CI/CD?

La integració entre configuration management i CI/CD crea un workflow complet des del codi fins a producció. Quan un desenvolupador fa push de codi, el pipeline de CI/CD pot automàticament:

  1. Executar tests del codi de l'aplicació
  2. Construir artefactes (imatges Docker, paquets, etc.)
  3. Actualitzar la configuració d'infraestructura si és necessari
  4. Desplegar l'aplicació utilitzant Ansible o Puppet
  5. Verificar que el desplegament ha tingut èxit
  6. Fer rollback automàticament si hi ha problemes

Integració d'Ansible amb Pipelines CI/CD

Ansible s'integra molt naturalment amb pipelines CI/CD perquè és una eina de línia de comandes que pot ser cridada des de qualsevol script.

Exemple amb GitLab CI:

stages:
  - build
  - test
  - deploy-staging
  - deploy-production

variables:
  ANSIBLE_VERSION: "9.0.0"

.ansible_setup: &ansible_setup
  before_script:
    - apt-get update -qq
    - apt-get install -y python3-pip sshpass openssh-client
    - pip3 install ansible==${ANSIBLE_VERSION}
    - ansible-galaxy collection install community.general
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - echo "$ANSIBLE_VAULT_PASSWORD" > .vault_pass

build:
  stage: build
  image: node:18
  script:
    - npm ci
    - npm run build
    - npm run test
  artifacts:
    paths:
      - dist/
      - node_modules/
    expire_in: 1 hour

deploy-staging:
  stage: deploy-staging
  image: ubuntu:22.04
  <<: *ansible_setup
  script:
    - ansible-playbook -i inventories/staging/hosts.ini 
        playbooks/deploy-app.yml
        --vault-password-file .vault_pass
        -e "deploy_version=${CI_COMMIT_SHORT_SHA}"
  only:
    - develop
  environment:
    name: staging
    url: https://staging.cloudshop.com

deploy-production:
  stage: deploy-production
  image: ubuntu:22.04
  <<: *ansible_setup
  script:
    - ansible-playbook -i inventories/production/hosts.ini 
        playbooks/deploy-app.yml
        --vault-password-file .vault_pass
        -e "deploy_version=${CI_COMMIT_TAG}"
        --extra-vars "confirm_production=yes"
  only:
    - tags
  when: manual
  environment:
    name: production
    url: https://www.cloudshop.com

Integració de Puppet amb Pipelines CI/CD

Amb Puppet, la integració és una mica diferent perquè Puppet utilitza un model pull. Hi ha diverses estratègies:

Estratègia 1: Deployament de Control Repository

El codi de Puppet (manifests, modules) es guarda en un repositori Git. El pipeline de CI/CD pot: 1. Executar tests del codi de Puppet (amb rspec-puppet, puppet-lint) 2. Desplegar el codi al Puppet Server 3. Esperar que els agents puguin la nova configuració

# .gitlab-ci.yml per Puppet Control Repo
stages:
  - validate
  - test
  - deploy

puppet-validate:
  stage: validate
  image: puppet/puppet-agent:7
  script:
    - puppet parser validate manifests/**/*.pp
    - puppet-lint --fail-on-warnings manifests/

puppet-test:
  stage: test
  image: ruby:3.1
  script:
    - bundle install
    - bundle exec rake spec

deploy-to-puppetserver:
  stage: deploy
  script:
    - rsync -avz --delete ./ puppetserver:/etc/puppetlabs/code/environments/production/
    - ssh puppetserver 'puppet code deploy production --wait'
  only:
    - main

Estratègia 2: Triggering Manual de Puppet Runs

El pipeline pot també disparar execucions de Puppet en nodes específics utilitzant l'API de Puppet Server o eines com Bolt:

deploy-application:
  stage: deploy
  script:
    # Actualitzar el control repo
    - ssh puppetserver 'cd /etc/puppetlabs/code/environments/production && git pull'
    - ssh puppetserver 'puppet code deploy production --wait'

    # Disparar Puppet en els webservers
    - bolt task run puppet agent=on_demand 
        --targets webservers 
        --user deploy 
        --private-key ~/.ssh/id_rsa

    # Verificar que els serveis estan healthy
    - ansible -i inventories/production/hosts.ini webservers 
        -m uri -a "url=http://localhost:3000/health status_code=200"
  only:
    - tags

Testing d'Infraestructura com a Codi

Una part important de la integració CI/CD és testejar el codi d'infraestructura abans de desplegar-lo.

Per Ansible:

Pots utilitzar Molecule per testejar roles d'Ansible:

# molecule/default/molecule.yml
---
dependency:
  name: galaxy
driver:
  name: docker
platforms:
  - name: instance
    image: ubuntu:22.04
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible

I després executar tests en el pipeline:

test-ansible-roles:
  stage: test
  image: python:3.11
  services:
    - docker:dind
  script:
    - pip install molecule[docker] ansible
    - cd roles/nginx
    - molecule test

Per Puppet:

Pots utilitzar rspec-puppet per tests unitaris:

# spec/classes/nginx_spec.rb
require 'spec_helper'

describe 'nginx' do
  context 'with default parameters' do
    it { should compile.with_all_deps }
    it { should contain_package('nginx') }
    it { should contain_service('nginx').with_ensure('running') }
  end
end

I beaker per tests d'integració que despleguen en màquines virtuals reals.

Rollback Strategies en CI/CD

Un aspecte crucial de la integració CI/CD és tenir estratègies de rollback clares.

Rollback amb Ansible:

Pots crear un job manual de rollback en el pipeline:

rollback-production:
  stage: deploy-production
  image: ubuntu:22.04
  <<: *ansible_setup
  script:
    - ansible-playbook -i inventories/production/hosts.ini 
        playbooks/rollback.yml
        --vault-password-file .vault_pass
        -e "rollback_to_version=${ROLLBACK_VERSION}"
  when: manual
  only:
    - main

El playbook de rollback podria reutilitzar el mateix playbook de deploy però amb una versió específica:

# playbooks/rollback.yml
---
- import_playbook: deploy-app.yml
  vars:
    deploy_version: "{{ rollback_to_version }}"