Pipeline DevOps del Futuro: GitOps, Terraform y Azure DevOps en 2026
¿Qué es un pipeline DevOps? (explicación sencilla)
Un pipeline DevOps es como una cadena de montaje automática para el software: toma el código, lo prueba, lo empaqueta y lo despliega en la nube, todo sin intervención manual.
GitOps es una forma moderna de gestionar todo esto usando Git (una herramienta para guardar y versionar código) y automatización.
En este artículo, te explico cómo funciona un pipeline DevOps moderno usando Terraform y Azure DevOps, aunque nunca hayas trabajado con estas herramientas.
Arquitectura del Pipeline
1. Estructura del Repositorio
Esta estructura organiza tu proyecto de forma clara, separando el código de la aplicación, la infraestructura y los pipelines. Así es más fácil mantener y colaborar en equipo.
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
Este archivo YAML define el pipeline de integración continua (CI) en Azure DevOps. Se activa cuando hay cambios en las ramas principales o en archivos específicos, y valida la infraestructura antes de desplegar.
# .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
Este pipeline de despliegue continuo (CD) se activa después del CI y aplica los cambios a la infraestructura y aplicaciones usando GitOps con Flux.
# .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
Este archivo configura Flux para que monitoree cambios en el repositorio Git y aplique automáticamente las actualizaciones a Kubernetes.
# 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
- Control de Versiones
- Ramificación por característica
- Pull requests obligatorios
- Revisiones de código automatizadas
- Seguridad
- Escaneo de secretos
- Análisis de dependencias
- RBAC granular
- Monitorización
- Métricas de pipeline
- Logs centralizados
- Alertas proactivas
- Automatización
- Pruebas automatizadas
- Despliegues automáticos
- Rollbacks automáticos
Conclusiones
Un pipeline DevOps moderno requiere:
- Automatización completa
- Seguridad integrada
- Observabilidad robusta
- GitOps como base
Próximos Pasos
- Implementar control de versiones
- Configurar CI/CD básico
- Integrar seguridad
- Implementar GitOps
- Añadir monitorización