Implantando contêineres docker para Metabase e GLPI com Portainer

Docker é uma ferramenta que permite a distribuição de softwares em contêineres, ambientes de execução independentes. Algo como máquinas virtuais, mas sem o mesmo overhead da virtualização de hardware e sem necessidade de outro kernel sendo executado.

Isso permite que os desenvolvedores tenham um maior controle sobre versões de dependências como bibliotecas e outros programas com que o software interage, independente da distribuição Linux onde o software vai ser executado.

Isso também facilita a implantação, já que muita coisa no ambiente não precisará ser configurada após a instalação.

Portainer é uma ferramenta para gerenciamento e monitoramento de contêineres Docker, podendo também gerenciar Podman e Kubernetes. É distribuído também como um contêiner Docker.

Começando pela instalação do Docker pelas fontes oficiais, nesse caso para o Ubuntu Server 24.04, é necessário primeiro importar a chave do repositório do Docker:

# curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc

Adicione o repositório Docker em um arquivo /etc/apt/sources.list.d/docker.list:

deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable

Atualize os repositórios e instale os pacotes do Docker:

# apt update
# apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Verifique que o serviço está sendo executado:

$ systemctl status docker.service

Adicione seu usuário ao grupo docker para que não seja necessário usar os comandos com sudo.

# usermod -aG docker daniel

Você talvez precise sair do shell atual e abrir outro, ou fazer logout e login novamente.

Então, crie um volume a ser usado para informações do Portainer:

$ docker volume create portainer_data

Isso cria uma pasta em /var/lib/docker/volumes/portainer_data.

E em seguida, baixe a imagem e execute o Portainer com:

$ docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:lts
  • O parâmetro -p é usado para mapear uma porta do host para uma porta do contêiner – docker usa iptables e isso pode contornar o firewall do sistema operacional.
  • O parâmetro -v é usado para mapear um volume docker ou um /caminho/no/seu/sistema para um caminho dentro do contêiner.

A porta 9443 é usada para acesso à interface web via HTTPS. Por padrão são gerados certificados autoassinados e, enquanto é possível especificar seus certificados já no comando “docker run”, também é possível alterá-los pelas configurações na própria interface web.

A porta 8000 é usada pela funcionalidade Edge computing, que permite gerenciamento e implantação de contêineres em dispositivos remotos através de um túnel TCP.

Verifique que o Portainer está sendo executado com:

$ docker ps

Então, acesse-o pelo navegador através da porta 9443 com protocolo HTTPS e siga a configuração pela página web.

Hora de instalar um contêiner: existem alguns templates mas a seção Containers permite que qualquer imagem seja baixada do Docker Hub e o contêiner construído a partir dela, com os parâmetros de configuração escolhidos.

Um software interessante que é distribuído como um contêiner docker é o Metabase: uma plataforma livre e aberta para análise de dados e Business Intelligence.

De acordo com o site oficial, a instalação como contêiner docker pode ser feita pelo seguinte comando:

$ docker run -d -p 3000:3000 --name metabase metabase/metabase

O que, pelo Portainer, fica:

Após inicializado, basta acessar o servidor na porta 3000 via HTTP.

O comando “docker run” é tipicamente usado para softwares ou sistemas que são distribuídos como um único contêiner. Alguns sistemas são compostos de múltiplos contêineres que trabalham em conjunto.

Nesses casos, em vez de usar o comando “docker run” passando os parâmetros de configuração como argumentos, o comando “docker compose” é usado com um arquivo docker-compose.yml que armazena esses parâmetros de configuração. A configuração do Metabase nesse formato, por exemplo, ficaria:

services:
  metabase:
    image: metabase
    container_name: metabase
    ports:
      - "3000:3000"

Outro sistema interessante de ser instalado é o GLPI: um sistema de gerenciamento de Helpdesk e ativos de TI. A instalação usa um arquivo docker-compose.yml, que pode ser encontrado no Docker Hub: https://hub.docker.com/r/glpi/glpi, e especifica dois contêineres: um com o GLPI empacotado com o servidor web e PHP e outro com o banco de dados MySQL. O exemplo abaixo teve alguns parâmetros adaptados:

volumes:
  glpi:
  glpi_mysql:

services:
  glpi:
    image: "glpi/glpi:latest"
    restart: "unless-stopped"
    volumes:
      - glpi:/var/glpi
    env_file: stack.env
    ports:
      - "8080:80"
  db:
    image: "mysql"
    restart: "unless-stopped"
    volumes:
      - glpi_mysql:/var/lib/mysql
    env_file: stack.env
    expose:
      - "3306"

Como a configuração especifica um arquivo com variáveis de ambiente, também precisamos dele, o stack.env, com o conteúdo abaixo.

O Portainer espera que o arquivo seja especificado com esse nome no yml, porque é o nome do arquivo que ele forma a partir das variáveis que são fornecidas. O arquivo para upload pode ter qualquer nome.

GLPI_DB_HOST=db
GLPI_DB_PORT=3306
GLPI_DB_NAME=glpi_db
GLPI_DB_USER=glpi_operator
GLPI_DB_PASSWORD=senhaNoPost-it

MYSQL_RANDOM_ROOT_PASSWORD=yes
MYSQL_DATABASE=glpi_db
MYSQL_USER=glpi_operator
MYSQL_PASSWORD=senhaNoPost-it

Adaptações feitas:

  • Todas as variáveis estão no stack.env. O Portainer não resolve variáveis no arquivo .yml, então todas precisam ser especificadas no stack.env ou no próprio .yml. Isso levou a variáveis com valores redundantes no stack.env
  • Pela mesma questão acima, o teste do banco de dados foi removido.
  • Volumes docker foram especificados em vez de caminhos para pastas no host.

Para uma implantação desse tipo no Portainer, vá na seção Stacks. Lá é possível fazer upload dos arquivos ou colar o conteúdo no editor web.

O GLPI leva um tempo após a inicialização do contêiner para ser instalado e ficar disponível na porta mapeada, nesse caso 8080. O MySQL gera uma senha aleatória para o usuário root, que você pode obter com:

$ docker logs <nome_do_conteiner_mysql> | grep GENERATED

Para acompanhar a instalação, verifique os logs do contêiner do GLPI via linha de comando ou no Portainer.

Após concluida, basta fazer login na interface web com o usuário e senha padrão, especificado no log do contêiner:

  • Usuário: glpi
  • Senha: glpi

Na interface web, o GLPI sugere remover o arquivo install/install.php, o que pode ser feito com:

$ docker exec -it <nome_do_conteiner_glpi> rm /var/www/glpi/install/install.php

Voltando ao Metabase: a implantação do Metabase abordada armazena as configurações em um banco de dados H2, no volume do próprio contêiner, sem nenhum volume persistente configurado. Ou seja, ao fazer uma atualização – que é feita por remover e adicionar um novo contêiner, todas as configurações, dashboards e conexões com bancos de dados seriam excluídos.

Para uso em produção, o metabase precisa ser combinado com um banco de dados para produção, como PostgreSQL. Abaixo, um exemplo de configuração em formato .yml para implantação:

volumes:
  metabase_config:

services:
  metabase:
    image: metabase/metabase:latest
    container_name: metabase
    hostname: metabase
    restart: "unless-stopped"
    volumes:
      - /dev/urandom:/dev/random:ro
    ports:
      - 3000:3000
    environment:
      MB_DB_TYPE: postgres
      MB_DB_DBNAME: metabase_db
      MB_DB_PORT: 5432
      MB_DB_USER: metabase_operator
      MB_DB_PASS: senhaNoBlocoDeNotas.txt
      MB_DB_HOST: meta_postgres
    networks:
      - metanet1
    healthcheck:
      test: curl --fail -I http://localhost:3000/api/health || exit 1
      interval: 15s
      timeout: 5s
      retries: 5

  postgres:
    image: postgres:latest
    container_name: postgres
    hostname: meta_postgres
    restart: "unless-stopped"
    volumes:
      - metabase_config:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: metabase_operator
      POSTGRES_DB: metabase_db
      POSTGRES_PASSWORD: senhaNoBlocoDeNotas.txt
    networks:
      - metanet1

networks:
  metanet1:
    driver: bridge