La rama main de Contoso ya está protegida por directivas, pero una de ellas apunta al vacío: la compilación con validación exige que un pipeline dé el visto bueno antes de fusionar, y ese pipeline todavía no existe. Sin él, las demás directivas comprueban formalidades —hay dos aprobaciones, hay un elemento de trabajo vinculado— pero nadie ha verificado lo más elemental: que el código compila y que las pruebas pasan.
Esta lección construye ese verificador. Azure Pipelines ejecuta, en cada cambio propuesto y en cada fusión, la misma secuencia repetible de restaurar, compilar, probar, analizar y empaquetar. El resultado es un artefacto —el paquete exacto que después se desplegará— y un veredicto binario en pocos minutos. Aquí nos ocupamos solo de construir y verificar; llevar ese artefacto a Azure es la lección siguiente.
Contenido
- Qué es la integración continua y qué problema elimina
- Agentes, grupos y sus costes reales
- Pipelines YAML frente a los clásicos por interfaz
- Anatomía de un
azure-pipelines.yml, línea a línea - Las tareas imprescindibles y la caché de dependencias
- Variables, grupos de variables y Key Vault
- Plantillas de pipeline reutilizables
- Validación de solicitudes de cambio y matriz de trabajos
- Artefactos, diagnóstico de fallos e insignia de estado
- Errores Comunes y Consejos
- Ejercicios
- Conclusión
- Qué es la integración continua y qué problema elimina
La integración continua consiste en que cada cambio se integre con el trabajo de todos y se verifique automáticamente, varias veces al día. No es «tener un servidor de compilación»: es una disciplina en la que el código de todo el mundo se junta constantemente en lugar de acumularse en rincones separados.
El problema que elimina tiene nombre: el infierno de la integración. Diego trabaja tres semanas en el mapa de cabina mientras otro compañero refactoriza el modelo de tarifas; cada uno prueba en su portátil y todo funciona. Al juntarlo aparecen conflictos, incompatibilidades de firma y un fallo que nadie sabe atribuir, justo el viernes de la entrega. El coste de integrar crece de forma no lineal con el tiempo que se tarda en hacerlo, y de ahí la conclusión contraintuitiva: si integrar duele, hazlo más veces.
| Requisito | Qué significa | Cómo lo cumple Contoso |
|---|---|---|
| Un repositorio compartido | Una única fuente de verdad | Azure Repos (05-02) |
| Compilación automática | Nadie compila a mano para validar | Este pipeline |
| Pruebas automáticas | El veredicto es objetivo, no una opinión | Pruebas unitarias con cobertura |
| Realimentación rápida | Menos de 10 minutos | Caché, paralelismo, pruebas rápidas |
La regla cultural que lo sostiene: si la compilación de main se rompe, arreglarla es la prioridad número uno del equipo. Una compilación rota que se tolera durante días convierte el pipeline en ruido que todo el mundo ignora.
- Agentes, grupos y sus costes reales
Un agente es la máquina que ejecuta los pasos. Hay dos modalidades, y elegir mal cuesta dinero o directamente impide desplegar:
| Agentes hospedados por Microsoft | Agentes autohospedados | |
|---|---|---|
| Quién los mantiene | Microsoft | Tú |
| Estado entre ejecuciones | Máquina nueva y limpia siempre | Persiste: caché rápida, pero también basura |
| Software preinstalado | Catálogo amplio (SDK, Docker, Node) | Lo que instales |
Acceso a vnet-contoso-pro |
No | Sí |
| Tiempo máximo por trabajo | 60 min (gratuito) / 360 min (de pago) | Sin límite |
| Coste | Minutos gratuitos y después por trabajo paralelo | La VM más su mantenimiento |
Aviso de coste real: un proyecto privado tiene 1 trabajo paralelo hospedado con 1.800 minutos al mes gratuitos. Agotados, las ejecuciones se encolan hasta el mes siguiente o hay que comprar trabajos paralelos adicionales (unos 40 $/mes cada uno). Los proyectos públicos tienen 10 trabajos paralelos gratuitos e ilimitados en minutos, lo que tienta a hacer público un repositorio: no lo hagas por ahorrar. Con agentes autohospedados, el primer trabajo paralelo es gratuito y los siguientes cuestan unos 15 $/mes, pero pagas la máquina virtual y su mantenimiento.
Contoso necesita ambos. El pipeline de compilación (esta lección) va en agentes hospedados: no toca nada privado y aprovecha imágenes siempre actualizadas. El pipeline de despliegue (05-04) que actúa contra sql-contoso-reservas-pro necesita estar dentro de vnet-contoso-pro, porque ese servidor ya solo es accesible por pe-sql-reservas desde que lo cerramos en 02-05: ahí hace falta un agente autohospedado en snet-gestion, agrupado en el grupo pool-contoso-privado.
# Instalar un agente autohospedado en una VM Linux dentro de snet-gestion
mkdir ~/agente && cd ~/agente
curl -O https://vstsagentpackage.azureedge.net/agent/3.243.1/vsts-agent-linux-x64-3.243.1.tar.gz
tar zxvf vsts-agent-linux-x64-3.243.1.tar.gz
./config.sh --unattended --url https://dev.azure.com/contoso-airlines \
--auth pat --token $PAT_AGENTE --acceptTeeEula \
--pool pool-contoso-privado --agent agente-contoso-01
sudo ./svc.sh install && sudo ./svc.sh start # Servicio, para sobrevivir a reiniciosLa VM del agente debe autenticarse contra Azure con identidad administrada, no con credenciales guardadas: el mismo criterio del módulo 4.
- Pipelines YAML frente a los clásicos por interfaz
| YAML | Clásico (interfaz gráfica) | |
|---|---|---|
| Dónde vive la definición | En el repositorio, junto al código | En la base de datos de Azure DevOps |
| Versionado y reversión | Con Git: historia y ramas | No versionado |
| Revisión | En la solicitud de cambios, como el código | Nadie revisa un clic |
| Reutilización | Plantillas | Grupos de tareas |
| Estado | Recomendado | Heredado, sin novedades |
El argumento decisivo es el primero: si el pipeline vive en el repositorio, un cambio en la forma de compilar pasa por la misma revisión que un cambio de código, queda registrado y se puede revertir. Con el clásico, alguien modifica un paso un martes por la tarde, la compilación empieza a comportarse distinto y no hay historia que consultar. Contoso usa YAML exclusivamente.
- Anatomía de un
azure-pipelines.yml, línea a línea
azure-pipelines.yml, línea a líneaEste es el pipeline contoso-reservas-ci, en la raíz del repositorio:
# Numero de compilacion de cada ejecucion; disponible como $(Build.BuildNumber).
# Que incluya la version es lo que permitira versionar paquetes en 05-05.
name: 2.5.$(Date:yyyyMMdd)$(Rev:.r)
trigger: # Que ENVIOS lanzan el pipeline
branches:
include: [ main, releases/* ]
paths:
exclude: [ docs/*, README.md ] # No gastar minutos por cambios de documentacion
pr: # Que SOLICITUDES de cambio lo lanzan: engancha con
branches: # la directiva de compilacion con validacion de 05-02
include: [ main ]
schedules: # Compilacion nocturna: detecta roturas que no vienen
- cron: "0 2 * * *" # de tu codigo (una dependencia actualizada, otra imagen)
displayName: Compilacion nocturna
branches: { include: [ main ] }
always: true # Ejecutar aunque no haya habido cambios
pool:
vmImage: ubuntu-latest # Agente hospedado por Microsoft
variables:
- group: vg-contoso-reservas-comun # Grupo de variables compartido (apartado 6)
- name: rutaSolucion
value: 'src/Contoso.Reservas.sln'
stages:
- stage: compilacion
jobs:
- job: compilar
timeoutInMinutes: 20 # Corta la ejecucion si algo se cuelga
steps:
- checkout: self
fetchDepth: 1 # Clon superficial: mas rapido
- task: UseDotNet@2 # No dependas de lo que traiga la imagen
inputs: { packageType: sdk, version: '8.0.x' }
- script: dotnet restore $(rutaSolucion)
displayName: Restaurar dependencias
- script: dotnet build $(rutaSolucion) -c Release --no-restore -warnaserror
displayName: Compilar
- script: |
dotnet test $(rutaSolucion) -c Release --no-build \
--logger trx --collect:"XPlat Code Coverage" \
--results-directory $(Agent.TempDirectory)/pruebas
displayName: Ejecutar pruebas unitarias
- task: PublishTestResults@2
condition: succeededOrFailed() # Publicar tambien si fallaron:
inputs: # es cuando mas interesa verlos
testResultsFormat: VSTest
testResultsFiles: '$(Agent.TempDirectory)/pruebas/**/*.trx'
failTaskOnFailedTests: true # Sin esto el pipeline queda verde
- task: PublishCodeCoverageResults@2 # aunque las pruebas fallen
condition: succeededOrFailed()
inputs:
summaryFileLocation: '$(Agent.TempDirectory)/pruebas/**/coverage.cobertura.xml'
- script: |
dotnet publish src/Contoso.Reservas.Web/Contoso.Reservas.Web.csproj \
-c Release --no-build -o $(Build.ArtifactStagingDirectory)/web
displayName: Preparar el paquete desplegable
- publish: $(Build.ArtifactStagingDirectory)/web
artifact: web-reservas # Lo que 05-04 tomara tal cualSobre la estructura: trigger y pr son los dos desencadenadores de envío (trigger: none desactiva el arranque automático, típico en pipelines de despliegue). La jerarquía stages → jobs → steps significa que una etapa es una fase lógica y puede llevar aprobaciones, un trabajo se ejecuta entero en un agente y varios pueden ir en paralelo, y un paso es una acción individual. La diferencia entre task y script es que una tarea es un componente reutilizable con entradas nombradas y versión (@2) mientras que un script es una orden de shell: usa tareas cuando aporten algo real —publicar resultados, autenticarse— y scripts cuando el comando sea claro, porque son más legibles y portables. Y condition: succeededOrFailed() fuerza un paso aunque el anterior haya fallado.
- Las tareas imprescindibles y la caché de dependencias
Restaurar siempre de forma explícita, sin depender de lo que «ya estaba» en la máquina. Compilar con -warnaserror, que convierte las advertencias en errores; sin ello se acumulan por cientos y dejan de leerse. Probar publicando resultados y cobertura, con failTaskOnFailedTests: true —y ojo con convertir la cobertura en objetivo: exigir un 90 % produce pruebas que recorren código sin comprobar nada—. Publicar el artefacto, que consagra el principio de construir una vez, desplegar muchas: el binario validado en desarrollo es exactamente el mismo bit a bit que llegará a producción; recompilar por entorno introduce diferencias imposibles de rastrear.
Falta el análisis estático, que busca fallos y vulnerabilidades antes de que existan en ejecución, y la caché, que baja el tiempo de restauración de minutos a segundos:
# La clave de la cache se deriva del sistema operativo y del resumen de
# los ficheros de proyecto: si cambia una dependencia, cambia la clave y
# no se reutiliza una cache obsoleta. Una clave fija sirve basura eterna.
- task: Cache@2
inputs:
key: 'nuget | "$(Agent.OS)" | **/*.csproj'
restoreKeys: 'nuget | "$(Agent.OS)"'
path: $(NUGET_PACKAGES)
- script: |
dotnet format --verify-no-changes # Estilo acordado
dotnet list package --vulnerable --include-transitive
displayName: Analisis de estilo y dependencias vulnerablesNunca caches resultados de compilación, solo dependencias descargadas.
- Variables, grupos de variables y Key Vault
| Dónde | Para qué | Visibilidad |
|---|---|---|
variables en el YAML |
Valores no sensibles del pipeline | Público en el repositorio |
| Grupo de variables en la biblioteca | Valores compartidos por varios pipelines | Proyecto, con permisos |
| Grupo vinculado a Key Vault | Secretos | Nunca se ven; se resuelven al ejecutar |
Un secreto no se escribe jamás en el YAML, que está en el repositorio y en cada clon; ya vimos en 05-02 lo que cuesta un secreto confirmado. La forma correcta es vincular un grupo de variables a kv-contoso-pro:
# Grupo normal, para valores no sensibles
az pipelines variable-group create --name vg-contoso-reservas-comun \
--variables entorno=comun proyecto=contoso-reservas centro-coste=CC-1042 \
--authorize false
# Grupo vinculado a kv-contoso-pro: los VALORES se quedan en el almacen y
# la conexion de servicio solo necesita el rol "Usuario de secretos de Key Vault"
az pipelines variable-group create --name vg-contoso-secretos-pro \
--variables pasarela-pago-clave="" token-meteo="" --authorize falsevariables:
- group: vg-contoso-secretos-pro # Sus valores se leen de kv-contoso-pro
steps:
- script: ./scripts/prueba-integracion.sh
env:
TOKEN_METEO: $(token-meteo) # Los secretos NO se inyectan solos en el
# entorno: hay que mapearlos a propositoTres detalles que evitan disgustos. Las variables secretas no se exponen automáticamente como variables de entorno; el mapeo explícito con env: es una protección deliberada. Azure Pipelines enmascara los secretos en los registros, pero no es infalible: si tu script imprime el valor transformado (en base64, por ejemplo), el enmascarado no lo reconoce. Y --authorize false obliga a autorizar qué pipelines pueden usar el grupo, que es el mínimo privilegio aplicado a los secretos de compilación: el pipeline de una aplicación de pruebas no tiene por qué poder leer la clave de la pasarela de pago.
- Plantillas de pipeline reutilizables
Contoso tiene cuatro repositorios que compilan igual. Copiar el YAML en cada uno son cuatro sitios que actualizar cuando cambie el SDK. Las plantillas lo resuelven. En contoso-infra, fichero plantillas/compilar-dotnet.yml:
parameters: # Tipados: si falta uno obligatorio, ni arranca
- { name: rutaSolucion, type: string }
- { name: nombreArtefacto, type: string }
- { name: versionSdk, type: string, default: '8.0.x' }
- { name: ejecutarPruebas, type: boolean, default: true }
steps:
- task: UseDotNet@2
inputs: { packageType: sdk, version: ${{ parameters.versionSdk }} }
- script: dotnet restore ${{ parameters.rutaSolucion }}
- script: dotnet build ${{ parameters.rutaSolucion }} -c Release --no-restore -warnaserror
# Condicion en tiempo de expansion: si ejecutarPruebas es false, estos pasos
# ni siquiera existen en el pipeline generado
- ${{ if eq(parameters.ejecutarPruebas, true) }}:
- script: dotnet test ${{ parameters.rutaSolucion }} -c Release --no-build --logger trx
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs: { testResultsFormat: VSTest, testResultsFiles: '**/*.trx', failTaskOnFailedTests: true }
- publish: $(Build.ArtifactStagingDirectory)
artifact: ${{ parameters.nombreArtefacto }}Uso desde el repositorio contoso-api-disponibilidad:
resources:
repositories:
- repository: plantillas
type: git
name: contoso-reservas/contoso-infra # proyecto/repositorio
ref: refs/tags/plantillas-v1.2 # ANCLADO a una etiqueta, no a main
steps:
- template: plantillas/compilar-dotnet.yml@plantillas
parameters:
rutaSolucion: 'src/Contoso.Api.sln'
nombreArtefacto: 'api-disponibilidad'El ref anclado a una etiqueta evita que un cambio en la plantilla rompa a la vez los cuatro pipelines: la actualización se hace subiendo la etiqueta, deliberadamente. Y existe una variante más estricta, extends, en la que el pipeline hijo no puede añadir pasos arbitrarios, solo rellenar los huecos previstos:
extends:
template: plantillas/pipeline-seguro.yml@plantillas
parameters:
pasosCompilacion:
- script: dotnet build src/Contoso.Reservas.sln -c Releaseextends es el mecanismo con el que un equipo de plataforma garantiza que ningún pipeline se salte el análisis de seguridad, por mucho que alguien edite su YAML. Es el equivalente en la entrega a las políticas de 04-06: no se confía en la buena voluntad, se hace estructuralmente imposible.
- Validación de solicitudes de cambio y matriz de trabajos
Con el desencadenador pr definido y la directiva de rama de 05-02 apuntando a este pipeline, el ciclo se cierra:
graph LR
A["Diego envía<br/>feature/1842"] --> B["Abre solicitud<br/>de cambios"]
B --> C["Desencadenador pr:<br/>se ejecuta el CI"]
C --> D{"¿Compila y<br/>pasan pruebas?"}
D -->|No| E["Estado rojo:<br/>fusión bloqueada"]
D -->|Sí| F["Verde + 2 aprobaciones<br/>+ elemento vinculado"]
F --> G["Squash sobre main"]
G --> H["Desencadenador trigger:<br/>CI sobre main"]
H --> I["Artefacto web-reservas<br/>listo para 05-04"]
Cuando hay que verificar en varias configuraciones, la matriz genera un trabajo por combinación:
- job: compatibilidad
strategy:
matrix:
linux_net8: { imagenAgente: 'ubuntu-latest', versionSdk: '8.0.x' }
windows_net8: { imagenAgente: 'windows-latest', versionSdk: '8.0.x' }
linux_net9: { imagenAgente: 'ubuntu-latest', versionSdk: '9.0.x' }
maxParallel: 2 # Limitado por los trabajos paralelos contratados
pool:
vmImage: $(imagenAgente)
steps:
- task: UseDotNet@2
inputs: { packageType: sdk, version: $(versionSdk) }
- script: dotnet test src/Contoso.Reservas.slnmaxParallel importa por dinero: con un solo trabajo paralelo contratado, una matriz de nueve combinaciones no va nueve veces más rápido, va en fila y consume nueve veces los minutos.
- Artefactos, diagnóstico de fallos e insignia de estado
Artefactos de canalización (publish/download) |
Artefactos de compilación (PublishBuildArtifacts@1) |
|
|---|---|---|
| Rendimiento | Mucho más rápido, con deduplicación | Lento con muchos ficheros |
| Almacenamiento | Optimizado | Copia completa |
| Estado | Recomendado | Heredado |
- publish: $(Build.ArtifactStagingDirectory)/web # Publicar en la etapa de compilacion
artifact: web-reservas
- download: current # Recuperarlo en otra etapa
artifact: web-reservasCuando un pipeline falla, el orden de diagnóstico que ahorra horas: (1) leer el registro del paso que falló, no el resumen —el error real suele estar 30 líneas por encima de la última línea roja—; (2) activar los registros de diagnóstico poniendo la variable system.debug a true al relanzar, que muestra la resolución de variables y las rutas reales, donde suele estar el problema; (3) reproducir en local ejecutando exactamente los comandos del YAML, porque el 80 % de los fallos «solo del pipeline» son diferencias de entorno —una variable que en tu portátil existe, un fichero ignorado por .gitignore que en tu máquina sí está, o mayúsculas de un nombre que en Linux importan y en Windows no—; y (4) comprobar permisos si el fallo menciona autorización: la conexión de servicio o el grupo de variables probablemente no están autorizados para este pipeline.
Y la insignia de estado en el README.md, que da visibilidad inmediata de si main está sano:
[](https://dev.azure.com/contoso-airlines/contoso-reservas/_build/latest?definitionId=12&branchName=main)Errores Comunes y Consejos
- Compilar en cada entorno. Rompe el principio de construir una vez y desplegar muchas: el binario de producción deja de ser el que se probó. Compila una vez, publica el artefacto y reutilízalo.
- Escribir secretos en el YAML. Están en el repositorio y en cada clon. Grupo de variables vinculado a
kv-contoso-pro, siempre. - Pipelines de 40 minutos. Si el veredicto tarda más que un café, la gente deja de esperarlo y sigue trabajando sobre código no verificado. Divide, cachea y paraleliza hasta bajar de 10 minutos.
- Tolerar una compilación rota en
main, o convivir con pruebas inestables. En cuanto el rojo es normal, el pipeline deja de significar algo y el equipo aprende a relanzar sin mirar. continueOnError: truepor comodidad. Convierte un paso en decorativo. Úsalo solo mientras ajustas el umbral de una herramienta nueva, y con fecha de caducidad.- Plantillas apuntando a
main. Un cambio rompe simultáneamente todos los pipelines. Ancla a etiqueta y versiona las plantillas. - Consejo: pon
timeoutInMinutesen todos los trabajos. Un trabajo colgado consume minutos facturables hasta el límite de 60 o 360. - Consejo: excluye
docs/*yREADME.mddel desencadenador. Es un minuto de trabajo que ahorra minutos de agente todos los meses.
Ejercicios
Ejercicio 1: leer un pipeline y detectar sus problemas
Un compañero propone este pipeline para Contoso Millas:
trigger:
branches: { include: ['*'] }
pool: { vmImage: ubuntu-latest }
variables:
claveApi: 'ak_millas_9f2b7c1d4e'
steps:
- script: dotnet build src/Millas.sln
- script: dotnet test src/Millas.sln
continueOnError: true
- script: dotnet publish src/Millas.Web -o salida- Identifica al menos cinco problemas.
- Enumera los cambios concretos que harías para corregirlos.
- ¿Cuál es un incidente de seguridad y qué hay que hacer además de corregir el fichero?
Ejercicio 2: agentes y coste
Contoso añade tres pipelines: uno compila la web, otro la API y otro ejecuta pruebas de integración contra sql-contoso-reservas-dev, que tiene punto privado. Los tres se ejecutan unas 20 veces al día, 12 minutos cada uno.
- ¿Qué tipo de agente necesita cada pipeline y por qué?
- Estima el consumo mensual de minutos hospedados y di si cabe en el nivel gratuito.
- Propón dos formas de reducir el gasto sin renunciar a la verificación.
Ejercicio 3: diseñar la reutilización
Los cuatro repositorios compilan .NET casi igual, pero contoso-infra no tiene pruebas unitarias (son plantillas de Bicep) y contoso-modelos publica un paquete en vez de una aplicación web. Seguridad exige que ningún pipeline pueda saltarse el análisis de dependencias vulnerables.
- ¿Usarías
templateoextends? Justifícalo respecto al requisito de seguridad. - Esboza los parámetros de la plantilla.
- ¿Cómo evitas que actualizarla rompa los cuatro pipelines a la vez?
Soluciones
Solución 1:
- (a) Secreto en el YAML:
claveApiestá en el repositorio. (b)triggersobre todas las ramas, que compila cada rama de trabajo y quema minutos. (c) Falta el desencadenadorpr, así que la directiva de compilación con validación no tiene nada a lo que engancharse. (d)continueOnError: trueen las pruebas: el pipeline pasa aunque fallen. (e) No se publican resultados ni cobertura. (f) No se publica artefacto alguno: no hay nada que desplegar después. (g) FaltaUseDotNetfijando la versión del SDK, así que se depende de lo que traiga la imagen del agente. (h) SintimeoutInMinutesnidisplayNamelegibles. triggerlimitado amainmáspr: [main];UseDotNet@2con8.0.x;dotnet restoreexplícito; compilación con-warnaserror;dotnet testcon--logger trx --collect:"XPlat Code Coverage";PublishTestResults@2confailTaskOnFailedTests: trueycondition: succeededOrFailed(); publicación de cobertura;dotnet publisha$(Build.ArtifactStagingDirectory)seguido de- publish:con nombre de artefacto; la clave sustituida por un grupo de variables vinculado akv-contoso-proy mapeada conenv:; ytimeoutInMinutes: 20.- El secreto. Además de sacarlo del fichero hay que rotarlo: está en la historia de Git y en los registros de todas las ejecuciones anteriores. Después, guardar el valor nuevo en el almacén y revisar si se usó indebidamente. Igual que en 05-02, borrar no basta.
Solución 2:
- Web y API, agentes hospedados: no necesitan acceso a nada privado y se benefician de una máquina limpia y mantenida. Las pruebas de integración, agente autohospedado en
pool-contoso-privadodentro desnet-gestion, porquesql-contoso-reservas-devsolo es accesible por su punto privado y un agente hospedado no tiene ruta hasta él. La alternativa serían agentes de conjunto de escalado gestionados dentro de la red virtual. - Los dos pipelines hospedados suman 2 × 20 × 12 = 480 minutos al día, unos 10.500 al mes con 22 días laborables. El nivel gratuito son 1.800, así que se supera con creces; y con un solo trabajo paralelo las ejecuciones además se encolarían. Habría que contratar trabajos paralelos adicionales (~40 $/mes cada uno).
- (a) Caché de dependencias y clon superficial, para bajar los 12 minutos a la mitad. (b) Excluir rutas irrelevantes del desencadenador y no compilar en cada envío a ramas de trabajo, sino en la solicitud de cambios. (c) Reservar la matriz completa y las pruebas lentas para la compilación nocturna, dejando en el ciclo rápido solo lo imprescindible. (d) Comparar el coste de una VM de agente autohospedado con el de los trabajos paralelos, que a este volumen puede salir a favor de la VM.
Solución 3:
extends. Contemplateel pipeline hijo incluye la plantilla pero puede añadir pasos, reordenarlos o sencillamente no llamarla; conextendsestá obligado a construirse sobre ella y solo puede rellenar los huecos previstos, de modo que el análisis de dependencias no se puede omitir editando el YAML. Es la diferencia entre una recomendación y una regla, la misma lógica de las políticas de 04-06.rutaSolucion(string, obligatorio),nombreArtefacto(string),versionSdk(string, por defecto8.0.x),ejecutarPruebas(boolean,falseparacontoso-infra),tipoSalida(webopaquete, para distinguircontoso-modelos) ypasosAdicionales(stepList) como único hueco de extensión.- Anclando la referencia del repositorio de plantillas a una etiqueta (
ref: refs/tags/plantillas-v1.2) y versionando las plantillas con versionado semántico. Cada repositorio sube su etiqueta cuando le conviene, con lo que un cambio incompatible se prueba en uno antes de propagarse. La plantilla vive encontoso-infra, con sus directivas de rama y la revisión obligatoria deContoso-Infraestructura.
Conclusión
La rama main de Contoso ya no solo está protegida: está verificada. Entiendes la integración continua como disciplina —integrar a menudo porque integrar tarde duele de forma no lineal— con sus cuatro requisitos y la regla cultural que la sostiene: una compilación rota es la prioridad número uno. Sabes elegir entre agentes hospedados, limpios y mantenidos por Microsoft, y agentes autohospedados, imprescindibles cuando hay que alcanzar recursos que solo existen tras un punto privado dentro de vnet-contoso-pro; y conoces los números reales: 1.800 minutos y un trabajo paralelo gratuitos por proyecto privado, y unos 40 $ al mes por cada trabajo paralelo adicional.
Has escrito el azure-pipelines.yml de contoso-reservas-ci entendiendo cada pieza: trigger con exclusión de rutas, pr para enganchar con la directiva de compilación con validación de 05-02, schedules para la compilación nocturna que detecta lo que se rompe sin que tú toques nada, y la jerarquía stages → jobs → steps con la diferencia entre task y script. Dentro has puesto lo imprescindible —restaurar, compilar con -warnaserror, probar publicando resultados y cobertura con failTaskOnFailedTests, analizar dependencias vulnerables y publicar el artefacto—, lo has acelerado con una caché cuya clave se deriva del manifiesto, y lo has hecho reutilizable con plantillas, distinguiendo template de extends: solo extends convierte el análisis de seguridad en algo que ningún equipo puede omitir. Y has mantenido intacta la regla del módulo 4: ningún secreto en el YAML, todos en un grupo de variables vinculado a kv-contoso-pro, mapeados explícitamente y autorizados solo a los pipelines que los necesitan.
El resultado de todo esto es un fichero: el artefacto web-reservas, compilado una sola vez, probado y esperando. Pero sigue esperando: nadie lo ha llevado a app-contoso-reservas-pro, y el despliegue del viernes por la noche continúa existiendo tal cual. En la próxima lección, Despliegue continuo con entornos y aprobaciones, ese artefacto viajará. Crearás los entornos desarrollo, preproduccion y produccion con su registro de qué versión hay en cada uno, pondrás la aprobación manual de Marta Ríos y las ventanas que impiden desplegar un viernes por la tarde, compararás las estrategias de despliegue y ejecutarás el azul-verde real de Contoso con el intercambio de la ranura preproduccion que ya conoces del módulo 2, con migraciones de base de datos compatibles hacia atrás y una reversión que funciona de verdad.
Curso de Azure
Módulo 1: Introducción a Azure
- ¿Qué es Azure?
- Modelos de servicio, regiones y zonas de disponibilidad
- Crear y configurar tu cuenta de Azure
- Recorrido por el portal de Azure
- Azure Resource Manager: suscripciones, grupos de recursos y etiquetas
- Azure CLI, PowerShell y Cloud Shell
Módulo 2: Servicios principales de Azure
- Máquinas virtuales de Azure
- Escalado y alta disponibilidad del cómputo
- Azure App Service
- Azure Storage: blobs, archivos, colas y tablas
- Redes en Azure: redes virtuales, subredes y NSG
- Conectividad híbrida y entrega global
Módulo 3: Bases de datos de Azure
- Elegir el servicio de datos adecuado
- Azure SQL Database
- Azure Cosmos DB
- Azure Database for MySQL
- Azure Database for PostgreSQL
- Analítica de datos: Data Lake, Data Factory y Synapse
Módulo 4: Seguridad en Azure
- Microsoft Entra ID y gestión de identidades
- RBAC e identidades administradas
- Azure Key Vault
- Protección DDoS y firewall de aplicaciones web
- Microsoft Defender for Cloud
- Gobernanza y cumplimiento con Azure Policy
Módulo 5: Azure DevOps
- Introducción a Azure DevOps
- Azure Repos
- Azure Pipelines: integración continua
- Despliegue continuo con entornos y aprobaciones
- Azure Artifacts
- Infraestructura como código con Bicep
Módulo 6: Servicios avanzados de Azure
- Contenedores en Azure: Container Registry y Container Apps
- Azure Kubernetes Service (AKS)
- Azure Functions
- Azure Logic Apps
- Mensajería y eventos: Service Bus, Event Grid y Event Hubs
- Servicios de IA de Azure
Módulo 7: Monitoreo y gestión
- Azure Monitor: métricas, alertas y paneles
- Log Analytics y consultas KQL
- Application Insights
- Azure Automation y runbooks
- Copias de seguridad y recuperación ante desastres
Módulo 8: Gestión y optimización de costos
- Calculadora de precios y estimación de costes
- Azure Cost Management: análisis, presupuestos y alertas
- Reservas, planes de ahorro y Azure Hybrid Benefit
- Azure Advisor
- Estrategias de optimización y cultura FinOps
