最新バージョンのビルドでエラーが発生しました

こんにちは。Discourse の最新リリースで ./installer rebuild web_only を実行した際に、以下のエラーが発生します。

fs.js:114
    throw err;
    ^

Error: ENOENT: no such file or directory, open 'root='/assets',url='/assets/vendor-4681e47c140b5a5bea2bfb1fec89365858288a8ea0c21979c0167ad9b570ee3d.js.map''
    at Object.openSync (fs.js:438:3)
    at Object.writeFileSync (fs.js:1189:35)
    at done (/usr/lib/node_modules/uglify-js/bin/uglifyjs:516:20)
    at cb (/usr/lib/node_modules/uglify-js/bin/uglifyjs:324:39)
    at /usr/lib/node_modules/uglify-js/bin/uglifyjs:391:9
    at FSReqWrap.readFileAfterClose [as oncomplete] (internal/fs/read_file_context.js:53:3)
rake aborted!
Errno::ENOENT: No such file or directory @ rb_file_s_size - /var/www/discourse/public/assets/vendor-4681e47c140b5a5bea2bfb1fec89365858288a8ea0c21979c0167ad9b570ee3d.js
/var/www/discourse/lib/tasks/assets.rake:268:in `size'
/var/www/discourse/lib/tasks/assets.rake:268:in `block (4 levels) in <top (required)>'
/var/www/discourse/lib/tasks/assets.rake:159:in `block in concurrent?'
/var/www/discourse/lib/tasks/assets.rake:259:in `block (3 levels) in <top (required)>'
/var/www/discourse/lib/tasks/assets.rake:250:in `each'
/var/www/discourse/lib/tasks/assets.rake:250:in `block (2 levels) in <top (required)>'
/var/www/discourse/lib/tasks/assets.rake:159:in `concurrent?'
/var/www/discourse/lib/tasks/assets.rake:247:in `block in <top (required)>'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/exe/rake:27:in `<top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => assets:precompile
(See full trace by running task with --trace)
I, [2019-12-11T22:53:15.806396 #18]  INFO -- : Downloading MaxMindDB...
Compressing Javascript and Generating Source Maps



FAILED
--------------------
Pups::ExecError: cd /var/www/discourse && su discourse -c 'bundle exec rake assets:precompile' failed with return #<Process::Status: pid 17151 exit 1>
Location of failure: /pups/lib/pups/exec_command.rb:112:in `spawn'
exec failed with the params {"cd"=>"$home", "hook"=>"assets_precompile", "cmd"=>["su discourse -c 'bundle exec rake assets:precompile'"]}
f565d457b97d7ff12a258b03a456563a5a0e928c707c70e194ef88ba170aaf3a
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one

すべてのプラグインを無効にしましたが、依然として解決しません。何か原因がわかる方がいれば教えてください。

以前どこかで見たことがあります。

以下のコマンドを試してみてください。

./launcher cleanup
git pull
./launcher rebuild app

それでも解決しない場合は、マシン上のすべてのコンテナとすべてのイメージを削除してください。

@sam さん、迅速なご対応ありがとうございます。試してみます。

少し質問です。「git pull」は、discourse-docker の最新バージョンを取得するものだと理解していますが、合っていますか?

一般的に、discourse-docker と discourse は同時にアップグレードする必要がありますか?

現在、私は discourse-docker を git で管理していません。代わりに、サーバー設定時に discourse-docker の特定のリビジョンを Zip としてダウンロードし、discourse のデプロイ時に特定のコミットにバージョンを固定しています。

この方法を選んだ理由は、ビルドの再現性を確保するためです。つまり、同じ設定とソースを使用して、異なる時点で同じコマンドを実行すれば、同じ成果物が得られるようにしたいと考えています。これは一般的に良い考えであり、過去数年間で他のソフトウェアに関する多くの運用上のトラブルから私を救ってくれました;) これは、既知の良好な設定へロールバックする能力を与えるからです。

しかし、discourse においては、ビルド中にさまざまなソフトウェアの最新バージョンをプルしようとするため、ここで流れに逆らっているような気がします。ビルドの再現性を高めようとする私の試みが、逆に足元をすくっているのではないかと疑い始めています。

おっしゃる通りです。このハック行為によって、完全にサポート不可能な状態に陥ってしまいました😳

できるだけ早く git から最新バージョンをプルすることをお勧めします。

Discourse ベースの古い Docker イメージは現在の Discourse と互換性がなく、さらに多くのセキュリティパッチも欠落しています。

@sam さん、ありがとうございます。その対応を試したところ、新しいバージョンをビルドできるようになりました。幸運なことに、すべてベータ版での作業だったため、被害はありませんでした :slight_smile: ただ、再現性のあるビルドを望むことが「ハック」だとは思わないのですがね :thinking:

私が目指しているのは、既知の正常なバージョンにロールバックする機能です。例えば、t1 の時点で ./launcher rebuild app を実行して Discourse が正常に動作したとします。その後、t2 の時点で同じコマンドを実行したところ、何かがおかしくなりました。どうすればソフトウェアを以前のバージョンに戻せるでしょうか?ロールバックして既知の正常な状態に戻せるのであれば、ビルドが再現性がないことには耐えられると思います。t1 の時点で launcher がすでに動作する Docker イメージを構築している以上、t2 に構築された悪いイメージではなく、特定のイメージを使うよう launcher に指示することは可能でしょうか?

何かご存知でしょうか?

少し話題がそれてしまい申し訳ありません。必要であれば、別のスレッドに投稿し直します。

再現性のあるビルドを実現するには、コンテナ設定を通じて Discourse のバージョンを特定の SHA に固定し、すべてのプラグインも同様に行う必要があります。

つまり、Discourse の修正や Docker イメージのセキュリティ修正などが適用されなくなりますが、ビルドは非常に再現性が高くなります。

テンプレートも修正して、APT 依存関係のセキュリティ修正を一切取り込まないよう、内容を固定化する必要があるかもしれません。

はい、Discourse のバージョンを特定のコミットに固定しており、プラグインについても同様に固定できます。しかし、discourse-docker も固定しない場合、ビルドのたびに discourse-base が更新され、Discourse は更新されない状況が生じる可能性があります。これでは、discourse-base が Discourse より先に更新されるという逆方向の同様の非互換性が生じることになりませんか?

混乱しています。Discourse が古いバージョンに固定されているのに、なぜこのエラーが表示されたのでしょうか?

NGINX に深刻な脆弱性がある場合、修正を希望しますか?

エラーは、Discourse のピン留めバージョンを 2.4.0.beta2 から 2.4.0.beta8 に変更した際に発生しました。

もちろん、新しいビルドを実行する際に依存ソフトウェアシステムの重要な脆弱性が修正されることを望んでいます!素晴らしいですね!

しかし、新しいバージョンに問題がある場合にもロールバックできることも望んでいます。

具体的な例を挙げて説明します。

現在の設定が以下の状態だと仮定します。

discourse : 2.4.0.beta2(web_only.yml でピン留め)

./launcher rebuild web_only を実行すると、すべて正常に動作します。

この時点でシステムの状態は以下のようになります。

discourse : 2.4.0.beta2
discourse-docker: LATEST-AT-TIME-T1

次に、設定を以下のように変更します。

discourse : 2.4.0.beta8(web_only.yml でピン留め)

./launcher rebuild web_only を実行すると、何かが壊れてしまいました。

システムの現在の状態は以下の通りです。

discourse : 2.4.0.beta8
discourse-docker: LATEST-AT-TIME-T2

ここで、すべてが正常に動作するように前のバージョンに戻したいと考えています。そのため、Discourse のピン留めバージョンを 2.4.0.beta2 に戻して再ビルドします。しかし、./launcher rebuild web_only を実行すると、システムの状態は以下のようになります。

discourse : 2.4.0.beta2
discourse-docker: LATEST-AT-TIME-T2

Discourse のピン留めバージョンは同じですが、discourse-base(および discourse-docker の残りの部分、テンプレート、./launcher 自体など)のバージョンが異なっているため、既知の正常な状態には戻らず、ビルド自体が失敗するのではないかと心配しています。

もし私が理解不足であれば申し訳ありません。私が求めているのは、アップデート中に問題が発生した場合に安全な状態に戻れるようにすることだけです。もしかすると、./launcher rebuild web_only を再実行するのはロールバックの適切な方法ではないのでしょうか?私がデプロイしている他のシステムでは、以前の Docker イメージを再デプロイするだけです。これを launcher に指示する方法はありますか?

はい、ここでのプロセスを見直す必要があります。当社のデータベースマイグレーションは不可逆です。

コミットせずにアップグレードをテストしたい場合は、ステージングサンドボックスで操作する必要があります。

はい、データベースマイグレーションをロールバックするのは難しいことは理解しています。Discourse は明らかに、私のようなリリースやデプロイ管理戦略を想定して設計されていません。ここで無理に流れに逆らうのはやめましょう。

ステージング環境は用意されていますので、再現性のあるビルドやデプロイのアイデアはあきらめ、ステージングでテストした後、本番環境に移行する際はひたすら祈るしかありません。

@sam さん、お手伝いいただきありがとうございました。