Executar Containers com Podman no RHEL

Red Hat Enterprise LinuxBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá como implantar uma aplicação web de múltiplas camadas usando Podman no Red Hat Enterprise Linux (RHEL). Você construirá uma solução completa implantando um container de banco de dados MariaDB como backend e um container de servidor web Apache como frontend. Esta experiência prática irá guiá-lo através das etapas essenciais da implantação de aplicações em containers, desde a configuração inicial até tornar o serviço publicamente acessível.

Você começará executando um container MariaDB e configurando-o na inicialização com variáveis de ambiente. Em seguida, você configurará armazenamento persistente para garantir a durabilidade dos dados do banco de dados e criará uma rede customizada para comunicação entre os containers. Depois, você implantará o servidor web Apache, exporá sua porta para testar a conectividade e, finalmente, aprenderá como gerenciar o container como um serviço systemd para uma operação robusta e automatizada.

Este é um Lab Guiado, que fornece instruções passo a passo para ajudá-lo a aprender e praticar. Siga as instruções cuidadosamente para completar cada etapa e ganhar experiência prática. Dados históricos mostram que este é um laboratório de nível iniciante com uma taxa de conclusão de 93%. Recebeu uma taxa de avaliações positivas de 98% dos estudantes.

Executar um Container de Banco de Dados MariaDB com Variáveis de Ambiente

Nesta etapa, você aprenderá como executar uma aplicação em container e configurá-la na inicialização usando variáveis de ambiente. Esta é uma habilidade fundamental no gerenciamento de containers, permitindo implantações flexíveis e seguras. Usaremos a imagem oficial do MariaDB como exemplo, pois ela requer vários parâmetros de configuração para inicializar um banco de dados.

Primeiro, certifique-se de estar no diretório de trabalho correto. Todo o trabalho para este laboratório será feito dentro do diretório ~/project.

cd ~/project

Antes de executar um container, é uma boa prática extrair explicitamente a imagem do registro. Isso garante que você tenha a versão correta localmente. Usaremos a imagem mariadb:10.6 para este laboratório para garantir a consistência.

podman pull mariadb:10.6

Selecione a imagem mariadb:10.6 do registro docker.

Você deve ver a saída indicando que a imagem está sendo baixada e extraída.

10.6: Pulling from library/mariadb
...
Status: Downloaded newer image for mariadb:10.6
docker.io/library/mariadb:10.6

Agora, você pode executar o container MariaDB. O comando podman run cria e inicia um novo container. Usaremos várias flags:

  • -d: Executa o container em modo detached (em segundo plano).
  • --name mariadb_server: Atribui um nome memorável ao nosso container.
  • -e VARIABLE=value: Define uma variável de ambiente dentro do container. A imagem MariaDB usa isso para configurar o banco de dados na primeira inicialização.

Execute o seguinte comando para iniciar seu container MariaDB. Estamos definindo a senha root e também criando um novo banco de dados chamado webappdb com um usuário dedicado webappuser.

podman run -d \
  --name mariadb_server \
  -e MARIADB_ROOT_PASSWORD=supersecret \
  -e MARIADB_DATABASE=webappdb \
  -e MARIADB_USER=webappuser \
  -e MARIADB_PASSWORD=userpass \
  mariadb:10.6

O comando gerará um longo ID do container, o que confirma que o container foi criado.

a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Para verificar se o container está em execução, use o comando podman ps.

podman ps

Você deve ver mariadb_server na lista de containers em execução.

CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS      NAMES
a1b2c3d4e5f6   mariadb:10.6   "docker-entrypoint.s…"   15 seconds ago   Up 14 seconds   3306/tcp   mariadb_server

Finalmente, vamos verificar os logs do container para garantir que o banco de dados foi inicializado corretamente usando as variáveis de ambiente que fornecemos.

podman logs mariadb_server

Role pelos logs. Você está procurando uma linha que indique que o servidor está pronto para conexões, o que confirma uma inicialização bem-sucedida. A saída será longa, mas uma mensagem de sucesso chave perto do final se parece com isto:

...
2024-05-20 10:30:00+00:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/
...
2024-05-20 10:30:15+00:00 [Note] mariadbd: ready for connections.
Version: '10.6.x-MariaDB-1:10.6.x+maria~ubu2004'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution

Você iniciou e configurou com sucesso um container MariaDB usando variáveis de ambiente.

Configurar Armazenamento Persistente para o Container MariaDB

Nesta etapa, você aprenderá como configurar armazenamento persistente para um container. Por padrão, qualquer dado criado dentro de um container é armazenado em uma camada gravável que está ligada ao ciclo de vida do container. Se você remover o container, todos esses dados serão perdidos. Para aplicações com estado (stateful applications), como bancos de dados, isso não é ideal. Para resolver isso, usamos volumes ou bind mounts do Podman para armazenar os dados no sistema de arquivos do host, independentemente do container.

