Entendendo e criando GitHub Docker Container Action

This post has been republished via RSS; it originally appeared at: New blog articles in Microsoft Community Hub.

Entendendo e criando GitHub Docker Container Action

 

Actions são tarefas individuais que podem ser combinadas para criar jobs (trabalhos) e personalizar workflows (fluxos de trabalho), ajudando a diminuir a quantidade repetitiva de código. Você pode utilizar as actions publicadas no GitHub Marketplace ou criar e customizar suas próprias actions.

 

O GitHub Actions permite criar 3 tipos de actions customizadas: Javascript, Composite e Docker Container. Nesse artigo, vamos entender sobre Docker Container Actions (DCA), como implementar sua primeira Docker action e testá-la em um GitHub workflow.

 

Docker container permite que você crie actions customizadas empacotando o ambiente com o código da action. Dessa forma, quem consumir sua action não precisa se preocupar com as dependências necessárias para executá-la, basta referenciar a action em seu workflow e executar, pois ela já conterá todos os componentes necessários para execução.

 

Quando usar Docker Container Action?

 

DCA é a opção ideal para actions que precisam ser executadas em ambientes com configurações específicas, já que permite personalizar o sistema operacional, as ferramentas, código e dependências sem necessitar adicionar ao runner (executor), basta apenas o runner possuir o Docker e é possível executar no mesmo runner diversas Docker actions e cada uma com sua personalização.

 

Você também pode utilizar DCA quando Javascript actions não for uma opção, seja por querer utilizar uma versão específica do Node, já que Javascript actions utilizam Node(16) ou até mesmo por familiaridade com outras linguagens, já que com Docker container é possível construir actions utilizando suas linguagens favoritas, seja Python, Go, Bash, Ruby e entre outras.

 

Criando Docker Container Actions

 

Agora vamos entender e executar os passos necessários para criar DCA, e teremos então uma Docker container action desenvolvida em Python que faz uma chamada a API do GitHub para listar branches de um repositório público.

 

Pré-requisitos

 

  • SO Linux e Docker: Para rodar DCA, os runners auto-hospedados precisam utilizar o sistema operacional Linux e ter o Docker instalado, mas você pode utilizar os runners hospedados no GitHub, que são gerenciados pelo GitHub e já possuem o Docker, como por exemplo ubuntu-latest.

  • Repositório: Antes de iniciar, é necessário criar um repositório GitHub.

    • Crie um novo repositório GitHub: Vamos utilizar list-branches-docker-action como nome do repositório, mas você pode criar com o nome que preferir. Para informações de criação de repositórios, consulte: Criando um novo repositório.

    • Clone o repositório: Após criar o repositório, clone em sua máquina. Saiba mais em: Clonando repositório.

    • Mude o diretório: Em seu terminal, execute o comando a seguir para mudar o diretório para o novo repositório:

      cd list-branches-docker-action

 

Código da action

 

No diretório raiz list-branches-docker-action, vamos criar o arquivo main.py que conterá o código escrito em Python que a action irá executar:

 

# Código da action
import requests
import json
import sys

r=requests.get("https://api.github.com/repos/"+sys.argv[1]+"/"+sys.argv[2]+"/branches", headers={"Accept": "application/vnd.github+json" ,"X-GitHub-Api-Version":"2022-11-28"})

objeto = json.loads(r.text)

print("\nLista de branches do repositório "+sys.argv[2]+ " :")
for v in objeto:
    print(v['name'])

Esse script faz uma chamada a API do GitHub https://api.github.com/repos/OWNER/REPO/branches, que recebe dois parâmetros: OWNER, representando o proprietário do repositório e REPO, que representa o nome do repositório do qual iremos listar as branches.

 

Para fazer essa chamada, inicialmente importamos os módulos necessários. Sendo requests, que possibilita realizarmos chamadas http, json para trabalharmos com os dados JSON e sys para manipularmos os parâmetros que são passados na execução do programa.

 

Onde fazemos a chamada da API, substituímos os argumentos OWNER e REPO por sys.argv[1] e sys.argv[2] correspondente, pois esses parâmetros serão atualizados com os valores passados como argumento para o contêiner.

 

Por fim, convertemos o json da resposta da API em um objeto Python Dictionary para conseguirmos percorrer esse objeto e trazer apenas o nome das branches.

 

Dockerfile

 

