Introdução
Se você já trabalhou com DevOps ou automação de tarefas, provavelmente já passou pela frustração de ter um script que funciona perfeitamente no terminal do servidor, mas falha misteriosamente quando executado via pipeline do Azure DevOps. Essa situação é mais comum do que parece e acontece por motivos bem fundamentados.
Neste artigo, vamos explorar em detalhes o que muda quando você executa um script Linux diretamente no terminal versus quando o mesmo script roda dentro de uma pipeline de CI/CD. Você vai entender as diferenças de usuário, ambiente, permissões, rede e efemeridade que causam esses comportamentos distintos. Ao final, terá em mãos um checklist de diagnóstico, um conjunto de boas práticas e um template Bash pronto para criar scripts que funcionam de forma consistente em ambos os cenários.
Este conteúdo é direcionado a desenvolvedores, engenheiros DevOps e administradores de sistemas que precisam garantir que seus scripts sejam reprodutíveis e confiáveis tanto localmente quanto em pipelines automatizadas. Se você quer eliminar o clássico “funciona na minha máquina”, continue lendo.
Visão Geral — O Que Muda
A tabela abaixo resume as principais diferenças entre executar um script no terminal do servidor e via pipeline do Azure DevOps. Cada aspecto pode impactar diretamente o comportamento do seu código.
| Aspecto | Terminal do servidor | Pipeline Azure DevOps |
|---|---|---|
| Usuário/Sessão | Seu usuário (ex.: lincoln), com perfil interativo | Usuário do agente (ex.: vsts/azure-pipelines), tipicamente não-interativo |
| Shell | O shell padrão do usuário (ex.: /bin/bash), com dotfiles carregados | Shell invocado pela task (ex.: bash), sem .bashrc/.profile (ou parcialmente) |
| Ambiente (ENV) | Variáveis definidas localmente, PATH “rico” | Ambiente controlado pela pipeline: PATH diferente, variáveis de Secrets mapeadas, menos lixo |
| Diretório de trabalho | Onde você está (ex.: /home/lincoln) | Workspace do agente (ex.: /_work/1/s), ou pasta do job |
| Permissões/Sudo | Você pode ter sudo e TTY | Agente geralmente sem TTY; sudo pode exigir NOPASSWD |
| Dependências | Usa libs, ferramentas e versões do servidor | Depende do que está instalado no agente (MS-hosted ou self-hosted) |
| Interatividade | Pode responder prompts, ver menus | Execução não-interativa; qualquer prompt bloqueia |
| Rede/Proxy | Usa rede do servidor | Pode haver proxy corporativo do agente; bloqueios de saída |
| Arquivos & Caminhos | Paths absolutos do servidor | Paths relativos ao repositório/artefatos da pipeline |
| Tempo/Recursos | Sem timeout (em geral) | Timeouts, quotas de CPU/Mem, paralelismo controlado |
| Logs e Auditoria | Logs locais (syslog, history) | Logs centralizados, mascaramento de segredos, retenção |
| Efemeridade | Estado persistente | Agentes (especialmente hosted) são efêmeros; não guardam estado |
| Confiabilidade/Reprodutibilidade | Pode “funcionar só na sua máquina” | Pipeline força reprodutibilidade e idempotência |
ℹ️ Informação: Entender cada linha desta tabela é essencial para diagnosticar problemas. Sempre que um script falhar na pipeline, volte a esta referência e identifique qual aspecto diverge do seu ambiente local.
Por Que Isso Causa Diferença
As diferenças listadas acima não são aleatórias — elas existem porque o contexto de execução é fundamentalmente diferente. Abaixo, detalhamos cada uma das causas principais.
Usuário e TTY
No terminal, o comando roda com seu usuário e um TTY (terminal interativo). Várias ferramentas detectam a presença do TTY e habilitam cores, prompts e até fluxos de autenticação interativos.
No Azure DevOps, a execução é não-interativa. Qualquer script que espere input (ex.: read, prompts de sudo, wizard de az login) vai travar ou falhar. Essa é uma das causas mais frequentes de erros em pipelines, especialmente para quem está migrando scripts legados. Conforme a documentação oficial do Azure Pipelines, os agentes executam jobs sem interação humana.
Ambiente e PATH
Localmente, seu PATH carrega /usr/local/bin, versões específicas do Node/.NET/Java, alias e funções do shell definidas em .bashrc ou .profile.
No agente, o PATH pode ser completamente diferente. Ferramentas “globais” podem não existir ou ter outra versão. Isso muda o comportamento de forma sutil — por exemplo: node 18 no servidor vs node 20 no agente pode gerar incompatibilidades em dependências.
Diretório e Caminhos Relativos
Scripts que assumem . como um diretório específico, ou que dependem de cd implícito, podem quebrar na pipeline. Na pipeline, o working directory geralmente é a pasta do código clonado ($(Build.SourcesDirectory)), e artefatos ficam em $(Build.ArtifactStagingDirectory).
⚠️ Atenção: Nunca assuma que o diretório atual é o que você espera. Use caminhos absolutos ou variáveis de ambiente da pipeline como
$(Build.SourcesDirectory)para referências explícitas.
Permissões e SELinux/AppArmor
No servidor, você pode ter sudo sem senha, ACLs permissivas, ou SELinux em modo permissivo. No agente, sudo pode precisar de NOPASSWD configurado no /etc/sudoers, e o serviço roda com um usuário independente. Acesso a /etc ou serviços do host pode ser negado.
Dependências e Versões
“Funciona no meu servidor” costuma significar acoplamento ao ambiente daquele host específico. No DevOps, cada agente tem seu próprio conjunto de ferramentas. Se não for um agente self-hosted idêntico ao servidor, espere divergências de versões e disponibilidade de pacotes.
Rede e Credenciais
Chamadas externas (ex.: Docker registries, APIs) podem depender de proxy, certificados corporativos ou regras de firewall. O Azure DevOps gerencia secrets via variáveis mascaradas. Scripts que procuram ~/.aws/credentials ou ~/.npmrc podem não encontrar esses arquivos no agente.
Para quem trabalha com segurança em aplicações, o gerenciamento correto de credenciais em pipelines é um ponto crítico que merece atenção especial.
Efemeridade e Estado
Scripts que escrevem em /var/tmp e esperam encontrar os dados depois, ou que contam com caches locais, falham em agentes efêmeros. Na pipeline, o ideal é usar artefatos, caches gerenciados e etapas declarativas.
Exemplos Práticos — Mão na Massa
A seguir, apresentamos três cenários reais que ilustram as diferenças mais comuns entre terminal e pipeline, com suas respectivas soluções.
1) sudo em Pipeline
| |
Solução: configure /etc/sudoers com NOPASSWD para o usuário do agente, ou execute via um service account. Evite operações de host em agentes hosted — use self-hosted.
| |
2) Variáveis e PATH
| |
Na pipeline: instale jq no agente (self-hosted) ou adicione uma etapa que garanta a ferramenta. Também é possível usar um container de job com jq pré-instalado.
| |
3) Prompt Invisível
| |
Na pipeline: remova prompts; use flags não-interativas (ex.: --yes, --force) e passe parâmetros via variáveis de pipeline.
| |
💡 Dica: Sempre projete seus scripts com uma flag de “modo não-interativo”. Isso os torna compatíveis com pipelines sem sacrificar a usabilidade no terminal.
Azure DevOps — Pontos Específicos
Se você trabalha com Azure DevOps, existem particularidades que valem destaque especial. Conhecê-las ajuda a evitar armadilhas comuns.
Hosted vs Self-hosted Agents
- Hosted: ambiente gerenciado pela Microsoft; efêmero; conjunto de ferramentas pré-definido. Ideal para projetos que seguem padrões comuns e não têm dependências exóticas.
- Self-hosted: você controla o SO, versões e pacotes instalados — melhor para paridade com o servidor de produção.
Tasks e Shells
- Use a task
Bash@3para scripts.sh. - Especifique o
workingDirectoryquando necessário. - Evite depender de
.bashrc; inicialize o ambiente no próprio script.
Secrets e Service Connections
- Passe credenciais via variáveis seguras (mascaradas).
- Para cloud CLIs (Azure/AWS/GCP), use service connections e login não-interativo (
az login --service-principal, etc.). - Confira também como funciona a autenticação e autorização de forma mais ampla.
Timeouts e Retentativas
- Configure
timeoutInMinutesno job para evitar builds presos. - Implemente retry com backoff em chamadas instáveis (APIs externas, downloads de pacotes).
📌 Exemplo: Um timeout de 60 minutos é comum para jobs de build. Para deploys que envolvem provisionamento de infra, considere valores maiores (90-120 minutos).
Checklist de Diagnóstico
Quando um script falhar na pipeline, percorra sistematicamente esta lista para identificar a causa raiz. Cada item pode ser verificado adicionando um echo ou printenv temporário ao seu script.
- Quem está rodando?
id -u -n,whoami,echo $SHELL,tty. - Ambiente
env | sort,echo $PATH,locale. - Diretório
pwd,ls -la, ver se paths relativos existem. - Ferramentas
command -v <tool>,--versionde cada binário crítico. - Permissões
Tente
sudo -n <cmd>(sem prompt). Veja/etc/sudoers. - Rede/Proxy
curl -I https://..., variáveisHTTP_PROXY/HTTPS_PROXY, certificados. - Logs
Verifique logs da pipeline e da aplicação (
journalctl, arquivos em/var/log). - Efemeridade O script persiste algo? Precisa de cache/artefatos?
💡 Dica: Inclua uma etapa de diagnóstico no início da sua pipeline que imprima
whoami,pwd,env | sorte as versões das ferramentas críticas. Em caso de falha, você já terá as informações necessárias nos logs.
Dicas e Boas Práticas
As práticas abaixo ajudam a minimizar as diferenças entre terminal e pipeline, garantindo que seus scripts sejam portáveis e confiáveis.
- Padronize o ambiente: use containers como runtime do job (cada pipeline roda a mesma imagem). Ou use self-hosted agent no mesmo SO e versão do servidor.
- Declare dependências no script: cheque e instale faltantes (ou falhe com mensagem clara). Trave versões (ex.:
node 20.x,dotnet 8.0.x). - Evite interatividade: use flags
--non-interactive,--yes. Removaread,selecte menus de scripts que rodam em pipeline. - Gerencie credenciais de forma segura: use variáveis secret, Key Vault e service connections. Não dependa de arquivos no
~do usuário. - Use caminhos explícitos: prefira paths absolutos para binários críticos. Defina
workingDirectoryna task. - Torne o script idempotente: rodar duas vezes não deve quebrar o estado. Verifique se um serviço já está no estado desejado antes de agir.
- Log detalhado: ative
set -euo pipefaileset -xem modo debug. Garanta saída clara de erros e códigos de retorno corretos.
⚠️ Atenção:
set -euo pipefailé essencial para scripts em pipeline. Sem essa diretiva, erros silenciosos podem propagar um estado corrompido por todo o restante do job.
Template Bash — Script à Prova de Pipeline
Abaixo, um template que incorpora todas as boas práticas discutidas neste artigo. Use-o como ponto de partida para qualquer script que precise funcionar tanto no terminal quanto na pipeline.
| |
ℹ️ Informação: Este template pode ser adaptado para qualquer linguagem ou contexto. O princípio é o mesmo: normalizar o ambiente, verificar dependências e evitar interatividade.
Conclusão
Ao longo deste artigo, vimos que as diferenças entre executar um script no terminal do servidor e via pipeline do Azure DevOps não são bugs — são consequências naturais de contextos de execução distintos. O terminal oferece um ambiente interativo, com seu usuário, seu PATH e suas configurações carregadas. A pipeline, por outro lado, prioriza reprodutibilidade, segurança e automação, operando com um usuário de serviço em um ambiente controlado e frequentemente efêmero.
Os principais pontos de atenção são: a ausência de TTY (que elimina interatividade), as diferenças no PATH e variáveis de ambiente, o gerenciamento de permissões via sudo, e a efemeridade dos agentes hosted. Para cada um desses desafios, apresentamos soluções práticas e um template reutilizável.
Se você aplicar as boas práticas discutidas — padronizar o ambiente, declarar dependências, evitar interatividade e tornar os scripts idempotentes — vai eliminar a grande maioria dos problemas de “funciona na minha máquina”. Scripts bem projetados para pipeline também são scripts melhores para qualquer ambiente.
Gostou deste conteúdo? Deixe um comentário com suas experiências ou dúvidas. Se quiser aprofundar em temas relacionados, confira os artigos sugeridos abaixo.
Leia Também
- Makefile: Automatizando tarefas para Python, Hugo e Docker
- Autenticação e Autorização: JWT, OAuth2 e OpenID Connect
- BFF Backend For Frontend: Segurança em SPAs
Referências
- Azure Pipelines — O que é Azure Pipelines? — documentação oficial da Microsoft sobre o serviço de CI/CD.
- Azure Pipelines Agents — como funcionam os agentes hosted e self-hosted.
- Definir variáveis secretas no Azure Pipelines — guia oficial para gerenciamento de secrets em pipelines.
- Pipeline Caching — como usar cache gerenciado para acelerar builds.
- Bash Reference Manual — GNU — referência completa do Bash, incluindo
set -euo pipefail. - What is SELinux? — Red Hat — introdução ao SELinux e controle de acesso mandatório no Linux.
Ao comentar, você concorda com nossa Política de Privacidade, Termos de Uso e Política de Exclusão de Dados.