3 minute read

La Evolución del Pipeline DevOps: Hacia un Futuro GitOps

La automatización y el control de versiones del código se han convertido en el estándar para la infraestructura moderna. Este artículo presenta una implementación completa de GitOps con Terraform y Azure DevOps.

Arquitectura del Pipeline

1. Estructura del Repositorio

repository/
├── .azure/
│   └── pipelines/
│       ├── ci.yml
│       └── cd.yml
├── terraform/
│   ├── environments/
│   │   ├── dev/
│   │   ├── staging/
│   │   └── prod/
│   ├── modules/
│   │   ├── compute/
│   │   ├── network/
│   │   └── database/
│   └── main.tf
├── kubernetes/
│   ├── base/
│   └── overlays/
└── src/
    └── microservices/

Implementación del Pipeline CI/CD

1. Azure Pipeline Principal

# .azure/pipelines/ci.yml
trigger:
  branches:
    include:
    - main
    - feature/*
  paths:
    include:
    - src/*
    - terraform/*
    - kubernetes/*

variables:
  - group: terraform-secrets
  - name: ENVIRONMENT
    value: 'dev'

stages:
- stage: ValidateInfrastructure
  jobs:
  - job: TerraformValidate
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - task: TerraformInstaller@0
      inputs:
        terraformVersion: '1.5.7'
    
    - task: TerraformTaskV4@4
      inputs:
        provider: 'azurerm'
        command: 'init'
        workingDirectory: '$(System.DefaultWorkingDirectory)/terraform'
        backendServiceArm: 'terraform-backend'
        backendAzureRmResourceGroupName: 'terraform-storage-rg'
        backendAzureRmStorageAccountName: 'tfstate'
        backendAzureRmContainerName: 'tfstate'
        backendAzureRmKey: '$(ENVIRONMENT).tfstate'

    - task: TerraformTaskV4@4
      inputs:
        provider: 'azurerm'
        command: 'plan'
        workingDirectory: '$(System.DefaultWorkingDirectory)/terraform'
        environmentServiceNameAzureRM: 'terraform-backend'

- stage: BuildAndTest
  jobs:
  - job: BuildCode
    steps:
    - task: DotNetCoreCLI@2
      inputs:
        command: 'build'
        projects: 'src/**/*.csproj'
    
    - task: DotNetCoreCLI@2
      inputs:
        command: 'test'
        projects: 'tests/**/*.csproj'

- stage: SecurityScan
  jobs:
  - job: CodeScan
    steps:
    - task: SonarCloudPrepare@1
      inputs:
        SonarCloud: 'sonarcloud'
        organization: 'your-org'
        scannerMode: 'CLI'
        configMode: 'manual'
        cliProjectKey: 'your-project'
        cliProjectName: 'Your Project'

    - task: SonarCloudAnalyze@1

2. Despliegue con GitOps

# .azure/pipelines/cd.yml
trigger: none
pr: none

resources:
  pipelines:
    - pipeline: CI
      source: CI-Pipeline
      trigger: 
        branches:
          include:
          - main

variables:
  - group: gitops-secrets

stages:
- stage: DeployInfrastructure
  jobs:
  - deployment: TerraformApply
    environment: $(ENVIRONMENT)
    strategy:
      runOnce:
        deploy:
          steps:
          - task: TerraformTaskV4@4
            inputs:
              provider: 'azurerm'
              command: 'apply'
              workingDirectory: '$(Pipeline.Workspace)/terraform'
              environmentServiceNameAzureRM: 'terraform-backend'

- stage: DeployApplications
  jobs:
  - deployment: FluxCD
    environment: $(ENVIRONMENT)
    strategy:
      runOnce:
        deploy:
          steps:
          - task: Kubernetes@1
            inputs:
              connectionType: 'Kubernetes Service Connection'
              kubernetesServiceEndpoint: 'aks-connection'
              command: 'apply'
              arguments: '-f $(Pipeline.Workspace)/kubernetes/flux/'