Com o código da action definido, seguindo a sintaxe e os padrões descritos em Suporte do arquivo Docker para GitHub Actions criamos o arquivo Dockerfile que será utilizado para criar a imagem que conterá o código da action.

 

#Imagem de contêiner que executa o código da action
FROM python:3.8-alpine

RUN pip install requests

COPY main.py /main.py

ENTRYPOINT ["python", "/main.py"]

Estamos utilizando python:3.8-alpine como base para nossa imagem, pois já inclui o Python. Com o comando RUN pip install requests Instalamos as bibliotecas necessárias para execução da action que são importadas no arquivo main.py, depois copiamos o arquivo que contém o código da action (main.py) para dentro do contêiner e ao final em ENTRYPOINT ["python", "/main.py"] adicionamos uma instrução para que o Docker execute o arquivo main.py assim que iniciar o contêiner. Dessa forma, estamos adicionando as dependências da action diretamente na imagem do contêiner juntamente com o código da action. Então, ao executar a imagem ela iniciará um contêiner com a action e suas dependências.

 

Note que estamos apenas instalando a biblioteca requests, pois json e sys são pacotes que já vêm integrado com o Python.

 

Arquivo de metadados da action

 

No diretório list-branches-docker-action, criamos um arquivo action.yml que contém toda a definição da action, como descrição, inputs (entradas) e outputs (saídas).

 

#action.yml
name: 'List Branches Docker Action'
description: 'Lista branches de um repositório público'
branding:
  icon: 'git-branch'
  color: 'blue'
inputs:
  owner: # id do input
    description: 'Sua organização ou usuário github'
    required: true
  repo: # id do input
    description: 'Nome do repositório' # que possui as branches a serem listadas
    required: true
runs:
  using: 'docker'
  image: 'Dockerfile'
  args:
    - ${{ inputs.owner }}
    - ${{ inputs.repo }} 

No action.yml acima, definimos o nome, descrição da action e o ícone e a cor que representará a action, caso deseje publicar no GitHub Marketplace.

 

Passar Inputs para o contêiner

 

Para passar os argumentos para o Docker container, precisamos declarar os inputs e então passá-los como argumento usando args. Em nosso arquivo, temos os inputs obrigatórios owner e repo, que são passados como argumentos inputs.owner e inputs.repo, pois serão utilizados para atualizar os parâmetros sys.args[1] e sys.argv[2] definidos em nosso arquivo main.py.

 

inputs:
  owner: # id do input
    description: 'sua organização ou usuário GitHub'
    required: true
  repo: # id do input
    description: 'nome do repositório' # que possui as branches a serem listadas
    required: true
runs:
  args:
    - ${{ inputs.owner }}
    - ${{ inputs.repo }} 

 

Definir a imagem da action

 

Precisamos especificar a imagem que será utilizada para iniciar o contêiner que contém o código da action. Na sessão run passamos a propriedade using como docker e podemos definir a imagem de 2 formas:

  1. Usando o arquivo Dockerfile presente no repositório da action:

    runs:
      using: 'docker'
      image: 'Dockerfile'

    Assim como em nosso action.yml, quando passamos Dockerfile em image, o GitHub runner construirá uma imagem a partir desse Dockerfile e iniciará um contêiner que executará o código definido em main.py.

  2. Usando uma imagem de um Docker registry:

    runs: 
      using: 'docker'
      image: 'docker://geovana10/list-branches-docker-action:v1'

    Ao utilizar uma imagem de um Docker registry, o GitHub runner não precisa construí-la, basta realizar pull (recuperação) dessa imagem, buscando ela e executando-a para iniciar o contêiner contendo o código da action.

Devido a latência que o runner tem de construir e recuperar a imagem, as Docker actions costumam ser mais lentas que Javascript actions.

 

Adicionar tag e realizar push da action para o repositório do GitHub

 

Após a criação dos arquivos main.py, Dockerfile e action.yml, podemos fazer o commit (confirmação), realizar o push (envio) para nosso repositório do GitHub e adicionar uma tag , que será utilizada posteriormente para identificar a versão da nossa action. No diretório local list-branches-docker-action, execute:

 

git add .
git commit -m "my actions file"
git tag -a v1 -m "Primeira versão list branches tag"
git push --follow-tags

 

Testar Docker container action em um GitHub Workflow

 

