Alura > Cursos de DevOps > Cursos de Builds > Conteúdos de Builds > Primeiras aulas do curso Integração Contínua: Pipeline Docker no Github Actions

Integração Contínua: Pipeline Docker no Github Actions

Rotinas existentes - Apresentação

Boas-vindas ao curso de Integração Contínua: Pipeline Docker no Github Actions. Sou o Leonardo Sartorello e vou te acompanhar neste curso.

Neste curso, veremos a história do Bruno. Ele já está trabalhando na nossa empresa no setor de DevOps e já fez automatização de alguns processos. Como, por exemplo, os testes automatizados da nossa aplicação.

Agora, o Bruno possui novos objetivos, que aprenderemos junto com ele.

O que vamos aprender?

Aprenderemos como criar um Container Docker, vamos ver como podemos fazer essa criação através das rotinas de CI. Isso vai envolver a melhoria das rotinas de integração contínua, para conseguirmos atingir o objetivo de criar o Container Docker com algumas vantagens. Principalmente em organização e facilidade de uso.

Vamos aprender a utilizar artefatos, bons para não precisarmos repetir códigos ou passos.

Qual ferramenta vamos usar?

Neste curso, utilizaremos, principalmente, o GitHub Actions. É uma ferramenta relativamente nova na área de CI (Integração contínua), que está sendo bem aceita e usada atualmente.

Para quem é esse curso?

Este curso é para todos que realizaram os cursos que constam nos pré-requisitos, tem vontade de aprender um pouco mais sobre CI e quer entender como conseguimos integrar a criação de Containers Docker. E também algumas funções a mais que veremos agora, no "Fazendo esse curso".

Fazendo esse curso

Ao longo do curso, você vai se aprofundar nas rotinas de CI, vendo como conseguimos utilizá-las. Criaremos um segundo arquivo para organizar rotinas, para estruturar melhor essas rotinas de CI. Usaremos os "Secrets", para guardar segredos e chaves de acesso que não podem ser expostas.

Vamos usar o "Go", para realizar modificações no programa. Isso para melhorarmos o que ele já possui. Depois, aproveitar e realizar testes para analisar se o código está funcionando com essas melhorias utilizando as rotinas de CI criadas por nós. Por fim, criar e salvar o Container Docker, no Docker Hub.

Espero que você esteja pronto e animado para este curso, porque eu estou!

Vamos lá?

Rotinas existentes - Sempre executar

Já trabalhamos com um time de DevOps em uma empresa de TI junto com o Bruno, que entrou recentemente para a equipe. Ele ficou responsável por automatizar alguns processos, como a execução dos testes automatizados.

Isso para poupar o tempo dos desenvolvedores e garantir que todas as etapas sejam sempre executadas e na ordem correta. Para automatizar os testes, o Bruno decidiu automatizar a criação de um Container Docker para a nossa aplicação. Já que a empresa está pensando em mudar todas as aplicações para uma infraestrutura de containers.

Os Containers são mais rápidos de serem criados e configurados que as máquinas virtuais que usamos atualmente na infraestrutura da empresa. Essa tarefa teria que ser feita manualmente para cada atualização. O Bruno, que automatizou os testes e quer deixar a criação de forma automática. Para isso, ele precisa da nossa ajuda.

Vamos ajudá-lo para analisarmos como podemos aprender mais com esse projeto?

Para começar, vamos abrir o repositório no GitHub e analisar o que ele já possui de automatização do GitHub Actions. Para isso, clicaremos na primeira pasta .github/workflows, sendo o arquivo referente às rotinas do GitHub Actions.

Dentro temos o arquivo go.yml, selecionaremos ele. No código temos quando vai ser executado, no caso é quando for rodado o comando push, para uma branch específica [ Aula_1 ]. Vamos ter que modificar isso, visto que queremos que sempre seja executado, em qualquer branch.

go.yml:

name: Go

on:
  push:
    branches: [ Aula_1 ]
  pull_request:
    branches: [ Aula_1 ]

A partir da linha 9, em jobs, analisaremos as etapas. É rodado os testes no Ubuntu, podemos alterar esse detalhe também, para que ele execute em vários sistemas. Em go_version são as versões que usa da ferramenta. Da linha 19 até a 22, é preparado as máquinas para o Go.

No run da linha 25, é efetuado um docker-compose build, para subir os dados que já estão no repositório, com o comando docker-compose up -d. Em seguida, é realizado os testes e, depois, um build, na linha 40.

O nosso código já realiza bastante coisa. Porém, já mencionamos dois pontos que podemos alterar. O primeiro é ser executado sempre que um push for rodado em qualquer branch que possui o nosso código.

Para isso, clicaremos no ícone de lápis na parte superior direita do código e selecionaremos "Edit this file". Para usarmos a parte de edição para realizarmos as modificações necessárias. Em branches, nas linhas 5 e 7, ao invés de "AULA_1" colocaremos '*', que significa "qualquer".