Primeiro, precisamos remover o container que criamos na etapa anterior, pois o relançaremos com uma nova configuração de armazenamento.

Pare o container mariadb_server em execução:

podman stop mariadb_server

Você verá o nome do container como saída, confirmando que o comando foi recebido.

mariadb_server

Agora, remova o container parado:

podman rm mariadb_server

Novamente, o nome do container será ecoado de volta.

mariadb_server

Em seguida, crie um diretório em sua máquina host dentro do diretório ~/project. Este diretório conterá os arquivos do banco de dados MariaDB.

mkdir ~/project/mariadb_data

Ao usar o Podman em modo rootless, precisamos definir as permissões corretas para o diretório montado. O container MariaDB é executado como um usuário específico (UID 999), então precisamos garantir que o diretório seja acessível. Usaremos a flag --userns=keep-id e definiremos as permissões apropriadas:

chmod 755 ~/project/mariadb_data

Agora, execute o container MariaDB novamente. Este comando é semelhante ao da etapa anterior, mas com a adição da flag -v e --userns=keep-id para lidar com o mapeamento do namespace do usuário corretamente. A flag -v monta o diretório ~/project/mariadb_data do seu host no diretório /var/lib/mysql dentro do container, que é onde o MariaDB armazena seus dados. Usamos $(pwd)/mariadb_data para fornecer o caminho absoluto necessário para o comando podman.

podman run -d \
  --name mariadb_server \
  --userns=keep-id \
  -e MARIADB_ROOT_PASSWORD=supersecret \
  -e MARIADB_DATABASE=webappdb \
  -e MARIADB_USER=webappuser \
  -e MARIADB_PASSWORD=userpass \
  -v $(pwd)/mariadb_data:/var/lib/mysql:Z \
  mariadb:10.6

O sufixo :Z na montagem do volume diz ao Podman para rotular o conteúdo com um rótulo privado não compartilhado, o que é importante para a compatibilidade com SELinux.

Após o início do container, você pode verificar se os dados estão sendo armazenados em sua máquina host. Liste o conteúdo do diretório ~/project/mariadb_data.

ls -l ~/project/mariadb_data

Como o mecanismo de banco de dados do container foi inicializado, você verá vários arquivos e diretórios criados dentro de ~/project/mariadb_data. Isso confirma que seus dados agora são persistentes. Mesmo que você remova o container, esses dados permanecerão.

total 110632
-rw-rw---- 1 labex labex    16384 May 20 10:45 aria_log.00000001
-rw-rw---- 1 labex labex       52 May 20 10:45 aria_log_control
-rw-rw---- 1 labex labex      983 May 20 10:45 ib_buffer_pool
-rw-rw---- 1 labex labex 12582912 May 20 10:45 ibdata1
-rw-rw---- 1 labex labex 50331648 May 20 10:45 ib_logfile0
-rw-rw---- 1 labex labex 50331648 May 20 10:45 ib_logfile1
drwx------ 2 labex labex     4096 May 20 10:45 mysql
drwx------ 2 labex labex     4096 May 20 10:45 performance_schema
drwx------ 2 labex labex     4096 May 20 10:45 sys
drwx------ 2 labex labex     4096 May 20 10:45 webappdb

Você configurou com sucesso seu container MariaDB para usar armazenamento persistente, garantindo que seus dados do banco de dados sobreviverão a reinicializações e remoções do container.

Criar uma Rede Personalizada e Implantar um Servidor Web Apache

Nesta etapa, você criará uma rede personalizada para seus containers e implantará um servidor web Apache. Embora o Podman forneça uma rede padrão, o uso de redes personalizadas é uma boa prática. Elas fornecem melhor isolamento e, o mais importante, permitem a resolução automática de DNS entre os containers. Isso permite que os containers se comuniquem entre si usando seus nomes, o que é mais confiável do que usar endereços IP que podem mudar.

Primeiro, vamos criar uma rede bridge personalizada para nossa aplicação. Vamos chamá-la de webapp-network.

podman network create webapp-network

O comando gerará o nome da rede recém-criada.

webapp-network

Você pode listar todas as redes Podman para confirmar se a sua foi criada com sucesso.

podman network ls

Você deve ver webapp-network na lista, juntamente com as redes padrão.

NETWORK ID     NAME               DRIVER    SCOPE
...
f1e2d3c4b5a6   webapp-network     bridge    local
...

Em seguida, precisamos recriar nosso container mariadb_server nesta nova rede. Devido à configuração do backend de rede neste ambiente, não podemos conectar um container existente a uma nova rede. Em vez disso, vamos parar e recriar o container com a nova configuração de rede.

