SDB:Discourse without Docker

跳转至: 导航, 搜索
本教学将向您演示如何在 openSUSE 服务器上面直接架设 discourse 论坛系统。

Docker or without Docker?

Docker 只是一种选择,discourse 官方选择了 docker image 作为他们的分发方式。但毕竟 discourse 只是一个 rails 程序,我们完全可以在 openSUSE 上面架设它,这样会避免很多问题(docker 也会死,那时候 debug 起来会多了一层 docker 的东西,可能是 discourse 的问题,也可能是 docker 的问题),也会减少一些内存占用,毕竟 discourse 作为一个论坛程序是要架设在 VPS 上的,少一些内存占用就少一些成本。

安装并配置 PostgreSQL 数据库

   sudo zypper in postgresql-server

查询一下你安装的 postgresql 版本:

   sudo zypper se postgresql

我这里是 postgresql14。接下来安装 hstore 和 pg_trgm 插件:

   sudo zypper in postgresql14-contrib

启动服务:

   sudo systemctl enable postgresql
   sudo systemctl start postgresql

进入:

   su - postgres -c psql

输入以下命令创建 discourse 数据库和 discourse 用户名,并挂载 discourse 所需的两个数据库扩展(注意最后面的分号一定不能丢):

   CREATE DATABASE discourse;
   CREATE USER discourse;
   ALTER USER discourse WITH ENCRYPTED PASSWORD 'password';
   ALTER DATABASE discourse OWNER TO discourse;
   \connect discourse #连接到 discourse 数据库
   CREATE EXTENSION hstore;
   CREATE EXTENSION pg_trgm;
   \q #退出 postgresql 的命令行

接着编辑 /var/lib/pgsql/data/pg_hba.conf,在最下方加上一行

   host    discourse       discourse      ::1/128                  md5
   host    discourse       discourse      127.0.0.1/32                  md5

重启 postgresql 服务

   sudo systemctl restart postgresql

安装并配置 Redis

安装 redis:

   sudo zypper in redis

创建配置:

   cd /etc/redis
   sudo cp -r default.conf.example discourse.conf
   sudo chown redis:redis discourse.conf

编辑配置,打开 discourse.conf 编辑里面的:

   pidfile /var/run/redis/discourse.pid
   logfile /var/log/redis/discourse.log
   always-show-logo no
   stop-writes-on-bgsave-error no
   dir /var/lib/redis/discourse

创建 redis 的 dir:

   install -d -o redis -g redis -m 0750 /var/lib/redis/discourse

touch 一下 logfile 并设置权限:

   touch /var/log/redis/discourse.log
   sudo chown redis:redis /var/log/redis/discourse.log

另外 openSUSE 的 /usr/lib/systemd/system/redis@.service 有问题,对照下面的改一下:

[Unit]
Description=Redis
After=network.target
PartOf=redis.target

[Service]
Type=notify
User=redis
Group=redis
PIDFile=/var/run/redis/%i.pid
PrivateTmp=true
PermissionsStartOnly=true
Environment=REDIS_STATE_DIR_%i=/var/lib/redis/%i

ExecStartPre=-/usr/bin/mkdir -p ${REDIS_STATE_DIR_%i}
ExecStartPre=/usr/bin/chown -R redis:redis ${REDIS_STATE_DIR_%i}
ExecStart=/usr/sbin/redis-server /etc/redis/%i.conf
ExecStop=/usr/bin/redis-cli shutdown
ExecReload=/usr/bin/pkill -HUP ${MAINPID}
LimitNOFILE=10240
Restart=on-failure

[Install]
WantedBy=multi-user.target redis.target

启动服务:

   sudo systemctl daemon-reload
   sudo systemctl enable redis@discourse.service
   sudo systemctl start redis@discourse.service

优化 redis

redis 有以下几个需要优化的地方:

1. stop-writes-on-bgsave-error

这是造成 “MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk” 错误的源头,这个设置用意上是好的,后台保存不上的时候就不写入,这会很快吃光你的内存,让你不得不查。

后台保存不上绝大多数是暂时的,缓过来的时候自动覆盖硬盘上 redis 数据库里的内容就好了。这个选项的过激之处在于,有一点问题就会让你的 redis 完全用不了。建议改为 no。

