A odisseia de rodar cPanel e systemd no Docker: de conflitos de Cgroups v1/v2 ao trap dos volumes persistentes
Voltar para blog

A odisseia de rodar cPanel e systemd no Docker: de conflitos de Cgroups v1/v2 ao trap dos volumes persistentes

03/09/2026 · 4 min · DevOps

Rodar o cPanel/WHM dentro de um container Docker pode parecer incomum pela arquitetura tradicional do painel, mas em cenários de teste, laboratórios locais e desenvolvimento isolado, torna-se um exercício prático muito interessante.

Recentemente, enfrentei uma jornada de testes para inicializar um container cPanel com o Systemd como PID 1. O que começou com um simples ajuste de sintaxe no YAML evoluiu para investigações sobre a transição de Cgroups v1 para Cgroup v2, falhas de alocação de escopo no Systemd e uma armadilha clássica de persistência de volumes no Docker.

Abaixo, compartilho o passo a passo, os erros analisados e a configuração final que tornou o setup funcional.

1. O primeiro tropeço: sintaxe no compose#

A ideia inicial era subir um container baseado em AlmaLinux 8, instalando pacotes base (openssh-server, passwd, iptables-services, systemd, rsyslog, wget, perl) no primeiro boot e passando o controle para o /usr/lib/systemd/systemd como PID 1.

Ao rodar o docker compose up, me deparei com o erro:

YAMLSemanticError: Implicit map keys need to be followed by map values

Causa raiz#

Ao inspecionar o arquivo, identifiquei um resquício colado do prompt do terminal no final dos volumes:

volumes:
  cpanel_home:
  cpanel_etc:
  cpanel_var:
  cpanel_usr:
  cpanel_logs:
  cpanel_core:root # <-- string "root" colada após os dois pontos

No YAML, chaves vazias em mapeamentos de topo exigem blocos explícitos {}:

volumes:
  cpanel_home: {}
  cpanel_etc: {}
  cpanel_var: {}
  cpanel_usr: {}
  cpanel_logs: {}
  cpanel_core: {}

2. O console mudo e o socket de syslog#

Com o arquivo corrigido, executei docker compose up e o container travou em:

Attaching to cpanel

Nenhum log de boot ou saída do dnf aparecia no terminal. Além disso, o cPanel depende do socket /dev/log para emissão de logs clássicos.

Soluções aplicadas:#

  1. Alocação de Pseudo-TTY: O Systemd verifica se está conectado a um console real (/dev/console). Sem TTY, ele silencia o stdout. Adicionei ao Compose:
   tty: true
   stdin_open: true
  1. Instalação do rsyslog: Adicionei o pacote rsyslog no script de bootstrap para garantir a criação e o consumo do socket /dev/log em paralelo ao systemd-journald.

3. O desafio dos Cgroups: v1 legada vs. v2 unificada#

Com o terminal exibindo a saída, surgiu a falha crítica do Systemd:

Welcome to AlmaLinux 8.10 (Cerulean Leopard)!

Failed to create /init.scope control group: No such file or directory
Failed to allocate manager object: No such file or directory
[!!!!!!] Failed to allocate manager object, freezing.
Freezing execution.

O que acontece no kernel?#

A restrição do kernel#

Tentar criar pastas ou fazer bind mounts manuais em /sys/fs/cgroup/systemd dentro do container resulta em:

mount: /sys/fs/cgroup/systemd: permission denied.
Failed to mount cgroup at /sys/fs/cgroup/systemd: Operation not permitted

Por restrições de segurança do Kernel Linux (Top-down Constraint), um container não pode criar controladores Cgroup v1 sobre uma árvore v2 já montada pelo Host.

4. Migração para AlmaLinux 9 e a armadilha dos volumes#

A saída técnica foi migrar para o AlmaLinux 9, cujo Systemd v252 possui suporte nativo ao Cgroup v2 unificado.

Mudei a imagem no Compose para almalinux:9, baixei a nova imagem e rodei o serviço. Para minha surpresa, o erro persistiu exatamente igual:

✔ Image almalinux:9 Pulled
...
Welcome to AlmaLinux 8.10 (Cerulean Leopard)!
Failed to allocate manager object: No such file or directory

O fantasma no volume persistente#

Por que o container baixou o AlmaLinux 9, mas continuou executando o AlmaLinux 8?

No Compose, havia mapeamentos persistentes de diretórios de sistema:

volumes:
  - cpanel_usr:/usr
  - cpanel_etc:/etc
  - cpanel_var:/var