Note que aparece um sublinhado em vermelho com um aviso "name of an alias node must contain at least one character". Isso significa que asterisco não é um nome válido para a branch, por isso usaremos aspas simples (''). Assim, vira uma string e, consequentemente, um nome válido.

go.yml:

name: Go

on:
  push:
    branches: [ '*' ]
  pull_request:
    branches: [ '*' ]

Para testar, na parte superior direita da tela, clicaremos no botão verde com o escrito "Start commit", em branco. Vai ser exibida uma aba com o título "Commit changes", em que no primeiro campo para escrever digitaremos "Aula_1". Após isso, vamos selecionar o botão verde com o escrito "Commit changes", na parte inferior esquerda da aba.

Pronto, o arquivo está salvo. Agora, podemos analisar se está sendo executado na aba "Actions", no menu superior da tela do GitHub. Clicando em "Actions", em "workflow runs" podemos visualizar "Aula_1", com um círculo em amarelo do lado esquerdo. Isso significa que está rodando.

Selecionando "Aula_1", temos o Status como "In progress" e em "View 3 jobs" temos "0/3 jobs completed". Com isso, a nossa rotina vai funcionar para qualquer branch, pode ser desenvolvedor(a), main ou para alguma feature específica.

Isso adianta bastante o nosso trabalho, dado que todos os testes automatizados serão executados independente da branch. Faltou só finalizar a execução, para rodarmos esse mesmo teste automatizado. Mas usando vários sistemas operacionais diferentes ou, pelo menos, várias versões do Ubuntu, sendo o que faremos no próximo vídeo.

Vamos lá?

Rotinas existentes - Múltiplos sistemas

A equipe de desenvolvedores nos alertou sobre o sistema que estamos usando. A aplicação que temos até o momento, pode não ter nenhum problema. Porém, outras aplicações podem apresentar algum contratempo.

Por exemplo, se a aplicação interage diretamente com o sistema operacional (SO) para ler um arquivo ou se comunicar com um periférico. Podemos ter problemas contra essa ação no sistema. Sabendo disso, é uma boa prática testarmos múltiplas versões de SO para investigar se está tudo funcionando.

SO: Sistema Operacional.

Para isso, vamos clicar na pasta .github/workflows, em seguida, no arquivo go.yml. Para alterar o arquivo, selecionaremos o ícone de lápis do lado direito da tela. O terceiro ícone, após o "Raw" e o "Blame".

Para testarmos em múltiplos sistemas operacionais, copiaremos o job inteiro e trocaremos o runs-on ou podemos usar o strategy matrix, igual temos para o go_version. No caso, faremos essa última opção, vamos copiar a estratégia de matriz e inserir na linha seguinte.

go.yml:

go_version: ['1.18', '1.17', '>=1.18']

Não queremos mais a versão do Go, podemos remover o go_version e inserir somente o os.

os: ['1.18', '1.17', '>=1.18']

Nas aspas simples dentro dos colchetes, colocaremos "ubuntu-latest" e "ubuntu-18.04", precisa ser a versão completa. Mesmo a versão 18.04 sendo um pouco antiga, é bastante usada ainda.

os: ['ubuntu-latest', 'ubuntu-18.04']

Na linha 12, em runs-on, faremos igual fizemos para rodar a estratégia de matriz do Go. Usamos o cifrão e duas chaves abertas e fechadas: (${{ matrix.go_version }}). Vamos apenas copiar e inserir no runs-on, alterando o "go_version" para "os", sendo o nome que colocamos para essa tentativa.

    runs-on: ${{ matrix.os }}

go.yml:

jobs:

  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        go_version: ['1.18', '1.17', '>=1.18']
                os: ['ubuntu-latest', 'ubuntu-18.04']

Agora colocaremos os testes para rodar na rotina de build, a partir da linha 35. Ao invés de "ubuntu-latest" no runs-on, colocaremos ${{ matrix.os }}.

build:
    needs: test
    runs-on: ${{ matrix.os }}

Vamos aproveitar para testar se ele vai conseguir usar a estratégia de matriz, que está em test dentro do build. Isso vai poupar algumas linhas de código.

Clicaremos no botão verde com o escrito "Start commit", na parte superior direita. Vai ser exibida uma aba com o título "Commit changes", em que no primeiro campo para escrever digitaremos "Aula_1". Após isso, vamos selecionar o botão verde com o escrito "Commit changes" para salvar o arquivo, na parte inferior esquerda.

Na aba "Actions", no menu superior da tela do GitHub, vamos visualizar se vai ser possível rodar várias versões do Ubuntu. Clicando em "Actions", em "workflow runs" podemos visualizar "Aula_1", com um círculo em amarelo do lado esquerdo.