Pare o container mariadb_server em execução:

podman stop mariadb_server

Remova o container parado:

podman rm mariadb_server

Agora, recrie o container MariaDB com a nova rede. Este comando é semelhante ao da etapa anterior, mas com a adição da flag --network webapp-network:

podman run -d \
  --name mariadb_server \
  --network webapp-network \
  --userns=keep-id \
  -e MARIADB_ROOT_PASSWORD=supersecret \
  -e MARIADB_DATABASE=webappdb \
  -e MARIADB_USER=webappuser \
  -e MARIADB_PASSWORD=userpass \
  -v $(pwd)/mariadb_data:/var/lib/mysql:Z \
  mariadb:10.6

Agora, vamos implantar nosso servidor web. Usaremos a imagem oficial do Apache httpd. Primeiro, crie um diretório no host para armazenar os arquivos do seu site.

mkdir ~/project/webapp_content

Crie um arquivo index.html simples neste novo diretório. Esta será a página inicial de nossa aplicação web.

echo "<h1>Welcome to My Web App</h1>" > ~/project/webapp_content/index.html

Defina as permissões corretas para o diretório de conteúdo do webapp para garantir que o container Apache possa acessar os arquivos:

chmod 755 ~/project/webapp_content

Agora, execute o container Apache httpd. Vamos anexá-lo à nossa webapp-network e montar o diretório webapp_content como um volume. Isso garante que o servidor web possa servir o arquivo index.html que acabamos de criar.

podman run -d \
  --name web_server \
  --network webapp-network \
  -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z \
  httpd:2.4

Vamos detalhar as opções:

  • --network webapp-network: Conecta o novo container à nossa rede personalizada.
  • -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z: Isso monta nosso diretório local webapp_content no container em /usr/local/apache2/htdocs/, que é o diretório padrão do qual o Apache serve arquivos. O sufixo :Z diz ao Podman para rotular o conteúdo com um rótulo privado não compartilhado para compatibilidade com SELinux.

Verifique se ambos os containers estão em execução.

podman ps

Você deve ver agora mariadb_server e web_server na lista de containers em execução.

CONTAINER ID  IMAGE                           COMMAND           CREATED         STATUS         PORTS       NAMES
6a3f46c0ab3a  docker.io/library/mariadb:10.6  mariadbd          29 seconds ago  Up 29 seconds  3306/tcp    mariadb_server
da5d52ce9c41  docker.io/library/httpd:2.4     httpd-foreground  7 seconds ago   Up 7 seconds   80/tcp      web_server

Ambos os containers agora estão na mesma rede personalizada e podem se comunicar entre si por nome.

Expor a Porta do Servidor Web e Testar a Conectividade

Nesta etapa, você aprenderá como expor a porta de um container para a máquina host, tornando o serviço acessível de fora da rede isolada do container. Nosso servidor web Apache está em execução, mas ainda não podemos acessá-lo do navegador ou da linha de comando do nosso host. Vamos corrigir isso publicando a porta do container.

Mapeamentos de porta são definidos quando um container é criado. Portanto, devemos primeiro parar e remover o container web_server que criamos na etapa anterior. Não se preocupe com o conteúdo do site; ele está seguro no diretório ~/project/webapp_content em nosso host porque usamos um bind mount.

Primeiro, pare o container:

podman stop web_server
web_server

Em seguida, remova o container parado:

podman rm web_server
web_server

Agora, executaremos o container web_server novamente, mas desta vez adicionaremos a flag -p (ou --publish) para mapear uma porta do host para uma porta no container. Mapearemos a porta 8080 no host para a porta 80 (a porta HTTP padrão) dentro do container.

podman run -d \
  --name web_server \
  --network webapp-network \
  -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z \
  -p 8080:80 \
  httpd:2.4

A nova flag -p 8080:80 diz ao Podman para encaminhar todo o tráfego da porta 8080 no host para a porta 80 dentro do container web_server.

Vamos verificar se o container está em execução e se a porta está corretamente mapeada usando podman ps.

podman ps

Observe a coluna PORTS para o container web_server. Agora, ela mostra o mapeamento de 0.0.0.0:8080 para 80/tcp, indicando que a porta foi exposta com sucesso.

CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                  NAMES
c5d4e3f2a1b6   httpd:2.4      "httpd-foreground"       10 seconds ago   Up 9 seconds    0.0.0.0:8080->80/tcp   web_server
a1b2c3d4e5f6   mariadb:10.6   "docker-entrypoint.s…"   25 minutes ago   Up 25 minutes   3306/tcp               mariadb_server

Finalmente, vamos testar a conectividade da nossa máquina host usando o comando curl. Isso envia uma requisição HTTP para localhost na porta 8080.

