CI/CD, continuous integration/continuous delivery, é um método para entregar aplicações com frequência aos clientes. Para isso, é aplicada a automação nas etapas do desenvolvimento de aplicações. Os principais conceitos atribuídos a esse método são a integração, entrega e implantação contínuas.Red Hat
Com o CI/CD, é possível solucionar os problemas que a integração de novos códigos pode causar para as equipes de operações e desenvolvimento (o famoso "inferno de integração").Red Hat
Especificamente, o CI/CD aplica monitoramento e automação contínuos em todo o ciclo de vida das aplicações, incluindo as etapas de teste e integração, além da entrega e implantação. Juntas, essas práticas relacionadas são muitas vezes chamadas de "pipeline de CI/CD" e são compatíveis com o trabalho conjunto das equipes de operações e desenvolvimento com métodos ágeis.Red Hat
O acrônimo CI/CD tem alguns significados. "CI" sempre se refere à integração contínua, que é um processo de automação para desenvolvedores. "CD" se refere à entrega contínua e/ou à implantação contínua, conceitos relacionados e usados alternadamente às vezes.Red Hat
Geralmente, a entrega contínua representa as mudanças feitas pelo desenvolvedor em uma aplicação, que são testadas contra bugs e carregadas em um repositório ou em um registro de container. Nesse repositório, a equipe de operações pode implantar essas mudanças em um ambiente de produção ativo.Red Hat
Isso resolve o problema de baixa visibilidade e comunicação entre as equipes de negócios e desenvolvimento. Para isso, a finalidade da entrega contínua é garantir o mínimo de esforço na implantação de novos códigos.Red Hat
A implantação contínua, outro significado para "CD", se refere ao lançamento automático das mudanças feitas por um desenvolvedor do repositório à produção, onde podem ser usadas pelos clientes. Isso evita a sobrecarga das equipes de operações por conta dos processos manuais que atrasam a entrega de aplicações.Red Hat
Com a integração contínua (CI), os desenvolvedores consolidam as mudanças no código de volta a uma ramificação compartilhada ou "tronco" com mais frequência (às vezes, até diariamente). As mudanças são consolidadas e depois validadas através da criação automática da aplicação.Red Hat
Vários testes automatizados, geralmente de unidade e integração, são feitos para garantir que as mudanças não corrompam a aplicação. Basicamente, tudo é testado, incluindo classes, funções e diferentes módulos que formam toda a aplicação. Em caso de conflito entre os códigos novos e existentes, a CI facilita a correção desses bugs com rapidez e frequência.Red Hat
Depois de realizar a automação de compilações e da unidade e os testes de integração na CI, a entrega contínua automatiza o lançamento desse código validado em um repositório.Red Hat
Portanto, para um processo eficaz de entrega contínua, é importante que a CI já esteja integrada ao pipeline de desenvolvimento. O objetivo da entrega contínua é garantir uma base de códigos que esteja sempre pronta para implantação em um ambiente de produção.Red Hat
Cada etapa da entrega contínua, da consolidação das mudanças de código à entrega de compilações prontas para produção, inclui a automação do lançamento de códigos e do teste. No final desse processo, a equipe de operações pode implantar uma aplicação na produção com rapidez e facilidade.Red Hat
A etapa final de um pipeline de CI/CD sólido é a implantação contínua. Ela é um complemento da entrega contínua, que automatiza o lançamento de compilações prontas para produção em um repositório de códigos.Red Hat
A implantação contínua automatiza o lançamento de uma aplicação para a produção. Como não há um canal manual na etapa do pipeline antes da produção, a implantação contínua depende muito da automação otimizada dos testes.Red Hat
Na prática, a implantação contínua significa que a mudança do desenvolvedor em uma aplicação será habilitada depois de alguns minutos após a gravação (supondo que ela seja aprovada no teste automatizado). Isso facilita muito mais o recebimento do feedback dos usuários e a incorporação dele.Red Hat
Juntas, todas essas práticas de CI/CD relacionadas diminuem o risco da implantação de aplicações, facilitando o lançamento das mudanças em pequenas partes, e não de uma só vez. No entanto, há também a necessidade de muitos investimentos iniciais, já que os testes automatizados precisam ser gravados para acomodar várias etapas de teste e lançamento no pipeline de CI/CD.Red Hat
Automatize, personalize e execute seus fluxos de trabalho de desenvolvimento do software diretamente no seu repositório com o GitHub Actions. Você pode descobrir, criar e compartilhar ações para realizar qualquer trabalho que desejar, incluindo CI/CD, bem como combinar ações em um fluxo de trabalho completamente personalizado.Documentação do GitHub Actions
Um Fluxo de trabalho ("workflow") é configurado através de um arquivo
YAML na pasta
.github/workflows
do seu repositório
Cada Fluxo é composto por:
name: Backend
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
job1:
name: Nome do primeiro job
runs-on: ubuntu-latest
steps:
- name: "Passo que usa um pacote pronto"
uses: autor/pacote@versao
with:
configuracao1: valor1
configuracao2: valor2
configuracao3: valor3
configuracao4: ${{ secrets.VARIAVEL_DO_SECRETS }}
- name: "Passo que executa comandos no shell"
run: |
comando1 args...
comando2 args...
comando3 args...
job2:
name: Nome do segundo job
runs-on: ubuntu-latest
needs: job1
if: github.ref == 'refs/heads/main'
steps:
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
Sintaxe de fluxo de trabalho para o GitHub Actions
Ao invés de ficar fazendo push ou outras ações reais no seu repositório para rodar um workflow, recomendo usar o nektos/act , ferramenta que permite executá-lo localmente em sua máquina, simulando os eventos de gatilho
Organize os jobs e steps para que as ações mais rápidas sejam executadas primeiro — assim, caso alguma etapa falhe, economizaremos tempo (e dinheiro)
Exemplo de pipeline:
jobs:
job1:
name: Nome do primeiro job
runs-on: ubuntu-latest
steps:
- name: Checkout do código
uses: actions/checkout@v4
- name: Configurando ambiente
run: apt-get update && apt-get install jq
- name: Instalando dependências de desenvolvimento
run: npm install --production=false
- name: Análise estática do código
run: |
npm run lint
sonarscanner src/
- name: Build de desenvolvimento
run: npm run build:dev
- name: Testes
run: npm test
- name: Instalando dependências de produção
run: npm install --production=true
- name: Build de produção
run: npm run build
- name: Deploy
run: ./deploy-to-production build/
Faça cache de dependências, layers de containers e outros arquivos para diminuir o tempo de execução do workflow
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout do código
uses: actions/checkout@v4
- name: Configurando Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Instalando dependências
run: npm ci
Execute em paralelo jobs que não possuem dependência entre si
jobs:
testFirefox:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: "Testando no Firefox"
run: npm run e2e:test-firefox
testChrome:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: "Testando no Chrome"
run: npm run e2e:test-chrome
testWebkit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: "Testando no Webkit"
run: npm run e2e:test-webkit
Para facilitar a escrita de jobs em paralelo, é possível usar matrizes para criar variações de versões, sistemas operacionais, configurações e mais
jobs:
build:
strategy:
matrix:
version: [20, 21, 22]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: "Node ${{ matrix.version }} em ${{ matrix.os }}"
run: ...
Se seu workflow possuir grandes etapas de configuração de ambiente, você pode criar uma imagem de container em algum Registry (como o Docker Hub) e especificá-la
jobs:
build:
container:
image: organizacao/imagem
credentials:
username: ${{ secrets.RUNNER_REGISTRY_USERNAME }}
password: ${{ secrets.RUNNER_REGISTRY_PASSWORD }}
Running jobs in a container - GitHub Docs
Se ainda assim sentir que seu workflow está lento, você pode pagar pelos planos GitHub Team ou GitHub Enterprise Cloud para ter runners maiores ou rodá-los em sua própria infraestrutura
Caso tenha planos pagos:
jobs:
build:
runs-on:
group: my-large-runners-group
steps:
- ...
Caso tenha configurado em sua infra:
jobs:
build:
runs-on: self-hosted
steps:
- ...
Nunca deixe credenciais (como senhas e chaves de API) nos workflows
Utilize os secrets para guardar essas informações, que não vazarão em logs e nem poderão ser lidas por outros colaboradores do repositório
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Requisição da API
env:
access_token: ${{ secrets.API_ACCESS_TOKEN }}
run: |
curl -X POST \
-H "Authorization: Bearer $access_token" \
https://api.com/endpoint
Para evitar que seu workflow pare de funcionar caso alguma ação ou pacote tenha uma quebra de compatibilidade reversa, marque exatamente as versões das ações e pacotes que irá precisar
Antes:
steps:
- name: Checkout do código
uses: action/checkout
- name: Configurando Node
uses: actions/setup-node
- name: Baixando e executando algum cliente
run: |
wget https://download.com/latest.zip
unzip latest.zip
./client ...
Depois:
steps:
- name: Checkout do código
uses: action/checkout@v4
- name: Configurando Node
uses: actions/setup-node@v4
- name: Baixando e executando algum cliente
run: |
wget https://download.com/v1.5.7.zip
unzip v1.5.7.zip
./client ...
Para evitar que seu workflow pare de funcionar caso alguma ação ou pacote tenha uma quebra de compatibilidade reversa, marque exatamente as versões das ações e pacotes que irá precisar
Antes:
steps:
- name: Checkout do código
uses: action/checkout
- name: Configurando Node
uses: actions/setup-node
- name: Baixando e executando algum cliente
run: |
wget https://download.com/latest.zip
unzip latest.zip
./client ...
Ou até mesmo:
steps:
- name: Checkout do código
uses: action/checkout@a5ac7e51b41094c92402da3b24376905380afc29
- name: Configurando Node
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
- name: Baixando e executando algum cliente
run: |
wget https://download.com/v1.5.7.zip
unzip v1.5.7.zip
./client ...
Crie um arquivo .github/CODEOWNERS
com a sintaxe a seguir para determinar um
time para aprovar pull requests que contenham modificações nos seus
workflows
/.github/workflows @sua-organizacao/nome-do-time
About code owners - GitHub Docs
Todo workflow é executado com um access token para autenticação no repositório
Dependendo das ações do seu workflow, será preciso permitir alguns acessos através da configuração permissions:
Acesso geral (não recomendado):
name: "Meu workflow"
on:
push:
branches: [ "main" ]
permissions:
contents: write
jobs:
build:
steps:
- ...
Acesso em um único job:
name: "Meu workflow"
on:
push:
branches: [ "main" ]
jobs:
build:
permissions:
contents: write
steps:
- ...
Vários serviços (como os provedores de cloud) possuem integrações via OpenID Connect (OIDC), protocolo de autenticação baseado no OAuth 2, removendo a necessidade de usar credenciais como access tokens e garantindo maior segurança e praticidade
About security hardening with OpenID Connect - GitHub DocsPara isso, configure no serviço uma relação de confiança, dizendo que determinados tokens emitidos pelo GitHub Actions podem ter acesso à sua conta, e configure a troca do token OIDC em seu workflow
Exemplo com a Amazon Web Services:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: "Checkout do código"
uses: actions/checkout@v4
- name: "Configurando AWS"
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE }}
aws-region: ${{ env.AWS_REGION }}
- name: "Subindo no S3"
run: aws s3 sync ./dist/ s3://${{ env.AWS_BUCKET_NAME }}/ --delete
Configuring OpenID Connect in Amazon Web Services - GitHub Docs