De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.

Como criar uma imagem com Containerfile

Colaboração: Rubens Queiroz de Almeida

Data de Publicação: 13 de agosto de 2026

Ao trabalhar com contêineres, podemos baixar imagens prontas de registros como Docker Hub e Quay.io. Entretanto, muitas vezes precisamos criar uma imagem personalizada, contendo nossa aplicação, arquivos de configuração e dependências.

No Podman, essa imagem pode ser criada por meio de um arquivo chamado Containerfile. Ele é um arquivo de texto que descreve, passo a passo, como a imagem deve ser construída.

Neste tutorial, criaremos uma imagem com o servidor Apache e uma página HTML personalizada. Depois, construiremos a imagem, iniciaremos um contêiner, examinaremos seu conteúdo e veremos as principais instruções utilizadas em um Containerfile.

1. O que é um Containerfile?

Um Containerfile contém instruções para construir uma imagem de contêiner. Entre outras coisas, ele permite definir:

  • a imagem que servirá como ponto de partida;
  • os pacotes que serão instalados;
  • os arquivos que serão copiados;
  • as variáveis de ambiente;
  • o diretório de trabalho;
  • o usuário utilizado pela aplicação;
  • as portas usadas pelo serviço;
  • o comando executado quando o contêiner for iniciado.

O Podman aceita tanto o nome Containerfile quanto Dockerfile.

A sintaxe interna é a mesma. Isso significa que, na maioria dos casos, um Dockerfile criado para o Docker pode ser usado pelo Podman sem modificações. A documentação do Podman confirma que os dois nomes são reconhecidos pelo comando podman build. Consulte o manual oficial do Podman.

O nome Containerfile é mais neutro, pois não vincula o arquivo a uma ferramenta específica.

2. Imagem e contêiner são coisas diferentes

Antes de começarmos, é importante distinguir os dois conceitos.

Uma imagem é um modelo imutável que contém os arquivos necessários para executar uma aplicação. Um contêiner é uma instância em execução dessa imagem.

Podemos criar vários contêineres a partir da mesma imagem:

flowchart TD A["Imagem personalizada"] --> B["Contêiner 1"] A --> C["Contêiner 2"] A --> D["Contêiner 3"]

O Containerfile cria a imagem. O comando podman run cria e inicia um contêiner usando essa imagem.

3. Verifique se o Podman está instalado

Execute:

$ podman --version

A saída será semelhante a:

$ podman version 5.7.0

Também podemos verificar as informações do ambiente:

$ podman info

Na maioria das distribuições, o Podman pode ser instalado diretamente pelo gerenciador de pacotes.

No Fedora:

$ sudo dnf install podman 

No Ubuntu e no Debian:

$ sudo apt install podman 

No openSUSE:

$ sudo zypper install podman 

4. Crie o diretório do projeto

Crie um diretório para o exemplo:

mkdir meu-site 

Entre nele:

cd meu-site 

Ao final, teremos a seguinte estrutura:

meu-site/
├── Containerfile
├── index.html
└── .containerignore

5. Crie a página HTML

Crie o arquivo index.html com o seguinte conteúdo:

<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Meu primeiro Containerfile</title>

    <style>
        body {
            background: #f4f4f4;
            color: #333;
            font-family: Arial, sans-serif;
            margin: 0;
        }

        main {
            background: white;
            border-radius: 10px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
            margin: 80px auto;
            max-width: 700px;
            padding: 40px;
            text-align: center;
        }

        h1 {
            color: #7c3aed;
        }
    </style>
</head>
<body>
    <main>
        <h1>Minha primeira imagem</h1>

        <p>
            Esta página está sendo servida por um contêiner
            criado com Podman e Containerfile.
        </p>
    </main>
</body>
</html>
</pre>

Esse arquivo substituirá a página padrão do Apache.

6. Crie o Containerfile

Crie um arquivo chamado exatamente Containerfile.

Adicione o seguinte conteúdo:

FROM docker.io/library/httpd:2.4-alpine

LABEL org.opencontainers.image.title="Meu site Apache"
LABEL org.opencontainers.image.description="Imagem de exemplo criada com Podman"
LABEL org.opencontainers.image.version="1.0"