Com a action disponível em nosso repositório, já podemos testá-la em um GitHub workflow. As actions públicas podem ser utilizadas em qualquer repositório, mas podemos ter actions em repositório privado onde podemos controlar o acesso e podemos publicá-las no GitHub Marketplace. Para mais informações, veja Publicar actions no GitHub Marketplace.

 

Para usarmos a action, precisamos ter um arquivo .yml no diretório .github/workflows, então nesse diretório criamos o arquivo main.yml, que é executado sempre que for realizado um push na branch main do repositório.

 

on:
  push:
    branches: [ main ]
    
jobs:
  List-Branches:
    runs-on: ubuntu-latest
    name: Job para listar Branches de repositório GitHub
    steps:
      - name: Listar Branches action step
        id: list
        uses: geovanams/list-branches-docker-action@v1
        with:
          owner: 'geovanams'
          repo: 'public-repo'

Esse workflow possui um único job chamado List-Branches que executará o step (etapa) List Branches action step. Nesse step em uses chamamos a action que criamos anteriormente.

 

Como a action está em um repositório público, estamos definindo a action usando a seguinte sintaxe: geovanams/list-branches-docker-action@v1, que você pode substituir com as suas informações, onde temos o nome do usuário GitHub ou organização, em seguida o nome do repositório e então @v1 representando a versão da action, que corresponde a tag que criamos anteriormente, mas podemos versionar usando commit ID ou até mesmo o nome da branch. Para mais informações sobre como gerenciar versão de actions com tags e releases, visite: Melhores práticas para gerenciamento de versões

 

Para passarmos os parâmetros da action, utilizamos o atributo with. Nesse workflow, passamos os parâmetros owner e repo que você pode substituir os valores pelo proprietário e nome do repositório do qual deseja listar as branches.

 

uses: geovanams/list-branches-docker-action@v1
with:
    owner: 'geovanams'
    repo: 'public-repo'

Após salvar o arquivo no repositório, o GitHub já iniciará o workflow. Na aba Actions, podemos visualizar os logs de execução do job e steps do workflow.

 

logjobLista de steps do workflow que foi executado

 

Note que temos 2 steps principais:

 

1- Build geovanams/list-branches-docker-action@v1: Como definimos Dockerfile em nosso arquivo action.yml, o GitHub adicionou esse step de build para construir a imagem a partir do arquivo Dockerfile presente no repositório.

 

buildimage-stepLog do step de build construindo a imagem

 

Como dito anteriormente, se utilizarmos a imagem de um Docker registry, para recuperar a imagem o GitHub adicionaria o step de pull ao invés do de build. Exemplo:

 

pullimage-stepLog do step de pull recuperando a imagem do Docker registry

 

2 - Listar Branches action: Esse é o step que de fato chamamos a Docker action, ele mostra os parâmetros passados para action e o resultado de sua execução, listando então todas as branches do repositório definido.

 

listarbranches-stepLog do step Listar Branches action trazendo os parâmetros e a lista de branches

 

README

 

Criar um README é uma ótima maneira de definir como as pessoas devem utilizar suas actions. No diretório raiz list-branches-docker-action criamos o arquivo README.md, que contêm as informações necessárias de como utilizar a action que criamos.

 

# List Branches Docker Action
Essa action lista as branches de um repositório público.

## Inputs

## `owner`

**Required** Sua organização ou usuário GitHub que possui o repositório do qual deseja listar.

## `repo`

**Required** nome do repositório que possui as branches a ser listadas.

## Example usage

uses: geovanams/list-branches-docker-action@v1
with:
  owner: 'geovanams'
  repo: 'public-repo'

 

Estrutura de arquivos do repositório

 

Ao concluir os passos anteriores, teremos então um repositório estruturado da seguinte forma:

 

.
├── .github/workflows
│   └── main.yml
├── Dockerfile
├── README.md
├── action.yml
└── main.py

Você pode baixar essa estrutura com o código completo da Docker action do repositório GitHub List-Branches-Docker-Action.

 

Conclusões

 

Docker Container Action é uma excelente escolha para a criação de actions personalizadas que requerem linguagens ou configurações específicas. Com ela, você pode criar actions da maneira que preferir e usando as linguagens que desejar. Neste artigo, explicamos o que são Docker container actions, quando devem ser usadas e como criá-las e testá-las em um GitHub workflow.

 

Referências

 

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.