2. somaxconn = 511 和 vm.overcommit_memory = 1

这两个 redis 包的维护者已经帮我们优化好了,但是要重启生效

立即生效:

   sudo sysctl net.core.somaxconn=512
   sudo sysctl vm.overcommit_memory=1

3. 关闭 Transparent Huge Pages (THP)

这个可以在 yast - bootloader - kernel parameters,在 showopts 后面加上 transparent_hugepage=never 来解决。

但同样是要重启生效。

立即生效:

   sudo echo never > /sys/kernel/mm/transparent_hugepage/enabled

安装 discourse

添加软件源:

   sudo zypper ar -f http://download.opensuse.org/repositories/home:/darix:/apps/openSUSE_Tumbleweed/ discourse

修改优先级

   sudo zypper mr -p 60 discourse

刷新:

   sudo zypper ref

安装 discourse:

   sudo zypper in discourse

配置 discourse

   cd /srv/www/vhosts/discourse/config
   cp -r discourse_defaults.conf discourse.conf
   sudo chown discourse:discourse discourse.conf

编辑 discourse.conf:

   db_host = localhost
   db_name = discourse
   db_username = discourse
   db_password = 之前你设置的 postgresql 密码
   host_name = 'discourse.suse.org.cn'
   smtp_address = smtp.gmail.com
   smtp_port = 587
   smtp_domain = gmail.com
   smtp_user_name = 你的
   smtp_password = 你的
   developer_emails = 你的

这里你可以用 QQ 邮箱,但是 QQ 邮箱使用 smtp 需要申请一个随机密码。gmail 在国内 VPS 上面无法访问。所以建议注册一个 mailgun 服务,每月免费一万封邮件。

初始化 discourse

   cd /srv/www/vhosts/discourse
   RAILS_ENV=production /usr/bin/bundler.ruby2.7 exec /usr/bin/rake.ruby2.7 db:migrate
   RAILS_ENV=production /usr/bin/bundler.ruby2.7 exec /usr/bin/rake.ruby2.7 assets:precompile

在 db:migrate 的过程中,可能提示你比如 thor 0.19 找不到之类的错误,你可以用:

   sudo zypper se -v ruby2.7-rubygem-thor

来查找 thor 的可用版本,一般来说是由于 tumbleweed 源里的 thor 比 discourse 源里的新,所以装上了比如 0.20 版本,可以降级:

   sudo zypper in --oldpackage ruby2.7-rubygem-thor-0.19.4-1.6.x86_64

在上面两步做完之后,你需要修正一下权限(因为你可能是使用 root 登录的 VPS):

   sudo chown -R discourse:discourse /srv/www/vhosts/discourse/public 
   sudo chown -R discourse:discourse /srv/www/vhosts/discourse/tmp

启动 discourse

我们先要修正一下 discourse 的 systemd 服务,一共有三个:

   /usr/lib/systemd/system/discourse-update.service
   /usr/lib/systemd/system/discourse-sidekiq.service
   /usr/lib/systemd/system/discourse-puma.service

把所有的 Environment 变量改成:

   Environment="RUBY_GC_MALLOC_LIMIT=4000100"
   Environment="RUBY_GC_MALLOC_LIMIT_MAX=16000100"
   Environment="RUBY_GC_MALLOC_GROWTH_FACTOR=1.1"
   Environment="RAILS_ENV=production"
   Environment="LANG=en_US.UTF-8"
   Environment="LC_ALL=en_US.UTF-8"
   #Environment="RUBY_GC_MALLOC_LIMIT=90000000" "LANG=en_US.UTF-8" "LC_ALL=en_US.UTF-8"

下面使用

   sudo systemctl enable discourse-sidekiq.service
   sudo systemctl start discourse-sidekiq.service

启动 sidekiq 服务。

然后:

   sudo systemctl enable discourse-puma.service
   sudo systemctl start discourse-puma.service

启动 puma 服务。

Nginx 相关设置

   sudo zypper in nginx

打开 /etc/nginx/nginx.conf 把里面的 server 部分注释掉。然后在 keepalive_timeout 65; 后面加上一行:

   server_names_hash_bucket_size 64;

保存。

建立 vhosts.d 文件夹

   sudo mkdir -p /etc/nginx/vhosts.d
   cd /etc/nginx/vhosts.d

把 /srv/www/vhosts/discourse/config/nginx.sample.conf 复制过来:

   cp -r /srv/www/vhosts/discourse/config/nginx.sample.conf /etc/nginx/vhosts.d/discourse.conf

编辑 discourse.conf,修改以下部分:

注释掉 upstream discourse thin 的部分,把 puma 的部分打开,因为我们用的是 puma。

server_name 改成你的,比如 discourse.suse.org.cn。

把 set $public 的部分改成正确的 /srv/www/vhosts/discourse/public。

保存。

启动 nginx:

   systemctl enable nginx.service
   systemctl start nginx.service

接着去你的 DNS parking 设置 discourse.suse.org.cn 指向这个 VPS 的外网 IP。

大功告成了!

安装插件

安装 git:

   sudo zypper in git

安装插件:

   systemctl stop discourse-puma
   systemctl stop discourse-sidekiq
   RAILS_ENV=production /usr/bin/bundler.ruby2.7 exec /usr/bin/rake.ruby2.7 plugin:install repo=https://github.com/openSUSE-zh/discourse-username-localization
   RAILS_ENV=production /usr/bin/bundler.ruby2.7 exec /usr/bin/rake.ruby2.7 db:migrate
   RAILS_ENV=production /usr/bin/bundler.ruby2.7 exec /usr/bin/rake.ruby2.7 assets:precompile
   systemctl stop discourse-sidekiq
   systemctl stop discourse-puma

升级插件

   systemctl stop discourse-puma
   systemctl stop discourse-sidekiq
   RAILS_ENV=production /usr/bin/bunlder.ruby2.7 exec /usr/bin/rake.ruby2.7 plugin:update plugin=[The name in /srv/www/vhosts/discourse/plugins]
   RAILS_ENV=production /usr/bin/bunlder.ruby2.7 exec /usr/bin/rake.ruby2.7 db:migrate
   RAILS_ENV=production /usr/bin/bunlder.ruby2.7 exec /usr/bin/rake.ruby2.7 assets:precompile
   systemctl start discourse-sidekiq
   systemctl start discourse-puma

升级 discourse

   systemctl stop discourse-puma
   systemctl stop discourse-sidekiq
   zypper up discourse
   RAILS_ENV=production /usr/bin/bundler.ruby2.7 exec /usr/bin/rake.ruby2.7 plugin:update_all
   RAILS_ENV=production /usr/bin/bundler.ruby2.7 exec /usr/bin/rake.ruby2.7 db:migrate
   RAILS_ENV=production /usr/bin/bundler.ruby2.7 exec /usr/bin/rake.ruby2.7 assets:precompile
   chown -R discourse:discourse public
   chown -R discourse:discourse tmp
   // 然后先去修正 discourse 的 systemd 服务
   systemctl start discourse-sidekiq
   systemctl start discourse-puma

其他问题

discourse 维护常看的 log

   /var/log/redis/discourse.log
   /srv/www/vhosts/discourse/log/production.log
   /srv/www/vhosts/discourse/log/sidekiq.log

提示找不到 optipng/jhead/jpegoptim/gifsicle/svgo/terser

optipng, jhead, gifsicle 和 jpegoptim 都在官方源里面。

svgo:

   cd ~
   npm install svgo
   ln -sf ~/node_modules/svgo/bin/svgo /usr/bin/svgo

uglifyjs:

   cd ~
   npm install terser
   ln -sf ~/node_modules/terser/bin/terser /usr/bin/terser
去掉了 uglifyjs 的相关表述。曾经 discourse 是调用 /usr/bin/uglifyjs 的,需要像 svgo 那么安装。后来和现在都使用了 uglifier 这个内置 uglifyjs 的 rubygem。但是 uglifyjs 已经失去维护了,而且不支持 es6。继任者是 terser。

提示找不到 GeoLite2-ASN.mmdb