COPY index.html /usr/local/apache2/htdocs/index.html

EXPOSE 80

Esse é um Containerfile pequeno, mas suficiente para produzir uma imagem funcional.

7. Entenda cada instrução

FROM

A instrução:

FROM docker.io/library/httpd:2.4-alpine 

define a imagem-base.

Nesse caso, estamos utilizando a imagem oficial do Apache HTTP Server, identificada como httpd. A variante alpine utiliza Alpine Linux como base e geralmente ocupa menos espaço do que imagens baseadas em distribuições maiores.

A referência completa contém:

docker.io/library/httpd:2.4-alpine 

Seus componentes são:

Componente Significado
docker.io Registro em que a imagem está armazenada
library Namespace das imagens oficiais
httpd Nome do repositório
2.4-alpine Tag da imagem

O uso do nome completo evita dúvidas sobre o registro em que o Podman deverá procurar a imagem.

LABEL

As instruções:

LABEL org.opencontainers.image.title="Meu site Apache"
LABEL org.opencontainers.image.description="Imagem de exemplo criada com Podman"
LABEL org.opencontainers.image.version="1.0"

acrescentam metadados à imagem.

Esses dados não interferem diretamente na execução do Apache, mas ajudam a documentar:

  • nome da aplicação;
  • descrição;
  • versão;
  • autor;
  • endereço do código-fonte;
  • licença;
  • finalidade da imagem.

As chaves usadas no exemplo seguem as convenções da Open Container Initiative, OCI.

COPY

A instrução:

 COPY index.html /usr/local/apache2/htdocs/index.html 

copia o arquivo index.html do diretório do projeto para dentro da imagem.

O primeiro caminho index.html é relativo ao contexto da construção.

O segundo /usr/local/apache2/htdocs/index.html é o destino dentro da imagem.

Na imagem oficial httpd, o diretório /usr/local/apache2/htdocs é usado para armazenar os arquivos publicados pelo Apache.

EXPOSE

A instrução:

 EXPOSE 80 

documenta que a aplicação utiliza a porta 80.

É importante entender que EXPOSE não publica automaticamente a porta no computador hospedeiro. A publicação será feita ao iniciar o contêiner:

$ podman run -p 8080:80 

8. Entenda o contexto da construção

Quando executamos:

$ podman build .  

o ponto no final representa o diretório atual. Esse diretório se transforma no contexto da construção.

O contexto é o conjunto de arquivos que o Podman pode acessar durante o processo. Instruções como COPY e ADD somente conseguem acessar arquivos que estejam dentro desse contexto.

Por exemplo, isto funciona se index.html estiver no diretório atual:

 COPY index.html /var/www/html/index.html 

Entretanto, não devemos tentar copiar um arquivo localizado fora do contexto:

 COPY ../index.html /var/www/html/index.html 

O ponto no comando abaixo, portanto, tem uma função importante:

$ podman build -t localhost/meu-site:1.0 .  

Ele não deve ser esquecido.

9. Crie o arquivo ".containerignore"

Nem todos os arquivos existentes no diretório do projeto precisam fazer parte do contexto.

Crie o arquivo .containerignore.

Adicione:

.git
.gitignore
*.log
*.tmp
*.tar
*.tar.gz
README.md

O Podman deixará esses arquivos fora do contexto da construção.

Isso ajuda a:

  • reduzir o volume de dados processados;
  • tornar a construção mais rápida;
  • impedir a inclusão acidental de arquivos desnecessários;
  • evitar o envio de senhas, chaves e outros dados sensíveis;
  • melhorar o aproveitamento do cache.

O Podman também reconhece .dockerignore. Quando os dois arquivos existem, .containerignore tem precedência. Nunca mantenha senhas, chaves privadas ou credenciais dentro do contexto sem necessidade.

10. Construa a imagem

Execute:

$ podman build \
    -t localhost/meu-site:1.0 \
    .

A opção -t atribui um nome e uma tag à imagem:

localhost/meu-site:1.0 

Os componentes são:

Parte Significado
localhost Indica uma imagem local
meu-site Nome da imagem
1.0 Tag ou versão

