Bootsnap::CompileCache::PermissionError

Olá, pessoal. Tenho uma instalação recente do Discourse em Docker.

O problema é que, após a reconstrução do container, ele sobe e consigo acessar a página do aplicativo. No entanto, recebo uma resposta 502. Nos logs ou ao tentar acessar, por exemplo, rails c (dentro do container), tudo o que vejo é este erro:

`permission_error’: bootsnap não tem permissão para escrever entradas de cache em ‘tmp/cache/bootsnap/compile-cache’ (ou, menos provavelmente, não tem permissão para ler ‘/usr/local/lib/ruby/2.7.0/set.rb’) (Bootsnap::CompileCache::PermissionError)

Para corrigir isso, tenho que executar chown -R discourse:discourse /var/www/discourse/tmp (para ser exato, é o diretório /var/www/discourse/tmp/cache/bootsnap) dentro do container, e imediatamente após isso o aplicativo funciona perfeitamente, mesmo sem reiniciar. É bastante incômodo ter que fazer isso manualmente após cada reconstrução.

Pensei em resolver isso usando a seção de comandos personalizados no arquivo app.yml, mencionando o comando chown -R discourse:discourse /var/www/discourse/tmp acima, mas, infelizmente, não funciona. Os comandos parecem ser executados (testei com mkdir apenas para verificar), mas as permissões dos arquivos não são alteradas.

Qual pode ser o problema aqui e como isso pode ser resolvido? Talvez exista alguma maneira correta de alterar as permissões dos arquivos?

Isso é estranho. Você seguiu a Instalação Padrão Oficial do Discourse?

Claro. Nenhuma etapa adicional foi realizada.

Você pode colar seu arquivo container.yml (sem senhas)?

Claro. Aqui está:

## este é o modelo de contêiner Docker Discourse tudo-em-um, autônomo
##
## Após fazer alterações neste arquivo, você DEVE reconstruir
## /var/discourse/launcher rebuild app
##
## TENHA *MUITO* CUIDADO AO EDITAR!
## ARQUIVOS YAML SÃO SUPER SUPER SENSÍVEIS A ERROS EM ESPAÇOS EM BRANCO OU ALINHAMENTO!
## visite http://www.yamllint.com/ para validar este arquivo conforme necessário

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## Descomente estas duas linhas se desejar adicionar o Lets Encrypt (https)
  - "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

## quais portas TCP/IP este contêiner deve expor?
## Se você deseja que o Discourse compartilhe uma porta com outro servidor web como Apache ou nginx,
## consulte https://meta.discourse.org/t/17247 para detalhes
expose:
  - "80:80"   # http
  - "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## Defina db_shared_buffers para no máximo 25% da memória total.
  ## será definido automaticamente pelo bootstrap com base na RAM detectada, ou você pode substituir
  #db_shared_buffers: "256MB"

  ## pode melhorar o desempenho de ordenação, mas aumenta o uso de memória por conexão
  #db_work_mem: "40MB"

  ## Qual revisão do Git este contêiner deve usar? (padrão: tests-passed)
  #version: tests-passed

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## Quantas solicitações web simultâneas são suportadas? Depende da memória e dos núcleos da CPU.
  ## será definido automaticamente pelo bootstrap com base nas CPUs detectadas, ou você pode substituir
  #UNICORN_WORKERS: 3

  ## TODO: O nome de domínio ao qual esta instância do Discourse responderá
  ## Obrigatório. O Discourse não funcionará com um número IP puro.
  DISCOURSE_HOSTNAME: 'example.com'

  ## Descomente se quiser que o contêiner seja iniciado com o mesmo
  ## nome de hostname (-h option) especificado acima (padrão "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: Lista de e-mails separados por vírgula que serão definidos como administradores e desenvolvedores
  ## no cadastro inicial, exemplo 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'test@mail.com'

  ## TODO: O servidor de correio SMTP usado para validar novas contas e enviar notificações
  ## ENDEREÇO SMTP, nome de usuário e senha são obrigatórios
  ## AVISO: o caractere '#' na senha do SMTP pode causar problemas!
  DISCOURSE_SMTP_ADDRESS: smtp.mail.io
  #DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: 111
  DISCOURSE_SMTP_PASSWORD: 111
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (opcional, padrão true)
  #DISCOURSE_SMTP_DOMAIN: discourse.example.com    # (obrigatório para alguns provedores)
  #DISCOURSE_NOTIFICATION_EMAIL: noreply@discourse.example.com    # (endereço para enviar notificações)

  ## Se você adicionou o modelo Lets Encrypt, descomente abaixo para obter um certificado SSL gratuito
  #LETSENCRYPT_ACCOUNT_EMAIL: me@example.com

  ## O endereço do CDN http ou https para esta instância do Discourse (configurado para buscar)
  ## consulte https://meta.discourse.org/t/14857 para detalhes
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com
  
  ## A chave de endereço IP do Maxmind para consulta de geolocalização
  ## consulte https://meta.discourse.org/t/-/137387/23 para detalhes
  #DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456

## O contêiner Docker é sem estado; todos os dados são armazenados em /shared
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## Plugins vão aqui
## consulte https://meta.discourse.org/t/19157 para detalhes
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## Quaisquer comandos personalizados para executar após a construção
run:
  - exec: echo "Início dos comandos personalizados"
  ## Se você quiser definir o endereço de e-mail 'De' para seu primeiro registro, descomente e altere:
  ## Após receber o primeiro e-mail de cadastro, comente novamente a linha. Ele só precisa ser executado uma vez.
  #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
  #- exec: chown -R discourse:discourse /var/www/discourse/tmp/cache/bootsnap  # exemplo de comando de como tentei corrigir permissões de arquivo
  - exec: echo "Fim dos comandos personalizados"

Você não executou discourse-setup, certo? Ele deveria ter definido algumas coisas que você comentou. Acabei de fazer essas alterações e quero ter certeza de que está funcionando como esperado.

Há algum motivo para você não estar usando o Let’s Encrypt?

No entanto, não vejo uma explicação para o seu problema.

Primeiramente, a aplicação foi construída usando o discourse-setup. Após algumas tentativas de recriá-la sem obter resultado positivo, migrei para uma das configurações .yml pré-definidas do diretório /samples e, em seguida, editei-a com minhas credenciais.

Por que não usar o Let’s Encrypt? Foi solicitado o uso de certificados do cliente. Mas, pelo que entendi, os certificados não têm nada a ver com isso, pois são válidos e não há problema relacionado a eles.

O problema parece estar no nível do projeto, especificamente relacionado às permissões do arquivo de cache do bootsnap (talvez o problema esteja no lado do Bootsnap).

Obrigado. Concordo que isso provavelmente não seja o problema. Fiz algumas instalações ontem que funcionaram perfeitamente. Não vejo nenhuma explicação para o seu problema.

Estávamos enfrentando o mesmo problema e confirmo que executar (dentro do contêiner Docker):

chown -R discourse:discourse /var/www/discourse/tmp

resolveu o problema! Nenhuma reinicialização foi necessária. As permissões do diretório ‘tmp’ estavam atribuídas a ‘discourse:www-data’ antes da alteração de proprietário. Espero que isso seja algo que possa ser corrigido no futuro, para que essa ação manual não seja necessária após cada reconstrução.

Você está executando o launcher como root?

Sim, @pfaffman, eu sou. Esse é o problema?

Acho que não. Sempre inicio minhas instâncias auto-hospedadas como root e nunca vi um problema assim.

Quem é o proprietário do diretório se você não usar chown? Em um container recentemente recriado, fica assim:

# ls -l /var/www/discourse/tmp
total 36
lrwxrwxrwx 1 root      root         19 Mar  2 14:56 backups -> /shared/tmp/backups
drwxr-xr-x 1 discourse discourse  4096 Mar  2 14:57 cache
drwxr-xr-x 1 discourse discourse  4096 Mar  2 14:57 ember-rails
drwxr-xr-x 1 discourse root       4096 Mar  2 15:04 pids
lrwxrwxrwx 1 root      root         20 Mar  2 14:56 restores -> /shared/tmp/restores
drwxr-xr-x 2 discourse root       4096 Mar  2 14:56 sockets
drwxr-xr-x 2 discourse discourse 12288 Mar  2 15:02 stylesheet-cache

Você adicionou algum comando ou hook personalizado ao seu app.yml além de clonar plugins?

O usuário e grupo de propriedade do diretório /var/www/discourse/tmp eram discourse:www-data após iniciar o container. A realocação para discourse:discourse resolveu o problema. Isso nunca havia acontecido comigo antes, embora eu já esteja usando o Discourse há vários meses. De qualquer forma, foi uma correção simples e pode ter sido algo aleatório, então não quero mais incomodá-los com isso. Muito obrigado, @gerhard!