Buildah: Tutorial Conciso para Construção de Imagens Leves e Sem Dependência do Docker

Buildah é uma ferramenta especializada na construção de imagens OCI, utilizando tecnologias de baixo nível como containers/image e containers/storage.

O trio de ferramentas OCI inclui:

  • Buildah, focado na construção de imagens
  • Podman, dedicado à gestão de imagens e contêineres
  • Skopeo, especializado em operações com imagens e repositórios remotos

Juntas, essas ferramentas formam um ecossistema de contêineres sem Docker, permitindo construir, gerenciar, enviar e operar imagens e contêineres sem depender do daemon do Docker.

É importante notar que existe alguma sobreposição de funcionalidades entre essas ferramentas, especialmente entre Buildah e Podman, mas cada uma tem seu foco específico. O uso combinado delas é recomendado.

Para entender melhor a relação entre Buildah e Podman, consulte a documentação oficial: buildah-and-podman-relationship

  1. O que é Buildah?

Buildah é uma ferramenta projetada especificamente para a construção de imagens OCI. A interface de linha de comando (CLI) do Buildah é implementada usando tecnologias baseadas em OCI, como os projetos containers/image e containers/storage.

A descrição oficial diz:

Uma ferramenta que facilita a construção de imagens OCI. A ferramenta de linha de comando Buildah (CLI) e as tecnologias baseadas em OCI subjacentes (por exemplo, containers/image e containers/storage).

A CLI do Buildah utiliza esses projetos para implementar funcionalidades de construção, movimento e gestão de imagens:

  • O projeto containers/image fornece mecanismos para copiar (enviar, buscar), inspecionar e assinar imagens de contêineres
  • O projeto containers/storage fornece mecanismos para armazenar camadas de sistema de arquivos, imagens de contêineres e contêineres

A questão que surge é: já existindo o Docker para a construção de imagens, por que precisaríamos do Buildah?

Buildah funciona sem daemon e pode ser executado em modo rootless, tornando-se mais leve em comparação com o docker. Se usado para substituir a capacidade de construção de imagens do Docker, por não requerer um daemon e poder ser executado sem privilégios root, torna-se muito conveniente mesmo quando usado dentro de contêineres, sendo uma excelente escolha para DevOps.

Em resumo: em comparação com as ferramentas de construção existentes, o Buildah é mais leve, oferece uma abordagem Dockerless e Rootless.

  1. Instalação do Buildah

Documentação oficial: buildah#install.md

O Buildah oferece pacotes para as principais distribuições Linux, que podem ser instalados facilmente usando gerenciadores de pacotes como yum, apt-get, dnf, etc. Também é possível instalar a partir do código fonte.

A instalação usando o gerenciador de pacotes da distribuição é recomendada:

# CentOS
sudo yum -y install buildah

# Ubuntu 20.10 e mais recentes
sudo apt-get -y update
sudo apt-get -y install buildah

# Fedora
sudo dnf -y install buildah


Para este demo, usaremos Ubuntu 22.04:

sudo apt-get -y update
sudo apt-get -y install buildah


Verificando a versão do Buildah

Nota: a versão do sistema é relativamente antiga, então a versão do buildah instalada também é mais antiga

root@construtor-ubuntu:~# buildah version
Versão:         1.23.1
Versão Go:      go1.17
Especificação de Imagem:      1.0.1
Especificação de Runtime:    1.0.2-dev
Especificação CNI:        0.4.0
Versão libcni:
Versão de imagem:   5.16.0
Commit Git:
Compilado:           Thu Jan  1 08:00:00 1970
SO/Arquitetura:         linux/amd64
Plataforma de Compilação:   linux/amd64


  1. Funcionalidades Básicas

Construção de imagens usando comandos

Em comparação com o Dockerfile, o Buildah oferece uma poderosa abordagem de construção baseada em comandos, transformando as instruções do Dockerfile em comandos individuais, proporcionando uma nova alternativa para a construção de imagens:

# Busca uma imagem, similar ao FROM do Dockerfile
contêiner=$(buildah from nginx)
# Similar ao RUN do Dockerfile
buildah run $contêiner -- bash -c 'echo "olá mundo" > /usr/share/nginx/html/index.html'
# Salva a imagem
buildah commit $contêiner nginx-ola


Saída esperada:

[root@construtor ~]# contêiner=$(buildah from nginx)
[root@construtor ~]# buildah run $contêiner -- bash -c 'echo "olá mundo" > /usr/share/nginx/html/index.html'
[root@construtor ~]# buildah commit $contêiner nginx-ola
Obtendo assinaturas da fonte da imagem
Copiando blob c0f1022b22a9 pulado: já existe
Copiando blob fc00b055de35 pulado: já existe
Copiando blob 2c3a053d7b67 pulado: já existe
Copiando blob b060cc3bd13c pulado: já existe
Copiando blob 8aa4787aa17a pulado: já existe
Copiando blob c28e0f7d0cc5 pulado: já existe
Copiando blob d32d820bcf1c pulado: já existe
Copiando blob c6a7a8084917 feito   |
Copiando config 19de2f1f4a feito   |
Escrevendo manifesto para destino da imagem
19de2f1f4afc6e0ff9da11e9dfb988619f4bcd1d388ea4c18413ab574487a0d4


Verificando a imagem construída recentemente

[root@construtor ~]# buildah images
REPOSITÓRIO                          TAG       ID DA IMAGEM       CRIADO          TAMANHO
localhost/nginx-ola               mais recente    19de2f1f4afc   22 segundos atrás   196 MB


Construção de imagens através de Dockerfile

Naturalmente, o Buildah também suporta a construção de imagens através de Dockerfile, que deve ser o método mais comum de uso.

Preparando um Dockerfile

FROM nginx
RUN echo "Olá Mundo" > /usr/share/nginx/html/index.html
EXPOSE 80


Usando o buildah para construir a imagem

buildah build -t nginx-ola2 .


Saída esperada

[root@construtor ~]# buildah build -t nginx-ola2 .
ETAPA 1/3: FROM nginx
ETAPA 2/3: RUN echo "Olá Mundo" > /usr/share/nginx/html/index.html
ETAPA 3/3: EXPOSE 80
COMMIT nginx-ola2
Obtendo assinaturas da fonte da imagem
Copiando blob c0f1022b22a9 pulado: já existe
Copiando blob fc00b055de35 pulado: já existe
Copiando blob 2c3a053d7b67 pulado: já existe
Copiando blob b060cc3bd13c pulado: já existe
Copiando blob 8aa4787aa17a pulado: já existe
Copiando blob c28e0f7d0cc5 pulado: já existe
Copiando blob d32d820bcf1c pulado: já existe
Copiando blob eec64f0b2723 feito   |
Copiando config 1b63bdb270 feito   |
Escrevendo manifesto para destino da imagem
--> 1b63bdb270c1
Imagem etiquetada com sucesso como localhost/nginx-ola2:latest
1b63bdb270c1066520a5ae37dcea3d5c3b9c5e9af581e76bf1287f9f79f77f03


O uso é basicamente idêntico ao docker build, com baixo custo de aprendizado para migração.

  1. Arquivos de Configuração

Assim como no trio de ferramentas OCI, os arquivos de configuração do Podman e Buildah são compartilhados.

Você pode encontrar os arquivos de configuração padrão do Podman e Buildah nos seguintes diretórios:

  • Arquivo de configuração global: /etc/containers/
  • Arquivo de configuração do usuário: ~/.config/containers/

Nota: o arquivo de configuração do usuário tem prioridade; se não existir, será usado o arquivo global.

Isso significa que diferentes usuários podem especificar seus próprios arquivos de configuração

No diretório /etc/containers, existem vários arquivos de configuração:

  • storage.conf: configurações relacionadas ao armazenamento
  • registries.conf: configurações relacionadas a repositórios de imagens
  • policy.json: configurações relacionadas à verificação de assinatura de contêineres
  • auth.json: informações de autenticação de repositórios de imagens, os tokens são armazenados neste arquivo após executar o comando login
  • ...

Para detalhes específicos de cada arquivo, consulte: Podman&Buildah Arquivos de Configuração

Como usuário, o arquivo registries.conf é o mais relevante, então vamos analisá-lo em detalhes.

vi /etc/containers/registries.conf


Conteúdo Completo

O conteúdo completo de /etc/containers/registries.conf é o seguinte:

unqualified-search-registries = ["registry.access.redhat.com", "registry.redhat.io", "docker.io"]

# Configuração do repositório Docker.io
[[registry]]
prefixo = "docker.io"
localização = "registry-1.docker.io"

# Configuração de espelho para Docker.io
[[registry.mirror]]
localização = "espelho.gcr.io"

[[registry.mirror]]
localização = "espelho2.gcr.io"


# Configuração do repositório privado 10.10.10.49:5000
[[registry]]
prefixo = "10.10.10.49:5000"
localização = "10.10.10.49:5000"
inseguro = true

# Configuração de espelho para repositório privado
[[registry.mirror]]
localização = "espelho.gcr.io"


modo-short-name = "permissivo"


Podemos dividir em várias seções:

  • Repositórios de imagens padrão
  • Configuração de Insecure, Mirror etc. para repositórios de imagens
  • Modo de processamento de shortName

Diferentes configurações de repositório são distinguidas usando blocos [[registry]].

Atenção: a seguinte configuração é da versão V1, que está obsoleta. Embora ainda possa ser usada, não é recomendada.

[registries.search]
registries = ['registry1.com', 'registry2.com']

[registries.insecure]
registries = ['registry3.com']

[registries.block]
registries = ['registry.nãoconfiável.com', 'registry.inseguro.com']


Explicação dos Parâmetros

Documentação oficial: containers-registries.conf.5.md

unqualified-search-registries

unqualified-search-registries é uma configuração que especifica quais repositórios (registries) devem ser tentados ao buscar uma imagem sem caminho copmleto (ou seja, sem domínio e caminho). Isso geralmente se aplica ao caso de "nome de repositório não especificado".

unqualified-search-registries = ["registry.access.redhat.com", "registry.redhat.io", "docker.io"]


Em uma frase: ao buscar uma imagem sem caminho completo (sem domínio e caminho), quais repositórios devem ser tentados.

short-name-mode

A opção short-name-mode define como nomes de imagem sem caminho de repositório (por exemplo, golang:1.20) são tratados. Existem três modos:

  • disabled: não permite o uso de nomes curtos, deve ser especificado o caminho completo do repositório.
  • permissive (padrão): permite o uso de nomes curtos e tenta encontrar a imagem na lista de repositórios configurados na ordem especificada.
  • full: só é possível buscar imagens quando o nome do repositório for completo.

O valor padrão é suficiente, sem necessidade de alteração.

modo-short-name = "permissivo"


prefixo

O prefixo sob o bloco Registry é usado para corresponder qual bloco de configuração de Registry será usado ao buscar imagens, apenas o bloco de correspondência mais longo será usado.

Suponha que tenhamos a seguinte configuração, com dois blocos Registry

[[registry]]
prefixo = "docker.io"

[[registry]]
prefixo = "docker.io.exemplo.com"


Quando buscamos a imagem docker.io.exemplo.com/library/busybox:latest, o domínio extraído do nome completo da imagem corresponderá ao prefixo no arquivo de configuração, e o segundo bloco de Registry será correspondido, usando assim as configurações desse bloco.

Em uma frase: geralmente preencha o endereço do Registry, mas no formato *.exemplo.com, ou especifique a localização.

localização

A localização no bloco Registry especifica o endereço final para buscar a imagem.

Ao buscar a imagem especificamos docker.io/library/busybox:1.36, mas o acesso final será feito no endereço registry-1.docker.io.

Para o docker.io, a seguinte configuração é necessária:

[[registry]]
prefixo = "docker.io"
localização = "registry-1.docker.io"


Além disso, quando o prefixo não está no formato *.exemplo.com, a localização também deve ser especificada, com o mesmo conteúdo do prefixo.

Em uma frase: usado para especificar o endereço real para buscar a imagem, por exemplo registry-1.docker.io, ou quando o prefixo não está no formato *.exemplo.com, a localização também deve ser especificada, com o mesmo conteúdo do prefixo.

inseguro

O parâmetro Insecure sob o bloco registry é comum, configura o uso de http para acessar o repositório, geralmente usado em repositórios privados autoconstruídos.

# Configuração do repositório privado 10.10.10.49:5000
[[registry]]
prefixo = "10.10.10.49:5000"
localização = "10.10.10.49:5000"
inseguro = true


bloqueado

A explicação oficial é: Se verdadeiro, a busca de imagens com nomes correspondentes é proibida.

O padrão é falso. Quando configurado como verdadeiro, não é mais possível buscar imagens do repositório especificado pelo prefixo.

# Configuração do repositório privado 10.10.10.49:5000
[[registry]]
prefixo = "10.10.10.49:5000"
bloqueado = false


Em uma frase: usado para desativar certos repositórios proibidos.

espelho

Para repositórios que não podem ser buscados ou cuja busca é lenta, podem ser configurados repositórios espelho.

# Configuração de espelho para Docker
[[registry]]
prefixo = "docker.io"
localização = "registry-1.docker.io"

[[registry.mirror]]
localização = "docker.m.daocloud.io"


O bloco registry.mirror deve estar sob o bloco Registry correspondente para configurar o espelho para esse repositório.

Arquivo de Configuração de Referência

A seguir está um exemplo de arquivo de configuração comum, incluindo configurações como localização, espelho, inseguro, que pode servir como referência ao adicionar outros repositórios de imagens.

unqualified-search-registries = ["docker.io"]
modo-short-name = "permissivo"

# Configuração de espelho para Docker
[[registry]]
prefixo = "docker.io"
localização = "registry-1.docker.io"

[[registry.mirror]]
localização = "docker.m.daocloud.io"

# Configuração do repositório privado "172.20.150.222"
[[registry]]
prefixo = "172.20.150.222"
localização = "172.20.150.222"
inseguro = true


  1. Uso Avançado

Aqui compartilharei alguns usos avançados, incluindo:

  • Construção multiestágio
  • Construção de imagens multiarquitetura
  • Uso do Buildah em ambientes CI

Construção Multiestágio

A construção multiestágio é uma técnica comum para otimizar o tamanho das imagens, separando o ambiente de compilação do ambiente de execução para reduzir o tamanho final da imagem. Vamos demonstrar com um simples programa Go.

main.go

Usando net/http para iniciar um serviço http.

// main.go
package main

import (
        "fmt"
        "log"
        "net/http"
)

func manipulador(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Olá, Mundo!")
}

func main() {
        http.HandleFunc("/", manipulador)
        log.Fatal(http.ListenAndServe(":8080", nil))
}


Dockerfile

O núcleo da construção multiestágio é o Dockerfile, que pode ver que o Dockerfile atual tem duas instruções FROM, correspondentes às fases de compilação e execução.

  • Fase de compilação: usa golang:1.20-alpine como imagem base para garantir que o programa Go possa ser compilado normalmente
  • Fase de execução: como o programa Go compilado pode ser executado diretamente sem depender do ambiente Go, usa diretamente alpine como imagem base, reduzindo o volume final da imagem
# Estágio 1: Estágio de compilação (construtor)
FROM golang:1.20-alpine as construtor

# Define o Diretório de Trabalho atual dentro do contêiner
WORKDIR /app

# Copia o código fonte para dentro do contêiner
COPY . .

# Compila o binário Go
RUN CGO_ENABLED=0 go build main.go

