构建最新版本时出错

你好。我在运行最新版本的 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?

目前,我没有通过 git 管理 discourse-docker。相反,我在配置服务器时下载特定版本的 discourse-docker(作为 Zip 包),并在部署 discourse 时将其锁定到特定的提交版本。

我这样做是为了让构建过程可重复,即:在不同时间使用相同的配置和源代码运行相同的命令,应生成相同的产物。一般来说,这是一个好主意,多年来帮我避免了许多其他软件带来的运维噩梦;因为它能让你回滚到已知良好的配置。

不过,我觉得在 Discourse 这里我可能是在逆流而行,因为它似乎在构建过程中会拉取各种软件的最新版本。我开始怀疑,我试图让构建可重复的做法是否反而在给自己制造麻烦?

您说得非常对,通过这种 hackery 操作,您已陷入一个完全无法获得支持的状态 :flushed_face:

建议您尽快从 git 拉取最新版本。

旧版的 Discourse 基础 Docker 镜像与当前版本的 Discourse 不兼容,而且缺少许多安全补丁。

谢谢 @sam。我已经照做了,现在可以构建新版本了。幸运的是,这一切都在测试阶段,所以没有造成任何损失 :slight_smile: 不过,我认为想要可重复的构建并不算是“黑客行为” :thinking:

我真正想要的是能够回滚到一个已知良好的版本。假设我在时间 t1 运行 ./launcher rebuild app,Discourse 正常工作。然后我在时间 t2 再次运行 ./launcher rebuild app,结果出了问题。我该如何将软件恢复到之前的版本?如果我能回滚到已知良好的状态,我可以接受构建不可重复的事实。既然 launcher 已经在时间 t1 构建了一个可用的 Docker 镜像,是否有可能让 launcher 使用该特定镜像,而不是在时间 t2 构建的错误镜像?

有什么建议吗?

抱歉稍微偏离了主题,如果你愿意,我可以重新发帖。

如果您希望构建可重复,您必须通过容器配置将 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.0beta2(在 web_only.yml 中固定)

我运行 ./launcher rebuild web_only,一切正常。

此时我的系统处于以下状态:

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

现在我更改配置为以下状态:

discourse : 2.4.0beta8(在 web_only.yml 中固定)

我运行 ./launcher rebuild web_only,结果出现了问题。

此时我的系统处于以下状态:

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

现在我想要回退到之前的版本以恢复正常运行。于是我将 Discourse 的固定版本改回 2.4.0beta2 并重新构建。然而,当我运行 ./launcher rebuild web_only 时,系统现在处于以下状态:

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

尽管 Discourse 的固定版本相同,但 discourse-base(以及 discourse-docker 的其他部分、模板、./launcher 本身等)的版本现在已不同,因此我无法回退到一个已知良好的状态,我担心这甚至可能无法成功构建。

如果我在这里显得迟钝,还请见谅。我只希望在更新过程中出现问题时能够安全回退。也许重新运行 ./launcher rebuild web_only 并不是正确的回滚方式?对于我部署的其他系统,我通常会重新部署之前的 Docker 镜像。是否有办法让 launcher 执行类似操作?

是的,你得重新思考一下这里的流程。我们的数据库迁移是不可逆的。

如果你想在正式提交之前测试升级,需要在预发布沙箱环境中进行操作。

是的,我明白回滚数据库迁移确实很困难。Discourse 显然不是为我的发布和部署管理策略而设计的。我不该再逆水行舟了。

我有一个预发布环境。所以,我将放弃可重复构建和部署的想法,在预发布环境测试后,上线生产环境时只能听天由命了。

感谢你的帮助 @sam