Bootsnap::CompileCache::PermissionError

こんにちは、皆さん。Docker 内で Discourse を新規インストールしました。
問題は、コンテナを再構築した後、コンテナは起動しアプリページにもアクセスできるのですが、502 エラーが返ってくるという点です。ログを確認したり、コンテナ内で rails c にアクセスしたりしても、以下のエラーしか表示されません。

permission_error': bootsnap doesn't have permission to write cache entries in 'tmp/cache/bootsnap/compile-cache' (or, less likely, doesn't have permission to read '/usr/local/lib/ruby/2.7.0/set.rb') (Bootsnap::CompileCache::PermissionError)

これを修正するには、コンテナ内で chown -R discourse:discourse /var/www/discourse/tmp(正確には /var/www/discourse/tmp/cache/bootsnap)を実行する必要がありますが、その直後にアプリは再起動なしで正常に動作します。しかし、再構築のたびに手動でこれを行うのは非常に面倒です。

app.yml のカスタムコマンドセクションで上記の chown -R discourse:discourse /var/www/discourse/tmp を使用して対処できないかと考えましたが、残念ながら機能しません。コマンドは呼び出されているようですが(確認のために mkdir を試しました)、ファイルの権限は変更されません。

ここでの問題は何で、どのように解決できるでしょうか?もしかすると、ファイルの権限を正しく変更する方法があるかもしれません。

それは奇妙ですね。Discourse 公式の標準インストールの手順に従いましたか?

もちろん、追加の手順は行われませんでした。

パスワードを除いた container.yml ファイルを貼り付けていただけますか?

はい、こちらです:

## これはオールインワンでスタンドアロンの Discourse Docker コンテナテンプレートです
##
## このファイルを編集した後は、必ず再構築が必要です
## /var/discourse/launcher rebuild app
##
## 編集時は非常に注意してください!
## YAML ファイルは空白やアライメントの誤りに非常に非常に敏感です!
## 必要に応じて http://www.yamllint.com/ にアクセスしてこのファイルを検証してください

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## Lets Encrypt (https) を追加したい場合は、以下の 2 行のコメントを外してください
  - "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

## このコンテナが公開する TCP/IP ポートはどれですか?
## Discourse を Apache や nginx などの他の Web サーバーとポートを共有したい場合は、
## 詳細については https://meta.discourse.org/t/17247 を参照してください
expose:
  - "80:80"   # http
  - "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## db_shared_buffers を総メモリの最大 25% に設定します。
  ## ブートストラップによって検出された RAM に基づいて自動的に設定されますが、上書きすることもできます
  #db_shared_buffers: "256MB"

  ## ソートパフォーマンスを向上させることができますが、接続ごとのメモリ使用量が増加します
  #db_work_mem: "40MB"

  ## このコンテナで使用する Git リビジョンはどれですか?(デフォルト: 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

  ## 同時にサポートされる Web リクエスト数はいくつですか?メモリと CPU コア数に依存します。
  ## ブートストラップによって検出された CPU に基づいて自動的に設定されますが、上書きすることもできます
  #UNICORN_WORKERS: 3

  ## TODO: この Discourse インスタンスが応答するドメイン名
  ## 必須です。Discourse は IP アドレスのみでは動作しません。
  DISCOURSE_HOSTNAME: 'example.com'

  ## コンテナを上記で指定したホスト名(-h オプション)と同じホスト名で起動したい場合は、
  ## 以下のコメントを外してください(デフォルト: "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: 初期登録時に管理者および開発者として設定されるメールアドレスのカンマ区切りリスト
  ## 例: 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'test@mail.com'

  ## TODO: 新規アカウントの検証と通知送信に使用する SMTP メールサーバー
  # SMTP アドレス、ユーザー名、パスワードは必須です
  # 警告: SMTP パスワードに含まれる文字 '#' は問題を引き起こす可能性があります!
  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           # (オプション、デフォルトは true)
  #DISCOURSE_SMTP_DOMAIN: discourse.example.com    # (一部のプロバイダーで必須)
  #DISCOURSE_NOTIFICATION_EMAIL: noreply@discourse.example.com    # (通知を送信するアドレス)

  ## Lets Encrypt テンプレートを追加した場合は、以下をコメント外して無料の SSL 証明書を取得してください
  #LETSENCRYPT_ACCOUNT_EMAIL: me@example.com

  ## この Discourse インスタンスの http または https CDN アドレス(プルするように設定)
  ## 詳細については https://meta.discourse.org/t/14857 を参照してください
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com
  
  ## IP アドレスの検索に使用する Maxmind 地理位置 IP アドレスキー
  ## 詳細については https://meta.discourse.org/t/-/137387/23 を参照してください
  #DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456

## Docker コンテナはステートレスです。すべてのデータは /shared に保存されます
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## プラグインはここに記述します
## 詳細については https://meta.discourse.org/t/19157 を参照してください
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## ビルド後に実行する任意のカスタムコマンド
run:
  - exec: echo "カスタムコマンドの開始"
  ## 最初の登録用の 'From' メールアドレスを設定したい場合は、以下のコメントを外して変更してください:
  ## 最初のサインアップメールを受信した後、再度その行をコメントアウトしてください。一度だけ実行すれば十分です。
  #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
  #- exec: chown -R discourse:discourse /var/www/discourse/tmp/cache/bootsnap  # ファイル権限の修正を試みた際の例コマンド
  - exec: echo "カスタムコマンドの終了"

discourse-setupを実行しませんでしたか?それによっていくつかの設定が定義されるはずですが、それらがコメントアウトされているようです。私はその変更を適用しましたが、期待通りに動作しているか確認したいです。

Let’s Encryptを使用していない理由は何でしょうか?

ただし、あなたの問題に対する明確な説明は見当たりません。

まず、アプリケーションは discourse-setup を使用して構築されました。再構築を何度か試みましたが、改善が見られなかったため、/samples ディレクトリにある事前に定義された .yml 設定ファイルのいずれかに移行し、そこに自分の認証情報を記述して編集しました。
「なぜ Let’s Encrypt を使わないのか」と尋ねられ、クライアント証明書を使用するように言われました。しかし、私の理解では、証明書は問題とは無関係です。証明書は有効であり、そこから生じる問題もありません。
問題はプロジェクトレベルにあるように思われ、具体的には bootsnap キャッシュファイルの権限に関連しています(問題の所在は Bootsnap 側にある可能性もあります)。

ありがとうございます。それが問題ではないだろうと思います。昨日も数回インストールを試みましたが、すべて正常に動作しました。あなたの問題の理由については、見当たりません。

同じ問題に直面しており、Docker コンテナ内で以下のコマンドを実行することで問題が解決したことを確認しました。

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

再起動は不要でした。所有者変更前、「tmp」ディレクトリの権限は「discourse:www-data」に割り当てられていました。今後、この手動操作が各ビルド後に不要になるよう、何らかの修正がなされることを願っています。

ランチャーを root 権限で実行していますか?

はい、@pfaffman さん、その通りです。それが問題でしょうか?

そうは思いません。私はセルフホストインスタンスを常に root で起動しており、そのような問題に遭遇したことはありません。

chown を使用しない場合、ディレクトリの所有者は誰になりますか?最近再構築したコンテナでは、以下のような状態になっています:

# 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

プラグインのクローン以外に、app.yml にカスタムコマンドやフックを追加しましたか?

コンテナ起動後、/var/www/discourse/tmp ディレクトリの所有者とグループは discourse:www-data になっていました。これを discourse:discourse に再割り当てすることで問題が解決しました。これは以前経験したことがなく、すでに数ヶ月間 Discourse を使用していました。とにかく、簡単な修正で、たまたま起きたことかもしれませんので、これ以上ご迷惑をおかけしたくありません。@gerhard さん、本当にありがとうございました!