# Estágio 2: Estágio de Runtime
FROM alpine:latest

# Instala as bibliotecas necessárias para executar o binário (se houver)
RUN apk --no-cache add ca-certificates

# Define o Diretório de Trabalho atual dentro do contêiner
WORKDIR /root/

# Copia o binário compilado do estágio construtor
COPY --from=construtor /app/main .

# Expõe a porta 8080
EXPOSE 8080

# Executa a aplicação Go
CMD ["./main"]


Construção

buildah build -t servidor:v0.0.1 .


Saída esperada:

[root@construtor ~]# buildah build -t servidor:v0.0.1 .
[1/2] ETAPA 1/4: FROM golang:1.20-alpine AS construtor
[1/2] ETAPA 2/4: WORKDIR /app
[1/2] ETAPA 3/4: COPY . .
[1/2] ETAPA 4/4: RUN CGO_ENABLED=0 go build main.go
[2/2] ETAPA 1/6: FROM alpine:latest
Resolvido "alpine" como um alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Tentando buscar docker.io/library/alpine:latest...
Obtendo assinaturas da fonte da imagem
Copiando blob 38a8310d387e feito   |
Copiando config 4048db5d36 feito   |
Escrevendo manifesto para destino da imagem
[2/2] ETAPA 2/6: RUN apk --no-cache add ca-certificates
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
(1/1) Instalando ca-certificates (20241010-r0)
Executando busybox-1.37.0-r8.trigger
Executando ca-certificates-20241010-r0.trigger
OK: 7 MiB em 16 pacotes
[2/2] ETAPA 3/6: WORKDIR /root/
[2/2] ETAPA 4/6: COPY --from=construtor /app/main .
[2/2] ETAPA 5/6: EXPOSE 8080
[2/2] ETAPA 6/6: CMD ["./main"]
[2/2] COMMIT servidor:v0.0.1
Obtendo assinaturas da fonte da imagem
Copiando blob 3e01818d79cd pulado: já existe
Copiando blob 529cb79624ea feito   |
Copiando config 8d0a6344f5 feito   |
Escrevendo manifesto para destino da imagem
--> 8d0a6344f55c
Imagem etiquetada com sucesso como localhost/servidor:v0.0.1
8d0a6344f55c0611c94b23f2571adb0ba1ce98ee1d5009c79fd656fd42247c1b


Construção de Imagens Multiarquitetura

Muitos aplicativos e serviços precisam ser executados em máquinas com diferentes arquiteturas, como amd64 e arm64, mas não é possível ter uma máquina dedicada para cada arquitetura.

Anteriormente, o Docker Buildx era a principle ferramenta, mas o Buildah também suporta construção multiarquitetura.

Nota: ambas as ferramentas dependem do qemu

Instalação do qemu-user-static

O buildah usa qemu para simular diferentes arquiteturas.

Primeiro, certifique-se de que o qemu está instalado no seu sistema.

Nota: após testes, se seu Dockerfile não tiver comandos RUN para executar certas operações, o qemu não é necessário para construir imagens multiarquitetura.

Instale diretamente usando o gerenciador de pacotes:

# Ubuntu
sudo apt-get install qemu-user-static
# Fedora
sudo dnf install qemu-user-static


Construir e enviar imagens multiarquitetura

Assim como o Docker buildx, o Buildah também usa o parâmetro --platform para especificar a arquitetura a ser construída.

No entanto, o Buildah não tem o parâmetro --push, não podendo gerar automaticamente o manifesto e enviar após a construção. Portanto, precisamos criar manualmente um manifesto e vincular as imagens construídas e o manifesto antes de enviar para o repositório final de imagens.

