部署 无缝部署 (0 down time deploy) 的正确姿势是什么?大家是怎么部署新 Rails 代码上线的?

1c7 · 2018年07月03日 · 最后由 lyfi2003 回复于 2018年08月06日 · 1829 次阅读

0. 环境

Puma + Mina + Rails 5.2 + Ubuntu 16.04

1. 期望

部署新代码期间网站依然可用,而不是卡 10-30 秒
发帖子前我谷歌查了半天依然搞不定,想看看大家的做法。
目前服务器我用的是 Puma。phased_restart 已经配置了
用了 mina-puma gem:https://github.com/untitledkingdom/mina-puma

mina puma:phased_restart

跑如上命令也毫无问题。结果如下图:

2. 实际结果

phased_restart 期间,网站有10秒-30秒不响应

3. 问题

大家是怎么做无缝部署的?(0 downtime deploy)
如果有人用 puma 实现过无缝部署,能分享下经验吗?

4. 贴 2 个文件

  1. config/deploy.rb(Mina)
  2. config/puma.rb(Puma 配置文件)

config/deploy.rb

require 'mina/rails'
require 'mina/git'
require 'mina/rvm'    # for rvm support. (https://rvm.io)
require 'mina/puma'  # https://github.com/untitledkingdom/mina-puma

set :application_name, '因隐私原因删除掉原有值'
set :domain, '因隐私原因删除掉原有值'
set :deploy_to, '因隐私原因删除掉原有值'
set :repository, '因隐私原因删除掉原有值'
set :branch, 'master'

set :user, 'ubuntu'          # Username in the server to SSH to.
set :port, '22'           # SSH port number.
set :forward_agent, true     # SSH forward_agent.

# For mina-puma
set :pumactl_socket, '/tmp/witt.sock'
set :puma_state, "/var/www/witticism.com/shared/tmp/sockets/puma.state"
set :puma_pid, "/var/www/witticism.com/shared/tmp/pids/puma.pid"

task :remote_environment do
  invoke :'rvm:use', 'ruby-2.4.1@default'
end

desc "Deploys the current version to the server."
task :deploy do
  deploy do
    invoke :'git:clone'
    invoke :'deploy:link_shared_paths'
    invoke :'bundle:install'
    invoke :'rails:db_migrate'
    invoke :'deploy:cleanup'

    on :launch do
      in_path(fetch(:current_path)) do
        command %{mkdir -p tmp/}
        command %{touch tmp/restart.txt}
      end
    end
  end
end

config/puma.rb

bind "unix:///tmp/witt.sock"

threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
threads threads_count, threads_count
environment ENV.fetch("RAILS_ENV") { "production" }

app_name = "witticism.com"
app_dir = File.expand_path("../..", __FILE__)
app_dir_parent = File.expand_path("../../", __FILE__)
application_path = "#{app_dir}"

pidfile "/var/www/witticism.com/shared/tmp/pids/puma.pid"
state_path "/var/www/witticism.com/shared/tmp/sockets/puma.state"

workers ENV.fetch("WEB_CONCURRENCY") { 2 }

before_fork do
  ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
end

on_worker_boot do
  ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
end
共收到 19 条回复

与此同时我也会继续查谷歌,如果有结果了会回来说

ny 回复

感谢回复,现在去看

swarm mode rolling update

如果你有多台机子,分批部署😂

有一个大胆的想法:

假设原来puma在3000端口运行

nginx负载均衡:3000和3001端口

然后deploy到3001端口,成功后,然后kill 3000端口的puma,kill -9 $(lsof -i:#{3000} -t)

同理,下次检测到3001端口被占用,则先部署到3000端口,然后kill -9 $(lsof -i:#{3001} -t)

从部署日志上看,你发送的是TERM信号,让进程先全部挂了,然后才重新启动。在进程挂掉到新的进程启动完成的过程中,你的服务肯定会有中断的。 给进程发送USR2信号,puma本身是支持平滑重启的,https://github.com/puma/puma/blob/master/docs/signals.md

多谢各位~~(我有别的事情就把这茬忘了,隔了一天才回来看到各位的回帖,非常感谢) 这些我都看看细节去,最后有结果了回来说~

tinyfeng 回复

ruby china的docker部署好像就是这么做的

dokku 可以 0 down check,成功后再切换proxy

建议你先好好读一下官方(比较权威)的文档说明和源代码里关键配置,不容易理解的地方,再 Google 进行补充。

puma 配置示例
mina-puma README
mina-puma tasks

你上面贴的配置,有的非常不合适,配置了还不如不配置(使用默认);
还有一些是错误配置。

leekelby 回复

好~ 谢谢

2018-8-3 更新进展

我碰到了什么问题

当初之所以问这个问题,是因为在 mina deploy --verbose 部署成功后用 mina puma:phased_restart 重启服务器 (我用了 mina gem + mina-puma gem)

然后(重点来了)服务器上 puma 会占用 100% CPU 持续2-8分钟才更新成功。
(我用 htop 命令看的)

我有两台机子,都在 UCloud ,都是 CPU 2核,内存4G。
在机器A(测试环境)上完全没问题。phased_restart 只需3秒。一切工作完美。
在机器B(生产环境)上,不论我怎么查谷歌来试图跟踪问题,就是搞不定(具体细节可参考末尾给出的链接)
最后决定不折腾这个问题了

我是怎么解决的

最后用 nginx load balancer 来指向 2 个 puma 里其中一个,每次要更新了就更新另一个,然后指向那个新的。
这样来回交替。
我写了篇博客:http://1c7.me/2018-8-3-solve-rubyonrails-puma-server-phased-restart-100percent-cpu-problem/
和 Github Issue:https://github.com/puma/puma/issues/1627

希望这篇回复能帮助以后遇到同样问题的人。

leekelby 回复

宽哥 其实配置两个进程 依次 Restart 就好了

1c7 回复

puma 启动时 100% cpu 的问题, 检查一下 bootsnap , 这个会有影响.

lyfi2003 回复

感谢新思路。但不知道具体怎么"检查"。Gemfile 里的确用到了 bootsnap。官方 README 也大概看了下。没有特别提到什么要注意的。

1c7 回复

先移掉, 再试试是否加快了.

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册