curl http://localhost:8080

Você deve ver o conteúdo HTML do seu arquivo index.html como saída, confirmando que seu servidor web agora está acessível do host.

<h1>Welcome to My Web App</h1>

Você expôs com sucesso seu servidor web em container para a máquina host, uma etapa crítica para disponibilizar aplicações aos usuários.

Gerenciar o Container do Servidor Web como um Serviço systemd

Nesta etapa final, você aprenderá como configurar um container para iniciar automaticamente, garantindo que seu serviço seja resiliente a falhas ou reinicializações do sistema. Em um sistema Red Hat Enterprise Linux padrão, o systemd é a principal ferramenta para gerenciar serviços. No entanto, o ambiente Podman neste laboratório não usa systemd para gerenciar containers diretamente.

Em vez disso, alcançaremos o mesmo resultado — reinícios automáticos do serviço — usando as políticas de reinício (restart policies) integradas do Podman. Esta é a maneira padrão, nativa de container, de garantir que um container seja iniciado automaticamente pelo daemon Podman. Configurararemos nosso web_server para sempre reiniciar se parar por qualquer motivo.

Primeiro, devemos remover o container existente, pois as políticas de reinício só podem ser aplicadas quando um container é criado.

Pare o container web_server:

podman stop web_server
web_server

E agora remova-o:

podman rm web_server
web_server

Em seguida, recrie o container web_server com a mesma configuração de antes, mas adicione a flag --restart always. Esta flag instrui o daemon Podman a monitorar o container e reiniciá-lo se ele sair.

podman run -d \
  --name web_server \
  --network webapp-network \
  -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z \
  -p 8080:80 \
  --restart always \
  httpd:2.4

O container iniciará como de costume. Para confirmar que a política de reinício está ativa, você pode inspecionar a configuração do container.

podman inspect web_server --format '{{.HostConfig.RestartPolicy.Name}}'

O comando deve retornar always, confirmando que a política está definida.

always

Agora, vamos demonstrar como a política de reinício funciona reiniciando manualmente o container para simular o que aconteceria após uma reinicialização do sistema ou falha do container.

Primeiro, vamos verificar a configuração atual da política de reinício:

podman inspect web_server --format '{{.HostConfig.RestartPolicy.Name}}'

Isso deve mostrar always, confirmando que nossa política de reinício está configurada.

always

Agora, vamos testar o reinício manual para simular a recuperação após uma falha:

podman start web_server
web_server

Verifique se o container está em execução:

podman ps

Você deve ver ambos os containers em execução com a política de reinício em vigor:

CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                  NAMES
e7f6g5h4i3j2   httpd:2.4      "httpd-foreground"       About a minute ago   Up 5 seconds        0.0.0.0:8080->80/tcp   web_server
a1b2c3d4e5f6   mariadb:10.6   "docker-entrypoint.s…"   About an hour ago    Up About an hour    3306/tcp               mariadb_server

Finalmente, confirme que o serviço está acessível:

curl http://localhost:8080
<h1>Welcome to My Web App</h1>

Entendendo as Políticas de Reinício:

A política --restart always que você configurou garante que:

  • O container reiniciará automaticamente se sair inesperadamente
  • O container iniciará automaticamente quando o serviço Podman iniciar (como após uma reinicialização do sistema)
  • Isso fornece resiliência para implantações de produção

Observação: Em alguns ambientes de laboratório, o comportamento de reinício automático pode variar dependendo da configuração do Podman e se o serviço do sistema Podman está em execução. O principal objetivo de aprendizado é entender como configurar políticas de reinício para implantações de produção.

Você configurou com sucesso seu container para ser gerenciado como um serviço, garantindo que ele permaneça disponível automaticamente. Isso completa o gerenciamento básico do ciclo de vida de uma aplicação em container.

Resumo

Neste laboratório, você aprendeu o processo fundamental de implantação de uma aplicação web multi-container no RHEL usando Podman. Você começou executando um container de banco de dados MariaDB, configurando seu estado inicial — incluindo a senha root, um novo banco de dados e um usuário dedicado — passando variáveis de ambiente em tempo de execução. Em seguida, você configurou o armazenamento persistente para o container do banco de dados, garantindo que dados críticos sejam preservados em reinícios do container.

Para completar a pilha de aplicações, você criou uma rede customizada para permitir uma comunicação segura e isolada entre os containers. Você implantou um container de servidor web Apache nesta rede e expôs sua porta para permitir o acesso de usuários externos. Finalmente, você integrou o container do servidor web com o systemd, gerenciando-o como um serviço do sistema para garantir que ele inicie automaticamente na inicialização e execute de forma confiável, demonstrando um padrão de implantação pronto para produção.