Selecionando "Aula_1", há uma mensagem escrita "Triggered via push 15 seconds ago", informando que fizemos um push a 15 segundos atrás. Um Status como "In progress" e em "View 6 jobs" temos "0/6 jobs completed". Desta vez, são 6 jobs.

Clicando em "0/6 jobs completed", vai ser expandido e exibido o título "Matrix:test", com os jobs que estão sendo executados. A primeira opção é "test(1.17, ubuntu-18.04)", sendo o Go 1.17 no Ubuntu 18.04. A segunda só altera o "ubuntu-latest", a terceira é "test(1.18, ubuntu-18.04)" e a quarta muda apenas o "ubuntu-latest".

Perceba que há um círculo em amarelo rodando ao lado esquerdo de cada opção, isso significa que está sendo executado. Está funcionando, deixaremos rodando para analisar o que vai ser mostrado no término.

Matrix:test em "Actions":

test(1.17, ubuntu-18.04)
test(1.17, ubuntu-latest)
test(1.18, ubuntu-18.04)
test(1.18, ubuntu-latest)
test(>=1.18, ubuntu-18.04)
test(>=1.18, ubuntu-latest)

Note que agora os círculos estão na cor verde com um ícone "✅", isso significa que foi executado. Porém, há uma caixa em cinza ligada por uma linha aos testes escrito "build", em branco. Perceba que o círculo do lado esquerdo está apenas com o contorno em branco e cinza dentro. Isso quer dizer que não rodou.

Descendo um pouco a tela, em "Annotations", temos uma mensagem "Error when evaluating 'runs-on' for job 'build'. .github/workflows/go.yml". Isto é, ele está tentando avaliar o que consta no runs-on.

Se clicarmos em "Show more" aparece uma mensagem informando o que era esperado: "Unexpected type of value '', expected type: OneOf". Ou seja, encontrou um valor inesperado, um vazio. Por que foi encontrado um valor vazio?

Subindo a tela e clicando duas vezes na seta se voltar do navegador, no canto superior esquerdo, vamos analisar esse erro. Podemos ir para a edição do arquivo selecionando o ícone de lápis e escolhendo a opção "Edit this file".

No caso, a estratégia só será executada dentro de um único job. Nós preparamos uma estratégia para o job de test, porém não formulamos nenhuma para o build. Assim, quando ele foi buscar a estratégia de matrix.os no build, não encontrou, por isso, retornou um valor vazio.

Portanto, incluiremos essa estratégia no build também. Para isso, copiaremos a do jobs e colaremos a partir da linha 38, podemos remover o go_version.

go.yml:

//código omitido

build:
    needs: test
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: ['ubuntu-latest', 'ubuntu-18.04']

//código omitido

Com isso, temos uma estratégia definida para o build. Isto é, uma estratégia de matriz para rodar no Ubuntu latest e no Ubuntu 18.04. Em seguida, clicaremos no botão verde com o escrito "Start commit".

Vai ser exibida uma aba com o título "Commit changes", em que no primeiro campo para escrever digitaremos "Aula_1". Logo após, vamos selecionar o botão verde com o escrito "Commit changes" para salvar o arquivo, na parte inferior esquerda.

Na aba "Actions" do menu superior da tela do GitHub, em "workflow runs" podemos visualizar "Aula_1", com um círculo em amarelo do lado esquerdo. Selecionando "Aula_1", há uma mensagem escrita "Triggered via push now", com um Status "In progress". Aguardaremos para analisar se vai executar o build nas versões que inserimos.

Após a finalização, temos um Status como "Success" e em "Total duration", consta 2 minutos e 13 segundos. Em "View 6 jobs" temos "6 jobs completed", com um círculo verde com um ícone "✅". Do lado direito, em "Matrix:build" temos "2 jobs completed".

Clicando em "6 jobs completed", vai ser expandido com os jobs que foram executados. Todos estão com o círculo verde. Selecionando o "2 jobs completed", temos o "build (ubuntu-18.04)" e "build (ubuntu-latest)", ambos com o círculo verde com o ícone "✅". Ou seja, tudo funcionou conforme o esperado agora.

Assim, estamos conseguindo executar os testes e as compilações em sistemas operacionais diferentes. Isso quer dizer que a aplicação está íntegra e pronta para colocarmos no Container Docker.

build do arquivo go.yml:

//código omitido

 build:
    needs: test
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: ['ubuntu-latest', 'ubuntu-18.04']
    steps:
    - uses: actions/checkout@v3
    - name: Build
      run: go build -v main.go

Sobre o curso Integração Contínua: Pipeline Docker no Github Actions

O curso Integração Contínua: Pipeline Docker no Github Actions possui 100 minutos de vídeos, em um total de 52 atividades. Gostou? Conheça nossos outros cursos de Builds em DevOps, ou leia nossos artigos de DevOps.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Builds acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas