[{"content":"O OpenCodeReview é um revisor de código com IA que encontra bugs, falhas de segurança e erros antes que eles cheguem à produção.\nE é gratuito e de código aberto (licença Apache-2.0).\nNão tem licença por assento, não prende você a um fornecedor e não tem uma IA pulando discretamente metade dos arquivos do seu PR.\nNão é um projeto de fim de semana. Durante cerca de dois anos ele foi o assistente oficial de code review da Alibaba. Segundo o repositório, foi usado por dezenas de milhares de desenvolvedores e apontou milhões de defeitos antes de virar open-source.\nO que ele faz Na prática, é uma CLI (ocr) que lê o diff do Git, manda os arquivos alterados para um LLM configurável por meio de um agente com ferramentas e devolve comentários presos à linha exata do problema.\nRevisa o diff do Git (staged, unstaged e untracked), de uma branch contra outra ou de um commit específico. Traz regras prontas por linguagem: ponteiro nulo, thread-safety, XSS e SQL injection, entre outras. A cobertura varia de linguagem para linguagem, como mostro no teste mais abaixo. Busca contexto além do diff. Ele lê o arquivo inteiro, pesquisa no codebase e olha os outros arquivos alterados no mesmo PR. Escaneia código sem diff com o ocr scan, útil para auditar um módulo legado inteiro. Funciona com qualquer endpoint compatível com OpenAI ou Anthropic. Pode ser usado de dentro do seu agente: Claude Code, Codex, Cursor, Kimi Code, OpenCode e outros que aceitam skills. Roda em CI/CD: GitHub Actions, GitLab CI, GitFlic CI e Gerrit. Inclui recursos de operação: retomada de sessão, visualizador de sessões, suporte a MCP e telemetria via OpenTelemetry. Por que um agente genérico não basta Quem já pediu para um agente de propósito geral \u0026ldquo;revisar esse PR\u0026rdquo; conhece os problemas:\nEm PRs grandes, arquivos são pulados sem nenhum aviso. Os comentários apontam para a linha errada, porque o número da linha foi alucinado ou ficou desatualizado. A qualidade muda com pequenas alterações no prompt, então a mesma revisão feita duas vezes dá dois resultados diferentes. A causa é a mesma nos três casos: deixar para o modelo decisões que não deveriam depender de julgamento. Escolher quais arquivos revisar ou em qual linha colocar um comentário são tarefas determinísticas e não têm por que passar pelo LLM.\nA arquitetura: código onde tem que ser código, IA onde tem que ser IA A ideia central do OpenCodeReview é dividir as responsabilidades.\nParte determinística (código):\nSeleção de arquivos. O código decide o que entra na revisão. Nenhum arquivo é \u0026ldquo;esquecido\u0026rdquo; pelo modelo. Agrupamento. Arquivos relacionados, como os arquivos de localização de um mesmo recurso, viram uma única unidade para um sub-agente, com contexto isolado. Match de regras. As regras são aplicadas por arquivo a partir de templates, e não porque o modelo \u0026ldquo;lembrou\u0026rdquo; delas. Posicionamento e reflexão. Módulos separados cuidam de ancorar o comentário na linha certa e de revisar o próprio resultado. Parte do LLM (agente):\nDecide o que for dinâmico: se aquilo é mesmo um problema, quão grave é e que contexto ainda falta. Busca esse contexto com um conjunto de ferramentas próprio e prompts ajustados para cada cenário. É a mesma lição que vale para qualquer sistema com agentes em produção: quanto menos o modelo tiver que decidir, mais previsível o sistema fica. A IA entra onde agrega valor, que é no julgamento. O resto fica no código, que é auditável e repetível.\nIsso também explica a economia de tokens. O modelo não precisa ler o repositório inteiro para descobrir o que revisar, porque já recebe uma unidade de trabalho pronta e delimitada.\nO benchmark Para comparar, a Alibaba montou o AACR-Bench:\n200 pull requests reais 50 repositórios open-source 10 linguagens 1.505 problemas reais anotados e validados por mais de 80 engenheiros sênior O resultado divulgado, comparando com o Claude Code usando o mesmo modelo por baixo:\nPrecisão e F1 maiores Cerca de 1/9 dos tokens Revisões mais rápidas O trade-off, que o próprio projeto assume: o recall é menor. Ou seja, ele encontra menos problemas no total, e isso é proposital. A escolha é por menos ruído e menos falsos alarmes.\nNa minha opinião, essa é a decisão certa para um revisor que roda em todo PR. Um revisor que gera 30 comentários dos quais 25 são irrelevantes treina o time a ignorar todos eles. Um revisor que gera 5 comentários e acerta 4 vira alguém que o time ouve.\nUm ponto de atenção: o benchmark foi feito pela própria Alibaba e os números detalhados estão em imagens no README. Vale olhar com calma e, de preferência, rodar no seu próprio código antes de tirar conclusões.\nComo começar Pré-requisitos: Git 2.41+ e um endpoint de LLM (compatível com OpenAI ou Anthropic). Roda em Windows, macOS e Linux.\n1 npm install -g @alibaba-group/open-code-review O comando instalado é o ocr. Configure o provedor e o modelo (o setup interativo pede a chave de API e testa a conexão):\n1 2 ocr config provider ocr config model Selecione um provedor integrado ou adicione um personalizado:\nEscolha um modelo para o provedor ativo\nTambém dá para instalar por script, pelo binário do GitHub Release ou compilando do código-fonte. Os detalhes estão na documentação.\nComandos base 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # Revisa as mudanças locais (staged, unstaged e untracked) ocr review # Revisa uma branch contra a base do merge ocr review --from main --to feature-branch # Revisa um commit específico ocr review --commit abc123 # Escaneia um diretório inteiro, sem diff ocr scan --path internal/agent # Saída em JSON para integrar com outras ferramentas ocr review --format json --output result.json # Lista e retoma revisões interrompidas ocr session list ocr review --from main --to feature-branch --resume \u0026lt;id\u0026gt; Modo delegação: sem chave de API própria Se você já usa Claude Code, Codex ou Cursor, existe o modo delegação. Nele o OCR continua fazendo a parte determinística (seleção de arquivos e regras), e o LLM do agente que você já usa faz a revisão. Não é preciso configurar uma chave de API separada para o OCR.\n1 2 ocr delegate preview ocr delegate rule \u0026lt;arquivos\u0026gt; É um bom ponto de partida para testar a ferramenta sem mexer em credenciais nem em custo.\nTestei na prática (sem chave de API) Quis ver o que a ferramenta entrega de fato antes de recomendar. Instalei a versão 1.13.3 no meu Windows 11 (Git 2.56, Node 24) e montei um repositório de teste: uma API Express de pedidos e clientes, com um PR (feature/customer-portal) de 71 linhas.\nAs imagens desta seção mostram a saída real dos comandos que rodei, renderizada numa janela de terminal para facilitar a leitura. O texto não foi editado. O prompt da janela é apenas ilustrativo.\nNesse PR eu plantei 8 problemas de propósito e anotei o gabarito antes de rodar qualquer comando:\n# Problema plantado Onde 1 SQL injection (concatenação de status na query) orders.js 2 Paginação errada (offset = page * pageSize pula a primeira página) orders.js 3 Chave de API de pagamento hardcoded customers.js 4 XSS refletido (name da query direto no HTML) customers.js 5 Null dereference (customer pode não existir) customers.js 6 Path traversal + IDOR no download de faturas customers.js 7 Race condition no saque (checa saldo, cobra e só depois debita) customers.js 8 Handlers async sem tratamento de erro, fetch sem checar response.ok customers.js Fiz o teste sem nenhuma chave de API, usando o modo delegação. Isso tem uma consequência importante: sem LLM, o OCR executa só a parte determinística, ou seja, decide o que revisar e com quais regras. O julgamento fica com o agente hospedeiro. Então este teste não mede precisão, recall nem consumo de tokens do benchmark. Ele mostra a base sobre a qual o modelo trabalha.\nSeleção de arquivos Aqui está a promessa de \u0026ldquo;não pular arquivo\u0026rdquo;: a lista é calculada pelo código a partir do merge-base, não pelo modelo. Os 3 arquivos do PR entraram.\nAs regras que ele aplica Os três arquivos caíram no mesmo grupo de regras, o de JS/TS. Isso também é a parte determinística: a regra é escolhida pelo padrão do arquivo, não pela memória do modelo.\nO que o teste revelou: a cobertura depende da linguagem Cruzando o gabarito com as regras de JS:\n# Problema Regra explícita para JS? 3 Segredo hardcoded ✅ Sensitive Information e Hardcoding 4 XSS ✅ XSS Protection 5 Null dereference ✅ Null Checks 8 Erros async não tratados ✅ Async Handling: Error Handling 1 SQL injection ❌ não mencionado 2 Paginação errada ❌ (bug de lógica, nenhuma regra cobre) 6 Path traversal / IDOR ❌ não mencionado 7 Race condition ❌ não mencionado 4 de 8 problemas têm uma regra explícita apontando para eles. O conjunto de JS é claramente voltado para front-end: tem seção inteira de React, innerHTML e document.write, mas nada sobre SQL, caminhos de arquivo ou concorrência no back-end.\nPara comparar, rodei ocr rules check em arquivos de outras linguagens.\nAs regras de Go pedem explicitamente para checar \u0026ldquo;SQL, shell commands, URLs, paths [\u0026hellip;] assembled from untrusted input\u0026rdquo; e check-then-act. As de Java e Python têm seções de thread-safety com check-then-act. Ou seja, a lista \u0026ldquo;ponteiro nulo, thread-safety, XSS e SQL injection\u0026rdquo; do README é verdadeira para o conjunto de linguagens, mas não vale igualmente para cada uma.\nIsso não quer dizer que o modelo não vá encontrar a SQL injection num arquivo JS. Um LLM decente provavelmente encontra, por julgamento próprio. Mas nesse caso a detecção depende do modelo, não da regra, e é exatamente essa variação que a arquitetura do OCR tenta eliminar.\nNa prática: se o seu back-end é Node, vale escrever regras próprias (o OCR aceita um arquivo de regras via --rule) cobrindo injeção, path traversal, autorização e concorrência. Sem isso, você está contando com o modelo justamente nos pontos mais críticos de um back-end.\nPara a revisão completa, com os comentários na linha e as métricas de tokens e tempo, é preciso configurar um provedor de LLM (ocr config provider). Esse é o próximo teste que pretendo fazer.\nOnde ele se encaixa num pipeline DevSecOps Ele não substitui SAST, SCA, linters nem revisão humana. Ele se soma a eles:\nAntes do commit, na máquina do dev: ocr review ou o modo delegação, dentro do agente que o time já usa. No PR, via CI: GitHub Actions, GitLab CI ou Gerrit comentando direto nas linhas. Na auditoria de legado: ocr scan em módulos que nunca passaram por revisão decente. O ganho real está no meio do caminho. Ferramentas de SAST são boas em padrões conhecidos, mas não entendem intenção. O revisor humano entende intenção, mas não tem tempo para ler cada linha de um PR de 40 arquivos. O OpenCodeReview ocupa esse espaço: tem regras explícitas como base, usa julgamento de LLM por cima e coloca o comentário na linha certa.\nE isso fica ainda mais relevante agora, com cada vez mais código gerado por IA entrando nos repositórios. Se a geração ficou barata, a revisão tem que ficar escalável. E escalável não quer dizer \u0026ldquo;mais um agente opinando\u0026rdquo;. Quer dizer um processo previsível, que não pula arquivo.\nPontos de atenção Recall menor. Ele vai deixar passar coisas. Não trate o \u0026ldquo;nenhum comentário\u0026rdquo; como garantia. Benchmark próprio. Os números são da Alibaba, com um dataset da Alibaba. Valide no seu contexto. Custo e dados. Fora do modo delegação, o código vai para o provedor de LLM que você configurar. Em ambientes regulados, avalie usar um endpoint interno ou self-hosted. Regras desiguais entre linguagens. No meu teste, as regras de JS não mencionam SQL injection, path traversal nem concorrência. Em back-end Node, complemente com regras próprias. Dependência de Git 2.41+. Imagens antigas de runner de CI podem precisar de atualização. Conclusão O mais interessante do OpenCodeReview não é \u0026ldquo;a IA da Alibaba ser melhor que o Claude Code\u0026rdquo;. É a abordagem: tirar do modelo tudo o que não exige julgamento. É isso que faz ele ser mais barato, mais rápido e mais confiável que um agente genérico revisando código só com prompt.\nVale testar. No mínimo, vale estudar a arquitetura.\nRepositório: https://github.com/alibaba/open-code-review Documentação: https://open-codereview.ai/docs\n","date":"2026-10-28T00:00:00Z","image":"https://i.imgur.com/S5s938Y.jpeg","lang":"pt-br","permalink":"https://luks.dev.br/p/a-alibaba-acaba-de-abrir-codigo-fonte/","title":"A Alibaba acaba de abrir o código-fonte de algo insano"},{"content":"Quando uma aplicação é escrita quase toda por IA, por um time que não tem base sólida de engenharia de software, colocá-la em produção deixa de ser uma questão de pipeline e vira um trabalho de contenção de risco. Este texto é sobre isso: o que chega para o time de DevSecOps, por que chega desse jeito e o que dá para fazer antes.\nSobre a base deste artigo. O texto parte da minha experiência no dia a dia, mas a espinha dorsal teórica vem do survey AI Agent Systems: Architectures, Applications, and Evaluation, de Bin Xu (Arizona State University, arXiv:2601.01743, 2026). Sempre que eu citar \u0026ldquo;o survey\u0026rdquo; ou \u0026ldquo;Xu (2026)\u0026rdquo; ao longo do texto, é dele que estou falando. As ideias de verificação, avaliação, autonomia proporcional ao risco e contratos de ferramenta que aparecem aqui foram tiradas desse trabalho e adaptadas para a realidade de quem opera software em produção.\nPor que escrevi isso Desenvolvimento assistido por IA já faz parte da rotina de quase todo time. Geração de código, testes, refatoração, manifests, Terraform, documentação: tudo isso passa por alguma ferramenta de IA hoje em dia. E eu não tenho nada contra. Uso bastante, inclusive.\nO que mudou recentemente é que boa parte desse código não vem mais de um autocomplete, e sim de agentes. Xu (2026) define agentes como sistemas que juntam um modelo de fundação com raciocínio, planejamento, memória e uso de ferramentas. Traduzindo: o agente lê o repositório, edita arquivo, roda comando, instala dependência e gera manifest, tudo num loop que pode dar dezenas de voltas sem ninguém olhando cada passo.\nEm time experiente, isso é ganho de escala de verdade. O problema começa quando a velocidade de geração passa a ser tratada como se fosse maturidade de engenharia.\nA pergunta que aparece na prática não é \u0026ldquo;a IA falhou\u0026rdquo;; é: \u0026ldquo;como a gente leva isso para produção sem virar uma operação de emergência?\u0026rdquo; Ao longo da minha experiência com DevOps e SRE, e em conversas com quem vive o mesmo dia a dia, esse cenário aparece com frequência: chega uma aplicação que \u0026ldquo;funciona\u0026rdquo; localmente e, olhando com um pouco de cuidado, está longe de aguentar produção. O que deveria ser uma entrada simples no pipeline vira análise de arquitetura, de operação, de segurança e de observabilidade. Chega um conjunto de arquivos com cara de software e comportamento de protótipo.\nNão estou escrevendo para reclamar do uso de IA. Estou escrevendo porque a conversa precisa sair do campo da promessa e entrar no da operação real. O objetivo aqui é simples: mostrar um caminho útil para receber essas aplicações com menos risco, menos retrabalho e mais clareza sobre o que precisa ser validado antes de qualquer deploy.\nO que o survey de Xu (2026) diz sobre isso Quando li o survey pela primeira vez, a sensação foi de que alguém tinha escrito, com linguagem acadêmica, o que a gente sente operando essas aplicações. O trabalho não é sobre DevSecOps. É uma revisão ampla de como agentes de IA são construídos, treinados e avaliados. Mas três pontos dele caem como uma luva no nosso problema.\nO primeiro está na parte sobre agentes de código e manutenção de software. O autor diz que as tarefas reais de software são longas, dependem de muitas ferramentas e que as falhas costumam ser sutis e tardias: regressões de segurança, comportamento que muda escondido atrás de feature flag, defeitos que só aparecem em teste de integração ou sob carga parecida com a de produção. Ou seja, o erro não aparece na máquina de quem gerou o código. Aparece quando a aplicação chega pra gente.\nO segundo vem logo em seguida: \u0026ldquo;plausible patches are not enough\u0026rdquo;. Um patch plausível não basta, é preciso correção de ponta a ponta e o mínimo de regressão. Uma API que compila e responde na porta 3000 é exatamente isso, um patch plausível.\nO terceiro está na conclusão, e é talvez a frase que mais resume este artigo: \u0026ldquo;reliability and governance are properties of the full stack\u0026rdquo;. Confiabilidade e governança são propriedades da stack inteira, não do modelo. Não adianta usar o modelo mais caro do mercado se não existe revisão, teste, pipeline, observabilidade e controle de permissão em volta dele.\nO survey fecha falando da distância entre demonstrações impressionantes e implantação robusta no mundo real. Pra quem trabalha com plataforma, essa distância tem nome: backlog.\n\u0026ldquo;Funciona\u0026rdquo; não é critério de pronto Uma parte do survey que eu gosto muito é a de avaliação. O autor argumenta que medir agente só pela taxa de sucesso é pouco, e propõe olhar várias dimensões ao mesmo tempo: desempenho fim a fim, custo e latência, se as ferramentas foram usadas corretamente, robustez sob perturbação, segurança ao longo da execução. Tem até uma observação ótima de que agentes podem \u0026ldquo;resolver\u0026rdquo; tarefas sendo lentos ou caros demais para uso real.\nTrocando \u0026ldquo;agente\u0026rdquo; por \u0026ldquo;aplicação\u0026rdquo;, vira um checklist de onboarding. \u0026ldquo;Funciona\u0026rdquo; é a taxa de sucesso. O resto é o que a gente precisa perguntar:\nFunciona num ambiente parecido com produção, ou só no localhost? Qual a latência p95 e quanto de CPU e memória ela consome sob carga de verdade? As integrações com banco, fila e APIs externas tratam timeout, erro e retry? O que acontece quando uma dependência fica instável, o pod reinicia ou o tráfego dobra? Tem segredo exposto, dado vazando ou ação sem autorização em algum ponto do fluxo? Se der incidente amanhã, dá para reconstruir o que aconteceu com os logs, métricas e traces que existem? Xu (2026) insiste que a segurança tem que ser avaliada ao longo de toda a trajetória de execução, e não só na resposta final. Pra aplicação vale igual: o 200 OK no fim da requisição não diz nada sobre o que aconteceu no caminho.\nO que costuma chegar Raramente o onboarding de uma aplicação gerada quase toda por IA começa com uma arquitetura limpa e um plano de operação. O que chega é um monte de sinais de que o software foi construído em cima da pergunta \u0026ldquo;como faço isso funcionar?\u0026rdquo;, e nunca da pergunta \u0026ldquo;como isso sobrevive em produção?\u0026rdquo;.\nA boa notícia é que isso não precisa virar uma crítica sem saída. O ponto central é simples: o problema não é a IA em si, e sim a falta de uma etapa de validação e de governança antes do serviço entrar em produção. Quando a equipe trata isso como uma etapa de disciplina operacional — e não como uma \u0026ldquo;queixa de plataforma\u0026rdquo; — a solução fica muito mais clara.\nOs sinais mais comuns, pela minha experiência, são:\nRepositório sem estrutura definida. Só pra entender o fluxo e onde estão os pontos de falha já vai um bom tempo. Teste inexistente ou superficial. Sem isso não tem CI confiável, nem rollback seguro. Teste gerado só pra passar. Esse é pior que o anterior, porque dá falsa sensação de segurança. Cobertura alta, assert fraco. Dockerfile improvisado. Imagem enorme, lenta, difícil de auditar. Configuração e segredo no meio do código. Manifest de Kubernetes genérico, sem probe, sem resource, sem estratégia de rollout. Log em texto solto, impossível de correlacionar. Dependência desatualizada, ou que ninguém sabe de onde veio. Nenhum registro de como o código foi gerado. Não dá pra saber o que foi decisão do agente e o que alguém de fato revisou. Muitas vezes, o primeiro trabalho não é fazer deploy. É descobrir se aquilo pode virar algo operável sem reescrever do zero. E, para isso, a abordagem mais útil é bem direta: validar a aplicação como se ela já estivesse em produção, antes de tratá-la como produto pronto.\nUma abordagem útil para o time Em vez de tratar o app gerado por IA como uma entrega acabada, vale pensar em cinco critérios simples:\nO sistema roda em ambiente parecido com produção? Ele tem testes mínimos que falham quando a regra quebra? Tem saúde, logs e métricas suficientes para diagnosticar problema? Os segredos e permissões estão controlados? A operação foi pensada antes do primeiro deploy? Se a resposta para qualquer um desses pontos for \u0026ldquo;não\u0026rdquo;, a próxima etapa não é reclamar — é fechar o gap com a menor mudança possível, de modo que o serviço fique seguro, observável e sustentável.\nArquitetura O primeiro problema quase sempre é arquitetural. Aplicação gerada sem direção tende a seguir o caminho de menor resistência: um monólito grande, regra de negócio misturada com tudo, sem fronteira de domínio.\nO survey ajuda a entender por quê. Xu (2026) descreve o funcionamento de um agente como um ciclo: observa, busca contexto, propõe uma ação, valida, executa e atualiza a memória. Se ninguém dá uma arquitetura-alvo como contexto, cada volta desse ciclo resolve o problema da vez do jeito mais direto possível. O sistema final é montado por acúmulo, não por desenho. E o autor lembra que, em tarefas longas, os erros se acumulam (compounding errors): uma decisão ruim no passo 3 vira premissa para tudo que vem depois.\nVale dizer: monólito não é problema por si só. O problema é o monólito sem modularização nenhuma, onde autenticação, regra de negócio, persistência, integração e apresentação vivem no mesmo fluxo. Aí qualquer mudança pequena quebra algo que parecia não ter relação nenhuma. É comum ver um único serviço que recebe a requisição, valida, consulta o banco, chama API externa, monta a resposta, grava auditoria e ainda implementa retry na mão. Função gigante, opaca e frágil.\nSOLID some. Padrões simples que ajudariam muito (Repository, Adapter, Strategy, Circuit Breaker, Outbox, Bulkhead) não aparecem. E não falo isso por apego a pattern, mas porque sem essa linguagem estrutural o sistema não tem como crescer de forma organizada.\nDuplicação de código também é frequente. Com agente, ela é ainda mais comum, porque o contexto de cada sessão é limitado: o agente não \u0026ldquo;lembra\u0026rdquo; que já existe um utilitário igual em outro módulo e escreve outro. Somam-se a isso as dependências circulares, que aparecem porque o código foi organizado por proximidade funcional e não por arquitetura. O build sofre, a refatoração fica cara e o grafo de dependências vira um novelo.\nSystem design Se a arquitetura mostra a forma do problema, o system design mostra o estrago na operação.\nAplicação gerada sem pensamento de sistema costuma assumir carga constante, latência estável e dependências sempre disponíveis. Nada disso existe em produção. Os pontos que mais vejo:\nEstado em memória e sessão local. Funciona até o primeiro restart, reschedule ou scale-out. Depois disso, usuário deslogado e dado perdido.\nNenhum cache. Toda leitura vai direto ao banco, que vira ponto único de verdade e de gargalo. A gente acaba olhando métrica de pool de conexão e saturação sem ter nenhuma camada intermediária pra aliviar.\nTudo síncrono. Uma chamada depende da outra, que depende de uma terceira. A latência se soma, o timeout aparece e uma falha derruba a cadeia inteira. Fila resolveria boa parte disso, mas não tem.\nSem idempotência, sem tolerância a falha. Sem idempotência, retry vira risco de operação duplicada. Sem tolerância a falha, uma API externa fora do ar derruba o fluxo todo.\nUm sistema bom não é o que nunca falha. É o que falha de um jeito previsível, que dá pra detectar e do qual dá pra se recuperar.\nCloud e Kubernetes Aqui é onde o onboarding dói de verdade. Muita aplicação gerada por IA foi pensada para rodar, não para ser operada num orquestrador. É bem o cenário descrito no survey: problemas que só aparecem sob carga parecida com a de produção.\nKubernetes pressupõe um contrato mínimo com a aplicação. Ela precisa dizer quando está viva, quando está pronta pra receber tráfego, como encerra e como lida com estado. Se o código não oferece isso, a plataforma vira uma camada de compensação.\nSem readinessProbe, o tráfego chega antes da aplicação estar pronta. Sem livenessProbe, um processo travado fica lá ocupando o pod. Sem startupProbe, aplicação que demora pra subir é morta antes de terminar de iniciar. E tem um clássico do código gerado: o /health que retorna 200 sempre, sem checar nada. Ele satisfaz o manifest e não informa coisa nenhuma ao cluster.\nGraceful shutdown é outro ponto. Muita aplicação ignora o SIGTERM: não fecha conexão, não drena requisição, não termina a transação. Em todo rollout, alguém perde uma requisição.\nEscalar horizontalmente também não é só aumentar réplica. Se o estado está em memória, o autoscaling quebra a experiência do usuário. E sem requests e limits o scheduler trabalha no escuro, o HPA escala no momento errado e ninguém entende por quê.\nPor fim, configuração misturada com código transforma deploy em intervenção manual, e storage persistente usado sem necessidade complica qualquer tentativa de resiliência.\nflowchart TD A[App entregue por IA] --\u0026gt; B[Build inicial] B --\u0026gt; C[Testes quase inexistentes] C --\u0026gt; D[Deploy em container] D --\u0026gt; E[Problemas em readiness/liveness] E --\u0026gt; F[Autoscaling ineficaz] F --\u0026gt; G[Incidentes, retrabalho e hotfix] DevSecOps Do lado de DevSecOps, o mais caro nem é achar vulnerabilidade. É não ter base nenhuma para automatizar o controle de qualidade.\nSem padrão de branch, estrutura e build, cada aplicação pede um pipeline praticamente artesanal. Sem teste, o pipeline deixa de ser mecanismo de confiança. CI não existe pra \u0026ldquo;passar\u0026rdquo;, existe pra provar que a mudança não quebrou o que já funcionava.\nE tem uma armadilha bem específica de código gerado: quando o mesmo agente escreve o código e o teste, o teste confirma o que o código faz, não o que ele deveria fazer. Por isso Xu (2026), ao falar de agentes de engenharia de software, diz que é essencial reportar a validade do patch e o comportamento de regressão, e não só se a tarefa passou. Cobertura alta com assert fraco me preocupa mais do que cobertura baixa honesta.\nDockerfile Build lento reduz feedback. Imagem grande custa mais pra baixar, escalar e corrigir. Normalmente o Dockerfile que chega é algo assim:\n1 2 3 4 5 6 FROM node:18 WORKDIR /app COPY . . RUN npm install EXPOSE 3000 CMD [\u0026#34;npm\u0026#34;, \u0026#34;start\u0026#34;] E uma versão razoável seria:\n1 2 3 4 5 6 7 8 9 10 11 12 13 FROM node:20-alpine AS deps WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production COPY --from=deps --chown=node:node /app/node_modules ./node_modules COPY --chown=node:node . . USER node EXPOSE 3000 CMD [\u0026#34;node\u0026#34;, \u0026#34;server.js\u0026#34;] Não esqueça do .dockerignore, com pelo menos node_modules, .git, .env* e artefatos de teste. Sem ele, o COPY . . sobrescreve as dependências do estágio anterior e ainda pode levar segredo local pra dentro da imagem.\nSegredos no código É um dos sinais mais perigosos. Quando aparece segredo no repositório, o problema já se espalhou: tem que rotacionar, revogar, auditar e torcer pra não ter vazado.\nCom agente, isso piora. A sessão do agente normalmente tem acesso ao .env local, ao histórico do shell e às credenciais de quem está rodando. Se nada impedir, essas informações vão parar em arquivo de configuração, exemplo de código ou até em mensagem de commit.\nO agente também é superfície de ataque Esse ponto quase nunca entra na conversa, e foi lendo o survey que eu passei a olhar pra ele com mais atenção. Um agente de código executa comando, instala pacote e altera arquivo. Ele faz parte da cadeia de suprimentos do software, quer a gente goste ou não.\nXu (2026) levanta alguns riscos que valem para qualquer empresa que deixa agentes mexerem em repositório:\nPrompt injection. Conteúdo não confiável (issue, ticket, documentação externa, README de dependência) pode carregar instruções que o agente segue. Ações sem volta. Migration, terraform apply, kubectl delete. O survey recomenda permission gates, ou seja, uma aprovação explícita antes de qualquer ação irreversível. Memória envenenada. Se o agente mantém memória entre sessões, conteúdo malicioso vindo de uma ferramenta pode persistir. Permissão demais. O autor defende permissões limitadas por papel, allowlist de ferramentas e execução em sandbox, para que um erro não se espalhe. Na prática, eu trato o agente como mais um ator do pipeline: identidade própria, token com escopo mínimo, execução isolada e log auditável. Se o time não consegue responder \u0026ldquo;quais comandos o agente rodou e com qual credencial?\u0026rdquo;, o problema de supply chain começou antes do primeiro build.\nFerramentas de segurança no pipeline Ferramenta não conserta arquitetura ruim, mas ajuda a não deixar passar o óbvio. O mínimo que costumo colocar:\nSAST para padrões inseguros no código; SCA para dependências vulneráveis. Em código gerado, confira também se o pacote existe mesmo e é o certo, porque modelo às vezes sugere nome parecido com biblioteca legítima; Secret scanning para chaves e tokens; Container scanning para a imagem; IaC scanning para Terraform, Helm e manifests; SBOM para saber o que de fato está dentro do software. Um exemplo de pipeline no GitLab CI:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 stages: - test - sast - sca - build - container_scan - deploy variables: IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA unit_tests: stage: test image: node:20 script: - npm ci - npm test -- --coverage semgrep_sast: stage: sast image: semgrep/semgrep script: - semgrep scan --config p/owasp-top-ten --json --output semgrep.json owasp_dependency_check: stage: sca image: owasp/dependency-check:latest script: - dependency-check.sh --scan . --format JSON --out dependency-check build_image: stage: build image: docker:27 services: - docker:27-dind script: - docker login -u \u0026#34;$CI_REGISTRY_USER\u0026#34; -p \u0026#34;$CI_REGISTRY_PASSWORD\u0026#34; \u0026#34;$CI_REGISTRY\u0026#34; - docker build -t \u0026#34;$IMAGE\u0026#34; . - docker push \u0026#34;$IMAGE\u0026#34; trivy_container: stage: container_scan image: aquasec/trivy:latest script: - trivy fs --severity HIGH,CRITICAL --exit-code 1 . - trivy image --severity HIGH,CRITICAL --exit-code 1 \u0026#34;$IMAGE\u0026#34; O equivalente no GitHub Actions:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 name: security-pipeline on: push: branches: [\u0026#34;main\u0026#34;] permissions: contents: read jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm ci - run: npm test -- --coverage - uses: aquasecurity/trivy-action@0.28.0 with: scan-type: fs severity: HIGH,CRITICAL exit-code: 1 Repare no permissions: contents: read. O token do workflow recebe só o que precisa. É o mesmo princípio de menor privilégio que vale para o agente.\nSe usar SonarQube, o quality gate bloqueando o merge já ajuda bastante:\n1 2 3 4 5 sonar.projectKey=app-gerada-por-ia sonar.sources=src sonar.tests=test sonar.javascript.lcov.reportPaths=coverage/lcov.info sonar.qualitygate.wait=true E pra rodar localmente antes do push:\n1 2 semgrep scan --config p/security-audit --config p/owasp-top-ten src/ trivy fs --scanners vuln,secret,misconfig . Observabilidade Observabilidade tem que nascer junto com a aplicação. Nas apps que recebo, geralmente o cenário é log espalhado, métrica inexistente e tracing só no slide da apresentação.\nO survey trata logs de chamadas de ferramenta, artefatos intermediários e traces como saídas de primeira classe, tão importantes quanto o resultado final, porque sem eles não tem depuração, conformidade nem reprodutibilidade. Achei curioso ver isso num trabalho sobre agentes, porque é exatamente o argumento que a gente usa com aplicação: se não dá pra reconstruir o que aconteceu, não dá pra operar.\nLog em texto livre ajuda no começo e atrapalha no primeiro incidente sério. Sem estrutura, não tem como correlacionar por trace_id, request_id, usuário ou serviço. Sem métrica, ninguém enxerga latência, erro, throughput ou saturação. Prometheus e Grafana não são enfeite, fazem parte do contrato operacional. E em sistema distribuído, tracing é o único jeito prático de seguir uma requisição entre serviços. Hoje o caminho mais simples pra isso é OpenTelemetry:\n1 2 3 4 5 6 7 env: - name: OTEL_SERVICE_NAME value: app-gerada-por-ia - name: OTEL_EXPORTER_OTLP_ENDPOINT value: http://otel-collector:4317 - name: OTEL_RESOURCE_ATTRIBUTES value: service.namespace=platform,deployment.environment=prod flowchart LR A[Aplicação] --\u0026gt; B[OpenTelemetry SDK] B --\u0026gt; C[OTel Collector] C --\u0026gt; D[Prometheus] C --\u0026gt; E[Grafana] C --\u0026gt; F[Backend de tracing] A --\u0026gt; G[Logs estruturados] Segurança da aplicação Quando a aplicação é feita sem revisão séria, a segurança é a primeira a sentir.\nJWT validado pela metade é muito comum: assinatura ignorada, expiração mal tratada, aud inexistente, refresh token sem proteção. Autenticação sem autorização também: a aplicação sabe quem é o usuário, mas não checa o que ele pode fazer.\nAlém disso, a lista de sempre aparece com frequência: SQL injection por concatenação de string, XSS, SSRF por aceitar qualquer URL, upload sem validação de tipo e tamanho, CORS liberado pra tudo, nenhum rate limiting e dependências com CVE conhecida.\nNada disso é detalhe. É o resultado de um projeto feito sem modelo mental de segurança. E é exatamente o tipo de regressão que, como lembra Xu (2026), passa despercebida até chegar perto de produção.\nUm Deployment com o mínimo que eu espero ver:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 apiVersion: apps/v1 kind: Deployment metadata: name: app-gerada-por-ia spec: replicas: 3 selector: matchLabels: app: app-gerada-por-ia template: metadata: labels: app: app-gerada-por-ia spec: terminationGracePeriodSeconds: 30 securityContext: runAsNonRoot: true containers: - name: app image: registry.example/app:1.0.0 ports: - containerPort: 3000 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: [\u0026#34;ALL\u0026#34;] resources: requests: cpu: \u0026#34;100m\u0026#34; memory: \u0026#34;128Mi\u0026#34; limits: cpu: \u0026#34;500m\u0026#34; memory: \u0026#34;256Mi\u0026#34; startupProbe: httpGet: path: /health port: 3000 failureThreshold: 30 periodSeconds: 2 readinessProbe: httpGet: path: /ready port: 3000 periodSeconds: 5 livenessProbe: httpGet: path: /health port: 3000 periodSeconds: 10 lifecycle: preStop: exec: command: [\u0026#34;sh\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;sleep 10\u0026#34;] E a base de infraestrutura versionada desde o início, mesmo que seja só o namespace:\n1 2 3 4 5 6 7 8 9 10 11 12 13 terraform { required_version = \u0026#34;\u0026gt;= 1.6.0\u0026#34; } resource \u0026#34;kubernetes_namespace\u0026#34; \u0026#34;app\u0026#34; { metadata { name = \u0026#34;app-gerada-por-ia\u0026#34; labels = { owner = \u0026#34;platform\u0026#34; tier = \u0026#34;prod\u0026#34; } } } O impacto na operação Quando uma aplicação chega nesse estado, o problema deixa de ser só técnico e passa a ser organizacional.\nCada incidente exige ler código, mexer em infraestrutura, corrigir build e, muitas vezes, fazer alguma intervenção manual. O time de plataforma para de operar um sistema e passa a sustentar um protótipo em produção. Sem teste, contrato e observabilidade, toda mudança vira risco, e o time de produto começa a depender de janela de manutenção e hotfix.\nO diagnóstico também fica mais lento. Sem log estruturado, trace e métrica útil, o tempo pra achar a causa raiz cresce e a gente acaba investigando sintoma. Pior ainda quando ninguém no time de produto conhece o código a fundo, porque ninguém escreveu de fato.\nO pipeline sofre junto. Ele precisa compensar a falta de padrão, bloquear segredo, achar vulnerabilidade, validar build e segurar regressão. Vira algo complexo, caro e, não raramente, questionado por quem gerou o código.\nE tem o custo que não aparece. O survey chama atenção para custos escondidos que a taxa de sucesso não mostra: retentativas, crescimento de contexto, tempo e intervenção humana. No onboarding é igual. A velocidade de geração aparece no relatório do time de produto. As horas de triagem, retrabalho e hotfix aparecem no backlog de outro time. Se a empresa só olha o primeiro número, vai sempre achar que a IA está saindo de graça.\nA dívida técnica que vem junto Dívida técnica não é código feio. É uma conta que cresce quando se escolhe velocidade sem controle, e com IA mal usada ela cresce em várias frentes ao mesmo tempo. Tem a dívida de arquitetura, de um sistema que nasce sem fronteiras e fica caro de modularizar depois. Tem a operacional, por falta de sinais e contratos para operar. Tem a de segurança, com vulnerabilidade que entra cedo e se espalha. E tem a de plataforma, com o time de DevSecOps criando exceção e remendo sob pressão.\nTem também uma que eu acho mais silenciosa: a dívida de conhecimento. Quando boa parte do código foi escrita por um agente e aceita sem revisão profunda, ninguém no time tem o modelo mental completo do sistema. O problema não está só no código, está na falta de gente capaz de explicá-lo.\nE como a IA acelera a criação dessa dívida, no curto prazo ela parece produtividade.\nComo evitar Evitar esse cenário não passa por proibir IA. Passa por colocar engenharia antes da automação. Uma coisa que me chamou atenção lendo o survey é que as recomendações que Xu (2026) faz para tornar agentes confiáveis são praticamente as mesmas que a gente faz para tornar aplicações confiáveis.\nDefina um baseline de arquitetura antes de gerar código. Fronteiras do sistema, modelo de estado, contratos de integração, padrão de persistência. E coloque isso como contexto para o agente, em arquivos de instrução no próprio repositório, em vez de deixar só na cabeça de quem desenhou.\nOfereça templates e starters oficiais. Skeleton de projeto, pipeline padrão, observabilidade já configurada, policy-as-code. Pro agente, um bom starter funciona como as interfaces estruturadas que o survey recomenda: limita o espaço de ação e reduz a chance de ele sair inventando.\nExija verificação, não só geração. O padrão que o survey propõe para agentes de código é um loop explícito: roda teste e linter, analisa a falha, corrige e repete até passar, sempre com base em diagnóstico concreto. No processo do time, isso significa CI bloqueando código sem validação mínima e alguém que entende a regra de negócio revisando os testes.\nColoque segurança desde o primeiro commit. SAST, SCA, secret scanning, container e IaC scanning, SBOM. No fluxo padrão, não numa etapa no fim.\nDê ao agente o mínimo de privilégio. Sandbox, token com escopo reduzido, allowlist de ferramentas e aprovação humana para ação irreversível. O survey chama isso de budgeted autonomy, que eu traduziria como autonomia proporcional ao risco: quanto maior o impacto e menor a chance de desfazer, mais verificação antes de executar. Gerar um teste unitário pode ser autônomo. Mudar uma policy de IAM, não.\nProjete para operar. Sem health check, sem shutdown decente, com estado em memória e sem plano de escala, a aplicação não está pronta, ponto.\nPara formalizar esse último item, eu me inspirei na ideia de tool contracts do survey, em que cada ferramenta do agente tem pré-condições, pós-condições e evidência para auditoria. Aplicado ao nosso caso, vira um contrato de onboarding, um checklist que a aplicação precisa cumprir antes de entrar no pipeline de produção:\nTestes automatizados com asserts que fazem sentido, e os críticos revisados por alguém Probes de startup, readiness e liveness que checam dependências de verdade Tratamento de SIGTERM testado num rollout Configuração em ConfigMap e Secret, nenhum segredo no repositório Logs estruturados, métricas e traces com trace_id correlacionável Imagem multi-stage, rodando como não-root, sem vulnerabilidade HIGH/CRITICAL SBOM gerado e SCA aprovado Registro de quais partes foram geradas por IA e de quem revisou Por último, IA é copiloto, não arquiteto. Ela sugere, acelera e padroniza, mas design, trade-off e operação continuam sendo responsabilidade de gente. Até o survey, escrito por quem constrói agentes, deixa as decisões de alto impacto com humanos e trata a taxa de intervenção humana como uma métrica a ser reportada, não como algo a esconder.\nflowchart TD A[Ideia ou backlog] --\u0026gt; B[Arquitetura mínima] B --\u0026gt; C[Starter padronizado] C --\u0026gt; D[IA acelera implementação em sandbox] D --\u0026gt; E[Loop de verificação: testes, lint, scans] E --\u0026gt; F[Revisão humana] F --\u0026gt; G[Contrato de onboarding cumprido] G --\u0026gt; H[Onboarding para produção] E -- falhou --\u0026gt; D F -- reprovado --\u0026gt; D Para fechar Time de DevSecOps não existe pra dizer \u0026ldquo;não\u0026rdquo;. Existe pra fazer software ir pra produção de forma segura, observável e sustentável.\nQuando chega uma aplicação gerada quase toda por IA sem base de engenharia, o que a gente encontra não são só bugs. É falta de pensamento de sistema, de disciplina de arquitetura e de preocupação com operação. Por isso a conversa certa não é sobre culpar a IA, e sim sobre responsabilidade técnica. A IA acelera o trabalho bom e acelera o erro na mesma medida, e quem decide qual dos dois sai é quem está conduzindo.\nO survey de Xu (2026) chega à mesma conclusão por outro caminho: confiabilidade e governança são da stack inteira, não do modelo. No fim, a diferença entre protótipo e software de produção continua sendo engenharia. Quando ela existe, a IA multiplica a capacidade do time. Quando não existe, o problema só fica mais rápido de criar e mais caro de corrigir.\nUma aplicação que funciona não é necessariamente uma aplicação pronta para produção.\nSe você quiser se aprofundar na parte de agentes, recomendo muito a leitura do survey completo. Ele vai bem além do que trouxe aqui, principalmente na parte de avaliação e nos desafios em aberto.\nReferências Referência principal\nXU, Bin. AI Agent Systems: Architectures, Applications, and Evaluation. arXiv:2601.01743, 2026. Disponível em: https://arxiv.org/html/2601.01743v1 Documentação técnica usada nos exemplos\nKubernetes Documentation Kubernetes: Configure Liveness, Readiness and Startup Probes Kubernetes: Configure a Security Context for a Pod or Container Kubernetes: Define a Command and Arguments for a Container OpenTelemetry Documentation Prometheus Documentation Grafana Documentation OWASP Top 10 OWASP Cheat Sheet Series OWASP Dependency-Check Semgrep Documentation Trivy Documentation GitLab CI/CD Documentation GitHub Actions Documentation GitHub Actions: Controlling permissions for GITHUB_TOKEN Dockerfile reference SonarQube Documentation Terraform Documentation ","date":"2026-07-13T00:00:00Z","image":"https://i.imgur.com/bhslPRc.jpeg","lang":"pt-br","permalink":"https://luks.dev.br/p/onboarding-aplicacoes-geradas-por-ia-devsecops/","title":"Onboarding de aplicações geradas por IA: o custo real para DevSecOps"},{"content":"Olá, pessoal! Quanto tempo hein!? Pois é, o tempo tem sido curto para mim ultimamente, muito trabalho 😒 \u0026hellip; mas vamos lá! Sem choro hehe\u0026hellip; decidi trazer esse tema aqui no blog pois tenho sido muito exposto aos SAMs ultimamente e tenho tentado divulgar sorrateiramente sua facilidade de uso para engenheiros de software e engenheiros de devsecops.\nPensando bem, eu nunca abordei esse assunto no meu blog, então escrevi este post como uma resenha.\nNeste post, irei apresentar os conceitos básicos de SAM (Serverless Application Model), realizando a construção de manifestos, métodos de teste locais e melhores práticas operacionais para que até mesmo usuários iniciantes possam usá-lo com confiança. Espero que o conteúdo deste blog ajude os leitores a entender um pouco mais sobre SAM 😊\nIntrodução ao AWS SAM ｜ Noções básicas sobre como criar aplicações Serverless AWS SAM (Serverless Application Model) é uma CLI com estrutura fornecida pela AWS para gerenciar centralmente recursos serverless, como funções Lambda, Amazon API Gateway, Amazon DynamoDB e Amazon S3. Estende o AWS CloudFormation para fornecer uma sintaxe exclusiva que permite declarar concisamente recursos serverless, como funções Lambda e tabelas API Gateway e DynamoDB.\nVocê pode definir um aplicativo inteiro com um modelo SAM (no formato YAML) e automatizar a compilação e a implantação com os comandos sam build e sam deploy. Isso evita o incômodo de escrever à mão modelos complexos do CloudFormation e aumenta drasticamente a produtividade do desenvolvimento serverless.\nOs principais componentes do SAM são os seguintes. Arquivo de modelo: configurado por template.yaml. Descreva definições de recursos, parâmetros, resultados, etc. Tipo de recurso: AWS::Serverless::Function, AWS::Serverless::Api, AWS::Serverless::SimpleTable, etc. Ferramentas CLI: Criação de modelo de projeto com sam init, empacotamento de dependências com sam build, implantação na AWS com sam deploy. Além disso, usar o comando sam local do SAM CLI facilita o teste e a depuração local, aumentando muito a eficiência do desenvolvimento.\nHello World Lambda ＋ Build API Gateway Vamos começar criando um aplicativo serverless com uma configuração mínima e verificar se funciona. O procedimento aqui apresentado segue o guia do SAM CLI para formatos interativos, portanto, mesmo pela primeira vez, você não hesitará em prosseguir.\nCriação de projeto Selecione o tempo de execução desejado, como Python ou Node.js Especifique o nome do projeto e o caminho padrão da API Editar modelo Recursos de função adicionados e definições de endpoint de API Defina variáveis de ambiente e camadas conforme necessário Construir Armazenando dependências em cache no ambiente local e gerando pacotes reproduzíveis Deploys A opção \u0026ndash;guiada permite a determinação interativa do bucket S3 e do nome da stack, bem como da região. Então, vamos seguir em frente.\nInstalação do AWS SAM CLI Se você já possúi esses requisitos instalados, pule essa etapa \u0026hellip;\nAntes de começarmos a criar aplicações serverless, precisamos instalar o AWS SAM CLI. Vou mostrar como fazer isso nos principais sistemas operacionais.\nPré-requisitos Antes de instalar o SAM CLI, certifique-se de ter:\nAWS CLI instalado, configurado e autenticado com sua conta de usuário. Docker instalado (para testes locais) Python 3.7+ ou Node.js 14+ (dependendo da linguagem escolhida) Windows Opção 1: Usando o instalador MSI (Recomendado)\nBaixe o instalador MSI oficial: 1 2 # Acesse: https://github.com/aws/aws-sam-cli/releases/latest # Baixe o arquivo: AWS_SAM_CLI_64_PY3.msi Execute o instalador e siga as instruções\nVerifique a instalação:\n1 $ sam --version Opção 2: Usando Chocolatey\n1 $ choco install awssamcli Opção 3: Usando pip\n1 $ pip install aws-sam-cli Linux (Ubuntu/Debian) Método 1: Download direto (Recomendado)\n1 2 3 4 5 6 7 8 9 10 11 # Baixar o arquivo ZIP wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip # Descompactar unzip aws-sam-cli-linux-x86_64.zip -d sam-installation # Executar o instalador sudo ./sam-installation/install # Verificar instalação sam --version Método 2: Usando pip\n1 pip3 install aws-sam-cli Docker (Qualquer SO) Se preferir usar Docker sem instalar localmente:\n1 2 3 4 5 6 # Criar alias para facilitar o uso echo \u0026#39;alias sam=\u0026#34;docker run --rm -v $(pwd):/var/task amazon/aws-sam-cli-build-image-python3.9\u0026#34;\u0026#39; \u0026gt;\u0026gt; ~/.bashrc source ~/.bashrc # Usar normalmente sam --version Verificação da Instalação Após a instalação, verifique se tudo está funcionando:\n1 2 3 4 5 6 7 8 # Verificar versão do SAM CLI sam --version # Verificar se o Docker está rodando docker --version # Verificar AWS CLI aws --version Hello World Lambda + Build API Gateway 1. Criação do projeto (vamos preparar nosso lab) Quando você executa o sam init, um projeto é criado interativamente. Desta vez, depois de selecionar 1 - AWS Quick Start Templates \u0026gt; 1 - Hello World Example, crie todos os outros itens usando valores padrão.\nNo exemplo abaixo, estou utilizando a versão do python \u0026ldquo;3.12\u0026rdquo; porque é a qual tenho instalado em meu computador mas \u0026hellip; você pode utilizar outra versão:\n1 2 $ sam init --runtime python3.12 --name hello-sam $ cd hello-sam Referência do output:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 C:\\Users\\Lucas\u0026gt;sam init --runtime python3.12 --name hello-sam Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 Choose an AWS Quick Start application template 1 - Hello World Example 2 - Hello World Example with Powertools for AWS Lambda 3 - Infrastructure event management 4 - Multi-step workflow 5 - Lambda EFS example 6 - Serverless Connector Hello World Example 7 - Multi-step workflow with Connectors Template: 1 Based on your selections, the only Package type available is Zip. We will proceed to selecting the Package type as Zip. Based on your selections, the only dependency manager available is pip. We will proceed copying the template using pip. Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]: y X-Ray will incur an additional cost. View https://aws.amazon.com/xray/pricing/ for more details Would you like to enable monitoring using CloudWatch Application Insights? For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: n Would you like to set Structured Logging in JSON format on your Lambda functions? [y/N]: Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment) ----------------------- Generating application: ----------------------- Name: hello-sam Runtime: python3.12 Architectures: x86_64 Dependency Manager: pip Application Template: hello-world Output Directory: . Configuration file: hello-sam\\samconfig.toml Next steps can be found in the README file at hello-sam\\README.md Commands you can use next ========================= [*] Create pipeline: cd hello-sam \u0026amp;\u0026amp; sam pipeline init --bootstrap [*] Validate SAM template: cd hello-sam \u0026amp;\u0026amp; sam validate [*] Test Function in the Cloud: cd hello-sam \u0026amp;\u0026amp; sam sync --stack-name {stack-name} --watch SAM CLI update available (1.148.0); (1.145.0 installed) To download: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html 2. Editar modelo (template.yaml) Desta vez, usaremos o modelo criado por padrão. Essa é a estutura de arquivos criados dentro do diretório gerado:\n1 2 3 4 5 6 7 8 9 10 11 12 26/11/2025 14:22 \u0026lt;DIR\u0026gt; . 26/11/2025 14:22 \u0026lt;DIR\u0026gt; .. 26/11/2025 14:22 3.973 .gitignore 26/11/2025 14:22 \u0026lt;DIR\u0026gt; events 26/11/2025 14:22 \u0026lt;DIR\u0026gt; hello_world 26/11/2025 14:22 8.483 README.md 26/11/2025 14:22 701 samconfig.toml 26/11/2025 14:22 1.766 template.yaml 26/11/2025 14:22 \u0026lt;DIR\u0026gt; tests 26/11/2025 14:22 0 __init__.py 5 arquivo(s) 14.923 bytes 5 pasta(s) 107.983.888.384 bytes disponíveis Agora, vamos editar o arquivo gerado: \u0026ldquo;template.yaml\u0026rdquo;\n3. Edição de código (/hello-world/app.py) Repare que dentro do diretório: \u0026ldquo;hello_world\u0026rdquo;, foi gerado um arquivo python: \u0026ldquo;app.py\u0026rdquo;. Pois é, esse é nosso arquivo de código \u0026ldquo;hello world\u0026rdquo;, \u0026ldquo;serveless\u0026rdquo; em python 😎\nAgora vamos editar esse arquivo app.py. Exemplo:\nAqui vou tentar explicar um pouco do que se trata nosso arquivo de código: \u0026ldquo;app.py gerado pelo nosso querido SAM-CLI:\nEste arquivo app.py é uma função AWS Lambda que implementa um endpoint de API REST simples. Aqui está um resumo do que ele faz:\nFuncionalidade Principal Função Handler: lambda_handler é o ponto de entrada que o AWS Lambda chama quando a função é executada API Gateway Integration: Está configurada para trabalhar com API Gateway como proxy, recebendo requisições HTTP e retornando respostas HTTP O que retorna atualmente Status Code: 200 (sucesso) Body: JSON com a mensagem \u0026ldquo;hello world\u0026rdquo; Código comentado: Há uma funcionalidade comentada que faria uma requisição para obter o endereço IP público usando requests.get(\u0026quot;http://checkip.amazonaws.com/\u0026quot;) Estrutura Recebe dois parâmetros: event (dados da requisição) e context (informações do runtime do Lambda) Retorna um objeto no formato esperado pelo API Gateway Lambda Proxy Inclui documentação detalhada sobre os formatos de entrada e saída Propósito É um exemplo básico de uma API serverless que pode ser deployada na AWS usando o SAM (Serverless Application Model), retornando uma simples mensagem \u0026ldquo;hello world\u0026rdquo; quando chamada via HTTP.\n4. Build \u0026amp;\u0026amp; Deploy Aqui nesse step, repare que as verificações de aplicabilidade do conjunto de alterações são exibidas interativamente durante a implantação. Se não houver problemas, digite y e implante.\n1 $ sam build Se tudo ocorrer bem, esse é o output esperado:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 C:\\Users\\Lucas\\hello-sam\u0026gt;sam build Starting Build use cache Manifest file is changed (new hash: 3298f13049d19cffaa37ca931dd4d421) or dependency folder (.aws-sam\\deps\\f4518d53-cf86-4be8-bef6-9273c0791941) is missing for (HelloWorldFunction), downloading dependencies and copying/building source Building codeuri: C:\\Users\\Lucas\\hello-sam\\hello_world runtime: python3.12 architecture: x86_64 functions: HelloWorldFunction Running PythonPipBuilder:CleanUp Running PythonPipBuilder:ResolveDependencies Running PythonPipBuilder:CopySource Running PythonPipBuilder:CopySource Build Succeeded Built Artifacts : .aws-sam\\build Built Template : .aws-sam\\build\\template.yaml Commands you can use next ========================= [*] Validate SAM template: sam validate [*] Invoke Function: sam local invoke [*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch [*] Deploy: sam deploy --guided E agora vamos para o deploy:\n1 $ sam deploy --guided --region us-east-1 Output esperado:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 PS C:\\Users\\Lucas\\hello-sam\u0026gt; sam deploy --guided --region us-northeast-1 Configuring SAM deploy ====================== Looking for config file [samconfig.toml] : Found Reading default arguments : Success Setting default arguments for \u0026#39;sam deploy\u0026#39; ========================================= Stack Name [hello-sam]: AWS Region [us-northeast-1]: #Shows you resources changes to be deployed and require a \u0026#39;Y\u0026#39; to initiate deploy Confirm changes before deploy [Y/n]: Y #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: Y #Preserves the state of previously provisioned resources when an operation fails Disable rollback [y/N]: N HelloWorldFunction has no authentication. Is this okay? [y/N]: Y Save arguments to configuration file [Y/n]: Y SAM configuration file [samconfig.toml]: SAM configuration environment [default]: Agora, quando acesso o endpoint do API Gateway, ele retorna \u0026ldquo;Hello World\u0026rdquo;. Os parâmetros podem ser definidos no formato interativo CLI e a implantação inicial pode prosseguir sem hesitação.\nAplicação em funcionamento 😎 Em outro post, detalho um pouco mais sobre como usar o AWS Sam em pipelines de CI/CD. Não sei quando, mas um dia sai hehe 😎\nReferência: Guia do Usuário (AWS) Modelo de aplicativo sem servidor AWS (AWS SAM): https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/what-is-sam.html\n","date":"2025-11-26T00:00:00Z","image":"https://i.imgur.com/tUMqz5m.jpeg","lang":"pt-br","permalink":"https://luks.dev.br/p/no%C3%A7%C3%B5es-b%C3%A1sicas-e-pr%C3%A1ticas-do-aws-sam-para-agilizar-o-desenvolvimento-serveless/","title":"Noções básicas e práticas do AWS SAM para agilizar o desenvolvimento serveless"},{"content":"🔖 Visão Geral Muitos desenvolvedores acreditam erroneamente que \u0026ldquo;em repositório privado, é seguro comitar .env\u0026rdquo;. Este post derruba esse mito, apresenta riscos reais baseado em experiências práticas (eu mesmo já cometi esse erro), e ensina práticas seguras — desde ferramentas modernas até integração contínua.\nNesse post, você vai aprender a:\nEntender por que é perigoso comitar .env, mesmo em repositórios privados Conhecer casos reais de incidentes de segurança Usar dotenv-cli para alternar ambientes com segurança Implementar verificações automáticas com git-secrets e hooks no pre-commit Utilizar serviços robustos como AWS Secrets Manager e Doppler 1. O mito: \u0026ldquo;Privado = seguro\u0026rdquo; A falsa sensação de segurança em repositórios privados é perigosa. Aqui compartilho alguns exemplos reais:\nAcesso concedido a consultores eventuais, sem revogação de acesso adequada \u0026hellip; Repositório privado que se tornou público por acidente e acreditem \u0026hellip; não é só o estagiário ou o júnior da empresa que cometem erros \u0026hellip; Tecnologia adquirida por outra empresa, expandindo o acesso, como por exemplo: \u0026ldquo;integrações de repositório com outras ferramentas de mercado\u0026rdquo; \u0026hellip; 2. Três razões pelas quais isso é arriscado 1. Controle de acesso é dinâmico Conforme o projeto cresce, mais pessoas ou organizações podem ganhar acesso.\n2. Histórico do Git é permanente Mesmo que você delete .env, ele permanece nos commits antigos:\n1 2 git rm .env git commit -m \u0026#34;removendo do repositório arquivo .env\u0026#34; 3. Erros humanos são comuns Exemplos: alteração acidental para public, push no repositório errado, falha ao tratar forks.\n3. Casos reais de vazamento Caso 1: Uso indevido de API\nChaves como OPENAI_API_KEY e credenciais AWS em .env foram expostas. Resultado: em vez de US$50 mensais, houve fatura de US$15.000 \u0026hellip; isso não aconteceu comigo (por sorte), mas aqui vai algumas fontes:\nRegarding the latest breach where .env files were leaked (Reddit) Attackers Exploit Public .env Files to Breach Cloud Accounts in Extortion Campaign (The Hackers News) Caso 2: Ataque ao banco de dados\nCredenciais do banco (por ex. DATABASE_URL) que podem vazar registros de clientes e serem expostos na internet, sim isso pode gerar multa por violação do GDPR ou no Brasil pela LGPD; Abaixo cito alguns exemplos reais de vazamento:\nReport: unidentified database exposes 200 million Americans (Cybernews) ✅ 4. Como gerenciar variáveis de ambiente corretamente ✅ Passo 1: configurar .gitignore 1 2 3 4 5 6 7 8 9 10 11 12 13 14 .properties .env .env.local .env.development .env.staging .env.production .env.*.local node_modules/ npm-debug.log* .next/ out/ .DS_Store Thumbs.db target/ ✅ Passo 2: criar .env.example 1 2 3 4 5 6 # .env.example NEXT_PUBLIC_APP_NAME=MyApp DATABASE_URL=postgresql://username:password@localhost:5432/myapp OPENAI_API_KEY=sk-xxxx AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... ✅ Passo 3: váriaveis de ambiente definidas em seu repositório Algumas das ferramentas de armazenamento de projetos Git podem te ajudar a definir variáveis de ambiente diretamente no repositório, evitando o uso de .env com valores sensíveis.\nFerramentas como:\nGitLab (https://gitlab.com) GitHub (https://github.com) Exemplo utilizando o Gitlab:\nNo GitLab, defina as varáveis que seriam utilizadas em seu .env e outros segredos em Settings \u0026gt; CI/CD \u0026gt; Variables:\nExemplo utilizando o Github:\nNo Github, adicione os secrets do seu .env em \u0026ldquo;Settings \u0026gt; Secrets and variables \u0026gt; Actions \u0026gt; Variables\u0026rdquo;:\n5. Alternância segura entre ambientes Gerenciar múltiplos ambientes de forma segura e organizada é essencial em qualquer projeto moderno — especialmente ao lidar com variáveis sensíveis como chaves de API, conexões com banco de dados e tokens de serviços externos.\n1 npm install --save-dev dotenv-cli E no package.json:\n1 2 3 4 \u0026#34;scripts\u0026#34;: { \u0026#34;dev\u0026#34;: \u0026#34;dotenv -e .env.development -- next dev\u0026#34;, \u0026#34;build:production\u0026#34;: \u0026#34;dotenv -e .env.production -- next build\u0026#34; } 6. Validação de variáveis 1 2 3 4 5 6 7 require(\u0026#39;dotenv\u0026#39;).config(); const requiredEnvVars = [\u0026#39;DATABASE_URL\u0026#39;,\u0026#39;OPENAI_API_KEY\u0026#39;]; const missing = requiredEnvVars.filter(v =\u0026gt; !process.env[v]); if (missing.length) { console.error(\u0026#39;❌ Variáveis faltantes:\u0026#39;, missing); process.exit(1); } Esse pequeno trecho de código é um exemplo de como boas práticas simples podem evitar dores de cabeça lá na frente. Verificar variáveis de ambiente logo na inicialização da sua aplicação é uma forma eficaz de manter seu ambiente mais seguro, estável e previsível — especialmente em cenários com múltiplos ambientes ou equipes.\n7. Plataformas cloud com gestão segura Vercel 1 2 vercel env add DATABASE_URL production vercel env pull .env.local O Vercel oferece uma CLI poderosa que permite controlar essas variáveis de forma segura e integrada com seus ambientes (development, preview e production).\nNext.js Variáveis privadas: process.env.OPENAI_API_KEY (somente server-side) Variáveis públicas (cliente): prefixo NEXT_PUBLIC_... 8. Ferramentas de segurança ✅ git-secrets 1 2 3 4 brew install git-secrets git secrets --install git secrets --register-aws git secrets --add \u0026#39;sk-[a-zA-Z0-9]{48}\u0026#39; ✅ Hooks com pre-commit Exemplo .pre-commit-config.yaml para prevenir commits de .env e outros erros.\n9. Fluxo em equipe Vaults como LastPass ou Bitwarden Arquivos criptografados com GPG Serviços temporários como Privnote Serviços especializados:\nAWS Secrets Manager Google Secret Manager HashiCorp Vault Doppler 10. Checklist de boas práticas .env* no .gitignore .env.example presente no repositório como exemplo para os demais desenvolvedores utilizar como base Compartilhamento seguro em equipe Ferramentas como git-secrets, pre-commit, dotenv-cli Validação de ambiente Gestão via cloud (e.g., Vercel) Rotação de segredos Uso de serviços de gestão de segredos 11. O que fazer se \u0026ldquo;commitou\u0026rdquo; o .env 1. Revogue credenciais imediatamente 2. Apague o histórico Git completamente: 1 2 3 git filter-branch --force --index-filter \u0026#39;git rm --cached --ignore-unmatch .env\u0026#39; --prune-empty --tag-name-filter cat -- --all git push origin --force --all git push origin --force --tags ⚠️ Todos devem re-clonar o repositório após isso.\nConsideraçções finais Gerenciar variáveis de ambiente é mais que técnica — é cultura de segurança. Mesmo repositórios privados não garantem proteção. Adotar práticas como dotenv-cli, validação, hooks e gestão via serviços de segredos eleva a segurança e eficiência do projeto. Comece mandando bem já no seu próximo projeto!\n","date":"2025-06-24T00:00:00Z","image":"https://i.imgur.com/8yrUcKa.jpeg","lang":"pt-br","permalink":"https://luks.dev.br/p/por-que-.env-no-git-%C3%A9-um-erro-fatal-mesmo-em-projetos-privados/","title":"Por que .env no Git é um erro fatal – Mesmo em projetos privados"},{"content":"Visão Geral A implementação de testes de vulnerabilidade tornou-se comum em registros de imagens de contêineres. Para compreender a importância das contramedidas de vulnerabilidade quando as empresas utilizam contentores como o Kubernetes, organizámos a inspeção de vulnerabilidades e normas internacionais relacionadas.\nPost relacionado Aqui no blog tenho um outro post que ensina como fazer um teste de vulnerabilidade do tipo SAST, utilizando o Semgrep para realizar scan em imagem Docker:\nIntegre Semgrep SAST no GitLab CI para automatizar a segurança do seu código e encontrar vulnerabilidades cedo Primeiros passos Os módulos contidos na imagem do contêiner estão constantemente melhorando e melhorando seus esforços para reduzir a vulnerabilidade. Imagens de contêiner uma vez construídas também são encontradas toda vez, um módulo com vulnerabilidades é descoberto. A medida contra a vulnerabilidade é atualizar para o módulo de contramedida e reconstruir a imagem do contêiner.\nSelecionando uma imagem confiável O código contido no contêiner é importante para a segurança. A maioria das imagens no contêiner são pacotes de código aberto, como Linux OS, servidores web, bancos de dados SQL, linguagens de programação e cada um desses projetos OSS também distribui na imagem do contêiner, então você precisa construir a imagem sozinho. No entanto, como acontece com o download de código de fontes externas, você deve verificar a origem da imagem do contêiner, o autor e se ela contém código malicioso dentro.\nBasicamente você deve seguir os seguintes princípios:\nAs imagens básicas, os pacotes de SO, os pacotes de linguagem de programa e o código do aplicativo trazem ameaças de segurança ao ambiente em execução do contêiner? As bibliotecas e os módulos usados pelo aplicativo estão atualizados e não são vulneráveis? Imagens básicas como SO e middleware estão usando as últimas versões lançadas e não são vulneráveis? Você sabe com que frequência a imagem do contêiner é atualizada ou há uma maneira de saber o que foi atualizado? Exemplos de ataques previamente descobertos Entender quais vulnerabilidades estão em um contêiner é importante para entender e abordar sua importância. Portanto, aqui estou listando os problemas de vulnerabilidade descobertos anteriormente.\nAtaque afogado DROWN mostra que apenas suportar SSLv2 é uma ameaça para servidores e clientes modernos. Permite que um atacante descriptografe conexões TLS modernas entre clientes e servidores atualizados enviando sondas para um servidor que suporta SSLv2 e usa o mesma chave privada.\nExplorar uma vulnerabilidade chamada \u0026ldquo;DROWN Attack\u0026rdquo; permite que os invasores descriptografem o TLS e leiam e roubem comunicações confidenciais, como senhas, números de cartão de crédito, segredos comerciais e dados financeiros, publicados em março de 2016. Em uma medição, 33% de todos os servidores HTTPS estavam vulneráveis a ataques. Após isso, procedeu-se à aplicação do programa de correção e, a partir de 2019 Laboratórios SSL Estima-se que seja vulnerável a 1,2% dos servidores HTTPS.\nFontes:\nExplicação do ataque de afogamento (Drown Attack) CVE-ID CVE-2016-0800 Ataque de Vaca Suja As vulnerabilidades do \u0026ldquo;Dirty COW\u0026rdquo; estão presentes no kernel do Linux desde setembro de 2007 e foram descobertas e exploradas em outubro de 2016. Essa vulnerabilidade afeta todos os sistemas operacionais baseados em Linux, incluindo o Android, e é muito séria. Os atacantes podem explorar essa vulnerabilidade para obter autoridade de raiz. Esta vulnerabilidade existe no código copy-on-light no kernel do Linux. Copy-on-light ( Copy-On-Write ) é uma das estratégias de otimização, mesmo que lhe seja pedido para duplicar dados grandes, pode lê-los (entre Read ), na verdade não faça nada e duplique). Em seguida, reescreva os dados (copie e reescreva quando Write) ocorrer. Se você não reescrevê-lo mesmo se você duplicá-lo, o custo de proteger a área de memória e processar a cópia dos dados na memória será desperdiçado. Portanto, o processamento estratégico descrito acima pode melhorar a velocidade de processamento e reduzir o tempo de CPU. Para mais informações, consulte o link abaixo.\nFontes:\nVaca Suja (Dirty Cow) CVE-ID CVE-2016-5195 Vulnerabilidade da glibc Glibc é uma implementação da biblioteca padrão libc do Projeto GNU. libc é o nome de biblioteca padrão para a linguagem C, e é uma biblioteca que coleta partes básicas, como chamadas de sistema. A maioria dos programas escritos em C usa libc. E o glibc é baseado em libc com funcionalidade adicional significativa, e no Linux, que herdou as características do UNIX, o glibc forma a base do sistema Linux. A Glibc está quase totalmente em conformidade com os padrões ISO C, POSIX e Unix98 e possui uma API de internacionalização em vigor. Um grande número de vulnerabilidades foram descobertas no glibc, que tem um histórico tão grande do passado, e você pode consultar a lista de vulnerabilidades, CVE-ID, CWE-ID, Score, etc. no link a seguir. Deve-se notar que muitos foram descobertos em 2019.\nFonte:\nDetalhes CVE GNU » Glibc: Vulnerabilidades de segurança Base de dados de vulnerabilidades Quando uma vulnerabilidade é descoberta, ela é registrada no banco de dados de vulnerabilidades de cada organização que desenvolve e distribui produtos SE. MITRA (Miter) é o nome de uma organização de pesquisa sem fins lucrativos apoiada pelo governo dos EUA, incluindo CERT/CC, HP, IBM, OSVDB, Red Hat e Symantec: \u0026ldquo;Mais de 80 sites de informações sobre grandes vulnerabilidades\u0026rdquo;. Em cooperação com o acima exposto, estamos trabalhando para coletar informações sobre vulnerabilidades e numerar CVEs sem duplicação.\nInstituto Nacional de Padrões e Tecnologia NIST Base de dados de informações de vulnerabilidade gerida por NVD Há. O NVD fornece ao NVD informações detalhadas sobre as informações de vulnerabilidade lançadas pelo CVE. E é caracterizada pelo fato de que o CVSS especificou a pontuação para o perigo.\nA CVE possui um sistema de certificação de compatibilidade CVE, e ferramentas de inspeção de vulnerabilidades e serviços de informações de prevenção de vulnerabilidades, etc., atendem à exibição exata dos números de identificação CVE, atendem a outros requisitos funcionais e solicitam que a MITRE receba a certificação de compatibilidade CVE. .. Uma vez certificado, o logotipo CVE pode ser usado e será listado na lista de sites certificados.\nIniciativas e fontes nacionais CERT.br – publicação de estatísticas sobre serviços vulneráveis e notificações de CVEs aplicáveis a ativos no Brasil. Excelente para monitorar exposição nacional.\nBoletins do CAIS/RNP – alertas periódicos com CVEs, orientações de atualização e correção. Varredura de vulnerabilidade Os scanners de vulnerabilidade permitem que pacotes contendo vulnerabilidades conhecidas sejam incluídos em uma imagem de contêiner ou inspecionados. No entanto, o excesso de crença é uma coisa proibida porque esse tipo de ferramenta não encontra todas as vulnerabilidades. Por outro lado, se os resultados da inspeção relatarem o problema, não é necessariamente um problema que deve ser resolvido imediatamente.\nPor exemplo, as seguintes razões podem ser consideradas:\nCasos que não utilizam os recursos de vulnerabilidade relatados Quando em container, ele move apenas o processo mínimo necessário, portanto, o caso é uma vulnerabilidade sem problemas práticos. Distribuidor Linux (Red Hat etc.) backporting para fornecer um programa de correção Como pode haver falsos positivos e não detecção, é desejável criar uma imagem compacta, como não acreditar demais no scanner de vulnerabilidade e reduzir os pacotes dependentes. Isso reduz a probabilidade de incluir vulnerabilidades e reduz o tempo gasto em falsos positivos.\nScanners de vulnerabilidade Existem vários scanners de código aberto e serviços comerciais, então vou resumir o que parece representativo abaixo \u0026hellip;\nBanco Docker para Segurança O Docker Bench for Security é um script que verifica as melhores práticas gerais apropriadas para implantar um contêiner Docker em produção, todas as inspeções são automatizadas CIS Docker Benchmark v1.2.0. Isso é fornecido pela imagem do contêiner, para que qualquer pessoa possa avaliar facilmente o contêiner docker.\nEssa ferramenta é executada no host do Docker para inspecionar a configuração do host do Docker e os contêineres em serviço e é um exemplo do que você fez no nó mestre do Kubernetes. Scripts Shell são inspecionados para cada disciplina para mostrar resultados.\nPara executar basta seguir o comando abaixo:\n1 2 3 4 5 6 7 8 9 10 docker run --rm --net host --pid host --userns host --cap-add audit_control \\ -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \\ -v /etc:/etc:ro \\ -v /usr/bin/containerd:/usr/bin/containerd:ro \\ -v /usr/bin/runc:/usr/bin/runc:ro \\ -v /usr/lib/systemd:/usr/lib/systemd:ro \\ -v /var/lib:/var/lib:ro \\ -v /var/run/docker.sock:/var/run/docker.sock:ro \\ --label docker_bench_security \\ docker-bench-security O resultado abaixo esperado:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 # Docker Bench for Security v1.6.0 # # Docker, Inc. (c) 2015-2025 # # Checks for dozens of common best-practices around deploying Docker containers in production. # Inspired by the CIS Docker Community Edition Benchmark v1.1.0. # ------------------------------------------------------------------------------ Initializing Sun Jun 22 11:44:51 UTC 2025 [INFO] 1 - Host Configuration [WARN] 1.1 - Ensure a separate partition for containers has been created [NOTE] 1.2 - Ensure the container host has been Hardened [INFO] 1.3 - Ensure Docker is up to date [INFO] * Using 18.06.1, verify is it up to date as deemed necessary [INFO] * Your operating system vendor may provide support and security maintenance for Docker ## A partir daqui, o contêiner é inspecionado para o status de execução [INFO] 5 - Container Runtime [PASS] 5.1 - Ensure AppArmor Profile is Enabled [PASS] 5.2 - Ensure SELinux security options are set, if applicable [WARN] 5.3 - Ensure Linux Kernel Capabilities are restricted within containers [WARN] * Capabilities added: CapAdd=[NET_ADMIN] to k8s_kube-flannel_kube-flannel-ds-amd64-jg7jv_kube-system_13b64578-419d-49c6-a8e4-9f75be3e51de_0 [WARN] 5.4 - Ensure privileged containers are not used [WARN] * Container running in Privileged mode: k8s_kube-proxy_kube-proxy-f9xlx_kube-system_19248345-58a8-48f1-b0f5-b9e67e2a1219_0 [PASS] 5.5 - Ensure sensitive host system directories are not mounted on containers [PASS] 5.6 - Ensure ssh is not run within containers [INFO] 6 - Docker Security Operations [INFO] 6.1 - Avoid image sprawl [INFO] * There are currently: 9 images [INFO] 6.2 - Avoid container sprawl [INFO] * There are currently a total of 19 containers, with 17 of them currently running [INFO] Checks: 105 [INFO] Score: 9 O relatório de Benchmark no meu ambiente destacou que no meu caso atualmente existe nove imagens Docker e dezenove contêineres (dos quais dezessete estão ativos). Isso não é necessariamente um problema, mas sugere revisar se há sobra de artefatos ou instâncias ociosas, pois isso pode acarretar confusão operacional e possíveis brechas.\nCom isso, no meu teste, a pontuação final foi 9 (em um universo de 105 testes avaliáveis). Como referência, quanto mais próximo do total de pontos possível, mais alinhado seu ambiente está com as recomendações do CIS Benchmarks.\nEm suma, seus principais focos de atenção devem ser:\nFortalecer o ambiente do host e segmentar as partições do Docker. Atualizar o Docker para uma versão suportada e com patches de segurança. Remover privilégios de kernel desnecessários dos contêineres, retirando flags como NET_ADMIN e \u0026ndash;privileged. Fazer uma limpeza criteriosa das imagens e instâncias ativas, eliminando o que estiver desnecessário. Essas ações não só elevam sua pontuação, mas aumentam significativamente a robustez do ambiente.\nAnchore (Âncora) O Anchore é uma ferramenta para inspecionar a segurança do contêiner usando dados CVE e políticas definidas pelo usuário.\nAnchor engine é um projeto de código aberto. Os motores âncora fornecem serviços centralizados, como auditoria, análise e certificação de imagens de contêineres. O mecanismo de ancoragem é fornecido como uma imagem de contêiner do Docker e pode ser executado sozinho ou em um ambiente de orquestração, como o Kubernetes ou o Docker Swarm. O usuário pode então usar a API RESTful ou a âncora CLI para operar o mecanismo de âncora.\nA implantação do mecanismo de ancoragem em seu ambiente fará o download da imagem do registro de contêiner e as políticas personalizáveis do usuário analisarão, avaliarão e verificarão as práticas de segurança, conformidade e melhores práticas.\nExemplo de inspeção de vulnerabilidade por motor âncora\nNesse exemplo irei utilizar o Docker-Compose pelo fato de ser mais fácil do que experimentar com o Kubernetes, então pode fazer isso como um método simplificado para testes. No meu ambiente, mover o motor de ancoragem por cerca de uma hora deixou o motor do Docker sem resposta, resultando em uma condição instável que exigia uma reinicialização do Docker. Eu simplesmente não acho que a alocação de memória seja suficiente, mas parece desejável usá-la com o CI/CD no cluster do Kubernetes para uso total.\nPrimeiro de tudo, crie um diretório para copiar o Docker-Compose YAML, execute o contêiner do mecanismo âncora e copie o arquivo Docker-Compose YAML localmente de dentro do contêiner. Em seguida, remova o recipiente usado.\n1 2 3 4 5 6 7 8 9 10 11 12 13 $ mkdir anchor $ cd anchor $ docker pull docker.io/anchore/anchore-engine:latest latest: Pulling from anchore/anchore-engine c8d67acdb2ff: Pull complete Status: Downloaded newer image for anchore/anchore-engine:latest docker.io/anchore/anchore-engine:latest $ docker create --name docker.io/anchore/anchore-engine:latest 47b152d2427862c5ad9c7853b0e32a58e0ae5040224531af7de2e086182cdf65 $ docker cp docker-compose.yaml /anchor/docker-compose.yaml Inicie o sistema do motor de ancoragem com o comando docker-compose\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ ls docker-compose.yaml $ docker-compose pull Pulling anchore-db ... done Pulling engine-catalog ... done Pulling engine-analyzer ... done Pulling engine-policy-engine ... done Pulling engine-simpleq ... done Pulling engine-api ... done $ docker-compose up -d Creating network \u0026#34;anchor_default\u0026#34; with the default driver Creating volume \u0026#34;anchor_anchore-db-volume\u0026#34; with default driver Creating volume \u0026#34;anchor_anchore-scratch\u0026#34; with default driver Creating anchor_anchore-db_1 ... done Creating anchor_engine-catalog_1 ... done Creating anchor_engine-simpleq_1 ... done Creating anchor_engine-api_1 ... done Creating anchor_engine-analyzer_1 ... done Creating anchor_engine-policy-engine_1 ... done Verifique os containers em execução:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #verificando os containers criados e em execução $ docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------------------------------- anchor_anchore-db_1 docker-entrypoint.sh postgres Up 5432/tcp anchor_engine-analyzer_1 /docker-entrypoint.sh anch ... Up (health: starting) 8228/tcp anchor_engine-api_1 /docker-entrypoint.sh anch ... Up (health: starting) 0.0.0.0:8228-\u0026gt;8228/tcp anchor_engine-catalog_1 /docker-entrypoint.sh anch ... Up (health: starting) 8228/tcp anchor_engine-policy-engine_1 /docker-entrypoint.sh anch ... Up (health: starting) 8228/tcp anchor_engine-simpleq_1 /docker-entrypoint.sh anch ... Up (health: starting) 8228/tcp # verificando o status da execução do container $ docker-compose exec engine-api anchore-cli system status Service analyzer (anchore-quickstart, http://engine-analyzer:8228): up Service policy_engine (anchore-quickstart, http://engine-policy-engine:8228): up Service simplequeue (anchore-quickstart, http://engine-simpleq:8228): up Service apiext (anchore-quickstart, http://engine-api:8228): up Service catalog (anchore-quickstart, http://engine-catalog:8228): up Engine DB Version: 0.0.11 Engine Code Version: 0.5.0 Imediatamente após iniciar o mecanismo de ancoragem, não tenho dados de vulnerabilidade, portanto, o download será iniciado. Desta vez, para uma tentativa rápida, escolha os meios simplificados de executar o comando anchor-cli a partir do contêiner lançado no docker-compose.\n1 2 3 4 5 6 7 8 9 $ docker-compose exec engine-api anchore-cli system feeds list Feed Group LastSync RecordCount nvdv2 nvdv2:cves None 0 vulnerabilities alpine:3.10 2025-06-22T12:10:49.756530 1485 vulnerabilities alpine:3.3 None 0 vulnerabilities alpine:3.4 None 0 vulnerabilities alpine:3.5 None 0 vulnerabilities alpine:3.6 None 0 No meu ambiente, completei o download de dados de vulnerabilidade em cerca de uma hora. Este mecanismo de ancoragem é uma versão gratuita, portanto, o suporte não inclui nada que exija um contrato de assinatura, como o RHEL.\nVou listar um relatório sobre a inspeção de vulnerabilidade das imagens de contêiner do NGINX que construí há alguns meses. Um URL com um ID de vulnerabilidade e detalhes são exibidos. Esta é certamente uma ferramenta útil. Se você pode obter um relatório de vulnerabilidade como um comando, anchore-cli image wait ao fazer isso, depois de registrar a imagem, você pode esperar até que a inspeção de vulnerabilidade seja concluída.\n1 2 3 4 5 6 7 $ docker-compose exec engine-api anchore-cli image vuln docker.io/luksjobs/web-nginx:11 all Vulnerability ID Package Severity Fix CVE Refs Vulnerability URL CVE-2018-20843 libexpat1-2.2.0-2+deb9u1 High 2.2.0-2+deb9u2 https://security-tracker.debian.org/tracker/CVE-2018-20843 CVE-2019-11068 libxslt1.1-1.1.29-2.1 High 1.1.29-2.1+deb9u1 https://security-tracker.debian.org/tracker/CVE-2019-11068 CVE-2019-1547 libssl1.1-1.1.0j-1~deb9u1 Low 1.1.0l-1~deb9u1 https://security-tracker.debian.org/tracker/CVE-2019-1547 CVE-2019-11038 libgd3-2.2.4-2+deb9u4 security-tracker.debian.org/tracker/CVE-2007-5686 Material de referência\nAnálise de Contêineres de Ancoragem, https://docs.anchore.com/current/ Âncora/motor de ancoragem GitHub https://github.com/anchore/anchore-engine Considerações finais Todos esses processos que fizemos de forma manual, para testes podem ser incorporados em uma verificação de vulnerabilidade no pipeline do CI/CD, os problemas podem ser descobertos cedo e resolvidos. Após a conclusão da etapa de compilação, execute uma verificação e um relatório de vulnerabilidade. Se uma vulnerabilidade grave for descoberta, implemente medidas de vulnerabilidade sem prosseguir para a próxima etapa de teste, como um \u0026ldquo;breaker\u0026rdquo; da pipeline, exibindo o \u0026ldquo;exit code 1\u0026rdquo; ou algo do tipo. Alguns dos scanners acima também podem realizar um teste de vulnerabilidade a partir da CLI e encerrar abruptamente a etapa com o código de terminação quando uma vulnerabilidade significativa é descoberta.\n","date":"2025-06-22T00:00:00Z","image":"https://i.imgur.com/bwPctrO.jpeg","lang":"pt-br","permalink":"https://luks.dev.br/p/introdu%C3%A7%C3%A3o-ao-scan-de-vulnerabilidades-em-containers-docker-utilizando-o-sast/","title":"Introdução ao Scan de Vulnerabilidades em Containers Docker utilizando o SAST"},{"content":"Visão Geral Imagine a cena: você está desenvolvendo aquela funcionalidade incrível, focado em entregar valor rápido. O código está \u0026ldquo;quase\u0026rdquo; pronto, passa nos testes unitários e de integração\u0026hellip; push! Merge Request criado! Tudo lindo, certo? 😊\nNem sempre 🫤. Por trás da funcionalidade ou das funcionalidades, podem existir falhas de segurança esperando para serem descobertas – infelizmente, muitas vezes, por pessoas mal-intencionadas. É aí que entram as ferramentas de segurança, e mais especificamente, o SAST (Static Application Security Testing).\nA grande sacada? Encontrar esses problemas cedo. Encontrar uma vulnerabilidade durante o desenvolvimento ou na pipeline de CI custa infinitamente menos para corrigir do que descobri-la em produção, talvez depois que um incidente já aconteceu. Integrar o SAST à sua pipeline de CI/CD, como a do GitLab (repositório utilizado como exemplo nesse post), significa que cada commit, cada Merge Request, pode ser automaticamente verificado, fornecendo feedback rápido para o time de desenvolvimento.\n🛸 Semgrep: Um SAST Diferente (e Ótimo para CI) Existem várias ferramentas de SAST por aí, algumas mais complexas, outras mais simples. O Semgrep se destaca por alguns motivos que o tornam um candidato ideal para pipelines de CI:\nVelocidade: Ele é rápido. Muito rápido. Isso é vital para não travar sua pipeline. Facilidade de Uso e Regras Flexíveis: O Semgrep usa um motor de padrões poderoso e relativamente fácil de entender. Ele vem com um vasto conjunto de regras prontas (o registro de regras do Semgrep) para várias linguagens e frameworks, e criar regras customizadas é surpreendentemente acessível. Precisão: Embora nenhum SAST seja perfeito (falsos positivos acontecem), o Semgrep costuma ter uma taxa de falsos positivos menor que ferramentas mais antigas, pois entende melhor a estrutura do código. Suporte a Múltiplas Linguagens: Ele suporta uma gama enorme de linguagens populares, o que é ótimo se você trabalha com um stack variado. O Semgrep (https://semgrep.dev) não tenta ser um scanner de segurança \u0026ldquo;caixa preta\u0026rdquo; gigante. Ele é mais como um \u0026ldquo;grep inteligente para código\u0026rdquo;, focado em encontrar padrões problemáticos de forma eficiente.\nDisponível em Open Source e Free Tier A versão open source do Semgrep está disponível no GitHub (https://github.com/semgrep/semgrep?tab=readme-ov-file) e o Free Tier pode ser usada gratuitamente por qualquer pessoa através do site oficial do Semgrep (https://semgrep.dev). Com ela, é possível:\nRodar regras de segurança e boas práticas localmente; Criar regras personalizadas para o seu código; Integrar com CI/CD pipelines sem custo; Contribuir com a comunidade criando ou ajustando regras. Essa abordagem democratiza o acesso à segurança no desenvolvimento, tornando o Semgrep uma excelente escolha para projetos pessoais, startups ou empresas que estão começando a investir em práticas de DevSecOps.\nFluxo de Scanner SAST na Pipeline Integrar o job de SAST (Static Application Security Testing) na pipeline de CI/CD imediatamente após o commit é uma prática essencial para a segurança do software. Ao identificar vulnerabilidades logo no início, evitamos que elas avancem para fases mais onerosas do ciclo de vida do desenvolvimento de software (SDLC), como QA e produção, onde a correção se torna exponencialmente mais cara e complexa.\nEste é, sem dúvida, um dos momentos mais estratégicos para fortalecer a segurança do código. A execução do SAST antes da revisão e aprovação do merge request (ou pull request) permite que:\nRevisores analisem um código já pré-validado contra potenciais falhas de segurança. A equipe de desenvolvimento pode aplicar e reforçar políticas de segurança mais rigorosas, como \u0026lsquo;impedir o merge caso existam vulnerabilidades críticas\u0026rsquo;. Integrando Semgrep (Cloud Free Tier) no GitLab CI Para reproduzir os cenários abordados neste artigo, você só precisará de uma conta gratuita no GitLab e no Semgrep. No entanto, é importante destacar que todas as funcionalidades que exploraremos também estão disponíveis no GitLab Community Edition (CE). Nesse exemplo, utilizaremos a versão \u0026ldquo;Free Tier\u0026rdquo; do Semgrep Cloud, e faremos a integração em nossa pipeline de CI no Gitlab.\n🦊 Repositório de exemplo: https://gitlab.com/luksjobs/dotnet-unit-test/-/blob/master/.gitlab-ci.yml?ref_type=heads\nAgora, a parte prática! Como fazemos para o Semgrep se tornar parte do seu fluxo de desenvolvimento no GitLab? Vamos configurar um job no seu arquivo .gitlab-ci.yml. Vamos criar um novo stage e um job dedicado para a análise de segurança com Semgrep.\nPasso: Configurar o Job do Semgrep Agora, vamos definir o job que vai executar o Semgrep. Usaremos a imagem Docker oficial do Semgrep, que já vem com tudo o que precisamos.\n1 2 3 4 5 6 7 8 9 10 11 12 semgrep_sast: image: semgrep/semgrep script: semgrep ci rules: - if: $CI_PIPELINE_SOURCE == \u0026#34;web\u0026#34; # allow triggering a scan manually from the gitlab UI - if: $CI_MERGE_REQUEST_IID # scan on merge request events - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # scan on push events to default branch variables: SEMGREP_APP_TOKEN: $SEMGREP_APP_TOKEN # To configure MR comments on gitlab.com, see https://semgrep.dev/docs/semgrep-cloud-platform/gitlab-mr-comments/#steps-to-set-up-mr-comments # GITLAB_TOKEN: $PAT Passo: Configurar token de CI Nas variáveis de \u0026ldquo;CI/CD\u0026rdquo; do seu projeto no GitLab, será necessário criar a variável: \u0026ldquo;SEMGREP_APP_TOKEN no qual o valor, será o token criado pelo snippet do Semgrep, assim quando você se autenticar na plataforma e criar um novo projeto de integração com o CI/CD do Gitlab, um token será criado.\nPasso: Executar a Pipeline no Gitlab Agora que já temos tudo configurado em nosso template do gitlab e o token definido nas variáveis do CI/CD e se tudo ocorrer bem, a pipeline será executada e logo em seguida o Semgrep aplicará as policies de segurança dependendo do tipo de Stack utilizada em seu projeto.\nInterpretando os Resultados via Logs do Gitlab Uma vez que a pipeline rodar e o job semgrep_sast for concluído (com sucesso ou falha), onde você vê os problemas encontrados?\nLogs do Job: Você sempre pode ver a saída completa do Semgrep diretamente nos logs do job na interface do GitLab. Aba \u0026ldquo;Security\u0026rdquo; na Pipeline: Se você usou artifacts: reports: sast: gl-sast-report.json, o GitLab processará este arquivo e exibirá um resumo na aba \u0026ldquo;Security\u0026rdquo; da página da pipeline. Widget de Segurança no Merge Request: Onde a mágica realmente acontece! No Merge Request, abaixo das informações de commit e pipelines, o GitLab mostrará um widget de segurança comparando os resultados do branch de origem com o branch de destino (default). Ele destacará novas vulnerabilidades introduzidas pelo seu código e vulnerabilidades que foram resolvidas. Isso fornece um feedback direto para o desenvolvedor revisando o MR. Interpretando os Resultados via Dashboard: Como executamos essa pipline utilizando a solução do \u0026ldquo;Free Tier\u0026rdquo; do Semgrep Cloud, então conseguimos verificar os resultados via dashboard, através do seu painel do seu projeto no: \u0026ldquo;https://semgrep.dev\u0026rdquo;.\nNo meu caso, como é uma aplicação Dotnet simples, nesse scan, não foram encontrados vulnerabilidades porém isso ainda assim não é uma garantia de ausência total de vulnerabilidades, mas indica que o Semgrep, com as regras e escopo aplicados, não encontrou padrões problemáticos. É um ponto de partida positivo, mas complemente com outras formas de teste de segurança (DAST, testes manuais, etc.), falarei com mais detalhes sobre esse tema em outro post 😁\nConsiderações Finais Integrar o Semgrep na sua pipeline de CI do GitLab é um passo proativo e relativamente simples para fortalecer a segurança das suas aplicações. Ao automatizar a varredura de código em cada alteração, você empodera seu time de desenvolvimento a encontrar e corrigir vulnerabilidades antes que elas se tornem um problema sério em produção.\nSe você é desenvolvedor, não encare o SAST como um obstáculo, mas sim como um aliado que te dá feedback rápido e ajuda a manter a qualidade e a segurança do seu código em alta. Com Semgrep e GitLab CI trabalhando juntos, você está construindo um fluxo de trabalho mais seguro e confiável, commit por commit.\nExperimente, ajuste as regras às suas necessidades e veja a diferença que uma análise de segurança contínua pode fazer!\n","date":"2025-04-21T00:00:00Z","image":"https://i.imgur.com/D5zEiSi.png","lang":"pt-br","permalink":"https://luks.dev.br/p/varrendo-o-c%C3%B3digo-automatizando-sast-com-semgrep-e-gitlab-ci/","title":"Varrendo o Código: Automatizando SAST com Semgrep e GitLab CI"},{"content":"No GitLab CI/CD, tanto artifacts quanto cache são recursos que ajudam no gerenciamento de arquivos durante as etapas de uma pipeline. Apesar de terem funcionalidades parecidas em alguns casos, existem diferenças importantes em como eles funcionam e para que são usados. Entender essas diferenças permite utilizá-los de forma mais eficiente para acelerar suas pipelines.\n🦊 Repositório prático utilizado no Gitlab como referência: Lucas Oliveira: Artifact vs Cache 📦 Artifacts Os artifacts são arquivos ou diretórios que você deseja preservar após a execução de um job. Esses arquivos podem ser disponibilizados para outros jobs na mesma pipeline, para download manual no GitLab ou armazenados por um período específico.\nPrincipais Características:\nSão usados para compartilhar arquivos entre jobs ou para serem salvos como resultado final de um processo. São armazenados de forma temporária, de acordo com o tempo definido no parâmetro expire_in. Podem ser baixados manualmente na interface do GitLab. São sempre ligados a uma execução específica de um job/pipeline. Quando usar artifacts:\nPara compartilhar resultados intermediários, como binários gerados em uma etapa de build. Para salvar relatórios, logs ou outros arquivos que precisam ser analisados após a execução da pipeline. Em pipelines que requerem aprovação manual, para os arquivos serem inspecionados antes de prosseguir. Exemplo de uso:\nArtefato criado na Pipeline:\nArtifact Criado (dist/): O artifact contém arquivos gerados durante o job (neste caso, o diretório dist/ com o build da aplicação). Ele é usado para transferir resultados de um job para outro (via dependencies) ou para ser baixado manualmente após o término do pipeline. Diferentemente do cache, o artifact é específico da execução do job e geralmente tem um prazo de expiração definido. 📦 Cache O cache é usado para armazenar arquivos reutilizáveis entre diferentes pipelines ou jobs dentro da mesma pipeline. Esses arquivos geralmente incluem dependências, bibliotecas, pacotes ou qualquer coisa que possa ser reutilizada para evitar reprocessamento.\nPrincipais Características:\nFocado em arquivos reutilizáveis (como dependências de linguagens de programação). Armazenado por runner, sendo reutilizável entre pipelines e jobs (se configurado corretamente). Pode ser compartilhado entre diferentes projetos (quando o cache é compartilhado no mesmo runner). Quando usar cache:\nPara economizar tempo na instalação de dependências em projetos que utilizam ferramentas como npm, Maven, Composer, pip, etc. Em projetos que geram ou consomem arquivos pesados em várias execuções, como imagens base ou arquivos de configuração. Exemplo de uso:\nCache extraído e utilizado por outro Job:\nCache Mantido (node_modules/): No nosso caso, esse cache foi utilizado no Job do \u0026ldquo;Build\u0026rdquo; e consumido pelo job seguinte: \u0026ldquo;Test\u0026rdquo;. O cache armazena arquivos reutilizáveis, como dependências instaladas (neste caso, node_modules/), para acelerar a execução de etapas futuras. Ele é compartilhado entre jobs e pipelines (se configurado corretamente), reduzindo o tempo necessário para reinstalar pacotes. Principais Diferenças Aspecto Artifacts Cache Finalidade Compartilhar arquivos entre jobs ou salvar resultados. Reutilizar arquivos para acelerar jobs repetidos. Persistência Relacionado a uma execução específica. Reutilizável entre pipelines e jobs. Local de Armazenamento Armazenado pelo GitLab no servidor. Armazenado no runner (ou cache compartilhado). Expiração Configurável com expire_in. Expiração definida globalmente ou conforme configuração do runner. Exemplo de Uso Salvar binários ou relatórios. Cachear dependências ou bibliotecas. Como usar ambos para acelerar a pipeline Cache para dependências:\nUse o cache para armazenar dependências que precisam ser instaladas repetidamente em jobs. Isso reduz significativamente o tempo de instalação de pacotes e bibliotecas. Exemplo: Armazenar o diretório dist, node_modules ou .m2 (Maven) para reutilização entre builds.\nArtifacts para resultados intermediários:\nUse artifacts para compartilhar resultados entre jobs. Isso evita a necessidade de regenerar arquivos ou reexecutar tarefas. Exemplo: Gerar um binário na etapa de build e disponibilizá-lo para a etapa de testes.\nCombinação eficiente:\nConfigure cache para armazenar arquivos reutilizáveis ao longo do tempo (como dependências). Use artifacts para os arquivos que precisam ser compartilhados entre jobs específicos dentro da mesma pipeline. Exemplo de pipeline completa:\nConsiderações Finais Ao usar ambos corretamente, você reduz o tempo de execução da pipeline e evita retrabalho, tornando seu processo mais eficiente.\n","date":"2024-12-01T00:00:00Z","image":"https://i.imgur.com/ki34PvF.png","lang":"pt-br","permalink":"https://luks.dev.br/p/otimizando-sua-pipeline-entenda-a-diferen%C3%A7a-entre-artifacts-e-cache-no-gitlab/","title":"Otimizando sua Pipeline: Entenda a diferença entre Artifacts e Cache no GitLab"},{"content":"No mundo do desenvolvimento de software, garantir a qualidade do código é fundamental. É aí que entra o SonarQube, uma ferramenta poderosa que nos ajuda a analisar e aprimorar nossos programas. Se você está em busca de uma maneira eficiente de monitorar a qualidade do seu código e avaliar a cobertura de testes, você está no lugar certo! Neste tutorial, vamos explorar como integrar o SonarQube com um aplicativo feito em Node.js e analisar os resultados dos testes de cobertura.\nO que é o SonarQube? Para quem ainda não conhece, o SonarQube é uma ferramenta de análise de código SAST (Static application security testing) que fornece insights valiosos sobre a qualidade do seu software. Ele examina seu código-fonte e oferece relatórios detalhados sobre potenciais problemas, como bugs, vulnerabilidades e código duplicado. Além disso, o SonarQube é excelente para medir a cobertura de testes, ajudando a garantir que seu código esteja bem testado e robusto.\nPasso a Passo: Integrando SonarQube com um Aplicativo Node.js Nesse post vou simplificar o processo de configuração usando o Docker, que facilita muito a implementação e a gestão das dependências.\nClonando o Projeto de Exemplo 👌 Para começar, você pode clonar o repositório do meu projeto de amostra feito com Node.js, isso fornecerá uma base sólida para que possamos aplicar o SonarQube e ver a análise em ação. O repositório está disponível aqui no meu repositório do: GitHub.\nConfigurando o SonarQube com Docker Para otimizar o processo de configuração do SonarQube, utilizaremos imagens Docker. O Docker permite criar ambientes isolados e replicáveis de forma rápida e fácil. Aqui está um resumo do que você precisa fazer:\nBaixe e execute a imagem do SonarQube: Utilizaremos uma imagem Docker oficial para garantir que nossa configuração seja a mais atual e estável possível: 1 docker run -d --name sonarqube -p 9000:9000 sonarqube Configure o SonarQube: Com o SonarQube em funcionamento na porta 9000 localhost:9000, você precisará configurá-lo para integrar com seu projeto Node.js. Aqui, nosso servidor SonarQube está em execução na porta 9000. Agora iremos criar um nome de projeto e uma chave de projeto. Em seguida realize o login com as credênciais base login: \u0026ldquo;admin\u0026rdquo; \u0026amp; senha: \u0026ldquo;admin\u0026rdquo;, clique em seguida redefina sua senha e logo após criaremos o nosso primeiro projeto na opção \u0026ldquo;Create a local project\u0026rdquo;:\nEm seguida, vamos gerar um token que o nosso aplicativo irá usar para se comunicar com o servidor do SonarQube:\nE agora iremos selecionar qual é o tipo de Stack que queremos que o SonarQube realize o scan:\nConfigurando a Conectidade da Nossa Aplicação Node com o SonarQube Primeiro, precisamos adicionar um novo arquivo chamado sonar-project.js, com esse arquivo, vamos definir o ponto de comunicação da nossa aplicação em nodo com o sonarqube, arquivo de teste unitário, chave do projeto e o token que geramos anteriormente:\nExecutando o Aplicativo Precisamos agora instalar as dependências do nosso projeto em NodeJS e para isso, será necessário executar o npm, como no comando abaixo:\n1 npm install Com as dependências instaladas, agora podemos rodar o nosso primeiro Scan no SonarQube com o comando abaixo:\n1 npm run sonar Aguarde o Scanner do Sonar finalizar, quando finalizado, basta agora acessar a interface do projeto e lá estará toda a análise feita pela SonarQube e a cobertura de código:\nRealizando o teste de cobertura Agora, para testarmos a nossa aplicação, faremos uma rápida análise de cobertura, para isso, será necessário executar nossa aplicação em container e o banco de dados \u0026ldquo;mongodb\u0026rdquo; executando o seguintes comandos:\n1 docker compose up -d Com o banco de dados e nossa aplicação em execução, poderemos agora executar nosso teste de cobertura:\n1 npm run test Com isso, será feito um teste de cobertura e logo em seguida gerará um diretório chamado de \u0026ldquo;coverage\u0026rdquo; que será exportado para o SonarQube quando realizado um novo scan.\n1 npm run sonar Espero que este artigo tenha sido útil para você. Se você tiver alguma dúvida ou comentário, sinta-se à vontade para deixar um comentário abaixo.\n","date":"2024-09-14T00:00:00Z","image":"https://buddy.works/guides/covers/sonarqube/sonarqube-share.png","lang":"pt-br","permalink":"https://luks.dev.br/p/como-integrar-sonarqube-em-projetos-node.js-an%C3%A1lise-de-c%C3%B3digo-e-cobertura-de-testes/","title":"Como Integrar SonarQube em Projetos Node.js: Análise de Código e Cobertura de Testes"},{"content":"Ontem eu tive a oportunidade incrível de participar do 1º Meetup Cloud Native RN no Sebrae, evento que foi organizado pelo Luan Carlos, Emídio Neto e Felipe Dantas no qual em sua estreia teve como principais palestras com temas sobre: \u0026ldquo;Concorrência x Paralelismo: da teoria à prática\u0026rdquo; e \u0026ldquo;O papel da orquestração de containers em redes 5G\u0026rdquo;. Esse evento foi uma experiência enriquecedora, repleta de insights valiosos proporcionados pelos palestrantes Mauro Carvalho e Ramon Fontes, sem falar no networking, conhecer gente da mesma área que mora no mesmo estado que você é sempre motivante! :)\nA palestra do Mauro Carvalho, Software Engineer na AB InBev, foi esclarecedora ao abordar a diferença entre concorrência e paralelismo, e como aplicá-los de forma eficaz na prática. Entender as nuances desses conceitos é fundamental para otimizar o desempenho e a eficiência em projetos de software, e as dicas práticas compartilhadas pelo Mauro certamente serão úteis em meus futuros projetos.\nJá a apresentação do Ramon Fontes, PhD Professor na UFRN e Contribuidor do Kernel Linux, foi fascinante ao discutir o papel crucial da orquestração de containers nas redes 5G. Com a crescente demanda por conectividade rápida e confiável, compreender como os containers são orquestrados para suportar as complexidades das redes 5G é essencial. A expertise do Ramon Fontes trouxe uma visão abrangente e aprofundada sobre esse tema tão relevante no cenário atual.\nTer um grupo como o \u0026ldquo;CNCF | Cloud Native Community Group RN\u0026rdquo; trazendo palestras sobre tecnologia e o mundo cloud é importante porque proporciona atualização profissional, networking, aprendizado contínuo, compartilhamento de experiências, promoção da comunidade, incentivo à inovação e visibilidade para empresas e projetos. Esses eventos mantêm os profissionais atualizados, permitem conexões valiosas, oferecem oportunidades de aprendizado, compartilham insights práticos, fortalecem a comunidade local, estimulam a criatividade e destacam empresas e projetos relevantes.\nAgradeço à comunidade do Cloud Native RN por promover eventos tão pertinentes e enriquecedores como esse, que contribuem significativamente para o desenvolvimento profissional e a atualização de conhecimentos.\n","date":"2024-05-28T00:00:00Z","image":"https://i.imgur.com/NmxQauj.jpeg","lang":"pt-br","permalink":"https://luks.dev.br/p/1%C2%BA-meetup-cloud-native-rn/","title":"1º Meetup Cloud Native RN"},{"content":"Fala pessoal, tudo bem com vocês!? Espero que sim! 😄 Então, nesse novo post irei falar um pouco sobre o uso do Terraform que permite a codificação da configuração da infraestrutura, proporcionando a vantagem conhecida como Infrastructure as Code (IaC). Conforme você avança no uso do Terraform, surge a necessidade de pensar, de maneira semelhante ao desenvolvimento de software, \u0026lsquo;Como lidar com informações confidenciais sem escrevê-las diretamente no código ou em .env ?\u0026rsquo;\nNeste artigo, abordaremos diversos tópicos, como métodos e considerações ao lidar com informações confidenciais no Terraform.\nAo escrever este artigo, percebi que a abordagem se assemelha ao conteúdo da seguinte página, então tentarei apresentar uma perspectiva diferente sempre que possível.\nHow to Handle Secrets in Terraform | Blog Git Guardian\nPontos Básicos a Serem Observados Não Inclua Informações Confidenciais diretamente nos Arquivos TF Não deve haver inclusão direta de informações confidenciais, como senhas, nos arquivos *.tf Embora seja uma prática óbvia, vale a pena mencionar.\nInformações Confidenciais Podem Estar Presentes nos Arquivos de Estado! Mais adiante, apresentarei algumas maneiras de evitar a inclusão de informações confidenciais nos arquivos *.tf no entanto, na maioria dos métodos, essas informações confidenciais podem ainda estar presentes nos arquivos de estado (terraform.tfstate).\nPara mais detalhes, consulte a seção \u0026lsquo;Sensitive Values\u0026rsquo; na seguinte página:\nSecure Storage of Variables | Hashicorp Blog\nPrincipais Métodos para Lidar com Informações Confidenciais Agora que entendemos os pontos básicos, vamos explicar alguns métodos gerais para lidar com informações confidenciais. Detalhes sobre como utilizá-los serão discutidos na próxima seção.\nMétodo 1: Externalização por meio de Variáveis de Ambiente ou `Arquivos Externos`` O primeiro método envolve o fornecimento de informações confidenciais através dos seguintes meios:\nVariáveis de ambiente (enviadas através de variáveis de ambiente com o nome de TF_VAR_*) Arquivos externos (*.tfvars) Embora seja fácil de implementar, distribuir variáveis de ambiente ou arquivos externos de alguma forma pode apresentar desafios:\n✘: As informações distribuídas não podem ser recuperadas. Portanto, se uma pessoa com informações confidenciais sair da equipe, pode ser necessário alterar as informações confidenciais (por exemplo, senhas). Além disso, este método escreve informações confidenciais nos arquivos de estado (state files).\nMétodo 2: Criptografar Arquivos O segundo método envolve a criptografia de arquivos que contêm informações confidenciais. Apenas os arquivos criptografados são commitados no controle de código-fonte.\nVamos listar os prós e contras gerais deste \u0026ldquo;Método 2\u0026rdquo;:\n✔ As informações confidenciais são versionadas após serem criptografadas. É fácil desfazer as alterações. Evita esquecimentos de configurações. × É necessário executar comandos para criptografar e descriptografar durante o processo. × Os arquivos descriptografados são armazenados localmente, apresentando um problema semelhante ao Método 1 se um funcionário sair. Neste método, a gestão da chave usada na criptografia é crucial. Abaixo, apresentamos métodos ruins, não tão bons, e por que são inadequados.\n× Commitar o arquivo de chave privada no controle de código-fonte. Razão do × (pró) Isso anula o propósito da criptografia. × Armazenar o arquivo de chave privada em outro repositório ou em uma unidade compartilhada com acesso restrito. Razões do \u0026ldquo;×\u0026rdquo; (contras) - O arquivo de chave privada ainda é armazenado localmente e pode exigir mudanças caso alguém com a chave saia da equipe. Um bom método é o uso de serviços de gerenciamento de chaves, como o AWS Key Management Service (KMS) ou o Cloud Key Management do GCP. Os prós e contras do KMS e CKM são listados abaixo:\nAWS Key Management Service (Prós e Contras) - https://aws.amazon.com/pt/kms/\n✔ O arquivo de chave privada é armazenado na AWS e não pode ser baixado. ✔ Rotação de chaves é possível. ✔ O acesso à chave pode ser gerenciado por usuários IAM e funções. × Incorre em custos mínimos. GCP Cloud Key Management (Prós e Contras) - https://cloud.google.com/security/products/security-key-management\n✔ Grenciamento de chave na nuvem rápido, centralizado e escalonável ✔ Cumpre com as necessidades de conformidade, privacidade e segurança ✔ Aprove ou recuse qualquer solicitação das suas chaves de criptografia com base em justificativas claras e precisas. × Incorre em custos mínimos. Outros fornecedores, como Azure Key Vault e Hashicorp Vault, oferecem funcionalidades semelhantes.\nLembre-se de que este método também escreve informações confidenciais nos arquivos de estado.\nMétodo 3: Armazenamento em Serviços Externos como AWS Secrets Manager O terceiro método envolve o armazenamento de informações confidenciais em serviços externos, como AWS Secrets Manager ou GCP Secret Manager, e a leitura dessas informações pelo Terraform ao criar recursos. Alguns serviços específicos incluem:\u0026quot;\nServiço AWS Secrets Manager AWS Systems Manager Parameter Store GCP Secrets Manager HashiCorp Vault Em outro post, falei um pouco sobre o Vault: \u0026ldquo;Utilizando o Vault para Gerenciar Segredos em Aplicações NodeJS\u0026rdquo;\nNo momento, com base na visualização da seguinte página, parece que o Azure não possui um serviço similar.\nAlém disso, a existência de dois serviços semelhantes na AWS é uma característica comum da AWS. Sobre as diferenças e o uso desses dois serviços, uma busca fornecerá uma variedade de informações.\nAgora, vamos listar os prós e contras deste método:\n✔ As informações não são armazenadas localmente. ✔ O serviço oferece várias funcionalidades úteis, como: Funcionalidade para alterar informações confidenciais periodicamente. Capacidade de recuperar informações confidenciais não apenas do Terraform, mas também de aplicativos e por final: Logs de auditoria.\n✔ O acesso às informações confidenciais pode ser gerenciado por usuários IAM e funções. × As informações confidenciais não são versionadas (*), sendo necessário registrá-las manualmente (principalmente via UI). × Gera um custo mínimo. É importante observar que, ao usar o Secrets Manager, embora o versionamento não seja feito pelo Git, o Secrets Manager possui sua própria funcionalidade de controle de versão. Consulte a documentação para obter mais detalhes.\nAlém disso, este método também escreve informações confidenciais nos arquivos de estado.\nMétodo 4: Não Lidar com Informações Confidenciais no Terraform Você pode pensar: \u0026lsquo;Mas este é um artigo de blog com o título \u0026lsquo;Lidando com Informações Confidenciais no Terraform\u0026rsquo;, por que estamos falando sobre isso?\u0026rsquo; Aquilo que estamos apresentando aqui é mais precisamente:\n\u0026lsquo;Não lidar diretamente com informações confidenciais no Terraform\u0026rsquo;\nQuando você especifica informações confidenciais, como senhas, ao criar recursos com o Terraform, mesmo que sejam obtidas de fora, seja através de variáveis de ambiente ou do Secrets Manager, elas serão gravadas nos arquivos de estado. Embora, em geral, isso não seja um problema se for gerenciado com segurança usando o estado remoto, dependendo dos requisitos de segurança, os métodos de 1 a 3 podem não ser adequados.\nO Método 4, basicamente, consiste em:\nArmazenar informações confidenciais em serviços como o Secrets Manager. Ao criar recursos com o Terraform, especificar as informações confidenciais de forma adequada. Após a criação dos recursos, alterar as informações confidenciais de outra forma. Embora isso envolva um pouco de trabalho, usando null_resource ou local-exec do Terraform, é possível iniciar um script separado após a conclusão da criação de recursos para recuperar e definir valores a partir do Secrets Manager.\nMétodos Específicos: A seguir, apresentamos comandos específicos. Os métodos 1 a 3 são detalhados no blogpost mencionado anteriormente pela Gruntwork - Using the Library, então vamos explicar brevemente.\nDetalhes do Método 1: Externalização por meio de Variáveis de Ambiente ou Arquivos Externos {#metodo-1}\nCrie um arquivo variables.tf da seguinte maneira:\u0026quot;\nUtilizando Variáveis de Ambiente: Se estiver utilizando variáveis de ambiente, configure conforme abaixo e logo após execute \u0026lsquo;$ terraform apply\u0026rsquo; normalmente:\n1 2 export TF_VAR_db_username=\u0026#34;luksjobs\u0026#34; export TF_VAR_db_password=\u0026#34;suasenha123\u0026#34; Utilizando Arquivos Externos: Se estiver utilizando arquivos externos, por exemplo, crie um arquivo chamado variables.tfvars da seguinte maneira. Lembre-se de adicionar este arquivo ao .gitignore:\n1 2 db_username = \u0026#34;luksjobs\u0026#34; db_password = \u0026#34;suasenha123\u0026#34; Em seguida, execute o seguinte comando:\n1 terraform apply -var-file=\u0026#34;variables.tfvars\u0026#34; Detalhes do Método 2: Criptografar Arquivos (utilizando KMS): {#metodo-2}\nNeste método, explicarei o uso do KMS, mas a abordagem é semelhante com outros serviços.s\nCrie um arquivo secrets.yaml em texto simples e adicione ao .gitignore. 1 2 db_username = \u0026#34;luksjobs\u0026#34; db_password = \u0026#34;suasenha123\u0026#34; Crie uma chave no AWS KMS (manualmente ou usando o Terraform) e anote o ID dessa chave. Execute o comando abaixo para criptografar o arquivo secrets.yaml. Obs: é importante ter o console (CLI) da AWS instalado, caso esteja executando esses passos do seu computador local. Baixar o AWS Command Line Interface.\n1 2 3 4 5 6 7 aws kms encrypt \\ --key-id \u0026lt;ID da Chave KMS\u0026gt; \\ --region \u0026lt;REGIÃO AWS\u0026gt; \\ --plaintext fileb://secrets.yaml \\ --output text \\ --query CiphertextBlob \\ \u0026gt; secrets.yaml.encrypted Agora, utilize o Terraform para decifrar o arquivo e criar o recurso: Para decifrar manualmente via bash, utilize o seguinte comando: 1 2 3 4 5 6 aws kms decrypt \\ --key-id \u0026lt;ID da Chave KMS\u0026gt; \\ --region \u0026lt;REGIÃO AWS\u0026gt; \\ --ciphertext-blob fileb://\u0026lt;(base64 -d ./secrets.yaml.encrypted) \\ --output text \\ --query Plaintext Lembrando que a utilização do base64 é crucial.\nDetalhes do Método 3: Armazenar em AWS Secrets Manager: {#metodo-3} Registre as informações confidenciais no AWS Secrets Manager em formato YAML ou JSON. Anote o nome do segredo ao registrar.\nCrie o seguinte arquivo no Terraform: Detalhes do Método 4: Não Lidar com Informações Confidenciais no Terraform: {#metodo-4}\nVeja os detalhes neste post do Google Práticas recomendadas para usar o Terraform Aqui, podem ser considerados dois métodos de implementação para o update_password.py:\nDeixar a senha no Secrets Manager antecipadamente Configurar o Secrets Manager antecipadamente e salvar a senha Obter a senha do Secrets Manager no script Alterar a senha do banco de dados Gerar a senha no script Gerar a senha no script novamente Gerar a senha do banco de dados no script O script salva essa senha no Secrets Manager Geralmente, essa abordagem é mais conveniente, especialmente para rotações automáticas. Outros tópicos: random_password No Terraform, há o random_password, que, como o nome sugere, gera senhas aleatórias. No entanto, as senhas geradas por ele também são gravadas no arquivo de estado (state file).\nPara obter detalhes sobre a implementação, consulte a seguinte página:\nTerraform password hack. A simple way to create passwords in… | por Marcelo Clavel | Medium\nVale ressaltar que nesta página é usado o random_string, que, conforme mencionado no final da página, apresenta o problema de exibir as senhas geradas na tela. Entretanto, esse problema foi resolvido na implementação subsequente do random_password.\nFlag sensitive A partir do Terraform 0.14, é possível adicionar a flag sensitive aos recursos. Configurando isso, as saídas do terraform plan ou terraform apply não incluirão os valores sensíveis. Para obter mais informações, consulte a seguinte página:\nTerraform 0.14 Adds the Ability to Redact Sensitive Values in Console Output\nConclusão O Terraform é uma ferramenta poderosa para gerenciar infraestrutura como código, mas pode ser um desafio lidar com informações confidenciais de forma segura. Neste artigo, exploramos várias abordagens para lidar com informações confidenciais no Terraform, incluindo o uso de variáveis, módulos e provedores. Também discutimos algumas considerações importantes ao trabalhar com informações confidenciais no Terraform, como criptografia e controle de acesso.\nEspero que este artigo tenha sido útil para você. Se você tiver alguma dúvida ou comentário, sinta-se à vontade para deixar um comentário abaixo.\n","date":"2024-01-28T00:00:00Z","image":"https://i.imgur.com/xs0WUZK.png","lang":"pt-br","permalink":"https://luks.dev.br/p/protegendo-secrets-no-terraform-estrat%C3%A9gias-eficazes-para-o-gerenciamento-de-informa%C3%A7%C3%B5es-confidenciais/","title":"Protegendo Secrets no Terraform: Estratégias Eficazes para o Gerenciamento de Informações Confidenciais"},{"content":"Olá folks, tudo bem com vocês? Espero que sim! 😅 Nesse post venho trazendo uma novidade dentro do universo de ferramentas do Docker: \u0026ldquo;Docker Scout\u0026rdquo; que é uma espécie de \u0026ldquo;linter\u0026rdquo; das imagens do docker que serve para analisar o conteúdo da imagem e gerar um relatório detalhado dos pacotes e vulnerabilidades que detecta. Ele pode fornecer sugestões sobre como remediar problemas descobertos pela análise de imagens. Nesse guia iremos utilizar uma imagem de contêiner vulnerável com o Node JS e mostrar como usar o Docker Scout para identificar e corrigir as vulnerabilidades, comparar versões de imagens ao longo do tempo e compartilhar os resultados obtidos com sua equipe de Segurança ou seja lá qual for sua intenção.\nO Docker Scout oferece as seguintes funcionalidades: Análise de segurança: O Docker Scout identifica vulnerabilidades de segurança conhecidas nas imagens (CVES). Ele também fornece informações sobre as vulnerabilidades, incluindo a gravidade, a data de descoberta e a versão da imagem em que a vulnerabilidade foi corrigida. Análise de conformidade: O Docker Scout pode ser usado para verificar a conformidade de imagens com padrões de segurança e conformidade. Análise de desempenho: O Docker Scout fornece informações sobre o tamanho, o número de camadas e o digest das imagens. Essas informações podem ser usadas para melhorar o desempenho dos contêineres. Como usar o Docker Scout? O Docker Scout está disponível como um pacote Docker, extensão do Docker Desktop ou em binário, via CLI. Nesse caso, iremos utilizar e instalar via CLI através do repositório oficial do Docker, no Github;\nPara instalá-lo é necessário antes realizar o login no Docker, caso você não tenha cadastro para continuar nessa etapa, será necessário se cadastrar no Docker Hub e logo após realizar o login pela linha de comando, execute o seguinte comando: 1 $ docker login Feito login, agora poderemos instalar o Docker Scout que está disponível como um script de instalação. Para instalá-lo, execute o seguinte comando:\n1 $ curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- 🚀 Obs: caso queira instalar de forma manual, recomendo fortemente seguir as orinetação do repositório oficial do Docker, no Github\nRealizado a instalação, agora basta testar executando o comando:\n1 $ docker scout version Se tudo tiver ocorriddo bem, você verá o seguint output:\nAnálise de Imagens Docker Agora que fizemos login no Docker Hub e temos o Docker Scout CLI instalado, estamos habilitados a começar a analisar nossas imagens Docker!\nAnalisar vulnerabilidades de imagem após a construção (docker build), iremos utilizar os comandos na CLI do docker scout para ver as vulnerabilidades detectadas pelo Docker Scout: No meu caso, irei utilizar uma simples aplicação em Node JS para realizar alguns testes e verificar se existe vunerabilidade, caso tenha interesse, o repositório está livre para você usar: NodeJS busybox Primeiro, iremos clonar o repositório 1 $ git clone https://github.com/LuksJobs/node-busy-box \u0026amp;\u0026amp; cd node-busy-box/ Com o repositório da nossa aplicação em \u0026ldquo;mãos\u0026rdquo; podemos buildar nossa imagem 1 $ docker build . -t luksjobs/nodejs:dev Agora com nossa imagem pronta, lets go analyze! Precisamos copiar o nome (repository) e a tag de nossa imagem, no meu caso \u0026ldquo;luksjobs/nodejs:dev\u0026rdquo;: Agora que temos as informações sobre a nossa imagem, iremos escaner com a função \u0026ldquo;quickview\u0026rdquo; (visão rápida) do Docker Scout: 1 $ docker scout quickview luksjobs/nodejs:dev Nesse ponto, de primeira analise, o docker scout nos trouxe informações de que a nossa imagem possui algumas CVES (vulnerabilidades) e para detalhar o que seria necessário fazer para corrigir essas vulnerabilidades precisamos rodar um outro comando para detalhar mais ainda o que de fato está vulnerável em nossa imagem para que posteriormente, possamos corrigir.\nCom a analise da nossa imagem feita, poderemos agora verificar as recomendações de como corrigir essas vulnerabilidades com o comando abaixo: 1 $ docker scout recommendations luksjobs/nodejs:dev Conclusão O Docker Scout reúne todas as informações que você precisa ao trabalhar para proteger o desenvolvimento do seu contêiner, incluindo uma visão camada por camada das dependências, suas vulnerabilidades conhecidas e caminhos de correção recomendados . É isso, temos agora uma tabela de recomendação de cada item que possuí uma CVE detectada e uma lista de reecomendações para resolver e corrrigir esses atributos da nossa imagem Docker, espero que você tenha gostado do post :)\nLista de comandos do Docker Scout em PDF: Scout Cheat Sheet\n","date":"2024-01-06T00:00:00Z","image":"https://cdn.dribbble.com/users/1079313/screenshots/2860638/media/5508a9eefd0e31f5db923f4a58b02df0.png","lang":"pt-br","permalink":"https://luks.dev.br/p/explorando-o-docker-scout-analisando-e-refor%C3%A7ando-a-seguran%C3%A7a-de-imagens-docker/","title":"Explorando o Docker Scout: Analisando e Reforçando a Segurança de Imagens Docker"},{"content":"Visão Geral O HashiCorp Vault é uma ferramenta projetada para armazenar e gerenciar informações sensíveis de forma segura, como chaves de API, senhas, certificados e muito mais. Ele fornece uma solução centralizada para gerenciamento de segredos e controle de acesso.\nCaso de Uso Nesse post o objetivo é integrar o Node.js com o Vault, iremos utilizar a imagem Docker do Vault. Dessa forma subiremos uma API para interagir com o Vault. Armazenar segredos no Vault é melhor do que armazenar segredos em arquivos do tipo \u0026ldquo;.env\u0026rdquo; porque o Vault fornece uma maneira mais segura de armazenar segredos. O Vault usa criptografia para proteger os segredos, o que significa que eles não podem ser acessados por pessoas não autorizadas. Além disso, o Vault permite controlar quem pode acessar quais segredos, o que ajuda a proteger os segredos de serem usados indevidamente.\nRecursos do Vault Gerenciamento de Segredos: O Vault oferece uma maneira segura de armazenar e gerenciar segredos, garantindo que os dados sensíveis sejam criptografados em repouso e em trânsito. Segredos Dinâmicos: Ele pode gerar segredos dinâmicos sob demanda para vários serviços, reduzindo o risco de credenciais de longa duração. Controle de Acesso: O Vault fornece políticas de controle de acesso detalhadas para restringir e gerenciar o acesso de usuários aos segredos. Criptografia como Serviço: Ele oferece criptografia como serviço, permitindo que aplicativos criptografem e descriptografem dados sem lidar diretamente com chaves de criptografia. Auditoria e Registro: O Vault mantém um registro detalhado de todas as interações, fornecendo visibilidade e rastreabilidade para fins de conformidade. Integração e Extensibilidade: Ele se integra a vários sistemas de autenticação, provedores de nuvem, bancos de dados e muito mais. Instalando e configurando o Vault utilizando o Docker O Vault pode ser executado em vários ambientes, só que nesse post, iremos utilizar containers Docker.\n— https://github.com/LuksJobs/secrets-with-vault (Repositório do Vault utilizado nesse post)\n1. Dockerfile A imagem do Vault que iremos utilizar é baseado na imagem base do Alpine na versão 3.18 e com a versão do Vault 1.13.3\n1.1 Buildando a nossa imagem do Vault Agora que temos nossa imagem definida em nosso Dockerfile, iremos preparar ela buildando nossa imagem:\n1 docker build . -t vault:prd 2. Docker Compose Agora que temos nossa imagem preparada, precisaremos instruir como iremos levantar nosso container Docker e iremos fazer isso utilizando o Docker Compose:\n3. Executando o Container Para levantar o container, basta rodar o comando abaixo:\n1 $ docker compose up -d Logo após para gerar as chaves de acesso ao cofre:\n1 $ docker exec -it vault vault operator init -n 2 -t 2 Esse comando irá gerar duas chaves para acesso ao banco de dados, 🚩 é de extrema importância guardar as chaves e o Token que foram gerados em um local seguro!\nConectando ao Vault via linha de comando (CLI) Para conectar-se ao Vault, via linha de comando é necessário primeiro instalar a linha executar o comando abaixo:\nExiste várias maneiras de realizar essa instalação, caso tenha dúvidas acesse o link da documentação: https://developer.hashicorp.com/vault/docs/install Em nosso caso, iremos instalar via pacote:\n1 1. sudo apt update \u0026amp;\u0026amp; sudo apt install gpg Baixando o pacote de Instalação da CLI do Vault:\n1 2. wget https://releases.hashicorp.com/vault/1.15.2/vault_1.15.2_linux_amd64.zip Em seguida, descompacte o pacote usando o seguinte comando:\n1 3. unzip vault_1.15.2_linux_amd64.zip Depois, mova o pacote para o diretório /usr/bin:\n1 4 mv vault /usr/bin Verifique a instalação usando o seguinte comando:\n1 5. vault -v Agora com a linha de comando instalada, poderemos nos conectar ao nosso Vault que está rodando em container Docker bastando apontar o ip e porta ou então DNS de onde ele está rodando:\n1 $ export VAULT_ADDR=\u0026#39;http://seu-servidor-vault:8200\u0026#39; Metódo de login utilizando \u0026ldquo;username\u0026rdquo; e \u0026ldquo;password\u0026rdquo;:\n1 $ vault login -method=userpass username=lucas.dantas Metódo de login por linha de comando utilizando o \u0026ldquo;Token\u0026rdquo;:\n1 $ vault login -method=token Criando política de acesso Política de acesso: list-secrets-policy.hcl(arquivo de texto com extensão \u0026ldquo;.hcl\u0026rdquo;)`\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 path \u0026#34;secret/metadata\u0026#34; { capabilities = [ \u0026#34;list\u0026#34; ] } path \u0026#34;secret/metadata/*\u0026#34; { capabilities = [ \u0026#34;list\u0026#34;, \u0026#34;read\u0026#34; ] } # Allow a token to manage its own credentials path \u0026#34;credentials/*\u0026#34; { capabilities = [\u0026#34;create\u0026#34;, \u0026#34;read\u0026#34;, \u0026#34;update\u0026#34;, \u0026#34;delete\u0026#34;, \u0026#34;list\u0026#34;] } # Allow a token to look up its own capabilities on a path path \u0026#34;sys/capabilities-self\u0026#34; { capabilities = [\u0026#34;update\u0026#34;] } # Allow general purpose tools path \u0026#34;sys/tools/hash\u0026#34; { capabilities = [\u0026#34;update\u0026#34;] } path \u0026#34;sys/tools/hash/*\u0026#34; { capabilities = [\u0026#34;update\u0026#34;] } Aplicar a política ao Vault: 1 vault policy write list-secrets-policy list-secrets-policy.hcl Aplicar a política aos usuários: 1 2 3 vault write auth/userpass/users/lucas.dantas policies=list-secrets-policy vault write auth/userpass/users/lucas.dantas policies=list-secrets-policy vault write auth/userpass/users/lucas.dantas policies=list-secrets-policy Criando o SecretID e o APP Role Habilitar o APP Role O AppRole no Vault é um mecanismo de autenticação que permite que aplicativos e serviços se autentiquem e obtenham tokens de acesso para acessar recursos no Vault. Ele fornece uma maneira segura para que aplicativos se autentiquem e obtenham tokens de autenticação sem a necessidade de credenciais de usuário.\n1 vault auth enable approle Execute o seguinte comando para criar o AppRole \u0026ldquo;node-app-role\u0026rdquo; e definir as políticas associadas a ele:\n1 2 3 4 5 6 7 8 vault write auth/approle/role/node-app-role \\ token_ttl=1h \\ token_max_ttl=4h \\ token_policies=default resultado esperado: Success! Data written to: auth/approle/role/node-app-role Após criar o AppRole, você pode obter as informações do \u0026ldquo;role-id\u0026rdquo; usando o seguinte comando:\n1 2 3 4 5 6 7 8 9 10 vault read auth/approle/role/node-app-role/role-id resultado esperado: Key Value --- ----- secret_id 000000000000000000000000000000000000 secret_id_accessor 000000000000000000000000000000000000 secret_id_num_uses 0 secret_id_ttl 0s SecretID Agora iremos gerar um \u0026ldquo;secret-id\u0026rdquo; para nosso \u0026ldquo;node-app-role\u0026rdquo; recentemente criado:\n1 2 3 4 5 6 7 8 9 10 11 vault write -f auth/approle/role/node-app-role/secret-id resultado esperado: Key Value --- ----- secret_id 000000000000000000000000000000000000 secret_id_accessor 000000000000000000000000000000000000 secret_id_num_uses 0 secret_id_ttl 0s Relizando Conexão do NodeJS com o Vault Certifique-se de que as variáveis de ambiente (ROLE_ID e SECRET_ID) estejam configuradas corretamente no seu ambiente de execução para garantir uma autenticação bem-sucedida. Este é um exemplo básico, e na prática, você pode precisar ajustar e expandir o código de acordo com as necessidades específicas do seu projeto e da sua configuração do Vault.\nNesse caso, declarei a variável de ambiente \u0026ldquo;Secret_ID\u0026rdquo; nas variáveis de ambiente do CI/CD do Gitlab; Pois o objeto é que em um estágio da minha pipeline, esse secret id seja adicionado no arquivo \u0026ldquo;.env\u0026rdquo; e que seja buildado em nossa aplicação, no caso, imagem docker;\nSeguindo essas etapas, sua aplicação Node.js será capaz de consumir segredos armazenados na engine do seu servidor Vault. Lembre-se de tratar erros adequadamente e implementar mecanismos de tratamento de erros e autenticação apropriados, de acordo com os requisitos da sua aplicação.\nExemplo de conexão para consumir o Secret Este código é um exemplo de como usar o NodeVault para se autenticar no HashiCorp Vault usando AppRole, o objetivo é obter um token de acesso, e então ler informações sensíveis (como credenciais de banco de dados) armazenadas no Vault.\nConclusão Certifique-se de que as variáveis de ambiente (ROLE_ID e SECRET_ID) estejam configuradas corretamente no seu ambiente de execução para garantir uma autenticação bem-sucedida. Este é um exemplo básico, e na prática, você pode precisar ajustar e expandir o código de acordo com as necessidades específicas do seu projeto e da sua configuração do Vault.\n","date":"2023-11-24T00:00:00Z","image":"https://i.imgur.com/soZxPoQ.png","lang":"pt-br","permalink":"https://luks.dev.br/p/utilizando-o-vault-para-gerenciar-segredos-em-aplica%C3%A7%C3%B5es-nodejs/","title":"Utilizando o Vault para Gerenciar Segredos em Aplicações NodeJS"},{"content":"O objetivo desse artigo é te ensinar a realizar a previsão dos títulos e das tags das tecnologias e linguagens de programação com base em perguntas mais frequentes criadas em \u0026lsquo;chamados\u0026rsquo; do GLPI, utilizamos um conjunto de dados importados da base de dados de homologação do Help Desk da empresa que trabalho, lógico que \u0026ldquo;peneiramos\u0026rdquo; todos os dados sensiveis.\n— https://github.com/Devopeiros/previsao-pln-publico (Repositório do Notebook utilizado nesse post)\nEstudo de Caso O Problema de Negócio que queremos resolver é realizar predições das respectivas tags a partir das perguntas geradas através da ferramenta de Help Desk da Unimed Natal: GLPI no qual faremos o treinamento do modelo através do aprendizado de máquina com algoritmo supervisionado.\nImportando as bibliotecas Para nosso estudo de caso, vamos fazer uso das seguintes bibliotecas:\nNumpy: um pacote para computação científica. Pandas: uma biblioteca de alta-performance, fácil para manipulação de dataframes e análises de dados. seaborn: para visualizações. scikit-learn: um pacote para ferramentas para aprendizado de máquinas. NLTK: uma plataforma para trabalhar com linguagem natural. Instalando as dependências (Pacotes) no Linux sudo apt install python3-numpy - Instalação da biblioteca do Numpy no Python3 sudo apt install python3-pandas - Instalação da biblioteca do Pandas no Python3 sudo apt install python3-seaborn - - Instalação da biblioteca do Seaborn no Python3 sudo apt install python3-nltk - Instalação da biblioteca do NLTK no Python3 sudo apt install python3-scikit-learn - Instalação da biblioteca do SCIKIT no Python3 sudo apt install python3-matplotlib - - Instalação da biblioteca do MATPLOTLIB no Python3 Importando o Dataset e Stopwords Neste projeto, contaremos com 2 conjuntos de dados: treino (train) e validação (validation), no qual é composto por títulos e suas tags correspondentes (somente essas duas colunas).\nImportando o Conjunto de Dados Vamos iniciar criando um função para importação dos dados. Nessa importação as tags são importadas entre aspas duplas, então utilizaremos a função literal_eval no qual converte a string em um objeto, lembrando que os objetos são o que estão dentro de colchetes e aspas duplas, para suprimirmos as aspas.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 # criando a função def read_data(filename): # importando o arquivo data = pd.read_csv(filename, sep=\u0026#34;\\t\u0026#34;) # removendo as aspas que são importadas juntas #data[\u0026#39;tags\u0026#39;] = data[\u0026#39;tags\u0026#39;].apply(literal_eval) # Tratamento dos valores NaN na coluna \u0026#39;tags\u0026#39; data[\u0026#34;tags\u0026#34;] = data[\u0026#34;tags\u0026#34;].apply(lambda x: literal_eval(x) if not pd.isna(x) else []) # retornando o arquivo return data Agora vamos importar os dois arquivos.\n1 2 3 4 5 6 7 8 9 10 11 # importando os dados de treino train = read_data(\u0026#39;data/traiin.tsv\u0026#39;) # Imprimir o DataFrame train #print(train.head()) # importando os dados de validação validation = read_data(\u0026#39;data/validatiion.tsv\u0026#39;) # Imprimir o DataFrame validation #print(validation.head()) Vamos dar uma olhada nas primeiras linhas de cada conjunto com o método head().\n1 2 # visualizando as primeiras 10 linhas do conjunto de arquivos treinandos train.head(10) Exemplo de saída:\n1 2 3 4 5 6 7 8 9 10 11 title\ttags 0\tComo desenhar um gráfico de pontos empilhados...\t[r] 1\tselecionar todos os registros do MySQL onde um...\t[php, mysql] 2\tComo encerrar um aplicativo do Windows Phone 8.1\t[c#] 3\tobter a hora atual em um país específico via j...\t[javascript, jquery] 4\tConfigurando o Tomcat para usar SSL... [java] 5\tPlugin Awesome Nested Set - como adicionar nov...\t[ruby-on-rails] 6\tComo criar um mapa a partir de uma resposta JS...\t[ruby, ruby-on-rails-3, json] 7\ttestar rspec se o método é chamado... [ruby] 8\tExceção SpringBoot Catalina LifeCycle... [java, spring, spring-mvc] 9\tComo importar dados do Excel para um banco de...\t[php, codeigniter] Agora das saídas do arquivo de validação:\n1 2 # visualizando as primeiras 10 linhas do conjunto de arquivos validados validation.head(10) Exemplo de saída:\n1 2 3 4 5 6 7 8 9 10 11 title\ttags 0\tPor que o odbc_exec sempre falha?\t[php, sql] 1\tAcessar uma variável de classes base de dentro...\t[javascript] 2\tContent-Type \u0026#34;application/json\u0026#34; não é obrigató...\t[ruby-on-rails, ruby] 3\tSessões no Sinatra: Usadas para Passar Variáveis...\t[ruby, session] 4\tRecebendo erro - tipo \u0026#34;json\u0026#34; não existe - no P...\t[ruby-on-rails, ruby, json] 5\tbiblioteca não encontrada para.....?\t[c++, iphone, ios, xcode] 6\tArquivo .csproj - Adição/Exclusão programática...\t[c#] 7\tTypeError: makedirs() recebeu um argumento de...\t[python, django] 8\tComo Pan um div usando JQuery...\t[javascript, jquery, html] 9\tTutoriais intermediários/avançados do Hibernate... [java, hibernate] Podemos notar que temos aspas, underlines, dois pontos, traços na coluna title e a coluna tags não tem uma quantidade fixa de palavras, além de cada termo está em formato de lista.\nVamos agora dar uma olhada na dimensão desses dados em quantidade de linhas e colunas:\n1 2 3 4 5 6 7 8 print(f\u0026#34;Os dados de TREINO possui:\u0026#34;) print(f\u0026#34;{train.shape[0]} linhas\u0026#34;) print(f\u0026#34;{train.shape[1]} colunas\\n\u0026#34;) # visualizando as dimensões em quantidade de linhas e colunas dos dados de treino; print(f\u0026#34;Os dados de VALIDAÇÃO possui:\u0026#34;) print(f\u0026#34;{validation.shape[0]} linhas\u0026#34;) print(f\u0026#34;{validation.shape[1]} colunas\u0026#34;) Resultado esperado de saída:\n1 2 3 4 5 6 7 Os dados de TREINO possui: 55 linhas 2 colunas Os dados de VALIDAÇÃO possui: 55 linhas 2 colunas Observamos que o conjunto de validação corresponde à 30% do conjunto de treino, um número bom para utilizarmos como validação do nosso modelo.\nVamos então, separar nossa variável preditora (coluna title) da nossa variável alvo (coluna tags), em ambos os conjuntos, utilizaremos o método values.\n1 2 3 4 5 # separando os dados de treino X_train, y_train = train[\u0026#39;title\u0026#39;].values, train[\u0026#39;tags\u0026#39;].values # separando os dados de validação X_val, y_val = validation[\u0026#39;title\u0026#39;].values, validation[\u0026#39;tags\u0026#39;].values Os arquivos viraram uma lista, no qual cada linha se tornou um elemento dessa lista, vamos dar uma olhada para entendermos melhor no X_train, as outras seguem da mesma forma.\n1 2 # visualizando X_train X_train Resultado esperado de saída:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 \u0026#39;Como desenhar um gráfico de pontos empilhados no R?\u0026#39;, \u0026#39;selecionar todos os registros do MySQL onde um campo de data e hora é menor que um valor especificado\u0026#39;, \u0026#39;Como encerrar um aplicativo do Windows Phone 8.1\u0026#39;, \u0026#39;obter a hora atual em um país específico via jQuery\u0026#39;, \u0026#39;Configurando o Tomcat para usar SSL\u0026#39;, \u0026#39;Plugin Awesome Nested Set - como adicionar novos filhos à árvore em vários níveis\u0026#39;, \u0026#39;Como criar um mapa a partir de uma resposta JSON no Ruby on Rails 3?\u0026#39;, \u0026#39;testar rspec se o método é chamado\u0026#39;, \u0026#39;Exceção SpringBoot Catalina LifeCycle\u0026#39;, \u0026#39;Como importar dados do Excel para um banco de dados MySQL usando PHP\u0026#39;, \u0026#39;Obtendo o objeto java.lang.Class\u0026lt;T\u0026gt; para um tipo parametrizado sem construir a classe em q_uestion?\u0026#39;, \u0026#39;iPad não seleciona todo o texto dentro de uma entrada de texto ao tocar\u0026#39;, \u0026#39;Como o $ do jQuery é uma função e um objeto?\u0026#39;, \u0026#39;Eclipse C++ MinGW - Não é possível iniciar o programa \u0026lt;Terminado\u0026gt;\u0026#39;, \u0026#39;Em JavaScript, como posso chamar um método de protótipo em outro método de protótipo?\u0026#39;, \u0026#39;obter interseção de uma lista de conjuntos\u0026#39;, \u0026#39;Não é mais possível ocultar o teclado durante o viewWillDisappear no iOS7\u0026#39;, \u0026#39;Como buscar a chave de um JSON em Swift?\u0026#39;, \u0026#39;Como alterar o modelo de cabeçalho do Pivot no Windows Phone 8\u0026#39;, \u0026#39;criptografia da connectionString\u0026#39;, \u0026#39;Como permitir que a interface do usuário seja atualizada durante uma operação UI demorada\u0026#39;, \u0026#39;Melhor maneira de executar um arquivo Ruby usando Python e como obter a saída do console Ruby quando o arquivo Ruby é executado a partir do Python?\u0026#39;, \u0026#39;criar 2 miniaturas de uma vez no CodeIgniter\u0026#39;, \u0026#39;Caractere Java vs char: o que dizer sobre o uso de memória?\u0026#39;, \u0026#39;Fechar modal do Bootstrap ao pressionar a tecla Enter\u0026#39;, \u0026#39;conversão de matriz de inteiros para matriz de objetos em Java\u0026#39;, \u0026#39;Erro ao fazer upload de arquivo em PHP\u0026#39;, \u0026#39;Métodos clear() em Java\u0026#39;, \u0026#39;Impressão de floats com um número específico de zeros\u0026#39; Em geral, quando trabalhamos com Processamento de Linguagem Natural, os dados são desestruturados, como podemos notar também nesse documento. Devemos analisar com cautela e escolher a melhor forma que não irá descaracterizar o sentido ou a palavra do que estamos tratando.\nVamos criar uma função para tratar nossos dados, removendo símbolos e caracteres especiais e também as stopwords, que são palavras que aparecem muitas vezes mas que não agregam valor ao nosso objetivo e se mantivermos podem causar ruidos e não termos uma boa precisão nas previsões.\nPreparação do texto Nesta etapa vamos começar a \u0026ldquo;limpar\u0026rdquo; nosso texto, removendo tudo que não tem valor para nosso objetivo.\nVamos iniciar criando uma função para isso, fazendo uso do pacote re, Regular Expression Operations e com ela podemos utilizar dos recursos do REGEX.\nFaremos uso do método compile (re.compile), dentro de um objeto, para compilar a expressão regular que queremos, com isso quando a função encontrar essa expressão no texto, ele a removerá. Podemos utilizar para remover caracteres especiais, números, entre outros padrões existentes. Depois usaremos esse objeto como uma função com o método sub, passando como parâmetros o que irá substituir e o conjunto de dados.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # criando os objetos com as expressões regulares remove_espec_carac = re.compile(\u0026#39;[/(){}\\[\\]\\|@,;]\u0026#39;) remove_symb = re.compile(\u0026#39;[^0-9a-z #+_]\u0026#39;) # criando um objeto para remoção de stopwords no idioma ingles stopwords = stopwords.words(\u0026#39;portuguese\u0026#39;) # criando a função def text_prepare(text): # normalizando nosso texto em letras minúsculas, assim facilita nossa preparação text = text.lower() # substituindo caracteres especiais por espaços em branco text = remove_espec_carac.sub(\u0026#39; \u0026#39;, text) # retornando apenas letras e números text = remove_symb.sub(\u0026#39;\u0026#39;, text) # removendo as stopwords text = \u0026#39; \u0026#39;.join(word for word in text.split() if word not in stopwords) # retornando o texto modificado return text Para verificarmos se nossa função de preparação está funcionando, vamos criar um pequeno texto com as informações que queremos remover e analisar.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # Criando a função def test_text_prepare(): # definindo os exemplos examples = [\u0026#34;SQL Server - algum equivalente à função CHOOSE do Excel?\u0026#34;, \u0026#34;Como liberar vetor de memória c++\u0026lt;int\u0026gt; * arr?\u0026#34;] # inserindo a resposta correta answers = [\u0026#34;equivalente do sql server excede a função de escolha\u0026#34;, \u0026#34;vetor de memória c ++ livre arr\u0026#34;] # Aplicando um loop e comparando a limpeza for ex, ans in zip(examples, answers): # condições para retornar se o resultado foi aprovado ou reprovado if text_prepare(ex) != ans: return \u0026#34;Resposta incorreta para: \u0026#39;%s\u0026#39;\u0026#34; % ex return \u0026#39;Testes básicos aprovados.\u0026#39; Nossa função passou no teste! Agora podemos pré-processar os titles usando a função text_prepare para os conjuntos de dados de treino e validação.\n1 2 3 4 5 # aplicando a função nos dados de treino X_train = [text_prepare(x) for x in X_train] # aplicando a função nos dados de validação X_val = [text_prepare(x) for x in X_val] Vamos dar uma olhada nas primeiras linhas, mas que na verdade são elementos porque estão contidos em uma lista e não mais como um dataframe.\n1 2 # visualizando os 10 primeiros elementos X_train[:10] O resultado esperado da saída:\n1 2 3 4 5 6 7 8 9 10 1. \u0026#39;desenhar grfico pontos empilhados r\u0026#39;, 2. \u0026#39;selecionar todos registros mysql onde data hora menor valor especificado\u0026#39;, 3. \u0026#39;encerrar aplicativo windows phone 81\u0026#39;, 4. \u0026#39;hora atual pas especfico via jquery\u0026#39;, 5. \u0026#39;configurando tomcat ssl\u0026#39;, 6. \u0026#39;plugin awesome nested set adicionar novos filhos rvore vrios nveis\u0026#39;, 7. \u0026#39;criar mapa partir resposta json ruby on rails 3\u0026#39;, 8. \u0026#39;testar rspec mtodo chamado\u0026#39;, 9. \u0026#39;exceo springboot catalina lifecycle\u0026#39;, 10. \u0026#39;importar excel banco mysql php\u0026#39;, Contando as palavras Seguindo aqui com nosso texto \u0026ldquo;limpo\u0026rdquo;, podemos calcular as quantidades de ocorrência de cada palavra nos conjuntos de treino. Vamos utilizar a função Counter do pacote Collections para fazer contagem e a função chain do pacote itertools que nos fornece um loop que irá iterar as palavras com suas respectivas frequencias.\n1 2 3 4 5 # realizando a contagem e inserindo em um dicionário words_counts = Counter(chain.from_iterable([i.split(\u0026#34; \u0026#34;) for i in X_train])) # ordenando do maior para o menor words_freq = sorted(words_counts.items(), key=lambda x: x[1], reverse=True) Vamos dar uma olhada no nas perguntas mais frequentes em uma escala de TOP 10, ou seja, as 10 palavras que mais apareceram.\n1 words_freq[:10] Exemplo da saída do resultado esperado:\n\u0026ldquo;[(\u0026lsquo;arquivo\u0026rsquo;, 6), (\u0026lsquo;jquery\u0026rsquo;, 5), (\u0026lsquo;ruby\u0026rsquo;, 5), (\u0026lsquo;usando\u0026rsquo;, 5), (\u0026lsquo;obter\u0026rsquo;, 4), (\u0026lsquo;usar\u0026rsquo;, 4), (\u0026lsquo;dados\u0026rsquo;, 4), (\u0026lsquo;java\u0026rsquo;, 4), (\u0026lsquo;mysql\u0026rsquo;, 3), (\u0026lsquo;campo\u0026rsquo;, 3)]\u0026rdquo;\nVamos visualizar em forma de gráfico, pois ficará mais visível e intuitivo, utilizando um barplot para visualizar.\nMas teremos que mudar o formato antes, pois como o resultado é uma tupla, vamos converter em um dicionário, separar e deixar as palavras em uma lista, assim como as ocorrências, separar e colocar também em outra lista.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # colocando as palavras em um objeto do tipo lista words_list = list(dict(words_freq[:10]).keys()) # colocando as ocorrências em um objeto do tipo lista occur_list = list(dict(words_freq[:10]).values()) # definindo a área de plotagem plt.figure(figsize=(10,6)) # criando o gráfico ax = sns.barplot(x = words_list, y = occur_list) # inserindo o título ax.set_title(\u0026#39;TOP 10 das palavras (title) mais frequentes no modelo treinado\u0026#39;) # rotacionando os rótulos do eixo x plt.xticks(rotation=30); [image_graph_1]\nA palavra arquivo é a que mais aparece, acredito que seja a palavra mais usada na maioria das perguntas que são sobre \u0026ldquo;como funciona\u0026rdquo; algo, em seguida entram algumas linguagens de programação, assim como buscas por erros.\nDa mesma forma vamos fazer todo esse processo de contagem para as tags.\n1 2 3 4 5 # realizando a contagem e inserindo em um dicionário tags_counts = Counter(chain.from_iterable([i for i in y_train])) # ordenando do maior para o menor tags_freq = sorted(tags_counts.items(), key=lambda x: x[1], reverse=True) Vamos também dar uma olhada no TOP 10, as 10 tags que mais apareceram.\n1 tags_freq[:10] Exemplo da saída do resultado esperado:\n[(\u0026lsquo;c#\u0026rsquo;, 11), (\u0026lsquo;javascript\u0026rsquo;, 10), (\u0026lsquo;java\u0026rsquo;, 10), (\u0026lsquo;jquery\u0026rsquo;, 8), (\u0026lsquo;python\u0026rsquo;, 7), (\u0026lsquo;php\u0026rsquo;, 6), (\u0026lsquo;ruby\u0026rsquo;, 4), (\u0026lsquo;json\u0026rsquo;, 4), (\u0026lsquo;mysql\u0026rsquo;, 3), (\u0026lsquo;ios\u0026rsquo;, 3)]\nVisualizando graficamente as TOP 10 tags mais frequentes no modelo treinado:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # colocando as palavras em um objeto do tipo lista tags_list = list(dict(tags_freq[:10]).keys()) # colocando as ocorrências em um objeto do tipo lista occur_list = list(dict(tags_freq[:10]).values()) # definindo a área de plotagem plt.figure(figsize=(10,6)) # criando o gráfico ax = sns.barplot(x = tags_list, y = occur_list) # inserindo o título ax.set_title(\u0026#39;TOP 10 (tags) que são mais frequentes no modelo treinado\u0026#39;) # rotacionando os rótulos do eixo x plt.xticks(rotation=30); [image_graph_2]\nAs tags que mais aparecem são linguagens de Programação, no qual são relacionadas com as perguntas, sobre o uso ou erros contidos nas perguntas, por exemplo.\n","date":"2023-11-10T00:00:00Z","image":"https://i.imgur.com/6ghHEKR.png","lang":"pt-br","permalink":"https://luks.dev.br/p/treinando-um-modelo-de-machine-learning-com-regress%C3%A3o-log%C3%ADstica-e-processamento-de-linguagem-natural/","title":"Treinando um Modelo de Machine Learning com Regressão Logística e Processamento de Linguagem Natural"},{"content":"Através da API do GitLab, você pode obter uma lista de todas as tags do repositório e, em seguida, filtrar as tags antigas com base em sua data de criação. Contudo, você pode usar a API para excluir essas tags selecionadas.\nRepositório: Use o repositório como exemplo: GitlabTag Autoremover\nAqui está um exemplo de como você pode fazer isso usando a API do GitLab com a linguagem Python:\nLembre-se de substituir as variáveis \u0026ldquo;seu_usuario/seu_repositorio\u0026rdquo; pelo caminho do seu repositório no GitLab e \u0026ldquo;seu_token_de_acesso\u0026rdquo; pelo seu token de acesso pessoal do GitLab, que pode ser gerado nas configurações da sua conta. Ou então, se preferir você pode passar esse valor através de uma variável de ambiente do própio gitlab e refernciar no script.\nEsse é apenas um exemplo básico para te ajudar a começar. Você pode personalizar e aprimorar o script para rodar em uma pipeline, nessem caso, fiz esse script para rodar no pipeline das aplicações de homologação que sofrem bastante alterações e que é necessário a criação de tags e as exclusões das mesmas depois de \u0026ldquo;backupeadas\u0026rdquo; pois assim, libera o espaço de armazenamento nos repositórios.\n","date":"2023-08-01T00:00:00Z","image":"https://i.imgur.com/m41BoXD.jpg","lang":"pt-br","permalink":"https://luks.dev.br/p/script-em-python-para-exclus%C3%A3o-de-tags-no-gitlab/","title":"Script em Python para Exclusão de Tags no Gitlab"},{"content":"A \u0026ldquo;Prioridade do pod\u0026rdquo; (Pod Priority) é um recurso de agendamento do Kubernetes que permite ao Kubernetes tomar decisões de agendamento comparando outros pods com base no número de prioridade. Vejamos os dois principais conceitos a seguir na prioridade do pod.\nCrédito pelo GIF: Amazon AWS Dev Blog\nPrioridade do sistema (System Priority): É a prioridade mais alta e é usada para pods do sistema que são essenciais para o funcionamento do cluster. Esses pods são críticos para a operação do Kubernetes e geralmente não devem ser interrompidos.\nPrioridade de classe (Class Priority): É uma prioridade intermediária e é usada para definir a importância relativa entre diferentes classes de pods. Por exemplo, você pode ter classes de pods como \u0026ldquo;alta prioridade\u0026rdquo;, \u0026ldquo;média prioridade\u0026rdquo; e \u0026ldquo;baixa prioridade\u0026rdquo;. Isso permite que você defina a ordem de execução dos pods dentro de cada classe, com base em suas necessidades específicas.\nPrioridade padrão (Default Priority): É a prioridade mais baixa e é atribuída a todos os pods que não têm uma prioridade específica definida. Esses pods serão executados após os pods de prioridade do sistema e de classe.\nAlém desses tipos de prioridade, o Kubernetes também suporta recursos como limites de recursos (resource limits) e solicitações de recursos (resource requests), que podem ser usados para controlar a alocação de recursos para os pods.\nExemplo de classe de prioridade do pod O exemplo a seguir mostra um objeto priorityClassName De um pod \u0026ldquo;Nginx\u0026rdquo; que usa o PriorityClassName:\nNeste exemplo, o campo priorityClassName está definido como \u0026ldquo;high-priority\u0026rdquo;. Isso se refere a uma classe de prioridade que você definiu em seu cluster. Você pode criar uma classe de prioridade usando o recurso PriorityClass:\n1 2 3 4 5 apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 1000000 No recurso PriorityClass, você pode especificar um nome para a classe de prioridade (neste caso, \u0026ldquo;high-priority\u0026rdquo;) e atribuir um valor a ela (neste caso, 1000000). Quanto maior o valor, maior a prioridade.\nAo definir o priorityClassName na especificação do pod, você atribui a classe de prioridade correspondente ao pod. Isso ajuda o Kubernetes a priorizar o agendamento e a alocação de recursos do pod com base em sua prioridade em comparação com outros pods no cluster.\nVamos analisar o que cada parte do arquivo faz:\nA primeira seção define o objeto PriorityClass. Ele possui os seguintes campos:\napiVersion: Define a versão da API usada (scheduling.k8s.io/v1). kind: Especifica o tipo do objeto (PriorityClass). metadata: Contém metadados adicionais, como o nome da classe de prioridade (high-priority-apps). value: Define o valor da classe de prioridade (1000000). Quanto maior o valor, maior a prioridade. preemptionPolicy: Define a política de preempção para a classe de prioridade. Neste caso, \u0026ldquo;PreemptLowerPriority\u0026rdquo; indica que os pods com prioridade inferior podem ser interrompidos para permitir a execução de pods de prioridade mais alta. globalDefault: Indica se essa classe de prioridade é a padrão para todos os pods, caso não seja especificada uma classe de prioridade. Neste caso, é definido como \u0026ldquo;false\u0026rdquo;. description: Fornece uma descrição opcional para a classe de prioridade (\u0026ldquo;Mission Critical apps\u0026rdquo;). A segunda seção define o objeto Pod. Ele possui os seguintes campos:\napiVersion: Define a versão da API usada (v1). kind: Especifica o tipo do objeto (Pod). metadata: Contém metadados adicionais, como o nome do pod (nginx) e rótulos (labels). spec: Define as especificações do pod, como os contêineres que serão executados. containers: Lista os contêineres que serão executados dentro do pod. Neste caso, há um contêiner chamado \u0026ldquo;web\u0026rdquo; com a imagem do Nginx. priorityClassName: Atribui a classe de prioridade (high-priority-apps) definida anteriormente a este pod. Como funciona a prioridade e a preferência do pod de Kubernetes? Se um pod for implantado com PriorityClassName, o controlador de admissão (admission controller) irá tratar de forma prioritária o POD com o valor prioritário mais alto, isso usando o valor do \u0026ldquo;PriorityClassName\u0026rdquo;.\nSe houver muitos pods na fila de agendamento, o agendador (schedule) organiza a ordem de agendamento com base na prioridade. Ou seja, o agendador coloca o pod de alta prioridade à frente dos pods de baixa prioridade , agora, se não houver nós disponíveis com recursos para acomodar um pod de prioridade mais alta, a lógica de preempção (preemptionPolicy) entrará em ação.\nO agendador antecipa o pod de baixa prioridade de um nó onde pode agendar o pod de prioridade mais alta. O pod despejado recebe um tempo de terminação padrão gracioso de 30 segundos. Se os pods tiverem definidos com o parametro \u0026ldquo;terminationGracePeriodSeconds então ao invés dele encerrar aos 30 segundos, encerrará de uma vez.\nNo entanto, se por algum motivo, os requisitos de agendamento não forem atendidos, o agendador prosseguirá com o agendamento dos pods de prioridade mais baixa.\nQual é o significado da prioridade do Pod? Quando você implanta aplicativos para o Kubernetes em produção, há certos aplicativos que você não deseja que sejam mortos. Por exemplo, um coletor de métricas Daemonset, agentes de registro, serviço de pagamento etc.\nPara garantir a disponibilidade de pods de missão crítica, você pode criar uma hierarquia de camadas de pod com prioridades; quando houver uma crise de recursos nos clusters, kubelet tenta matar os pods de baixa prioridade para acomodar pods com PriorityClass mais alto.\nConclusão Ao trabalhar com Kubernetes, é muito importante entender a prioridade do pod principalmente nas aplicações que estarão rodando no ambiente de produção. É importante entender que, embora a PriorityClassName seja uma ferramenta útil para o sistema de agendamento, não é a única consideração para determinar a alocação de recursos em um cluster Kubernetes. Outros fatores, como limites e requisições de recursos, também desempenham um papel importante na decisão do agendador. Além disso, a PriorityClassName pode não ter efeito em clusters que não estejam configurados para suportar prioridades ou quando os recursos disponíveis são suficientes para atender a todas as demandas de recursos dos Pods.\n","date":"2023-07-28T00:00:00Z","image":"https://i.imgur.com/X9OwRBv.png","lang":"pt-br","permalink":"https://luks.dev.br/p/configurando-a-prioridade-de-execu%C3%A7%C3%A3o-de-um-pod/","title":"Configurando a Prioridade de Execução de um POD"},{"content":"O CI (Integração Contínua) do GitLab é uma ferramenta essencial para a construção de imagens Docker, criação de tags no Git e envio para o registro Docker. Ele automatiza todo o processo de integração, teste e implantação contínua, garantindo que suas alterações de código sejam testadas e implantadas de forma confiável.\nRepositório: Use o repositório como exemplo: Docker Tag Pipeline\nIntrodução Ao usar um CI do GitLab em conjunto com o Docker, você pode criar pipelines automatizados que executam etapas como compilação, teste e empacotamento de aplicativos em contêineres Docker. Isso ajuda a garantir que suas imagens Docker estejam sempre atualizadas e prontas para implantação.\nAlém disso, o CI do GitLab permite que você crie tags no Git, que são marcadores significativos para versões específicas do seu código. Essas tags podem ser usadas para rastrear e identificar facilmente versões estáveis do seu aplicativo ou serviço.\nUma vez que suas imagens Docker estejam construídas e suas tags estejam definidas, o CI do GitLab também facilita o envio dessas imagens para um registro Docker, como o Docker Hub. Isso permite que você compartilhe e distribua suas imagens Docker de maneira eficiente.\nConfiguração da Pipeline Na raiz do seu repositório crie um arquivo chamado de \u0026quot;.gitlab-ci.yml\u0026quot;, esse arquivo será responsável pelas configurações definidas nos estágios do seu pipeline:\nVariáveis de Ambiente do Gitlab Crie uma variável no GitLab para REGISTRY_USER e REGISTRY_PW. Onde \u0026ldquo;REGISTRY_USER\u0026rdquo; é o nome de usuário e \u0026ldquo;REGISTRY_PW\u0026rdquo; senha do seu registro de imagems do Docker! No seu projeto, vá para Configurações \u0026gt; CI/CD \u0026gt; Variáveis e crie as duas variáveis.\nCrie uma Chave de Implantação (Deploy Key) com acesso de gravação ao seu repositório e adicione-a como SSH_DEPLOY_KEY às variáveis. Primeiro, você precisa criar uma chave pública e privada. Para fazer isso, abra o seu terminal Git-Bash e digite: ssh-keygen -o -t rsa -b 4096 -C \u0026quot;email@example.com\u0026quot; -f ssh-key. Copie a chave pública para o token em Settings \u0026gt; Repository \u0026gt; Deploy Keys e a chave privada para as sua variável \u0026ldquo;SSH_DEPLOY_KEY\u0026rdquo;.\nObs: a chave ssh gerada é a qual o Runner for utilizar, então se você está usando o usuário padrão do Gitlab (gitlab-runner) será necessário criar a chave para esse usuário e cadastrar nas variáveis mencionadas acima;\nConfigurando as Dependências Essa pipeline utiliza: \u0026ldquo;scripts em shell\u0026rdquo;, script em \u0026ldquo;python\u0026rdquo; e um arquivo \u0026ldquo;.env\u0026rdquo; em determinados estágios do Pipeline, então, será necessário criar os arquivos de script:\nscript.sh\n1 2 3 4 5 #!/bin/bash # Leia o valor da variável \u0026#34;IMAGE_TAG\u0026#34; do arquivo \u0026#34;.env\u0026#34; image_tag=$(grep IMAGE_TAG .env | cut -d \u0026#39;=\u0026#39; -f2) # Copiar o valor para o arquivo \u0026#34;VERSION\u0026#34; echo \u0026#34;$image_tag\u0026#34; \u0026gt; VERSION Esse script é responsável em ler os valores do nosso arquivo de variáves \u0026quot;.env\u0026quot; e alterar os valores de versão do arquivo \u0026ldquo;VERSION\u0026rdquo; pois esse arquivo version é necessário para o nosso código em python interpretar qual a tag do nosso repositório git;\n.env\n1 2 3 4 DOCKER_USERNAME = \u0026#34;usuariodorepositoriodeimagens\u0026#34; APPLICATION_NAME = \u0026#34;nomedaaplicao\u0026#34; IMAGE_TAG =0.0.1 VERSION =0.0.1 Agora será necessário criar o script que irá versionar o nosso repositório do Gitlab:\nEsse script forçará o uso de uma nova tag sempre que um novo commit ou merge request subir para a branch especificada no CI; E esse estágio será o estágio que tanto adicionará uma nova tag ao repositório do gitlab quanto ao tag utilizado na imagem Docker.\nVERSION\n1 0.0.1 Com as dependências e variáveis criadas agora basta criar o runner e rodar o projeto, se tudo der certo, o seu pipeline versionará tanto o seu repositório GIT tanto quanto as versões da suas imagens Docker serão igual à versão da tag do seu repositório.\n","date":"2023-07-26T00:00:00Z","image":"https://i.imgur.com/v8f4vqF.png","lang":"pt-br","permalink":"https://luks.dev.br/p/gitlab-ci-para-constru%C3%A7%C3%A3o-de-imagens-docker-cria%C3%A7%C3%A3o-de-tags-no-git-e-envio-para-o-registro-docker/","title":"Gitlab CI para construção de imagens Docker, criação de tags no Git e envio para o registro Docker"},{"content":"Com as pipelines do Azure DevOps, você pode definir etapas e tarefas personalizadas para compilar, testar e implantar seu código. Isso inclui integração contínua (CI) e entrega contínua (CD).\nO template abaixo pode ser usado como um ponto de entrada inicial para seus pipelines de DevOps. Ele foi projetado levando em consideração as melhores práticas, com estágios e jobs para isolar diferentes funcionalidades e torná-lo modular. Você pode incluir mais estágios, jobs e tarefas copiando e colando o código.\nSe tudo tiver dado certo, esse é o resultado esperado: Essa pipeline do Azure DevOps é estruturada da seguinte forma: Cabeçalho da estrutura da Pipeline:\nTrigger (Gatilho):\nA pipeline é acionada quando há alterações no branch \u0026ldquo;main\u0026rdquo;. Pool:\nA pipeline utiliza uma imagem de máquina virtual baseada no kernel do Ubuntu para execução. Estágios da Pipeline: Estágio de Build: O primeiro estágio é chamado de \u0026ldquo;Build Stage\u0026rdquo; (Estágio de Construção). Ele consiste em um único job chamado \u0026ldquo;BuildJob\u0026rdquo; (Trabalho de Construção) responsável por construir a aplicação. O job executa um script que exibe a mensagem \u0026ldquo;Building the application\u0026hellip;\u0026rdquo; (Construindo a aplicação\u0026hellip;) e inclui comandos para compilar o código-fonte. Estágio de Teste: O segundo estágio é chamado de \u0026ldquo;Test Stage\u0026rdquo; (Estágio de Teste). Ele depende da conclusão bem-sucedida do estágio \u0026ldquo;Build\u0026rdquo;. Ele inclui um único job chamado \u0026ldquo;TestJob\u0026rdquo; (Trabalho de Teste) responsável por executar os testes automatizados. O job executa um script que exibe a mensagem \u0026ldquo;Running tests\u0026hellip;\u0026rdquo; (Executando testes\u0026hellip;) e inclui comandos para executar os testes automatizados. Estágio de Implantação: O terceiro estágio é chamado de \u0026ldquo;Deployment Stage\u0026rdquo; (Estágio de Implantação). Ele depende da conclusão bem-sucedida do estágio \u0026ldquo;Test\u0026rdquo;. Ele inclui um único job de implantação chamado \u0026ldquo;DeployJob\u0026rdquo; (Trabalho de Implantação) responsável por implantar a aplicação em um ambiente de produção. O job de implantação executa um script que exibe a mensagem \u0026ldquo;Deploying the application\u0026hellip;\u0026rdquo; (Implantando a aplicação\u0026hellip;) e inclui comandos para implantar a aplicação em um ambiente de produção. Essas são as estruturas da pipeline, onde cada estágio depende do estágio anterior para ser executado. Cada job dentro dos estágios executa etapas específicas, como compilar, testar e implantar a aplicação. Em resumo, essa pipeline não possui um gatilho (trigger) configurado para ser executada automaticamente. Ela é um template que tem um estágio com dois jobs, onde cada job executa um script específico. Essa pipeline pode ser usada para realizar tarefas personalizadas ou executar etapas específicas do fluxo de trabalho de desenvolvimento. Sinta-se a vontade para utiliza-lá em seus projetos!\n","date":"2023-04-02T00:00:00Z","image":"https://media.architecturaldigest.com/photos/6312123d2e2056d449048be5/16:9/w_1280,c_limit/MAF_20220830__KSC_Artemis1_epb_005_medium.jpeg","lang":"pt-br","permalink":"https://luks.dev.br/p/introdu%C3%A7%C3%A3o-ao-azure-devops-template-para-pipeline-docker/","title":"Introdução ao Azure Devops: Template para pipeline Docker"},{"content":"Nesse post eu vou compartilhar minha experiência com pods em estado de “evicted” e, especialmente, explicar um pouco mais sobre o que é esse estado “evicted” de um pod. Antes de entrarmos no assunto, é obrigatório entender alguns vocabulários usados no Kubernetes.\nVocabulário Um pouco de vocabulário primeiro! Para entender bem este artigo, precisamos falar a mesma língua, então você encontrará a seguir alguns conceitos essenciais para entender.\nRequests e limits: Requests: Parâmetro utilizado para definir os requisitos base de um Pod. Esse parâmetro é a quantidade mínima de recursos que um contêiner precisa para iniciar. Os “requests”, em português “solicitações”, não significam que o recurso é dedicado ao pod.\nLimits: Esta é a quantidade máxima de um recurso que o nó concederá aos contêineres para usar. Classes do pod:\n“Guaranted ou Garantido“: são os pods que têm solicitações e limites configurados em recursos de memória e CPU: Cada contêiner no pod deve ter um limite de CPU e uma solicitação de CPU, e eles devem ser iguais. Cada Container no Pod deve ter um limite de memória e uma requisição de memória, e eles devem ser iguais. “Burstable ou Explosivo”: são os pods com pelo menos uma configuração de solicitação na CPU ou memória para pelo menos um de seus contêineres. “Best Effort ou Melhor esforço”: pods sem solicitações ou limites. O que é um pod em estado “Evicted”? Agora que sabemos o que são solicitações/limites e que os pods têm classes, vamos nos aprofundar no processo de remoção.\nQuando um nó atinge seu limite de disco, memória ou quando existe algum problema de rede, uma flag é definida no nó do Kubernetes para indicar que ele está sob pressão. Esta flag também bloqueia novas alocações neste nó, e em seguida inicia-se um processo de “eviction” um tipo de “despejo” para liberar alguns recursos.\nEste é o Kubelet do nó sob pressão que cuidará do processo de despejo. Este começará a falhar nos Pods até que os recursos usados ​​do nó estejam abaixo do limite de despejo, o que significa que o Kubelet encerrará todos os contêineres do Pod e definirá seu PodPhase como Failed.\nSe uma implantação gerencia o pod removido, a implantação cria outro pod para ser agendado pelo Kubernetes.\nComo os recursos são liberados? A primeira coisa que o Kubelet fará é liberar o disco excluindo os pods que não estão em execução e suas imagens (essa é uma limpeza rápida, um “garbage collection”) . Então, se a limpeza do disco não for suficiente, o Kubelet iniciará um processo de eviction, ‘despejo’, de pods nesta ordem precisa:\nPods que demandam de mais limits e requests são os primeiros a serem excluídos Pods com capacidade de explosão (bustable) e que estão usando mais recursos do que a solicitação definida no recurso faz com que o nó sofra; Pods com capacidade de explosão e que estão usando menos recursos do que a solicitação definida no recurso faz com que o nó sofra; Por exemplo, vamos pegar um nó que tem alguns problemas de CPU. Se um pod tiver uma solicitação no recurso de CPU e usar metade de sua solicitação de CPU, ele será removido após um pod com uma solicitação no recurso de CPU, mas que usa mais do que sua solicitação.\nResolução de problemas A resolução de pods em estado de “evicted” depende da causa subjacente do problema. Aqui estão algumas possíveis soluções técnicas para resolver esse problema:\nVerificar os logs e eventos do Kubernetes: O primeiro passo para solucionar um pod em estado de “evicted” é verificar os logs e eventos do Kubernetes para determinar a causa subjacente do problema. Isso pode ajudar a identificar problemas de rede, falta de recursos ou outros problemas que possam estar afetando o pod.\nPara listar os pods de um namespace especifico que está em estado de evicted, você pode utilizar o comando abaixo:\n1 kubectl get pods --all-namespaces --field-selector=status.phase=Failed | grep Evicted E para remover todos os pods em evicted, através do namespace, basta usar o comando:\n1 kubectl get pods --all-namespaces --field-selector=status.phase=Failed | awk \u0026#39;{if ($4 == \u0026#34;Evicted\u0026#34;) system(\u0026#34;kubectl delete pod --namespace=\u0026#34; $1 \u0026#34; \u0026#34; $2)}\u0026#39; No comando acima, estamos procurando os pods com status ‘Evicted‘ e limpando-os usando o comando “kubectl delete pod” para todos eles.\nEm geral, resolver pods em estado de “evicted” pode ser um processo complexo que exige uma análise cuidadosa do ambiente Kubernetes e da configuração do pod. Certifique-se de investigar cuidadosamente as causas subjacentes do problema antes de tentar uma solução.\n","date":"2022-09-21T00:00:00Z","lang":"pt-br","permalink":"https://luks.dev.br/p/resolvendo-o-problema-do-pod-em-estado-de-evicted-no-kubernetes/","title":"Resolvendo o problema do pod em estado de “evicted” no Kubernetes"},{"content":"Nesse post, desenvolvi um simples aplicativo utilizando o Node.js para demonstrar que ao invés de você rodar esse seu software localmente (self hosted) com o express por exemplo, também há a possibilidade de rodar em container de forma persistente utilizando o docker e docker-compose.\nOs códigos usados nesse post estão no repositório: https://gitlab.com/luksjobs/nodejs-aula-dev\nCriando a “receita de bolo”, nosso Dockerfile Para rodar uma aplicação dentro do Node.js utilizando o Docker, você precisará seguir alguns passos básicos:\nCrie um arquivo chamado de: Dockerfile, sim com o “D” maiúsculo na raiz do diretório do projeto, com o seguinte conteúdo:\nEste arquivo define a imagem base a ser utilizada (node:14), cria um diretório de trabalho (/usr/src/app), copia os arquivos de configuração (package.json e package-lock.json) e instala as dependências do projeto. Em seguida, copia o restante do código para o diretório de trabalho, expõe a porta em que a aplicação irá rodar (3000) e define o comando para iniciar a aplicação (npm start).\n‘Buildando’ nossa imagem Docker Este comando irá construir a imagem Docker a partir do Dockerfile e dará um nome à imagem (nome-da-imagem). O ponto final (.) indica que o Dockerfile está na raiz do diretório atual.\nRodando nosso container a partir da imagem criada Este comando irá rodar o container Docker a partir da imagem criada anteriormente (nome-da-imagem) e mapeará a porta da máquina host (3000) para a porta do container Docker (3000).\nCom esses passos básicos, você deve ser capaz de rodar sua aplicação Node.js em um container Docker. É importante lembrar que você pode precisar adaptar o Dockerfile dependendo das necessidades específicas do seu projeto.\nAcessando sua aplicação via Web Para acessar seu container, bata digitar em seu navegador de internete preferido: “localhost:3000” ou então especificar seu IP e Porta: “10.10.1.0:3000“.\nParando ou Removendo o Container Já terminou os testes e agora não há mais a necessidade de manter o container em “pé” ou “rodando”, para parar ou remover esse container, existe os dois comandos abaixo:\nParando o Container 1 docker container stop nome-do-container Removendo o Container 1 docker container rm -f \u0026#34;nome-do-container\u0026#34; Criando o Docker-compose Para criar um docker-compose para uma aplicação Node.js, você precisa seguir os seguintes passos:\nCrie um arquivo docker-compose.yml na raiz do seu projeto. Defina os serviços necessários para a sua aplicação, como o serviço do Node.js. Defina as configurações para cada serviço, como as portas de exposição, as variáveis de ambiente, os volumes, etc.\nAqui está um exemplo básico de um arquivo docker-compose.yml para uma aplicação Node.js:\nRodando o Container a partir do Compose No terminal, navegue até o diretório onde o arquivo docker-compose.yml está localizado.\nExecute o comando docker-compose up para iniciar todos os serviços definidos no arquivo docker-compose.yml . Se você quiser executar os serviços em segundo plano, adicione a opção -d ao comando, ficando docker-compose up -d .\nO Docker Compose irá baixar as imagens necessárias, criar os containers e iniciar os serviços especificados. Você poderá ver os logs de cada serviço sendo executado.\nEspero que você tenha gostado do artigo! Você pode me ajudar compartilhando esse post em suas redes sociais 🙂\n","date":"2022-06-12T00:00:00Z","image":"https://i.imgur.com/xOP6tgn.png","lang":"pt-br","permalink":"https://luks.dev.br/p/rode-seu-aplicativo-node.js-em-container-usando-o-docker/","title":"Rode seu aplicativo Node.js em container usando o Docker"},{"content":"Essa API era usada para criar e gerenciar contêineres em tempo de execução no Kubernetes, mas foi substituída por outras APIs mais recentes e melhores, como a “Container Runtime Interface” (CRI). Portanto, se você estiver usando uma versão mais antiga do Kubernetes e estiver enfrentando problemas com a API “runtime.v1alpha2.RuntimeService”, é recomendável atualizar para uma versão mais recente do Kubernetes e usar as APIs mais recentes para gerenciar seus contêineres.\nResolvendo o problema sem precisar atualizar o Kubernetes: Se você não pretende atualizar a versão do seu kubernetes e quer resolver esse erro mantendo a versão 1.22 ou mais antiga, aqui vão alguns comandos que pode te ajudar a resolver essa bronca:\n1 rm /etc/containerd/config.toml O comando acima remove a configuração do “containerd” e faz com que o serviço ao ser iniciado novamente, seja reconfigurado para a configuração padrão do containerd;\n1 systemctl restart containerd Assim como explciado acima, quando removido o “config.toml” iremos iniciar o containerd para que esse arquivo no qual removemos, seja recriado com a configuração padrão.\n1 kubeadm init Logo após, iremos iniciar novamente nosso kubernetes com o comando “kubeadm init” e se tudo der certo, seu cluster kubernetes iniciará novamente, sem problemas de API;\nEspero que isso tenha te ajudado com seu problema, caso não, entre em contato e eu prometo que te ajudarei a resolver essa bronca 🙂\n","date":"2021-09-04T00:00:00Z","lang":"pt-br","permalink":"https://luks.dev.br/p/resolvendo-o-problema-runtime.v1alpha2.runtimeservice-na-inicializa%C3%A7%C3%A3o-do-kubernetes/","title":"Resolvendo o problema: “runtime.v1alpha2.RuntimeService” na inicialização do Kubernetes"},{"content":"In this post, I will talk about the HPA, which stands for \u0026ldquo;Horizontal Pod Autoscaler\u0026rdquo;. It is a Kubernetes resource that automatically adjusts the number of replicas (pods) in a deployment based on observed CPU or memory utilization.\nWhy use an HPA The goal of an HPA is to make sure your application has enough resources to handle demand. If resource utilization goes up, the HPA increases the number of replicas (more pods running) so the load is properly distributed. Likewise, if utilization goes down, the HPA reduces the number of replicas, saving resources. This keeps your application scalable and performant automatically and efficiently.\nMake sure to replace the name \u0026ldquo;meu-hpa\u0026rdquo; with the name you want for the HPA, and meu-deployment with the name of the deployment the HPA will be applied to. This ensures the HPA automatically adjusts the number of replicas of your deployment based on memory and CPU usage, keeping them at around 80% utilization.\n","date":"2020-03-16T00:00:00Z","lang":"en","permalink":"https://luks.dev.br/en/p/hpa-based-on-cpu-and-memory-utilization/","title":"HPA based on CPU and Memory utilization"},{"content":"Docker Compose é uma ferramenta de orquestração de contêineres que permite agrupar vários serviços de contêiner em uma única aplicação. Ele é usado para definir e gerenciar aplicações em contêineres de forma simples e eficiente.\nComo funciona O Docker Compose usa um arquivo de configuração chamado docker-compose.yml para definir a aplicação. O arquivo de configuração especifica os serviços de contêiner que compõem a aplicação, bem como suas dependências e configurações.\nO Docker Compose usa o arquivo de configuração para criar e iniciar os serviços de contêiner. Ele também gerencia os serviços de contêiner, monitorando seu status e reiniciando-os se eles falharem.\nBenefícios\nO Docker Compose oferece uma série de benefícios, incluindo:\nSimplicidade: O Docker Compose simplifica a criação e o gerenciamento de aplicações em contêineres. Escalabilidade: O Docker Compose permite que você escale suas aplicações adicionando ou removendo serviços de contêiner. Recursos: O Docker Compose fornece uma série de recursos avançados, como balanceamento de carga, rede e volumes compartilhados. Exemplo Aqui está um exemplo de arquivo de configuração docker-compose.yml para uma aplicação web simples:\n1 2 3 4 5 6 7 8 9 10 11 YAML version: \u0026#39;3.8\u0026#39; services: web: image: nginx ports: - 80:80 db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: password Este arquivo de configuração define dois serviços de contêiner: um serviço web que hospeda um servidor web nginx e um serviço db que hospeda um banco de dados MySQL.\nPara criar e iniciar a aplicação, execute o seguinte comando: 1 docker-compose up Este comando criará os dois serviços de contêiner e os iniciará. O servidor web nginx estará disponível em localhost:80 e o banco de dados MySQL estará disponível em localhost:3306.\nInstalação do Docker Compose Página oficial de instalação: https://docs.docker.com/compose/install/ Instalação de forma automática via \u0026ldquo;curl\u0026rdquo;: 1 2 3 4 1. $ mkdir -p ~/.docker/cli-plugins/ 2. $ curl -SL https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose 3. $ chmod +x ~/.docker/cli-plugins/docker-compose 4. $ docker compose version Instalação de forma manual: Esta opção requer o gerenciamento de atualizações manualmente. Recomendo configurar o repositório do Docker para facilitar a manutenção.\nPara baixar e instalar o plugin Compose CLI, execute o seguinte comando: 1 2 3 DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} mkdir -p $DOCKER_CONFIG/cli-plugins curl -SL https://github.com/docker/compose/releases/download/v2.14.0/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose Este comando baixa a versão mais recente do Docker Compose (do repositório de lançamentos do Compose) e instala o Compose para o usuário ativo no diretório $HOME.\nPara instalar: Docker Compose para todos os usuários do sistema, substitua ~/.docker/cli-plugins por /usr/local/lib/docker/cli-plugins. Uma versão diferente do Compose, substitua v2.14.0 pela versão do Compose que você deseja usar. Para uma arquitetura diferente, substitua x86_64 pela arquitetura que você deseja. Aplique permissões executáveis ao binário: Melhorias:\nTornei o texto mais natural e direto. Substituí \u0026ldquo;latest release\u0026rdquo; por \u0026ldquo;versão mais recente\u0026rdquo; para maior fluidez. Usei \u0026ldquo;substitua\u0026rdquo; para facilitar a compreensão das opções de alteração de versão e arquitetura. Escrevi \u0026ldquo;binário\u0026rdquo; em minúsculo para padronização. Espero que esteja adequado!\n1 chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose Verificando se a instalação deu certo: 1 docker compose version E por último: permissão para executar o Docker 1 2 3 4 5 6 docker permission $ sudo groupadd docker $ sudo usermod -aG docker $USER # docker-compose permission $ sudo chmod 666 /var/run/docker.sock É isso! Espero que tenha te ajudo e tirado algumas dúvidas :)\n","date":"2019-10-12T00:00:00Z","image":"https://i.imgur.com/WMMXkQn.png","lang":"pt-br","permalink":"https://luks.dev.br/p/introdu%C3%A7%C3%A3o-e-instala%C3%A7%C3%A3o-do-docker-compose/","title":"Introdução e Instalação do Docker Compose"},{"content":"Um Dockerfile é um arquivo de texto simples que contém uma lista de comandos que o cliente do Docker chama durante a criação de uma imagem. É uma maneira simples de automatizar o processo de criação de imagens. Em essência, é uma lista de comandos que o mecanismo do Docker executa para montar a imagem e, assim, instâncias de imagens como contêineres.\nA melhor parte é que os comandos que você escreve em um Dockerfile são quase idênticos aos seus comandos equivalentes no Linux. Isso significa que você não precisa aprender a nova sintaxe para criar seus próprios dockerfiles.\nNesse tutorial iremos realizar a instalação do Alpine pela forma automatica via DockerHub e depois com uma imagem Dockerfile. O Alpine Linux é uma distro GNU/Linux construída em torno das bibliotecas musl, libc e do Busybox.Estas características permitem que seja bastante pequena e muito eficiente em termos de uso de recursos do sistema. Para rodar no Docker, o contêiner não requer mais do que 8 MB.\nObtendo imagens Via Dockerhub Agora iremos baixar e usar uma imagem do Alpine Linux, não iremos precisar de um Dockerfile, porquê!? Quando uma imagem não é encontrada localmente, ela é baixada automaticamente, pelo Docker Hub. Então ao executarmos o comando abaixo ele dará um pull direto do dockerhub, nos trazendo a imagem do Alpine pronta, veja só:\n1 docker pull alpine Após isso, veja o resultado abaixo:\n1 2 3 4 latest: Pulling from library/alpine ee54741ab35b: Pull complete Digest: sha256:24a36bbc059b1345b7e8be0df20f1b23caa3602e85d42fff7ecd9d0bd255de56 Status: Downloaded newer image for alpine:latest Repare agora que se você executar o comando \u0026ldquo;docker ps\u0026rdquo; em seu terminal neste momento, já é possível ver a imagem na relação de disponíveis localmente:\n1 2 REPOSITORY TAG IMAGE ID CREATED SIZE alpine latest 90239124c352 1 minute ago 4.79 MB Agora o próximo passo é rodar a imagem, use o comando run. Como o Alpine é baseado no Busybox (software que fornece várias ferramentas Unix), é fácil iniciar esta imagem executando o comando:\n1 $ docker run -t -i alpine busybox Dá para fazer mais do que isto. Nos exemplos abaixo, determinamos a versão do Alpine em uso no contêiner:\n1 docker run -t -i alpine cat /etc/alpine-release 3.3.1 Quando uma imagem não é encontrada localmente, ela é baixada automaticamente, pelo Docker. Se você quiser rodar uma shell dentro do contêiner Alpine, use o ash (semelhante ao Bash):\n1 docker run -t -i alpine /bin/ash Importante: Você pode buscar e baixar imagens públicas do Docker Hub livremente. Contudo, para enviar e armazenar suas imagens no hub é necessário ter uma conta cadastrada.\nDetalhando um Dockerfile Se você baixou um dockerfile via GitHub ou até mesmo pelo DockerHub, inicialmente é preciso entender a composição do arquivo listada abaixo:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 FROM: Informa a partir de qual imagem será gerada a nova imagem, lembrando que em poucos casos (Veremos em posts futuros), uma imagem será gerada se um imagem base; MAINTAINER: Campo opcional, que informa o nome do mantenedor da nova imagem; RUN: Especifica que o argumento seguinte será executado, ou seja, realiza a execução de um comando; CMD: Define um comando a ser executado quando um container baseado nessa imagem for iniciado, esse parâmetro pode ser sobrescrito caso o container seja iniciado utilizando alguma informação de comando, como: docker run -d imagem comando, neste caso o CMD da imagem será sobrescrito pelo comando informado; LABEL: Adiciona metadados a uma imagem, informações adicionais que servirão para identificar versão, tipo de licença, ou host, lembrando que a cada nova instrução LABEL é criada uma nova layer, o Docker recomenda que você não use muitas LABEL. É possível realizar filtragens posteriormente utilizando essas LABEL. EXPOSE: Expõem uma ou mais portas, isso quer dizer que o container quando iniciado poderá ser acessível através dessas portas; ENV: Instrução que cria e atribui um valor para uma variável dentro da imagem, isso é útil para realizar a instalação de alguma aplicação ou configurar um ambiente inteiro. ADD: Adiciona arquivos locais ou que estejam em uma url, para dentro da imagem. COPY: Copia arquivos ou diretórios locais para dentro da imagem. ENTRYPOINT: Informa qual comando será executado quando um container for iniciado utilizando esta imagem, diferentemente do CMD, o ENTRYPOINT não é sobrescrito, isso quer dizer que este comando será sempre executado. VOLUME: Mapeia um diretório do host para ser acessível pelo container; USER: Define com qual usuário serão executadas as instruções durante a geração da imagem; WORKDIR: Define qual será o diretório de trabalho (lugar onde serão copiados os arquivos, e criadas novas pastas); ONBUILD: Define algumas instruções que podem ser realizadas quando alguma determinada ação for executada, é basicamente como uma trigger. Buildando uma imagem depois de ter baixado o Dockerfile: 1 $ sudo docker build -t + \u0026#34;nome da aplicação\u0026#34; 1 sudo docker build -t + \u0026#34;nome da aplicação\u0026#34; para adicionar tag, basta usar dois pontos \u0026#34;:1.0\u0026#34; se estiver no diretório do docker file \u0026#34;espaço . \u0026#34;. Depois verifique se a imagem está ok através do comando \u0026ldquo;docker images\u0026rdquo;. Se estiver tudo ok, agora vamos rodar sua aplicação com o comando: 1 $ \u0026#34;docker run -ti \u0026#34;nome da imagem\u0026#34; Lembrando que se você adiciou tag a sua imagem, ao rodar o comando docker run, você deve especificar o nome e a tag da imagem. Para acessar sua imagem, basta rodar o comando \u0026ldquo;docker attach nome da imagem\u0026rdquo;.\nPara obter um Shell (Bash) em um container que já esteja rodando, execute isso:\n1 $ docker exec -i -t nginx /bin/bash NOTA: quando saímos do nosso container com o comando \u0026ldquo;exit\u0026rdquo;, ele mata o nosso processo. Para darmos um dettach, ou em outras palavras, sair sem fecharmos ele, precisamos dos comandos: Ctrl+p + Ctrl+q. Para subirmos ele novamente, basta utilizar o comando start.\nDocker Compose O Docker Compose é uma ferramenta usada para definir e gerenciar aplicativos multi-container do Docker. Ele permite que você defina todo o ambiente de um aplicativo em um arquivo YAML, chamado de arquivo docker-compose.yml. Com esse arquivo, você pode especificar todos os serviços, redes e volumes necessários para executar e interligar diferentes contêineres como um único aplicativo.\nO Docker Compose é útil principalmente para cenários em que você tem uma aplicação que requer vários serviços diferentes (como bancos de dados, servidores web, caches, etc.) e deseja orquestrá-los facilmente.\nAqui está uma explicação básica de como usar o Docker Compose:\nInstalação: Antes de começar, verifique se você tem o Docker Compose instalado em sua máquina. Se ainda não o tiver, você pode encontrar as instruções de instalação na documentação oficial do Docker.\nCrie o arquivo docker-compose.yml: Crie um arquivo chamado docker-compose.yml na raiz do seu projeto ou diretório de trabalho. Este arquivo será onde você definirá a configuração do seu aplicativo.\nDefina serviços:\nNo arquivo docker-compose.yml, você deve definir os serviços que compõem seu aplicativo. Cada serviço representa um contêiner separado. Para cada serviço, você especifica a imagem Docker que será usada, portas expostas, volumes compartilhados, variáveis de ambiente e outras configurações relevantes.\nDefina redes e volumes (opcional):\nAlém dos serviços, você pode definir redes personalizadas e volumes compartilhados que os serviços usarão para se comunicar e armazenar dados.\nExecute o aplicativo:\nApós definir o arquivo docker-compose.yml, vá para o diretório onde ele está localizado e execute o seguinte comando para iniciar o aplicativo:\n1 docker-compose up Isso fará com que o Docker Compose inicie todos os contêineres especificados no arquivo docker-compose.yml.\nGerencie o aplicativo:\nUma vez que o aplicativo esteja em execução, você pode usar comandos como docker-compose stop, docker-compose start, docker-compose restart, docker-compose down, entre outros, para gerenciar os contêineres.\nÉ importante mencionar que o Docker Compose facilita a orquestração de contêineres e a configuração de um ambiente de desenvolvimento consistente. Ele não é recomendado para ambientes de produção de alto nível, onde soluções mais avançadas de orquestração, como Kubernetes, são mais apropriadas.\nO Docker Compose é uma ferramenta poderosa e valiosa, especialmente para desenvolvedores e equipes que desejam simplificar o gerenciamento de aplicativos baseados em contêineres e evitar a complexidade de configurar manualmente vários contêineres separados.\nReferências utilizadas nesse guia:\nhttps://docs.docker.com/docker-hub/overview/. http://www.alpinelinux.org/about/. https://www.mundodocker.com.br/o-que-e-dockerfile/\n","date":"2019-09-22T00:00:00Z","image":"https://i.imgur.com/UYrnMfy.png","lang":"pt-br","permalink":"https://luks.dev.br/p/dockerfile-a-receita-de-bolo-do-docker-guia-pr%C3%A1tico/","title":"Dockerfile, a receita de bolo do Docker (Guia Prático)"}]