O fluxo geral pode ser dividido em três etapas:

    1. Criar Manifesto
  • O manifesto criado aqui é na verdade uma imagem, que aparecerá na lista buildah images
  • O nome é recomendado usar o nome completo da imagem, por exemplo: 172.20.150.222/lixd/nginx-ola:v0.0.2, mas usar outro não afeta
    1. Construir imagem multiarquitetura
  • Note que o parâmetro --manifest deve ser usado em vez de --tag para vincular a imagem ao manifesot
    1. Enviar Manifesto e Imagem para o repositório de imagens
  • Ao enviar, é necessário especificar o nome do Manifesto e o caminho completo do Registry
  • Se o manifesto já usar o nome completo da imagem, os dois serão iguais

Comandos:

PUSH_WAY=172.20.150.222/lixd/nginx-ola:v0.0.2

# Criar manifesto
buildah manifest create ${PUSH_WAY}

# Construir
buildah build --manifest ${PUSH_WAY} --platform linux/amd64,linux/arm64 .

# Enviar
buildah manifest push ${PUSH_WAY} --all "docker://${PUSH_WAY}"


Definimos um script simples para implementar a construção de imagens multiarquitetura, o conteúdo completo do build.sh é o seguinte:

# Definir as variáveis necessárias
export REGISTRO="172.20.150.222"
export REPOSITORIO="lixd"
export NOME_IMAGEM="servidor"
export TAG_IMAGEM="v0.0.1"
export CAMINHO_CONSTRUÇÃO="."

# Arquiteturas para construir
export ARQUITETURAS="linux/amd64,linux/arm64"

PUSH_WAY="${REGISTRO}/${REPOSITORIO}/${NOME_IMAGEM}:${TAG_IMAGEM}"
NOME_MANIFESTO=$PUSH_WAY
echo $PUSH_WAY

# Criar manifesto multiarquitetura
### Na verdade, este comando pode ser ignorado, pois durante a construção o manifesto será criado se não existir
buildah manifest create ${NOME_MANIFESTO}

# Construir o contêiner para todas as arquiteturas
### Nota: quando há mais de uma plataforma, use manifest em vez da flag tag.
buildah build \
--manifest ${NOME_MANIFESTO} \
--platform ${ARQUITETURAS} \
${CAMINHO_CONSTRUÇÃO}

# Enviar o manifesto completo, com ambas as Arquiteturas de CPU
### Se enviando para Docker Hub ou Gitlab Registry, é necessário adicionar a flag: --format v2s2, o Padrão é oci
buildah manifest push --all \
  ${NOME_MANIFESTO} \
  "docker://${PUSH_WAY}"


Vamos usar o Demo Go anterior para compilar e gerar uma imagem multiarquitetura:

bash build.sh


Saída esperada:

root@construtor-ubuntu:~/multiestágio# bash build.sh
172.20.150.222/lixd/servidor:v0.0.1
e6ba6ec459a1fd7303c19242ab0d85c7c23af8cb156ce348928e2a4135327f15
# amd64
[linux/amd64] ETAPA 1/4: FROM golang:1.20-alpine AS construtor
[linux/amd64] ETAPA 2/4: WORKDIR /app
[linux/amd64] ETAPA 3/4: COPY . .
[linux/amd64] ETAPA 4/4: RUN CGO_ENABLED=0 go build main.go
[linux/amd64] ETAPA 1/6: FROM alpine:latest
[linux/amd64] ETAPA 2/6: RUN apk --no-cache add ca-certificates
[linux/amd64] ETAPA 3/6: WORKDIR /root/
[linux/amd64] ETAPA 4/6: COPY --from=construtor /app/main .
[linux/amd64] ETAPA 5/6: EXPOSE 8080
[linux/amd64] ETAPA 6/6: CMD ["./main"]
# arm64
[linux/arm64] [1/2] ETAPA 1/4: FROM golang:1.20-alpine AS construtor
[linux/arm64] [1/2] ETAPA 2/4: WORKDIR /app
[linux/arm64] [1/2] ETAPA 3/4: COPY . .
[linux/arm64] [1/2] ETAPA 4/4: RUN CGO_ENABLED=0 go build main.go
[linux/amd64] [2/2] ETAPA 1/6: FROM alpine:latest
[linux/arm64] [2/2] ETAPA 3/6: WORKDIR /root/
[linux/arm64] [2/2] ETAPA 4/6: COPY --from=construtor /app/main .
[linux/arm64] [2/2] ETAPA 5/6: EXPOSE 8080
[linux/arm64] [2/2] ETAPA 6/6: CMD ["./main"]
[linux/arm64] [2/2] COMMIT
# push
Obtendo assinaturas da fonte da imagem
Copiando blob 977340364f39 pulado: já existe
Copiando blob d8b4b7adc1e8 feito
Copiando config d97c60d03e feito
Escrevendo manifesto para destino da imagem
Armazenando assinaturas
--> d97c60d03e8
d97c60d03e822bb29c02c6b5c2c51b0f47871e52bc8c210c1e6324863797ce64
Obtendo lista de assinaturas de imagem
Copiando 4 de 4 imagens na lista
Escrevendo manifesto de lista para destino da imagem
...


