why
Discourse 官方仅支持一种部署方法,即 用 dicourse_docker 仓库里的 shell, yaml, ruby 混合的代码里的代码 构建容器,
导致 每次改) 代码都要花 20 分钟重构容器,非常蛋疼.
本 thread 将记录我的另类部署方式.
为什么要用官方不支持的方式运行 Discourse?
Discourse 唯一的部署方式不允许别人修改源代码的 URL,
导致我想要修改默认运行的方式只能写插件并花 20 分钟重建容器,不能 fork 完直接在源代码上面改,迭代周期长,开发效率极低
Discourse 是个牛逼的软件,界面也很现代,但是安装部署的方式真的是 10 年前的:
创始人 Sam 在十几年前用 ruby 脚本写了个程序 pups 构建容器
Broadcom Bitnami 维护了 另一种部署方法,但也没比官方的好到哪里去。
原厂的 Gemfile
里甚至没有 rails
, 只有个自家的 rails_multisite
导致我想要用 Rubymine 调试程序的时候提示我 rails 没有安装? 然而我用命令行运行rail s
却是可以的,害得我以为是 Rubymine 出 bug 或者配置错了或者 rvm 出 bug 了
procedures
以开发模式运行
开发环境运行 rails 应用的命令:
ALLOW_EMBER_CLI_PROXY_BYPASS=1 DISCOURSE_DEV_LOG_LEVEL=warn DISCOURSE_ENABLE_CORS=true RAILS_DEVELOPMENT_HOSTS=xjtu.app RAILS_ENV=development HOST_URL=xjtu.app DISCOURSE_HOSTNAME=xjtu.app NUM_WEBS=8 rails s
rails 区分开发/生产运行模式,使用的配置不一样,例如开发模式缺少 cache 和 asset minimization,所以访问起来性能非常低下,低得夸张:
https://pagespeed.web.dev/analysis/https-xjtu-app/g5sfcvavle?form_factor=mobile
从 Docker 里复制
本来我想比较一下 config/environments/development.rb 和 production.rb 的配置选项,但无奈 assets pipeline pre-compilation 不太懂,就不学了。直接开大招,把容器里的 discourse 复制出来,找到启动命令,在容器外面直接运行得了
先看看容器的入口 ./launcher start-cmd webxj
- true run --shm-size=512m --link dataxj:dataxj -d --restart=always -e LANG=en_US.UTF-8 -e RAILS_ENV=production … --name webxj -t -v /var/discourse/shared/webxj:/shared … local_discourse/webxj /sbin/boot
查看 /sbin/boot
root@mnz-webxj:/var/www/discourse# cat /sbin/boot
#!/bin/bash
# we use this to boot up cause runit will not handle TERM and will not exit when done
shutdown() {
echo Shutting Down
/etc/runit/3
ls /etc/service | SHELL=/bin/sh parallel sv force-stop {}
kill -HUP $RUNSVDIR
wait $RUNSVDIR
# give stuff a bit of time to finish
sleep 0.1
ORPHANS=`ps -eo pid | grep -v PID | tr -d ' ' | grep -v '^1$'`
SHELL=/bin/bash parallel 'timeout 5 /bin/bash -c "kill {} && wait {}" || kill -9 {}' ::: $ORPHANS 2> /dev/null
exit
}
/etc/runit/1 || exit $?
/etc/runit/2&
RUNSVDIR=$!
echo "Started runsvdir, PID is $RUNSVDIR"
trap shutdown SIGTERM SIGHUP
wait $RUNSVDIR
shutdown
容器里面用的 sv 管理进程,查看cat /etc/service/unicorn/run
#!/bin/bash
exec 2>&1
# redis
# postgres
cd /var/www/discourse
chown -R discourse:www-data /shared/log/rails
PRECOMPILE_ON_BOOT=0
if [[ -z "$PRECOMPILE_ON_BOOT" ]]; then
PRECOMPILE_ON_BOOT=1
fi
if [ -f /usr/local/bin/create_db ] && [ "$CREATE_DB_ON_BOOT" = "1" ]; then /usr/local/bin/create_db; fi;
if [ "$MIGRATE_ON_BOOT" = "1" ]; then su discourse -c 'bundle exec rake db:migrate'; fi
if [ "$PRECOMPILE_ON_BOOT" = "1" ]; then SKIP_EMBER_CLI_COMPILE=1 su discourse -c 'bundle exec rake assets:precompile'; fi
LD_PRELOAD=$RUBY_ALLOCATOR HOME=/home/discourse USER=discourse exec thpoff chpst -u discourse:www-data -U discourse:www-data bundle exec config/unicorn_launcher -E production -c config/unicorn.conf.rb
参考 Install Discourse on Ubuntu or Debian for Development - Developer Guides - Discourse Meta 安装 ImageMagick, oxipng, jhead
安装 pnpm, rvm 和 ruby
pnpm env use --global lts
rvm install 3.3
rvm use 3.3 --default
## 看看是否支持 YJIT
ruby --yjit -v
把 redis 和 PG 的数据复制一份,再把 start-cmd 里的环境变量复制到.zshrc,新建数据库用户,配置 config/discourse.conf
, 复制 bundle 那行启动命令启动bundle exec config/unicorn_launcher -E production -c config/unicorn.conf.rb
# pnpm
export PNPM_HOME="/home/discourse/.local/share/pnpm"
case ":$PATH:" in
*":$PNPM_HOME:"*) ;;
*) export PATH="$PNPM_HOME:$PATH" ;;
esac
# pnpm end
alias npm='pnpm'
alias npx='pnpx'
export PATH="$PATH:$HOME/.rvm/bin"
export RAILS_ENV=production
export UNICORN_WORKERS=6
export UNICORN_SIDEKIQS=1
export RUBY_GC_HEAP_GROWTH_MAX_SLOTS=40000
export RUBY_GC_HEAP_INIT_SLOTS=400000
export RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=1.5
export RUBY_YJIT_ENABLE=1
export RUBY_CONFIGURE_OPTS="--enable-yjit"
export DISCOURSE_HOSTNAME=xjtu.app
...
https://www.postgresql.org/download/linux/ubuntu/
apt install postgresql postgresql-client-17 postgresql-common postgresql-contrib postgresql-client-common postgresql-server-dev-17 postgresql-17 postgresql-17-pgvector libpq-dev
sudo -u postgres createuser -s discourse
sudo -u postgres createdb discourse
$sudo -u postgres psql discourse
psql>
ALTER USER discourse WITH PASSWORD 'xxx';
CREATE EXTENSION hstore;CREATE EXTENSION pg_trgm;
CREATE EXTENSION plpgsql;
CREATE EXTENSION unaccent;
CREATE EXTENSION vector;
$ gunzip < dump.sql.gz | psql discourse
dump.sql.gz 是 Discourse 备份解压出来的,容器里是 PG13,导入到新安装的 PG17 竟然无比丝滑
再把容器里的 nginx 复制出来,把 cache 和文件目录重新配一下,启动成功
cd /shared/
chown discourse:www-data backups tmp uploads
upgrade
参考:
chown -R discourse:discourse /var/www/discourse/
chown -R discourse:www-data /var/www/discourse/public
su - discourse
cd /var/www/discourse
git stash
git pull
git checkout tests-passed
rm lib/tasks/custom.rake db/migrate/20241213085000_add_external_id_to_posts.rb
git apply mypatch20241225v1.patch
# LOAD_PLUGINS=0 bundle exec rake plugin:pull_compatible_all
cd plugins
for plugin in *
do
echo $plugin
pushd ${plugin}
git pull
popd
done
cd ../
# may need this when migrate to another system
# rm plugins/*/gems -r
bundle install && pnpm i && bundle exec rake db:migrate && bundle exec rake assets:precompile
pumactl phased-restart
直接用 pg_dump 备份
discour+ 1142358 0.0 0.0 2384 1408 pts/3 S+ 13:54 0:00 sh -c PGPASSWORD='191549' pg_dump --schema=public -T public.pg_* --file='/var/www/discourse/tmp/backups/default/2024-12-14-135427/dump.sql.gz' --no-owner --no-privileges --verbose --compress=4 --host=localhost --username=discourse discourse 2>&1
discour+ 1142359 94.1 0.1 32240 18388 pts/3 R+ 13:54 0:12 /usr/lib/postgresql/17/bin/pg_dump --schema=public -T public.pg_* --file=/var/www/discourse/tmp/backups/default/2024-12-14-135427/dump.sql.gz --no-owner --no-privileges --verbose --compress=4 --host=localhost --username=discourse discourse