Rails 旧项目的 Rails、Puma、Sidekiq 升级

clousky2020 · 2020年12月22日 · 最后由 xinyuewaisong 回复于 2021年01月02日 · 1139 次阅读

背景

有需求要使用新版本的 rails、puma、sidekiq,今天对升级做一下基础测试。

还有多个使用 systemd 启动的 puma 做一下部署测试,看一下部署过程中会不会产生干扰。

旧项目的 rails、puma、sidekiq 升级

拿了我自己刚开始学习的时候的一个微信的项目做测试,是用 rails5.1,PUMA3.7、sidekiq5.2.9 的。

参考资料

从其他 ruby 使用者听说:只要没有用到 Active Storage,直接可以直接改版本号升级。加上有 git 保底,所以直接在 gemfile 里改了版本号

- gem 'rails', '~> 5.1.6'
+ gem 'rails', '~> 6.1'

- gem 'sidekiq'
+ gem 'sidekiq', '~>6'

- gem 'puma', '~> 3.7'
+ gem 'puma', '~> 5.1'

输入bundle update

结束后 IDE 提示再bundle install一下

然后本地rails s,打开页面能看且正常操作。但这个项目主要还是微信公众号的回复,这其中也涉及到 sidekiq 的使用,所以还得部署到服务器上测试下。

使用的是 capistrano+passenger 的部署方式,所以后续也不用处理项目重启之类的操作,在把代码提交到 git 后直接输入

cap production deploy

等待部署完成。

但之后发现服务器里项目启动不了,之后查询日志,

[ E 2020-12-20 21:37:32.5919 22106/T6z age/Cor/App/Implementation.cpp:221 ]: Could not spawn process for application /home/ruby/weixin/current: The application encountered the following error: Couldn't find Active Storage configuration in /home/ruby/weixin/releases/20201220132931/config/storage.yml (RuntimeError)

说是找不到 config/storage.yml 文件,经人帮助,在 config 里新建了 storage.yml 文件,里面的内容:

test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

rails5.1 的时候还没有这个文件,update 后也没有生成,所以报错了。之后顺利启动。

微信进入公众号,输入文字内容,自动图文回复正常,但计算结果图文回复就出错了,进入 sidekiq 的仪表盘查看错误内容,发现是程序去找以前的 releases 里的素材了,但经过多次部署后已经删除了,所以出错。不过起码证明了 sidekiq 的运行正常。不过后面我手动 kill sidekiq 进程后就不能启动,查看日志发现对 redis 的版本号有了要求,要 redis4.0 及以上,而现在服务器里 redis 的版本是 3.0.6,那就升级吧。

参考升级到了 6.0.5.

之后在使用redis-server redis.conf启动了 redis,

sudo systemctl start sidekiq.service启动 sidekiq,

进入 sidekiq 的仪表盘发现队列信息全部都被清空了,应该是重装 redis 的过程中把过去的信息删除掉了。幸好是个人项目而且没什么重要的需要持久化的信息在里面。之后程序的自动图文回复和问题回复都能正常使用了。

查看由 systemd 启动的两个 puma 会不会相互影响

新建了项目 demo1 和 demo2,用mina deploy放到服务器上用 systemd 启动, 进入/etc/systemd/system目录,新建puma-demo1.servicepuma-demo2.service这两个文件,主要内容如下:

[Unit]
Description=Puma HTTP Server
After=network.target

[Service]
Type=simple
User=ruby
WorkingDirectory=/home/ruby/demo1/current
Environment=RAILS_ENV=production
ExecStart=/home/ruby/.rbenv/bin/rbenv exec bundle exec puma -C /home/ruby/demo1/current/config/puma.rb
ExecStop=/home/ruby/.rbenv/bin/rbenv exec bundle exec pumactl -F /home/ruby/demo1/current/config/puma.rb stop
ExecReload=/home/ruby/.rbenv/bin/rbenv exec bundle exec puma -F /home/ruby/demo1/current/config/puma.rb phased-restart
TimeoutSec=15

Restart=always

RestartSec=5
KillMode=process

[Install]
WantedBy=multi-user.target

其中ExecStart表示启动命令,正常我们在服务器上可能就是bundle exec puma就启动了,但这是因为已经配好了系统环境,这里我们要把使用的命令完整的写上去。

前半段/home/ruby/.rbenv/bin/rbenv exec bundle exec puma表示使用rbenv的路径名里的rbenv启动 puma,后面增加一个-C /home/ruby/demo1/current/config/puma.rb表示要使用这个路径下的配置文件puma.rb。这里使用了默认安装时自带的puma.rb文件,我在生产环境的话会用/home/[user_name]/[project_name]/shared/puma.rb代替,然后上述目录下新建一个puma.rb配置文件。

#更换了ExecStart的启动路径
ExecStart=/home/ruby/.rbenv/bin/rbenv exec bundle exec puma -C /home/ruby/demo1/shared/puma.rb
#新建/home/ruby/demo1/shared/puma.rb文件

#!/usr/bin/env puma
#运行目录
directory '/home/ruby/demo1/current'
rackup "/home/ruby/demo1/current/config.ru"
#运行环境
environment 'production'
tag ''
#生成.pid文件位置
pidfile "/home/ruby/demo1/shared/tmp/pids/puma.pid"
#存放相关信息的文件路径
state_path "/home/ruby/demo1/shared/tmp/pids/puma.state"
stdout_redirect '/home/ruby/demo1/current/log/puma.access.log', '/home/ruby/demo1/current/log/puma.error.log', true
threads 4,16
bind 'unix:///home/ruby/demo1/shared/tmp/sockets/myblog-puma.sock'
workers 0
restart_command 'bundle exec puma'
preload_app!
on_restart do
  puts 'Refreshing Gemfile'
  ENV["BUNDLE_GEMFILE"] = ""
end
before_fork do
  ActiveRecord::Base.connection_pool.disconnect!
end
on_worker_boot do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Base.establish_connection
  end
end

以上准备好后可以用 systemd 启动了,执行

sudo systemctl daemon-reload

sudo systemctl start puma-demo1.service

sudo systemctl start puma-demo2.service

启动完毕后使用指令ps aux|grep puma查询运行情况,

ruby     25056  0.8  5.1 900620 101744 ?       Ssl  15:09   0:00 puma 5.1.1 (tcp://0.0.0.0:3001) [1]
ruby     25686 43.5  4.9 824772 96368 ?        Ssl  15:10   0:00 puma 5.1.1 (tcp://0.0.0.0:3000) [2]
ruby     26000  0.0  0.0  14428  1032 pts/0    S+   15:10   0:00 grep --color=auto puma

接着在本地计算机使用mina deploy然后重新部署了一下 demo1,因为我在 mina 中没有配置部署后重启的脚本,所以 mina deploy 后进程号没变。

然后在服务器上重启了 demo1 服务sudo systemctl restart puma-demo1.service

ruby     25056  0.4  5.1 900620 101744 ?       Ssl  15:09   0:00 puma 5.1.1 (tcp://0.0.0.0:3001) [1]
ruby     26313 44.0  4.9 824776 96216 ?        Ssl  15:12   0:00 puma 5.1.1 (tcp://0.0.0.0:3000) [2]
ruby     26626  0.0  0.0  14428  1156 pts/0    S+   15:12   0:00 grep --color=auto puma

demo1 的进程变了,demo2 的进程没变,这说明 systemd 里不同进程也是相互隔离的,互不影响。

使用 mina 启动 sidekiq 并测试多个 sidekiq 进程相互间是否有影响

完成 mina 的配置

首先碰到的问题是 mina-sidekiq 的 gem 不能自动更新到支持 sidekiq>6.0 内容,虽然 git 上的文档说是支持的,但实际上 bundle install 后,mina tasks 里并没有适配 sidekiq6 的 install 的任务。后来发现 mina-sidekiq 的作者已经不维护这个项目了,support sidekiq6 的代码是别人提交过来的,也不知道是哪里没设置好,新的内容不能通过 bundle 直接更新。

既然自动更新不行,那我们就自己改。mina-sidekiq 新的内容主要就改了两个文件,一个说明 MD,这个对于我们使用者来说不重要,可以忽略。

还有一个主要改动的文件是lib/mina_sidekiq/tasks.rb,这里新增加了对 sidekiq6 的支持,所以我们在本地找到这个文件,我本地是用 rvm 管理的,所以我的文件是在/Users/mac/.rvm/gems/ruby-2.7.1/gems/mina-sidekiq-1.0.3/lib/mina_sidekiq/tasks.rb,复制官方内容覆盖到这个文件里,这样我们就算是手动更新了~

然后在/config/deploy.rb里添加以下内容

set :init_system, :systemd  #做标示,让mina-sidekiq脚本执行systemd的指令
set :service_unit_path, '/home/ruby/.config/systemd/user'  #脚本默认的存放位置需要root权限,改成用户下面的.config文件
set :bundler_path, '/home/ruby/.rbenv/shims/bundler'  #我的服务器上用rbenv,改成这个地址,脚本默认地址里没有我安装的rbenv

关于官方文档里写的给 linux 添加loginctl enable-linger username指令,我试了下,加或不加都不影响后续操作,我就不加了。

接下来就按照官方文档本地项目启用

mina sidekiq:install

会显示已经在设定的位置 Creating systemctl unit file,之后启动

mina sidekiq:start

我们登上服务器看一下:

ruby@iZbp130:~$ ps aux|grep sidekiq
ruby     26286 10.0  4.6 820520 91000 ?        Ssl  10:13   0:01 sidekiq 6.1.2 demo1 [0 of 10 busy]
ruby     26615  0.0  0.0  14428  1016 pts/0    S+   10:13   0:00 grep --color=auto sidekiq

可以看到 sidekiq 已经启动,关闭也和原来一样使用mina sidekiq:stop

测试两个 sidekiq 进程会不会相互影响

接下来要把 demo2 的 sidekiq 也启动,但需要先在/config/deploy.rb里增加一行

set :service_unit_name, "sidekiq-2-#{fetch(:rails_env)}.service" #自定义服务文件名称

因为两个项目都是在同一个用户下且.service 文件是放在相同的目录里,所以文件名要不同,这里我在 sidekiq 后面加了个 -2 作为区分。

然后启动两个项目的 sidekiq,mina sidekiq:start,在服务器上查看一下:

ruby@iZbp130:~$ ps aux|grep sidekiq
ruby       532  0.3  5.2 824972 103196 ?       Ssl  10:31   0:01 sidekiq 6.1.2 demo1 [0 of 10 busy]
ruby      2097 13.5  5.0 900332 99120 ?        Ssl  10:37   0:01 sidekiq 6.1.2 demo1 [0 of 10 busy]
ruby      2418  0.0  0.0  14428  1084 pts/0    S+   10:37   0:00 grep --color=auto sidekiq

可能是因为我的 demo2 是复制 demo1 的,里面 sidekiq 的配置没改动过,这里两条进程信息都写着 demo1,实际上后面这条 2097 的应该属于 demo2。现在我们本地发指令关掉 demo2 试试,

demo2 mac$ mina sidekiq:stop

服务器上查看:

ruby@iZbp130bctfwzkh4bsns7iZ:~$ ps aux|grep sidekiq
ruby       532  0.2  5.5 826988 109532 ?       Ssl  10:31   0:01 sidekiq 6.1.2 demo1 [0 of 10 busy]
ruby      2757  0.0  0.0  14428  1008 pts/0    S+   10:42   0:00 grep --color=auto sidekiq

很好,后面属于 demo2 的 sidekiq 已经没了,而 demo1 的 sidekiq 进程还存在且没有变动过,说明两者互不干扰,这就达成今天的测试目标了。

使用 mina-systemd

在他人的帮助下,找到了另一种方法,就是使用mina-systemd(修改版)

这是 mina 的 systemd 服务管理器的封装,上面的 puma 还没有达到本地启停,正好就用这个远程启动。

但要注意的是 mina-systemd 的原作者也是很久没更新了,所以这里我们要安装修改版的内容,Gemfile 里要写:

gem 'mina-systemd', require: false, git: 'https://github.com/leebo/mina-systemd.git'

如果是安装原作者的版本,会出现和现在mina 1.2.3版本不适配的情况,要降到mina 1.0.7才行,而这个版本在mina deploy的时候又会出错,所以还是使用别人修改好的版本吧。

前面已经在服务器上创建了 PUMA 的 service 文件

puma-demo1.service

接下来登录服务器,输入

sudo vim /etc/sudoers

在其中添加以下内容:

ruby   ALL=NOPASSWD: /bin/systemctl status puma-demo1
ruby   ALL=NOPASSWD: /bin/systemctl start puma-demo1
ruby   ALL=NOPASSWD: /bin/systemctl stop puma-demo1
ruby   ALL=NOPASSWD: /bin/systemctl restart puma-demo1

最前面是操作的用户名,后面是每次操作的指令和操作的 service 名字,这样让本地的指令直接无密码操作。如果没加这条直接去操作的话,就卡住了。

在/config/deploy.rb 里添加

require 'mina/systemd'

现在可以在本地终端里输入

mina systemctl:start['puma-demo1']

服务器上ps aux|grep puma查看:

ruby     12737  5.1  5.2 900328 101812 ?       Ssl  20:36   0:00 puma 5.1.1 (tcp://0.0.0.0:3000) [1]
ruby     13068  0.0  0.0  14428  1068 pts/0    S+   20:36   0:00 grep --color=auto puma

确实的启动了,再关闭它,

mina systemctl:stop['puma-demo1']

服务器上ps aux|grep puma查看:

ruby     13415  0.0  0.0  14428  1052 pts/0    S+   20:36   0:00 grep --color=auto puma

这当中主要的内容就是要在 sudoers 文件里添加免密指令,今天折腾了一天部署脚本后来就是卡在登录的问题上了。

sidekiq 也能用这个方式去启停,这里就不演示了。这样 mina-puma 和 mina-sidekiq 这两个 gem 也算是完成了自己的使命,可以退休了。

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号