https://dev.maxmind.com/geoip/geoip2/geolite2/ 下载,解压了放到 discourse 的 vendor/data 下面Maxmind 公司现在不允许不使用 license key 直接下载 GeoLite2-City.mmdb。/usr/sbin/discourse-update 里定义了使用 rake task 下载的方式。您也可以手动运行下载:

 sudo /usr/bin/bundler.ruby2.7 exec /usr/bin/rake.ruby2.7 maxminddb:get
 chown root:discourse vendor/data/*.mmdb
 chmod u=rw,g=r,o=    vendor/data/*.mmdb

postgresql 跨大版本升级

在升级完系统后,最好检查一下 postgresql 是否有跨大版本升级:

   sudo zypper se -i postgresql

如果是跨大版本升级的话,我们需要升级 pg 数据库。这里使用 pg_upgrade 进行升级。你也可以使用 pg_dumpall 把数据库导出再重新导入到新版本 pg 里来升级,但是不要在网上找 pg_cluster 这些 Debian 专有的命令来做。 首先要以 postgres 用户登录:

   su
   输入 root 口令
   su - postgres 

第一必须要先切换为 root,因为直接 su - postgres 会提示你输入密码,而 postgres 用户是没有设置密码的。第二登录的用户名是拥有 /var/lib/pgsql/data 这个文件夹的用户,不可以为了将就当前用户(pg 不可以用 root)而去 chown -R 777 /var/lib/pgsql/data。因为 pg 对文件夹权限要求很严格,而且文件夹的所有者同时也是数据库的所有者,单纯的修改文件权限是没用的。 登录后会发现 HOME 自动切换到了 /var/lib/pgsql。我们需要先停掉新老版本的 postgresql:

   sudo systemctl stop postgresql 
   ps -A | grep postgres
   sudo killall postgres

然后备份 data 文件夹:

   sudo mv data data.old 
   mkdir data 

注意 openSUSE 是不会在你跨大版本升级 pg 的时候自动为你迁移数据库的,这个 data 里面依然是老版本数据库,data/PG_VERSIO N 里依然是 13。你也不会因为删除了 postgresql13-server 就丢失数据库。 用新版本的 pg 初始化新的 data:

   /usr/lib/postgresql14/bin/initdb 

然后开始真正的迁移:

   /usr/lib/postgresql14/bin/pg_upgrade -b /usr/lib/postgresql13/bin -B /usr/lib/postgresql14/bin -d data.old -D data 

会生成一堆 pg_upgrade_*.log,如果出错了去看 pg_upgrade_server.log。如果成功了会出现两个 shell script 需要运行: 先启动新版本的 pg:

   /usr/lib/postgresql14/bin/pg_ctl -D data -l pg_ctl.log start 

运行脚本:

   ./analyze_new_cluster.sh
   ./remove_old_cluster.sh

有的时候会提示生成了一个更新 extensions 的 sql,可以这么运行:

   psql -f ./update_extensions.sql

然后再停止新的 pg:

   sudo killall postgres

大功告成!现在你就可以使用 sudo systemctl start postgresql 来启动新版本的 pg 啦。

插件由于依赖的 gem 下载失败而安装失败

这是由于 openSUSE 的 yast2 依赖的 ruby 版本已经到了 3.1,导致系统上同时有 ruby2.7 和 ruby3.1。而安装或升级插件里面有一条命令是这样的:

   gem install auto-correct -v 0.3.1 -i /srv/www/vhosts/discourse/plugins/discourse-cjk-text-spacing/gems/2.7.5 —-no-document —-ignore-dependencies —-no-user-install

这里面的 gem 命令没有指定版本,变成:

   /usr/bin/gem.ruby2.7 install auto-correct -v 0.3.1 -i /srv/www/vhosts/discourse/plugins/discourse-cjk-text-spacing/gems/2.7.5 —-no-document —-ignore-dependencies —-no-user-install

就可以了。手动安装了 gem 再去安装升级插件就可以了。

precompile assets 由于 rubygem uglifier 无法处理某个 js 文件失败

是由于没有安装 terser。只能退而求其次用 uglifyjs 处理所有 javascript assets,而 uglifyjs 不支持 es6。discourse 嘛,它的绝大部分 javascript 都是 es6 标准的。