O Docker faz a cópia dos arquivos da imagem para o volume nomeado (copy-up) apenas na primeira criação. Como o volume cpanel_usr já estava populado com os binários do AlmaLinux 8 das tentativas anteriores, o Docker montou o volume antigo por cima da imagem nova do AlmaLinux 9. O container estava tentando rodar o systemd 239 do Alma 8 em cima da base do 9.

A limpeza necessária#

Foi necessário remover completamente os volumes antigos:

docker compose down -v
docker volume rm public_html_cpanel_usr public_html_cpanel_etc public_html_cpanel_var

5. Estrutura final funcional no Docker compose#

Após limpar os volumes, o AlmaLinux 9 inicializou o systemd 252 sem falhas. Ajustei também o compartilhamento de namespace com cgroup: host e o sinal de parada limpa SIGRTMIN+3.

Abaixo está o arquivo docker-compose.yaml funcional:

services:
  almalinux9-cpanel:
    image: almalinux:9
    container_name: ${CONTAINER_NAME}
    hostname: ${HOSTNAME}
    privileged: true
    restart: always
    tty: true
    stdin_open: true
    
    # Compartilha o namespace de cgroup para suporte nativo ao Cgroup v2
    cgroup: host

    security_opt:
      - label:disable
      - seccomp:unconfined
    
    cap_add:
      - NET_ADMIN
      - SYS_ADMIN
      - SYS_RAWIO
    
    command: 
      - /bin/bash
      - -c
      - |
        if [ ! -f /etc/firstboot_done ]; then
          echo "Provisionando pacotes base no AlmaLinux 9...";
          mkdir -p /etc && touch /etc/fstab;
          dnf install -y openssh-server passwd systemd iptables-services wget perl hostname rsyslog;
          echo "root:${ROOT_PASSWORD}" | chpasswd;
          echo "Port ${SSH_PORT_CONTAINER}" >> /etc/ssh/sshd_config;
          sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config;
          systemctl enable rsyslog sshd;
          touch /etc/firstboot_done;
          echo "Provisionamento concluido.";
        fi;
        echo "Iniciando Systemd v252 (PID 1)...";
        exec /usr/lib/systemd/systemd --log-level=info --unit=multi-user.target;

    stop_signal: SIGRTMIN+3
    
    tmpfs:
      - /run
      - /run/lock
      - /tmp
    
    ports:
      - "${SSH_PORT_HOST}:${SSH_PORT_CONTAINER}"
      - "${CPANEL_SSL_PORT}:${CPANEL_SSL_PORT}"
      - "${WHM_SSL_PORT}:${WHM_SSL_PORT}"
      - "${CPANEL_NON_SSL_PORT}:${CPANEL_NON_SSL_PORT}"
      - "${WHM_NON_SSL_PORT}:${WHM_NON_SSL_PORT}"
      - "${HTTP_PORT_HOST}:${HTTP_PORT_CONTAINER}"
      - "${HTTPS_PORT_HOST}:${HTTPS_PORT_CONTAINER}"
    
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
      - /lib/modules:/lib/modules:ro
      - cpanel_home:/home
      - cpanel_etc:/etc
      - cpanel_var:/var
      - cpanel_usr:/usr
      - cpanel_logs:/var/log
      - cpanel_core:/usr/local/cpanel

    environment:
      - LANG=${LANG}
      - TZ=${TIMEZONE}
      - ROOT_PASSWORD=${ROOT_PASSWORD}
      - container=docker

volumes:
  cpanel_home: {}
  cpanel_etc: {}
  cpanel_var: {}
  cpanel_usr: {}
  cpanel_logs: {}
  cpanel_core: {}

Lições práticas aprendidas#

  1. Incompatibilidade de Cgroups: O Systemd 239 (EL8) não consegue rodar dentro de containers em hosts com Cgroup v2 puro sem modificar o boot do host. A solução mais simples e limpa é utilizar uma base com Systemd 250+ (como AlmaLinux 9).
  2. Cuidado ao persistir /usr e /etc: Montar volumes nomeados em diretórios de binários congela o estado do sistema de arquivos. Ao trocar a versão da imagem base, limpe os volumes antigos com docker compose down -v para evitar que binários antigos mascarem o novo sistema.
  3. Systemd como PID 1 exige TTY e Signals adequados: Sem tty: true os logs de boot são silenciados, e sem SIGRTMIN+3 o encerramento do container envia SIGKILL destrutivo antes do Systemd desmontar os serviços com segurança.

Este artigo foi útil?

Deixe uma reação rápida para apoiar o conteúdo:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários