Skip to main content

Como gerenciar imagens Docker do Node.js no GitHub Packages usando GitHub Actions

Escrito por
blog hero github actions docker push

13 de julho de 2021

0 minutos de leitura

Se você trabalha com desenvolvimento de código aberto hoje, é bem provável que participe da comunidade do GitHub — contribuindo para projetos e repositórios de código aberto. Uma adição recente ao ecossistema do GitHub é o GitHub Packages, anunciado em 2019 e que agora recebe ainda mais atualizações com a disponibilidade geral do registro de contêineres do GitHub Packages. Isso significa que podemos publicar e baixar imagens baseadas em Docker, além de outros formatos compatíveis com OCI, inteiramente dentro do ecossistema do GitHub.

Nesta publicação, vou explicar cada etapa de um workflow do GitHub Actions. Você vai aprender a publicar projetos Node.js como imagens Docker e enviá-las ao registro de contêineres do GitHub Packages.

Antes de começarmos, você sabia que existe um fórum de suporte dedicado aos usuários do GitHub, chamado GitHub Support Community? Vale a pena visitar se você precisar de ajuda.

O projeto Node.js deste artigo é o dockly, uma ferramenta de linha de comando de código aberto para Node.js que oferece uma interface imersiva no terminal para gerenciar contêineres e serviços Docker.

README do Dockly, mostrando uma interface de terminal para gerenciar contêineres Docker, com listas de contêineres, gráficos de status e registros.

Criando um workflow do GitHub Actions

Acesse seu repositório de código aberto no GitHub, clique na aba Actions, depois em New Workflow e em set up a workflow yourself. A tela deve ser parecida com esta:

Página do GitHub Actions exibindo o título “Escolha um modelo de workflow” e opções para selecionar ou configurar um workflow

Primeiro, definimos o nome do arquivo de workflow: docker-publish.yml ou qualquer outro padrão de nomenclatura que você preferir.

O GitHub pode preencher o código do workflow automaticamente. Nesse caso, basta removê-lo e colar o seguinte:

name: Docker

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

on:
  push:
    branches: [ main ]
    tags: [ 'v*.*.*' ]
  pull_request:
    branches: [ main ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

O workflow acima estabelece as seguintes convenções:

  • O workflow é executado apenas em commits na branch main ou em pull requests para a branch main. Observação: se o seu repositório ainda usa a convenção antiga da branch master, renomeie-a aqui e em todo o restante do trecho de código. O workflow também é executado quando qualquer tag no formato semver <v*.*.*> é enviada ao repositório. Isso é útil porque nos permite publicar imagens Docker para cada versão.

  • Ele garante que, quando uma nova imagem Docker é publicada, também sejam criadas tags no repositório do GitHub.

  • Ele configura variáveis de ambiente globais para os demais jobs do workflow, apontando para o GitHub Container Registry (ghcr.io), e define o nome da imagem Docker usando a convenção padrão do Docker Hub, <user>/<repo>, como lirantal/nodejs-app.

Em seguida, vamos definir nossos jobs, que estabelecerão um processo para criar a imagem Docker e publicá-la.

Criação da imagem Docker como parte do workflow do GitHub Actions

Para publicar imagens Docker no registro de contêineres do GitHub Packages (ou mesmo apenas no GitHub), primeiro precisamos autenticar com uma conta válida. Por isso, as primeiras etapas do job de criação e publicação são para fazer login.

Dê continuidade ao código anterior copiando o trecho a seguir:

jobs:
  build_and_publish:

    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Log into registry ${{ env.REGISTRY }}
        if: github.event_name != 'pull_request'
        uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

Vamos analisar as ações executadas pelos jobs definidos aqui:

  1. A primeira etapa é fazer checkout do código-fonte do repositório.

  2. Em seguida, fazemos a autenticação no registro de contêineres do GitHub Packages. Como você pode ver, reutilizamos a variável de ambiente REGISTRY que definimos antes, apontando para ghcr.io, o registro do próprio GitHub para imagens de contêineres.

    O nome de usuário usado para autenticação é o da pessoa que iniciou o workflow, que deve ser o mesmo usuário proprietário do repositório. Para a senha, usamos o GITHUB_TOKEN, disponibilizado automaticamente aos workflows do GitHub Actions. Você não precisa adicioná-lo manualmente como segredo ou variável de ambiente no repositório. Repare que o login no registro não é feito em pull requests — o que não é necessário e poderia expor informações confidenciais em execuções de CI de pull requests e forks.

  3. A última etapa do trecho de código acima extrai metadados da imagem e os disponibiliza no processo de criação da imagem Docker (nossa próxima e última etapa neste workflow!). Os metadados incluem informações sobre tags e rótulos, disponibilizadas para a ação de criação do Docker. Especificamente, a entrada images define a imagem Docker usada como nome-base para as tags.

Criando uma imagem Docker e publicando-a no registro de contêineres do GitHub Packages

A etapa final é criar e publicar a imagem Docker. Isso é feito em uma única etapa, usando uma ação que oferece suporte a esse processo. Observe, porém, que definimos a entrada pushdesse workflow com uma condição para só tentar publicar a imagem no registro quando o evento não for um pull request:

      - name: Build and push Docker image
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Pronto.

Depois de salvar o workflow (com a indentação correta!) e acioná-lo ao mesclar esse workflow na branch main, uma imagem deverá ser criada e publicada no registro de contêineres do GitHub Packages.

Se tudo deu certo, você verá a tão esperada marca de seleção verde indicando que o job foi concluído com sucesso, como aconteceu comigo:

Fluxo do GitHub Actions mostrando a criação e o envio bem-sucedidos de uma imagem para o GHCR na branch master

Como faço para enviar uma imagem Docker ao registro de contêineres do GitHub Packages?

Use a ação oficial do Docker para GitHub, docker/build-push-action, no arquivo de workflow do GitHub Actions e verifique se a variável de ambiente REGISTRY está definida como ghcr.io.

Baixando imagens Docker do registro de contêineres do GitHub Packages

Agora que publicamos a imagem Docker do nosso projeto em um registro público, vamos testá-la baixando-a para o ambiente de desenvolvimento local:

$ docker pull ghcr.io/lirantal/my-nodejs-app
Using default tag: latest
latest: Pulling from lirantal/my-nodejs-app
b4d181a07f80: Pulling fs layer
de8ecf497b75: Pulling fs layer
69b92f9e5e70: Pulling fs layer
1f2b8e2c8ad8: Waiting
d0f4259cb643: Waiting
9ae47f3f99ba: Waiting
87270829eb60: Waiting
905fc634546c: Waiting

Como especifico a versão da imagem Docker que quero baixar?

O comando docker pull recebe um argumento adicional no formato <registry>/<user>/<repo>:<image tag>. Por exemplo, para baixar a imagem Docker com a tag "latest" do registro de contêineres do GitHub Packages para a my-nodejs-app image, use o seguinte comando: docker pull ghcr.io/lirantal/my-nodejs-app

Oba, deu certo!

Mas espere... não existe uma maneira melhor de visualizar as imagens Docker que envio ao GitHub Packages? É só conferir!

Encontrando imagens Docker no GitHub Packages

Acesse a página do seu perfil no GitHub (como a minha: https://github.com/lirantal?tab=packages) para ver todas as suas imagens Docker disponíveis publicamente.

Se você acompanhou este tutorial e criou sua própria imagem Docker, consegue encontrá-la? Esta é a página do pacote de imagem Docker que enviei ao GitHub Packages como parte do CI do GitHub Actions do repositório:

Página do GitHub Container Registry para dockly, exibindo o comando Docker pull, as versões da imagem com tags e o README.

A imagem Docker publicada não tem a tag latest?

Se você tentou baixar a imagem Docker pelo nome, sem especificar a tag da imagem Docker para a branch main ou master que está usando, talvez tenha percebido que a tag de imagem Docker mais comum, latest, não está disponível. Isso acontece quando nenhuma tag semver (versionamento semântico) é enviada. Se você estiver enviando essas tags no seu repositório, ela deverá ficar disponível.

Para garantir que a imagem Docker publicada tenha o alias de tag latest, podemos atualizar a ação de metadados da seguinte forma (repare na chave flavor adicional, com várias linhas):

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          flavor: |
            latest=true
            prefix=
            suffix=

Mas atenção: isso sempre definirá a tag de imagem latest como alias da imagem Docker publicada quando um job de CI for acionado pela branch main.

Como marco uma imagem Docker com a tag latest?

Para marcar localmente uma imagem criada anteriormente, podemos usar a seguinte estrutura do comando Docker tag: <local image name> <new tag>. Por exemplo: docker tag my-nodejs-app lirantal/my-nodejs-app:latest

Como executo uma imagem Docker com uma tag?

Para usar uma tag específica ao executar uma imagem Docker, basta fornecer o nome completo da imagem e a tag ao comando docker run. Por exemplo: docker run --rm -p 27017:27017 mongo:latest

Integrações relevantes de Docker e contêineres no GitHub Actions Marketplace

Outra forma de encontrar e criar workflows do GitHub Actions é acessar o GitHub Actions Marketplace, que oferece mais de 9.000 workflows nas áreas de qualidade de código, gerenciamento de dependências, segurança e muito mais. Você também encontrará o Snyk GitHub Actions, que ajuda a proteger seus projetos contra vulnerabilidades de terceiros em bibliotecas de código aberto e garante que sua equipe siga práticas de programação segura.

Para o foco deste artigo — criar, testar e publicar imagens Docker em um registro — há uma maneira mais simples de começar do que navegar pelo marketplace. Se o seu repositório já tiver um Dockerfile, o GitHub vai detectá-lo automaticamente e sugerir workflows relevantes para o GitHub Actions. Basta acessar a aba Actions:

Página de configuração do GitHub Actions exibindo fluxos de trabalho sugeridos para Dockerfile, para publicar um contêiner Docker ou criar uma imagem Docker

O primeiro workflow sugerido, Publish Docker Container, configura um processo de criação e publicação de imagens Docker semelhante ao que acabamos de analisar.

Resumo e próximos passos

Ficou um pouco mais interessado em práticas de desenvolvimento seguro? Ótimo! Separei alguns materiais de leitura para você começar e ganhar pontos de segurança com sua equipe:

  1. A segurança da cadeia de suprimentos é importante. Confira estas 10 boas práticas de segurança do GitHub para evitar repetir os erros.

  2. Você trabalha com Node.js e cria pacotes npm? Eu também! Escrevi um artigo para ajudar você a começar a publicar pacotes npm com segurança usando GitHub Actions

  3. Se você passa muito tempo no ecossistema do GitHub, conheça a análise de código da Snyk, que oferece uma experiência mais integrada aos seus workflows: GitHub Security Code Scanning: proteja suas dependências de código aberto

Comece a jogar Capture the Flag

Aprenda a resolver desafios de Capture the Flag assistindo sob demanda ao nosso workshop virtual introdutório.

Publicado em: