{{< youtube id="s23QvNz2WuY?si=L5HNCesomlIeqzfN" title="Running Github self hosted runner with EKS Auto" >}}
Em 5 de abril de 2025 fiz uma transmissão ao vivo sobre como rodar Github Actions Self Hosted Runners no EKS Auto com AWS Heroes Arshad Zackeriya e Jones Zachariah Noel.
Aviso: 🐶 Nenhum Beagle foi ferido. Um pouco irritado, talvez — mas ileso.
Os resultados '{Performance, Speed, Cost}' não foram apenas impressionantes, mas também impecáveis e suficientemente promissores para adotar essa solução em nível empresarial. Essa solução não é apenas agnóstica em relação à AWS, com o conhecimento adquirido neste blog pode ser estendido para Azure (AKS), Google (GKE) ou se você estiver rodando K8 em seus próprios servidores bare metal.
Para quem quiser começar direto a tentar a solução, pode seguir meu repositório aqui
Esse vai ser um pouco longo, então pegue um café, fique confortável e certifique-se de estar na posição™ ideal de revelador — você sabe qual é.
- Arquitetura
- Por que essa solução
- Conceito de Corredor Autohospedado no K8
- Guia do Código do Terraform
- Como testar essa solução
- Github Large Hosted Runner vs Running Runners no EKS Auto
- Sob a perspectiva de um arquiteto de soluções
Arquitetura
Por que essa solução
Trabalho como Engenheiro Sênior de DevOps na Colorkrew , onde temos muitos produtos, e para apoiar o fluxo de trabalho de desenvolvimento temos muitos repositórios no GitHub.
À medida que começamos a aumentar nosso portfólio de produtos, nossos pipelines de CI/CD também começaram a se tornar mais complexos, simultâneos e frequentes, levando à necessidade de mais poder de computação e, eventualmente, de uma camada de infraestrutura mais robusta que suporte nossas necessidades crescentes.
Rodar Ações do Github em máquinas livres padrão (chamadas de runners) começou a ficar lento e a solução inicial foi usar grandes runners hospedados pelo GitHub, que são pagos, ou rodar os runners em nossa infraestrutura, como o Kubernetes.
Então comecei a 'comparar ambas as soluções em desempenho, velocidade e custo', e isso levou ao início de rodar os runners autohospedados do GitHub no EKS Auto.
Conceito de Runner Autohospedado no K8
Runners: As máquinas (servidores ou ambientes virtuais) que realmente executam os jobs definidos nos seus fluxos de trabalho. Quando você gerencia, chamados de Self Hosted runners ou GitHub Hosted runners. Os runners são de natureza efêmera.
Conjuntos de Escalas de Runners: Pense nisso como um agrupamento lógico de runners que são homogêneos por natureza, o que significa que todos os runners de um determinado grupo terão a mesma configuração. Podem ser instalados em nível de repositório, organização ou empresa.
Se você quer uma configuração heterogênea, o que significa configurações diferentes para runners para diferentes trabalhos de CI/CD, então precisa de conjuntos de escalas com múltiplos runners.
Outra coisa importante a saber sobre os conjuntos de escalas Runner é que você configura quantos corredores mínimos e máximos você quer o tempo todo.
Nome dos conjuntos de escalas de runner: Conjuntos de escalas de runner são endereçáveis pelo nome, então lembre-se disso, porque quando você precisar especificar o nome do conjunto de escalas de runner na propriedade 'runs on:' do GHA para atribuir esse fluxo de trabalho em um conjunto de escalas de runner específico.
- Endpoints: ARC se comunica com dois endpoints, 'api.github.com' e 'pipelines.actions.githubusercontent.com'. Certifique-se de que o firewall, proxies, gateway NAT, seja lá o que for usado para acessar a internet, da sua organização estejam configurados para permitir os endpoints acima para o controlador ARC.
- Controlador ARC: contém 2 elementos/pods.
- 'controller-manager': Primeiro pod que entra online. Esse é o que tem diferentes controladores gerenciando diferentes recursos no cluster. Um importante a entender é que o controlador 'AutoScalingListener' gerencia o pod de ouvintes.
- Responsável por criar os recursos e garantir que correspondam à contagem e ao estado desejados.
- 'Runner ScaleSet Listener': Gerencia a tomada de decisão sobre necessidades de escalabilidade. Responsável por decidir quantos runners criar. Cada ouvinte tem seu próprio pod, o que significa 1 pod de ouvinte por conjunto de escala de runner. Se você tiver 2 escalonamentos de runners, então 2 pods de ouvinte, ou no mesmo namespace, como o gerenciador de controladores, ou em namespace diferente (configurável).
- 'controller-manager': Primeiro pod que entra online. Esse é o que tem diferentes controladores gerenciando diferentes recursos no cluster. Um importante a entender é que o controlador 'AutoScalingListener' gerencia o pod de ouvintes.
achei que deveria dar uma explicação mais fácil com minhas próprias 😋🫣 analogias
O Controlador Actions Runner (ARC * é como o gerente de uma cafeteria inteligente e automatizada — ele observa quantos clientes estão entrando (fluxos de trabalho) e contrata ou dispensa instantaneamente baristas (runners) conforme necessário.
Em vez de ter baristas esperando o dia todo por precaução, a ARC ativa baristas temporários (contêineres no Kubernetes) apenas quando os clientes chegam, e os libera quando o trabalho termina. Isso mantém o sistema rápido, eficiente e econômico.*
Com Conjuntos de Escala Runner, você pode definir as regras de quantos baristas deseja ao mesmo tempo, com base em quão movimentada está sua loja — e o ARC cuida do resto.
Você pode ler mais sobre fluxos de trabalho detalhados de ponta a ponta aqui
Visualização do Guia do Código Terraform
Configurando Ações do GitHub Escalonando Automaticamente Runners Auto-Hospedados no Amazon EKS
Introdução
Neste guia, vamos configurar o GitHub Actions Runner Controller (ARC) no Amazon EKS para escalar automaticamente runners auto-hospedados com base na demanda do fluxo de trabalho.
Estrutura do Projeto
Aqui está a estrutura da nossa implementação:
eks-auto-auto-corredores-auto-hospedados/
├── README.md
├── arquitetura/
├── commit_log.txt
├── roteiros/
└── terraform/
├── base/
└── módulos/
├── Arco/
├── eks/
├── karpenter_config/
└── VPC/
1. Diretório raiz - Contém o principal README e diagramas de arquitetura
2. scripts/ - Contém scripts utilitários para limpeza e testes de desempenho
3. terraform/ - O principal código de infraestrutura
base/ - O ponto de entrada para a implantação do Terraform
módulos/ - Módulos reutilizáveis do Terraform:
arc/ - Configuração do Controlador Actions Runner
eks/ - Configuração do cluster EKS
karpenter_config/ - Configuração de escalonamento automático de nós
vpc/ - Configuração da infraestrutura de rede
Visão Geral da Arquitetura
Nossa solução utiliza os seguintes componentes:
- Amazon EKS Auto: Serviço Kubernetes gerenciado para hospedar nossa infraestrutura de runners com Karpenter para provisionamento de nós sob demanda para o processamento de runners
- GitHub Actions Runner Controller (ARC): Controlador Kubernetes que gerencia runners auto-hospedados
- Terraform: ferramenta Infrastructure as Code para implantar e gerenciar todos os componentes
A arquitetura permite que os fluxos de trabalho GitHub Actions solicitem dinamicamente runners, que são provisionados sob demanda em nosso cluster EKS e automaticamente reduzidos quando não necessários.
Passo 1: Configuração da Infraestrutura
Configuração do VPC
Começamos criando uma VPC com sub-redes públicas e privadas. Nossa configuração de VPC usa um bloco CIDR 10.0.0.0/16 com sub-redes distribuídas por duas zonas de disponibilidade. A
sub-redes privadas hospedam nossos nós EKS, enquanto sub-redes públicas são usadas para gateways NAT e balanceadores de carga.
A configuração em terraform/base/vpc.tf faz referência ao módulo VPC e configura todos os componentes de rede necessários com a marcação apropriada para integração com Kubernetes.
Configuração do Cluster EKS
Em seguida, criamos um cluster EKS usando o módulo EKS definido em terraform/modules/eks. Nosso cluster roda Kubernetes versão 1.31 e inclui um grupo de nós do sistema para execução
Serviços essenciais de cluster.
O arquivo terraform/base/eks.tf configura o cluster com acesso ao endpoint público e posiciona os nós de trabalho nas sub-redes privadas para maior segurança.
Passo 2: Configurando o Karpenter pré-instalado do EKS Auto para Auto-Scaling
O EKS Auto vem com o Karpenter pré-instalado. Utilizamos o Karpenter para provisionar e escalar automaticamente instâncias spot Ec2 a partir do tipo, capacidade e configuração desejados para o cálculo do nosso runner GHA.
Nossa configuração Karpenter em terraform/base/karpenter_config.tf usa tipos de instância m7a com preço spot para eficiência de custos. A política de consolidação está definida como "WhenEmpty" com um timeout de 5 minutos, o que significa que os nós serão removidos quando não forem mais necessários.
Os principais parâmetros de configuração incluem:
• Tipos de instância: família m7a com 8 CPUs
• Tipo de capacidade: Instâncias spot para economia de custos
• Armazenamento: 300GB com 5000 IOPS
• Zonas de disponibilidade: US-East-1A e US-East-1B
Passo 3: Implantando o Controlador Actions Runner (ARC)
Agora implantamos o GitHub Actions Runner Controller usando o módulo ARC definido em terraform/modules/arc. O módulo é referenciado em terraform/base/arc.tf com parâmetros de configuração de locals.tf.
A implantação do ARC consiste em dois componentes principais:
- Controlador: Gerencia o ciclo de vida dos pods runner
- Conjuntos de Runners: Defina a configuração dos runners
Implantação do Controlador
O controlador é implantado usando um gráfico de Helm do repositório oficial do GitHub Actions Runner Controller. A configuração está definida em terraform/modules/arc/controller.tf e usa valores de helm/controller_values.yaml.
Configuração dos Conjuntos Runner
Implantamos dois tipos de conjuntos de runners:
- Corredores Padrão: Para trabalhos gerais de fluxo de trabalho
- Docker-in-Docker (DinD) Runners: Para trabalhos que precisam construir imagens Docker
- Existe também outro tipo de conjunto de runners chamado 'modo Kubernetes ', que deve ser usado quando organizações não podem arcar com o docker com contexto de superusuário, como no caso de runners DinD usarem o modo Kubernetes (não abordado neste blog)
Os conjuntos de runners são definidos em terraform/modules/arc/runner_sets.tf e usam valores de helm/arc_listener_values.yaml e helm/arc_listener_values_dind.yaml , respectivamente.
Nota: É muito importante que o pod controlador e o pod de conjunto de escalas de runner sejam configurados para serem implantados em instâncias EC2 sob demanda para confiabilidade, e que pods de corredores efermais sejam configurados para rodar instâncias spot.
# Configuração do controlador para nó sob demanda
Seletor de nó:
karpenter.sh/nodepool: sistema
Tolerâncias:
- chave: "Acontecimentos CríticosApenas"
operador: "Existe"
# Configuração do ouvinte para nó sob demanda
Modelo de ouvinte:
Especificação:
Seletor de nó:
karpenter.sh/nodepool: sistema
Tolerâncias:
- chave: "Acontecimentos CríticosApenas"
operador: "Existe"
Passo 4: Configuração de Autenticação no GitHub
O ARC autentica com o GitHub usando um aplicativo GitHub. As credenciais são armazenadas em segredos do Kubernetes e usadas pelo controlador runner para autenticar com o GitHub.
Para configurar a autenticação:
- Criar um aplicativo no GitHub com as permissões necessárias
- Gerar uma chave privada para o aplicativo
- Armazene o ID do app, ID de instalação e chave privada no terraform/modules/arc/secrets (Não esqueça de criar, gitignorado) no diretório
- O arquivo terraform/modules/arc/secrets.tf cria um segredo Kubernetes com essas credenciais
Passo 5: Gerenciamento do Namespace
Criamos namespaces dedicados para componentes ARC:
- sistemas de arco: Para os componentes do controlador
- arc-runners: Para os pods de runner
Esses namespaces são definidos em terraform/modules/arc/namespaces.tf.
Passo 6: Limpeza e Manuseio
Para garantir a limpeza adequada dos recursos, incluímos um script de limpeza nos scripts/cleanup-finalizers.sh que remove finalizadores dos recursos do Kubernetes. Esse script é chamado durante o processo de destruição do Terraform para garantir que os recursos sejam devidamente limpos.
O script lida com vários tipos de recursos, incluindo:
• AutoscalingRunnerSet
• EphemeralRunnerSet
• AutoscalingListener
• Contas de Serviço
• RoleBindings
• Funções
Como Funciona
- Quando um fluxo de trabalho de Ações do GitHub roda, ele solicita um runner com rótulos específicos
- O controlador ARC detecta essa solicitação e cria um pod runner no cluster EKS
- Se necessário, Karpenter provisiona uma nova instância EC2 para hospedar o pod runner
- O runner se registra no GitHub e executa o trabalho de fluxo de trabalho
- Após a conclusão do trabalho, o pod de corredores é encerrado
- Quando não são necessários mais runners, Karpenter consolida e remove nós não utilizados
Benefícios dessa abordagem
- Eficiência de Custos: Os runners só são provisionados quando necessários e automaticamente reduzidos quando estão ociosos
- Flexibilidade: Ambientes personalizados de runner podem ser definidos para atender a requisitos específicos de fluxo de trabalho
- Escalabilidade: O sistema pode lidar com um grande número de fluxos de trabalho simultâneos
- Segurança: Runners rodam em pods Kubernetes isolados com contextos de segurança definidos
- Confiabilidade: Runners com falha são automaticamente substituídos, garantindo confiabilidade do fluxo de trabalho
Como testar essa solução
Criei 3 GHA de tipos diferentes para testar diferentes cenários.
Teste simples
O primeiro tipo é o GHA simples, mas ponto importante a se prestar atenção é o parâmetro runs-on , que usa o rótulo 'arc-runner-set'.
No momento em que você executa o primeiro fluxo de trabalho, leva cerca de 1 minuto porque o 'Karpenter' está provisionando uma instância EC2.
Uma vez provisionado e se você rodar o fluxo de trabalho novamente porque a instância Ec2 já está presente, a ação completa sua execução imediatamente.
Karpenter apaga o nó se ele ficar sem uso por pelo menos 5 minutos.
Agora, se você tiver a necessidade sensível à latência de executar suas ações imediatamente, defina minRunners>0 para a configuração do conjunto de escalas do runner
Teste de trabalho concorrente
Neste GHA estou rodando 5 trabalhos simultâneos com duração de exatamente 1 minuto, cada um acionado por push ou manualmente.
Teste de emprego DinD
Há momentos em que queremos rodar microserviços em containers como o Redis e fazer testes e2e.
É aí que precisamos do tipo Docker Inside Docker.
Ponto importante a se prestar atenção aqui é o parâmetro runs-on , que usa diferentes conjuntos de runners configurados especialmente para fluxos de trabalho dind
Nesse fluxo de trabalho, o contêiner busy box executa o trabalho principal, que pode se comunicar com o contêiner de serviço Redis.
Github Large Hosted Runner vs Running Runners no EKS Auto
Desempenho & Velocidade
Tentei comparar desempenho e velocidade entre o processador de 8 núcleos e a nossa solução.
Tentei rodar o GHA da matriz de sono usando script de auto-commit por 10 minutos e cada commit acontecendo a cada 45 segundos, simulando efetivamente situações de trabalho concorrentes tanto para a solução EKS Auto quanto para os grandes Runners do Github, e os resultados foram claramente favoráveis à nossa solução
Nossas soluções têm desempenho estável com tempo de execução constante de 1 minuto e 8 segundos.
Atualização de Preço
[21 de abril de 2025] : Cometi um erro no preço do EKS Auto node management antes, mas após correção nossa solução torna ainda mais barato
Isso é um pouco complicado e pode não ser 100% preciso, mas ainda pode ser considerado 70-80% preciso.
Suponha ao longo de um mês de 30 dias com 1 hora de cargas de trabalho de CI simultâneas por dia (12 trabalhos rodando em paralelo). Vamos calcular o custo na nossa solução e também nos runners auto-hospedados do Github
Para nossa solução
Para o grande runner do Github
Também existe uma assinatura de custo do Github Teams/Enterprise. Estou supondo que seja mais barato, ou seja, o plano do Team para uma equipe de 10 desenvolvedores
auto-hospedagem no EKS com nós Spot m7a.2xgrandes custa aproximadamente $170,38/mês, enquanto os runners grandes de 8 núcleos do mesmo GitHub custam $731,20/mês, *então minha solução no EKS Auto ESTÁ GERANDO UMA ECONOMIA IMPRESSIONANTE DE 76,7%. *
Nota: Mesmo se adicionarmos a solução do Github Team para EKS, ou seja, $40 a mais, o que é 170+40 = $210/mês, o que ainda é uma economia impressionante de 72%
Vamos supor que não seja 1 hora, são 2 horas de cargas de trabalho de CI simultâneas por dia (12 tarefas rodando em paralelo)
Nota: Sei que não adicionei o custo dos componentes de rede como o 'gateway nacional', mesmo somando ainda será mais barato para os grandes runners do GitHub :D
Do ponto de vista de um arquiteto de soluções
Ao combinar Amazon EKS Auto e GitHub Actions Runner Controller, criamos uma solução que está alinhada com o AWS Well-Architected Framework:
Excelência Operacional:
• Infraestrutura como código via Terraform garante implantações consistentes
• Os runners de escalonamento automático eliminam o gerenciamento manual de capacidade
• A separação limpa dos componentes melhora a manutenção
Segurança:
• Autenticação do aplicativo GitHub com acesso com escopo
• Grupos de segurança EKS e funções do IAM aplicam o privilégio mínimo
• Sub-redes privadas reduzem a superfície de ataque
Confiabilidade:
• Implantação multi-AZ garante alta disponibilidade
• O auto-escalonamento a partir do zero acomoda cargas de trabalho variadas sem intervenção manual
• O Karpenter do EKS Auto fornece provisão inteligente de nós, garantindo que os recursos estejam disponíveis quando necessário
Eficiência de Desempenho:
• Escalonamento sob demanda garante que os recursos sejam usados apenas quando necessários
• Instâncias spot reduzem custos enquanto mantêm o desempenho
• Tipos de instância personalizáveis permitem otimização para requisitos específicos de carga de trabalho
• Suporte ao Docker-in-Docker permite fluxos de trabalho baseados em contêineres com sobrecarga mínima
Otimização de Custos:
• Capacidade de escala para zero elimina custos quando não há fluxos de trabalho em execução
• Instâncias spot proporcionam economias significativas de custo (até 90%) em comparação com instâncias sob demanda
• Consolidação de recursos por meio da política WhenEmpty de Karpenter reduz os recursos ociosos
Sustentabilidade:
• Utilização eficiente de recursos por meio de auto-escalonamento minimiza o impacto ambiental
• Capacidade de escala até zero reduz o consumo de energia durante períodos ociosos
• Redução dos recursos ociosos, menor consumo de energia
Esta solução oferece às organizações uma plataforma escalável e econômica para executar fluxos de trabalho de GitHub Actions, mantendo controle total sobre sua infraestrutura. A arquitetura pode facilmente escalar de pequenas equipes de desenvolvimento para implantações em nível empresarial, adaptando-se às mudanças nos requisitos do fluxo de trabalho sem comprometer a segurança ou o desempenho.
Ao aproveitar serviços gerenciados da AWS como o EKS e implementar infraestrutura como código via Terraform, essa solução reduz a sobrecarga operacional enquanto oferece a flexibilidade necessária
para pipelines modernos de CI/CD. O resultado é uma plataforma robusta e eficiente que permite que as equipes foquem em entregar valor em vez de gerenciar a infraestrutura.
Siga o programa Talking AWS do The Zacs no YouTube ou entre em contato com eles se quiser compartilhar seu conhecimento sobre AWS.
Se tiver dúvidas sobre essa solução, entre em contato comigo pelo Linkedin, X.
Estelar Promovida
🚀 Série Stellar Dev Diaries: Episódio 1 está AO VIVO!
Já se perguntou o que é necessário para construir uma startup web3 do zero? Na série Stellar Dev Diaries, acompanhamos a jornada de uma equipe de desenvolvedores que desenvolvem a Stellar Network enquanto vão da vitória de hackathon até conseguir financiamento e lançamento na mainnet.
Leia Mais