Durante a construção, o Podman executará aproximadamente estas etapas:

  1. localizará o Containerfile;
  2. baixará a imagem httpd:2.4-alpine, caso ela ainda não exista;
  3. criará as camadas da nova imagem;
  4. copiará o arquivo index.html;
  5. adicionará os metadados;
  6. atribuirá o nome localhost/meu-site:1.0.

Ao final, uma mensagem indicará que a imagem foi criada.

11. Liste as imagens

Execute:

$ podman images 

A saída será semelhante a:

REPOSITORY            TAG         IMAGE ID      CREATED        SIZE
localhost/meu-site    1.0         a1b2c3d4e5f6  1 minute ago   58 MB
docker.io/library/httpd 2.4-alpine 7f8e9d0c1b2a  3 days ago    57 MB

Também podemos procurar somente nossa imagem:

$ podman images localhost/meu-site 

12. Inicie um contêiner

Crie e inicie um contêiner:

$ podman run -d \
    --name meu-site \
    -p 8080:80 \
    localhost/meu-site:1.0

As opções utilizadas são:

Opção Função
-d Executa o contêiner em segundo plano
--name meu-site Define um nome para o contêiner
-p 8080:80 Liga a porta 8080 do host à porta 80 do contêiner
localhost/meu-site:1.0 Define a imagem utilizada

Confira o contêiner:

$ podman ps 

A saída mostrará algo parecido com:

CONTAINER ID  IMAGE                       COMMAND           STATUS       PORTS
123456789abc  localhost/meu-site:1.0      httpd-foreground  Up 1 minute  0.0.0.0:8080->80/tcp

13. Teste a aplicação

Abra no navegador:

http://localhost:8080 

Também podemos testar pelo terminal:

curl http://localhost:8080 

O código HTML da página deverá ser exibido.

Para conferir somente o código HTTP:

curl -I http://localhost:8080 

A resposta deverá conter:

HTTP/1.1 200 OK 

14. Consulte os logs

Para visualizar as mensagens do Apache:

$ podman logs meu-site 

Para acompanhar os logs continuamente:

$ podman logs -f meu-site 

Pressione Ctrl+C para encerrar o acompanhamento. Isso não interromperá o contêiner.

15. Examine o interior do contêiner

Podemos executar um shell dentro do contêiner:

$ podman exec -it meu-site /bin/sh 

Como a imagem utiliza Alpine Linux, o shell disponível é normalmente /bin/sh, e não necessariamente /bin/bash.

Dentro do contêiner, verifique o arquivo:

$ ls -l /usr/local/apache2/htdocs 

Examine seu conteúdo:

$ cat /usr/local/apache2/htdocs/index.html 

Para sair:

$ exit 

16. Examine os metadados da imagem

Execute:

$ podman inspect localhost/meu-site:1.0 

O resultado será um documento JSON bastante extenso.

Para consultar somente os rótulos:

$ podman inspect \
    --format '{{json .Labels}}' \
    localhost/meu-site:1.0

Para visualizar as portas declaradas:

$ podman inspect \
    --format '{{json .Config.ExposedPorts}}' \
    localhost/meu-site:1.0

Para consultar a arquitetura:

$ podman inspect \
    --format '{{.Architecture}}' \
    localhost/meu-site:1.0

Para obter o identificador da imagem:

$ podman inspect \
    --format '{{.Id}}' \
    localhost/meu-site:1.0

17. Veja as camadas da imagem

Uma imagem de contêiner é formada por camadas. Para examinar o histórico:

$ podman history localhost/meu-site:1.0 

A saída mostrará as instruções que contribuíram para sua construção.

A imagem-base já possui várias camadas. As instruções do nosso Containerfile acrescentam novas informações sobre elas.

Podemos representar o resultado desta forma:

flowchart TD A["Imagem Alpine Linux"] --> B["Apache HTTP Server"] B --> C["Metadados LABEL"] C --> D["Página index.html"] D --> E["Imagem meu-site:1.0"]

As camadas podem ser compartilhadas por diferentes imagens. Se duas imagens usam a mesma base, o Podman não precisa guardar duas cópias completas dela.

18. Faça uma alteração na página

Modifique o conteúdo de index.html. Por exemplo:

<h1>Minha imagem foi atualizada</h1>

A imagem já criada não será alterada automaticamente. Precisamos construí-la novamente.

Podemos criar uma nova versão:

$ podman build \
    -t localhost/meu-site:1.1 \
    .

Liste as versões:

$ podman images localhost/meu-site 

Agora deverão existir duas tags:

localhost/meu-site  1.1 localhost/meu-site  1.0 

Pare e remova o contêiner antigo:

$ podman stop meu-site
$ podman rm meu-site

Inicie a nova versão:

$ podman run -d \
    --name meu-site \
    -p 8080:80 \
    localhost/meu-site:1.1

Atualize a página no navegador.

Esse processo demonstra uma propriedade importante: a imagem 1.0 continua existindo. A reconstrução com outra tag gerou uma nova versão, permitindo retornar à anterior se necessário.

19. Como funciona o cache

Durante a segunda construção, provavelmente algumas etapas serão executadas rapidamente porque o Podman reaproveitará resultados anteriores.

Se a imagem-base e as instruções não mudaram, suas camadas podem ser recuperadas do cache.

Quando alteramos apenas o index.html, as etapas anteriores ao COPY podem continuar sendo reutilizadas. O COPY e as instruções posteriores precisarão ser avaliados novamente.

Por isso, a ordem das instruções influencia a eficiência da construção. As etapas que mudam raramente devem aparecer antes das etapas que mudam com frequência.

Quando for necessário ignorar o cache:

$ podman build \
    --no-cache \
    -t localhost/meu-site:1.1 \
    .

Para procurar uma versão atualizada da imagem-base:

$ podman build \
    --pull=always \
    -t localhost/meu-site:1.1 \
    .

Recriar imagens regularmente ajuda a incorporar correções de segurança presentes na imagem-base.

20. Principais instruções de um Containerfile

Além das instruções utilizadas no exemplo, existem outras muito importantes.

RUN

Executa um comando durante a construção da imagem:

 RUN apk add --no-cache curl 

Esse comando instala curl em uma imagem baseada no Alpine.

Em uma imagem baseada no Debian ou Ubuntu, poderíamos usar:

