有需求要使用新版本的 rails、puma、sidekiq,今天对升级做一下基础测试。
还有多个使用 systemd 启动的 puma 做一下部署测试,看一下部署过程中会不会产生干扰。
拿了我自己刚开始学习的时候的一个微信的项目做测试,是用 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 的过程中把过去的信息删除掉了。幸好是个人项目而且没什么重要的需要持久化的信息在里面。之后程序的自动图文回复和问题回复都能正常使用了。
新建了项目 demo1 和 demo2,用mina deploy
放到服务器上用 systemd 启动,
进入/etc/systemd/system
目录,新建puma-demo1.service
和puma-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 的 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
接下来要把 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 服务管理器的封装,上面的 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 也算是完成了自己的使命,可以退休了。