Introducción
Un script que funciona en el terminal de un servidor puede fallar en un pipeline CI/CD porque el entorno de ejecución es distinto. El agente puede utilizar otra cuenta, un shell diferente, un PATH restringido, otro directorio de trabajo o credenciales distintas. Una ejecución interactiva correcta no demuestra que el script funcione sin intervención humana.
Cuando investigo este problema, comparo ambos contextos antes de cambiar la lógica del script. Un binario ausente, un directorio inesperado o una solicitud de autenticación pueden explicar un fallo aparentemente misterioso. El objetivo es declarar el entorno necesario en lugar de depender de la configuración personal de quien realizó la prueba.
Este artículo explica qué cambia entre un terminal Linux y un pipeline de Azure DevOps: usuario, variables, permisos, red y estado efímero. Incluyo ejemplos, una lista de diagnóstico y un punto de partida en Bash. Los principios también se aplican a otros sistemas CI/CD.
Está dirigido a desarrolladores, ingenieros DevOps y administradores que necesitan automatizaciones repetibles. El artículo sobre automatización con Makefile ofrece contexto relacionado en portugués. La meta práctica es reducir las suposiciones para ejecutar scripts tanto localmente como en jobs sin una persona disponible para responder preguntas.
No supongo que todos los pipelines dispongan de los mismos permisos o herramientas. Los agentes hosted y self-hosted tienen contratos distintos. Un diagnóstico útil identifica la cuenta real, la imagen y la configuración de la tarea, y después verifica las dependencias que el script utiliza.
Qué cambia entre terminal y pipeline
| Aspecto | Terminal del servidor | Pipeline |
|---|---|---|
| Usuario/sesión | Tu cuenta interactiva | Cuenta del agente o servicio, normalmente no interactiva |
| Shell | Shell y perfil del usuario | Shell de la tarea; carga de perfiles distinta |
| Entorno | Variables locales y PATH personalizado | Variables controladas y otro PATH |
| Directorio | Directorio abierto en el terminal | Workspace del agente o directorio configurado |
| Permisos | Permisos personales y posiblemente TTY | Permisos del agente, normalmente sin TTY interactivo |
| Dependencias | Herramientas y versiones del servidor | Herramientas de la imagen o agente seleccionados |
| Interacción | Puedes responder preguntas | Los prompts pueden bloquear o fallar |
| Red | Rutas, proxy y certificados del servidor | Red y restricciones de salida del agente |
| Archivos | Rutas persistentes del servidor | Repositorio y artefactos del pipeline |
| Recursos | Límites del host | Timeouts, cuotas y concurrencia del job |
| Logs | Historial y archivos locales | Logs centralizados, enmascaramiento y retención |
| Estado | Máquina persistente | Agentes hosted normalmente efímeros |
Información: Utiliza la tabla para encontrar diferencias concretas. El pipeline no es simplemente tu terminal abierto a distancia: necesita su propia cuenta, directorio y contrato de dependencias.
Por qué importa el contexto de ejecución
Usuario y TTY
En el terminal, los comandos utilizan tu usuario y un dispositivo de terminal. Las herramientas pueden detectar el TTY y activar preguntas, colores o autenticación interactiva. El agente normalmente funciona sin una persona presente. Una instrucción read, una contraseña de sudo o un asistente de login pueden bloquear el job.
La documentación de agentes describe su función. Comprueba la identidad del servicio y cómo se inicia, en lugar de suponer que hereda la identidad de quien lanzó el pipeline.
Entorno y PATH
Tu perfil puede añadir /usr/local/bin, versiones específicas de Node/.NET/Java, alias y funciones de shell. Estas comodidades no deben darse por supuestas en el agente. Una herramienta puede faltar, estar en otra ruta o tener otra versión. Cambiar la versión de Node, por ejemplo, puede modificar el comportamiento de dependencias aunque el script sea idéntico.
Los perfiles se cargan de manera diferente en shells interactivos, de login y no interactivos. No trates .bashrc y .profile como equivalentes ni asumas que una tarea carga ambos. Inicializa explícitamente el entorno que necesita la automatización.
Directorios y rutas relativas
Los scripts que interpretan . como un directorio fijo o dependen de un cd anterior son frágiles. En Azure Pipelines, el código suele estar bajo $(Build.SourcesDirectory) y los artefactos pueden escribirse en $(Build.ArtifactStagingDirectory). Una tarea también puede configurar su directorio.
Atención: No supongas que el directorio actual coincide con el terminal. Configura el directorio de la tarea y usa rutas explícitas para los archivos necesarios.
Permisos y políticas de seguridad
Tu usuario puede tener acceso sudo que la cuenta del agente no posee. ACLs, SELinux y AppArmor también afectan al acceso. Una cuenta de servicio sin permiso para leer una configuración o reiniciar un servicio no queda autorizada porque la operación funcionó en tu sesión.
Verifica los permisos de la identidad real del agente. No desactives controles de seguridad para ocultar diferencias. Un agente hosted de compilación y un servidor de producción son máquinas con responsabilidades distintas.
Dependencias y versiones
El éxito local puede depender de paquetes instalados meses antes. Los agentes hosted utilizan imágenes predefinidas; los self-hosted dependen de tu mantenimiento. Si los entornos no están alineados deliberadamente, espera diferencias. Fija versiones críticas y declara dependencias para que una ausencia produzca un error útil.
Red, credenciales y estado
Los registries y APIs pueden necesitar proxy, certificados corporativos o rutas permitidas. Archivos bajo el home personal, como ~/.aws/credentials o ~/.npmrc, pueden no existir para el agente. Utiliza los mecanismos de secretos del pipeline, no copias de credenciales personales.
Los agentes efímeros invalidan suposiciones sobre archivos de ejecuciones anteriores. Usa artefactos administrados y caché de pipeline cuando los datos deban sobrevivir al job. Un archivo temporal local no constituye un contrato de persistencia.
Ejemplos prácticos
Sudo sin terminal interactivo
Este comando puede solicitar una contraseña y fallar en un job desatendido:
| |
El ejemplo original permite una operación concreta a la cuenta del agente:
| |
Requiere revisión administrativa; no justifica conceder sudo sin restricciones. Las operaciones sobre servicios del host corresponden a un entorno self-hosted adecuado de despliegue, no a una máquina hosted ajena de compilación.
Herramienta disponible solo en tu PATH
| |
Si jq solo está en tu servidor, el agente necesita una instalación declarada o un contenedor de job que lo incluya. El ejemplo original instala el paquete en Ubuntu antes de ejecutar:
| |
No apliques este paso a cualquier agente indiscriminadamente: requiere un gestor de paquetes compatible y los privilegios correspondientes. Una imagen fijada es otra forma de declarar esa dependencia de manera reproducible.
Pregunta invisible
| |
Un job desatendido no puede contestar. Usa un modo no interactivo explícito y parámetros del pipeline. El ejemplo original conserva una pregunta opcional para el terminal:
| |
Consejo: Separa la comodidad interactiva de la ejecución automática. Un modo explícito hace visible el contrato, pero las operaciones destructivas siguen necesitando autorización adecuada fuera del prompt.
Consideraciones de Azure DevOps
Los agentes hosted ofrecen un entorno efímero administrado por Microsoft con herramientas predefinidas. Los self-hosted permiten controlar sistema operativo, versiones y dependencias. Elegir la máquina puede mejorar la paridad, pero también implica mantenimiento y aislamiento.
Para Bash, utiliza Bash@3 y configura workingDirectory cuando corresponda. Evita depender de .bashrc: inicializa el entorno en la tarea o el script.
Entrega credenciales mediante variables secretas o service connections compatibles. La autenticación debe ser no interactiva y limitada a la operación. El artículo de autenticación y autorización ofrece contexto en portugués.
Configura timeoutInMinutes para evitar jobs bloqueados indefinidamente. Utiliza reintentos acotados con backoff para fallos externos realmente transitorios. Aumentar el timeout no corrige permisos insuficientes ni dependencias ausentes.
Lista de diagnóstico
- Identidad: revisa
id -u -n,whoami, shell y presencia de TTY. - Entorno: compara
PATHy locale; inspecciona solo variables no sensibles. No vuelques secretos en los logs. - Directorio: revisa
pwd, rutas de archivos y directorio de la tarea. - Herramientas: usa
command -vy comprueba versiones críticas. - Permisos: verifica el acceso de la cuenta de servicio. No ejecutes acciones destructivas solo para probar permisos.
- Red: comprueba endpoint, proxy y certificados sin imprimir credenciales.
- Logs: compara errores de aplicación y job, no únicamente el código final.
- Estado: identifica archivos que necesitan persistencia, caché o artefactos.
Un diagnóstico breve puede detectar versiones incompatibles antes del trabajo principal. Limita la salida: el logging detallado y el tracing del shell pueden exponer credenciales aunque el pipeline enmascare algunos secretos registrados.
Consejos y buenas prácticas
- Estandariza el entorno. Usa una imagen fijada o un agente mantenido deliberadamente. El código idéntico no basta si cambia el runtime.
- Declara dependencias. Comprueba binarios y versiones antes de actuar. La ausencia debe provocar un fallo comprensible, no un error secundario después.
- Evita interacción. Utiliza flags compatibles y parámetros explícitos. No dejes
read, menús ni asistentes de autenticación en jobs desatendidos. - Gestiona credenciales con seguridad. Prefiere variables secretas y service connections. Evita depender del home personal.
- Usa rutas explícitas. Configura el directorio y resuelve entradas desde una ubicación conocida. Así eliminas una causa habitual de éxito solo local.
- Busca idempotencia. Repetir el script debe converger, no romper un estado ya correcto. Comprueba antes de modificar.
- Haz visibles los errores.
set -euo pipefailayuda, pero no reemplaza el manejo deliberado. Usa tracing solo cuando no exponga datos sensibles.
Plantilla Bash
La plantilla original ilustra normalización del entorno, comprobación de dependencias y reintentos acotados. Es un punto de partida, no una política de despliegue lista para producción. Revisa permisos, logs y endpoint antes de utilizarla.
| |
El original continúa pasando un token a curl. No actives tracing alrededor de llamadas con secretos ni incluyas argumentos que contienen tokens en los mensajes de error. Estas partes necesitan hardening antes de usar credenciales reales.
Resumen Objetivo
- Contexto de ejecución incluye cuenta, shell, directorio, dependencias y red, y puede explicar diferencias sin un error de lógica.
- Jobs no interactivos necesitan un contrato desatendido explícito y no pueden depender de preguntas.
- PATH y versiones deben declararse o verificarse, no heredarse de perfiles personales.
- Agentes efímeros requieren artefactos o cachés administradas para el estado persistente.
- Seguridad exige credenciales acotadas, permisos revisados y logs sin secretos.
Lee También
- Automatización de tareas con Makefile (portugués).
- Autenticación y autorización: JWT, OAuth2 y OpenID Connect (portugués).
- Seguridad BFF para SPAs (portugués).
Referencias
- Qué es Azure Pipelines: servicio CI/CD.
- Agentes de Azure Pipelines: ejecución hosted y self-hosted.
- Variables secretas: gestión de secretos.
- Caché de pipeline: comportamiento de cachés administradas.
- Bash Reference Manual: comportamiento del shell y errores.
- SELinux: control de acceso obligatorio en Linux.

Al comentar, aceptas nuestra Política de Privacidad, Términos de Uso, Política de Eliminación de Datos.