RUN apt-get update \
    && apt-get install -y --no-install-recommends curl \
    && rm -rf /var/lib/apt/lists/*

Tudo o que for feito por RUN torna-se parte da imagem construída.

CMD

Define o comando padrão executado quando o contêiner é iniciado:

 CMD ["httpd-foreground"] 

Uma imagem pode ter somente um CMD efetivo. Se houver mais de um, prevalecerá o último.

O usuário pode substituir esse comando ao executar o contêiner:

$ podman run localhost/minha-imagem outro-comando 

ENTRYPOINT

Define o programa principal do contêiner:

 ENTRYPOINT ["/usr/local/bin/minha-aplicacao"] 

Os argumentos passados ao podman run normalmente são acrescentados ao ENTRYPOINT.

Uma combinação possível é:

ENTRYPOINT ["/usr/local/bin/minha-aplicacao"]
CMD ["--help"]

Nesse caso, --help funciona como argumento padrão.

WORKDIR

Define o diretório de trabalho:

 WORKDIR /app 

As instruções seguintes serão executadas em relação a esse diretório:

WORKDIR /app

COPY aplicacao.sh .
RUN chmod +x aplicacao.sh

CMD ["./aplicacao.sh"]

É preferível utilizar WORKDIR em vez de repetir comandos como:

 RUN cd /app && algum-comando 

ENV

Define uma variável de ambiente permanente:

 ENV AMBIENTE=producao 

Ela estará disponível dentro do contêiner:

$ podman run --rm localhost/minha-imagem env 

Não use ENV para armazenar senhas, tokens ou chaves privadas, pois esses valores podem permanecer nos metadados e nas camadas da imagem.

ARG

Define uma variável usada somente durante a construção:

 ARG VERSAO=1.0 

Ela pode ser informada na linha de comando:

$ podman build \
    --build-arg VERSAO=2.0 \
    -t localhost/minha-imagem:2.0 \
    .

No Containerfile:

ARG VERSAO
RUN echo "Construindo a versão ${VERSAO}"

Embora ARG seja voltado para a construção, também não deve ser considerado um mecanismo seguro para fornecer segredos.

USER

Define o usuário utilizado pelas instruções seguintes e pelo processo do contêiner:

 USER 1000 

Quando a aplicação não precisa de privilégios administrativos, executá-la como usuário comum reduz os possíveis impactos de uma falha de segurança.

ADD

Assim como COPY, ADD acrescenta arquivos à imagem, mas possui comportamentos adicionais, como o tratamento de determinados arquivos compactados e origens remotas.

Para cópias comuns, prefira:

 COPY arquivo.conf /app/arquivo.conf 

O uso de COPY deixa a intenção mais clara.

VOLUME

Indica um ponto destinado a dados persistentes:

 VOLUME ["/dados"] 

A instrução não cria, por si só, uma política de backup. Os volumes ainda precisam ser administrados pelo Podman.

HEALTHCHECK

Define uma verificação de saúde para a aplicação:

HEALTHCHECK --interval=30s --timeout=5s \
    CMD wget -q --spider http://localhost/ || exit 1

A verificação ajuda a detectar situações em que o processo ainda está ativo, mas a aplicação não está respondendo corretamente.

21. Um exemplo com instalação de pacotes

Podemos personalizar ainda mais a imagem do Apache:

FROM docker.io/library/httpd:2.4-alpine

LABEL org.opencontainers.image.title="Meu site Apache"
LABEL org.opencontainers.image.description="Apache personalizado com ferramentas de diagnóstico"
LABEL org.opencontainers.image.version="2.0"

RUN apk add --no-cache \
        curl \
        tzdata

ENV TZ=America/Sao_Paulo

COPY index.html /usr/local/apache2/htdocs/index.html

EXPOSE 80

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
    CMD curl --fail http://localhost/ || exit 1

CMD ["httpd-foreground"]

Construa a imagem:

$ podman build \
    -t localhost/meu-site:2.0 \
    .

Teste o curl instalado:

$ podman run --rm \
    localhost/meu-site:2.0 \
    curl --version

Nesse caso, o comando informado substitui o CMD padrão.

22. Por que não modificar manualmente um contêiner?

Seria possível iniciar um contêiner, entrar nele e modificar seus arquivos:

$ podman exec -it meu-site /bin/sh 

Entretanto, essas alterações ficariam somente na camada gravável daquele contêiner. Se ele fosse removido, as modificações seriam perdidas.

O Containerfile torna o processo:

  • documentado;
  • repetível;
  • automatizável;
  • versionável;
  • auditável;
  • fácil de compartilhar.

Qualquer pessoa que receba o Containerfile e os arquivos do contexto poderá reconstruir uma imagem equivalente.

23. Marque uma imagem com outra tag

Podemos atribuir uma nova tag sem reconstruir a imagem:

$ podman tag \
    localhost/meu-site:2.0 \
    localhost/meu-site:latest

Confira:

$ podman images localhost/meu-site

As tags 2.0 e latest poderão apontar para o mesmo identificador de imagem.

Também podemos preparar a imagem para um registro:

$ podman tag \
    localhost/meu-site:2.0 \
    docker.io/meuusuario/meu-site:2.0

24. Salve a imagem em um arquivo

Para transportar a imagem sem utilizar um registro:

$ podman save \
    -o meu-site-2.0.tar \
    localhost/meu-site:2.0

Em outro computador, ela poderá ser carregada com:

$ podman load \
    -i meu-site-2.0.tar

Use podman save e podman load para preservar a estrutura da imagem e suas camadas. podman export e podman import trabalham com o sistema de arquivos de contêineres e têm outra finalidade. Veja a distinção no manual do Podman.

25. Remova os recursos do exemplo

Pare o contêiner:

$ podman stop meu-site 

Remova-o:

$ podman rm meu-site 

Remova uma versão específica da imagem:

$ podman rmi localhost/meu-site:1.0 

Para remover todas as tags do exemplo, examine primeiro o que será afetado:

$ podman images localhost/meu-site 

Depois, remova explicitamente as versões desejadas:

$ podman rmi \
    localhost/meu-site:1.1 \
    localhost/meu-site:2.0 \
    localhost/meu-site:latest

Se duas tags apontarem para a mesma imagem, a remoção de uma tag não necessariamente eliminará imediatamente todas as camadas.

26. Problemas comuns

O Podman não encontrou o Containerfile

Mensagem semelhante:

no Containerfile or Dockerfile specified or found 

Verifique o nome:

ls -l 

O arquivo deve se chamar Containerfile ou Dockerfile.

Se possuir outro nome, informe-o com -f:

$ podman build \
    -f Containerfile.apache \
    -t localhost/meu-site:1.0 \
    .

Arquivos com extensões adicionais não são encontrados automaticamente por podman build ..

O arquivo usado por COPY não foi encontrado

Mensagem semelhante:

no such file or directory 

Confira se o arquivo está dentro do contexto:

ls -l index.html 

Verifique também se ele não foi excluído por .containerignore.

A porta já está em uso

Mensagem semelhante:

address already in use 

Descubra se existe outro contêiner usando a porta:

$ podman ps 

Escolha outra porta no host:

$ podman run -d \
    --name meu-site \
    -p 8081:80 \
    localhost/meu-site:1.0

Acesse:

http://localhost:8081 

A página antiga continua aparecendo

Pode existir um contêiner baseado na versão anterior da imagem.

Confira qual imagem ele utiliza:

$ podman inspect \
    --format '{{.ImageName}}' \
    meu-site

Remova e recrie o contêiner com a nova tag:

$ podman rm -f meu-site 
$ podman run -d \
    --name meu-site \
    -p 8080:80 \
    localhost/meu-site:1.1

Também pode ser necessário atualizar o cache do navegador.

O build está usando conteúdo antigo

Faça uma construção sem cache:

$ podman build \
    --no-cache \
    -t localhost/meu-site:1.1 \
    .

Use essa opção para diagnóstico. Em condições normais, o cache reduz bastante o tempo de construção.

27. Boas práticas

Ao criar imagens com Containerfile, procure seguir estes princípios:

  • utilize imagens-base de fontes confiáveis;
  • informe explicitamente o registro da imagem;
  • prefira tags específicas em vez de depender sempre de latest;
  • instale somente os pacotes necessários;
  • remova arquivos temporários e caches de instalação;
  • use .containerignore;
  • não copie senhas, tokens ou chaves privadas para a imagem;
  • execute a aplicação como usuário sem privilégios, quando possível;
  • mantenha os dados persistentes fora da camada do contêiner;
  • reconstrua as imagens periodicamente para incorporar atualizações;
  • atribua versões às imagens;
  • teste a imagem antes de publicá-la;
  • use construções em múltiplos estágios para aplicações compiladas;
  • mantenha o Containerfile junto ao código-fonte e sob controle de versão.

A escolha de uma imagem-base pequena e confiável, a exclusão de arquivos desnecessários e a instalação apenas das dependências necessárias estão entre as recomendações oficiais para produzir imagens mais seguras e eficientes. Consulte as boas práticas de construção.

Conclusão

O Containerfile transforma a criação de uma imagem em um processo documentado e reproduzível. Em vez de iniciar um contêiner e configurá-lo manualmente, descrevemos tudo o que ele precisa em um arquivo de texto.

No exemplo deste tutorial, partimos de uma imagem oficial do Apache, adicionamos metadados, copiamos uma página HTML e construímos nossa própria imagem:

$ podman build \
    -t localhost/meu-site:1.0 \
    .

Em seguida, criamos um contêiner:

$ podman run -d \
    --name meu-site \
    -p 8080:80 \
    localhost/meu-site:1.0

Embora o exemplo seja simples, o mesmo princípio pode ser usado para criar imagens com PHP, Python, Java, bancos de dados, servidores web e aplicações completas. O que muda é o conteúdo do Containerfile. O processo básico permanece o mesmo: escolher uma imagem-base, acrescentar os componentes necessários, construir a imagem e testá-la em um contêiner.



Veja a relação completa dos artigos de Rubens Queiroz de Almeida