Configuración de GitOps con Flux

1. Flux Bootstrap

# kubernetes/flux/gotk-components.yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
  name: flux-system
  namespace: flux-system
spec:
  interval: 1m0s
  ref:
    branch: main
  secretRef:
    name: flux-system
  url: ssh://git@github.com/your-org/your-repo.git

---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: flux-system
  namespace: flux-system
spec:
  interval: 10m0s
  path: ./kubernetes/base
  prune: true
  sourceRef:
    kind: GitRepository
    name: flux-system

2. Aplicación Base

# kubernetes/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
  - ingress.yaml

commonLabels:
  app: microservice
  environment: base

Seguridad y Cumplimiento

1. Policy as Code

# terraform/policies/main.tf
resource "azurerm_policy_definition" "require_tags" {
  name         = "require-tags"
  policy_type  = "Custom"
  mode         = "Indexed"
  display_name = "Require tags on resources"

  policy_rule = <<POLICY_RULE
{
  "if": {
    "field": "tags",
    "exists": "false"
  },
  "then": {
    "effect": "deny"
  }
}
POLICY_RULE
}

2. Seguridad en Pipeline

# .azure/pipelines/security.yml
trigger: none

schedules:
- cron: "0 0 * * *"
  displayName: Daily Security Scan
  branches:
    include:
    - main
  always: true

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: ContainerStructureTest@0
  inputs:
    dockerFile: '**/Dockerfile'
    testFile: '**/test.yaml'

- task: Checkmarx@1
  inputs:
    projectName: '$(Build.Repository.Name)'
    checkmarxUsername: '$(checkmarx.username)'
    checkmarxPassword: '$(checkmarx.password)'
    checkmarxServerUrl: '$(checkmarx.url)'

Monitorización y Observabilidad

1. Prometheus y Grafana

# kubernetes/monitoring/prometheus.yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  name: prometheus
spec:
  serviceAccountName: prometheus
  serviceMonitorSelector:
    matchLabels:
      team: frontend
  resources:
    requests:
      memory: 400Mi

2. Logging con Azure Monitor

resource "azurerm_log_analytics_workspace" "main" {
  name                = "workspace-${var.environment}"
  location            = var.location
  resource_group_name = azurerm_resource_group.main.name
  sku                = "PerGB2018"
  retention_in_days   = 30
}

Automatización de Pruebas

1. Pruebas de Infraestructura

# tests/main.tf
module "test" {
  source = "../modules/network"

  providers = {
    azurerm = azurerm.test
  }

  # Test inputs
  vnet_name = "test-vnet"
  address_space = ["10.0.0.0/16"]
}

# Test assertions
resource "test_assertions" "network" {
  component = "network"

  equal "vnet_name" {
    description = "VNet name should match input"
    got         = module.test.vnet_name
    want        = "test-vnet"
  }
}

2. Pruebas de Integración

# tests/integration/test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: integration-test
spec:
  containers:
  - name: test
    image: test-runner:latest
    env:
    - name: API_ENDPOINT
      value: http://api-service
    command: ["pytest", "-v", "tests/"]

Mejores Prácticas

  1. Control de Versiones
    • Ramificación por característica
    • Pull requests obligatorios
    • Revisiones de código automatizadas
  2. Seguridad
    • Escaneo de secretos
    • Análisis de dependencias
    • RBAC granular
  3. Monitorización
    • Métricas de pipeline
    • Logs centralizados
    • Alertas proactivas
  4. Automatización
    • Pruebas automatizadas
    • Despliegues automáticos
    • Rollbacks automáticos

Conclusiones

Un pipeline DevOps moderno requiere:

  1. Automatización completa
  2. Seguridad integrada
  3. Observabilidad robusta
  4. GitOps como base

Próximos Pasos

  1. Implementar control de versiones
  2. Configurar CI/CD básico
  3. Integrar seguridad
  4. Implementar GitOps
  5. Añadir monitorización

Referencias