Uso em Sistemas CI

Aqui usaremos o Github Action como exemplo para demonstrar como usar o Buildah para construir imagens multiarquitetura.

Código-fonte: lixd/github-action-lab

O Dockerfile e o main.go são os mesmos de antes, então não serão repetidos. Os interessados podem verificar no Github~

Workflow.yaml

O Workflow é o pipeline final executado, dividido em várias etapas:

    1. Iniciar o ambiente de execução, aqui ubuntu-20.04
    1. Clonar o código
    1. Instalar QEMU
    1. Construir imagem multiarquitetura com Buildah
    1. Enviar para o repositório de imagens
name: Build and Push Multi-Arch Image

on:
  push:

env:
  NOME_IMAGEM: test-multi-arch
  TAG_IMAGEM: latest
  REGISTRO_IMAGEM: docker.io
  ESPAÇO_NOMES: lixd96

jobs:
  build:
    name: Build and Push Multi-Architecture Image
    runs-on: ubuntu-20.04

    steps:
      # Checkout do repositório
      - name: Checkout repository
        uses: actions/checkout@v2

      # Configurar QEMU para builds multi-plataforma
      - name: Set up QEMU for multi-arch support
        uses: docker/setup-qemu-action@v1

      # Construir imagem Docker usando Buildah
      - name: Build multi-architecture image
        id: build-image
        uses: redhat-actions/buildah-build@v2
        with:
          image: ${{ env.NOME_IMAGEM }}
          tags: ${{ env.TAG_IMAGEM }}
          archs: amd64,ppc64le,s390x,arm64  # Especificar as arquiteturas para suporte multi-arquitetura
          dockerfiles: |
            ./Dockerfile

      # Enviar a imagem construída para o registro de contêineres especificado
      - name: Push image to registry
        id: push-to-registry
        uses: redhat-actions/push-to-registry@v2
        with:
          image: ${{ steps.build-image.outputs.image }}
          tags: ${{ steps.build-image.outputs.tags }}
          registry: ${{ env.REGISTRO_IMAGEM }}/${{ env.ESPAÇO_NOMES }}
          username: ${{ secrets.REGISTRY_USERNAME }}  # Nome de usuário do registro seguro
          password: ${{ secrets.REGISTRY_PASSWORD }}  # Senha do registro seguro

      # Imprimir o URL da imagem após o envio
      - name: Print pushed image URL
        run: echo "Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}"


Verificação

Após enviar o código, o Workflow será executado automaticamente. Verifique no Dockerhub se a imagem foi enviada com sucesso:

Podemos ver que as 4 arquiteturas especificadas foram construídas e enviadas com sucesso.

  1. Conclusão

O Buildah oferece uma forma flexível e eficiente de construir imagens, sem dependência do Docker, com suporte ao modo seguro rootless, adequado para vários ambientes DevOps e CI/CD. Ele suporta métodos de construção baseados em comandos e Dockerfile, além de permitir construções multiestágio e multiarquitetura.

Tags: Buildah OCI containers Dockerless podman

Publicado em 7-3 07:45