分享 [折腾向] 使用 systemd 来管理你的 Rails 应用

a-wing · 2018年09月11日 · 最后由 ericguo 回复于 2020年12月03日 · 4337 次阅读

原文地址: https://a-wing.top/ruby/2018/09/10/systemd_rails.html

这篇文章属于没什么卵用系列

我并不喜欢 capistrano

众所周知 rails 的项目启动用 RAILS_ENV=production bundle exec rails server -p 3000 -d

如果服务器经常重启。。最简单的办法:那我们就要把这条命令放在 /etc/rc.local 里 (目前 deb 系的发行版是保留的。本质上是用 systemd 来执行这里的命令)。。。

不过目前。大部分 Linux Distribution 都是 systemd 来启动的(gentoo 除外。gentoo 默认是 openrc,可以换成 systemd)

在改之前。我们先把 rails 监听的端口换成 unix sock

sed -i 's#port        ENV.fetch("PORT") { 3000 }#bind        "unix://\#{Rails.root}/tmp/sockets/puma.sock"#g' config/puma.rb

例如我的项目叫 kiss2u 大概是这样:

$ cat ~/.config/systemd/user/kiss2u.service
[Unit]
Description=KISS2U Puma application server
After=network.target

[Service]
WorkingDirectory=/home/a-wing/.srv/KISS2U
PIDFile=/home/a-wing/.srv/KISS2U/tmp/pids/puma.pid
ExecStart=/usr/bin/sh /home/a-wing/.srv/KISS2U/run.sh

[Install]
WantedBy=default.target

没错。这个是用户级 systemd

但由于 systemd 要写绝对路径。。但我可不想手动改 QAQ

然后我们定义一个 template,就像这样。定义几个标签

$ cat config/kiss2u.service.template
[Unit]
Description=KISS2U Puma application server
After=network.target

[Service]
WorkingDirectory=<DIR>
Environment=RAILS_ENV=production
PIDFile=<DIR>/tmp/pids/puma.pid
ExecStart=<BUNDLE> exec rails server

[Install]
WantedBy=default.target

在 bin 目录下创建生成真正的 systemd 的配置文件 bin/generate_service.sh

当然我们是要新建一个用户来跑的。不然 generate_service.sh 就没意义了

#!/bin/bash

SYSTEMD=kiss2u.service

cp config/${SYSTEMD}.template ${SYSTEMD}
sed -i s#\<DIR\>#`pwd`#g ${SYSTEMD}
sed -i s#\<BUNDLE\>#`which bundle`#g ${SYSTEMD}


echo "Install ~/.config/systemd/user/${SYSTEMD}"
echo "Please Run: systemctl --user start ${SYSTEMD}"

install ${SYSTEMD} -D ~/.config/systemd/user/${SYSTEMD}
rm ${SYSTEMD}

然后来使用 systemctl --user start kiss2u 就可以启动了

要开机启动的话 systemctl --user enable kiss2u 就可以

不过。这么做仍然有问题

我在 rbenv 下测试是好使的。。。在有些环境下就会出现启动不了的情况。我也不知道是为什么啊 QAQ

如果你启动出问题请更改 ExecStart=

解决办法:兼容性最好ExecStart= 来启动一段 shell 脚本。在 shell 脚本里加载必要的变量

source ./config.sh

echo RAILS_ENV=${RAILS_ENV}
ruby -v

if test -e tmp/pids/server.pid
then
  echo 'Restarting'
  kill `cat tmp/pids/server.pid`
else
  echo 'Starting'
fi

bundle install --path vendor/bundle
bundle exec rake db:migrate
bundle exec rails server -p ${PORT} -d

类似这样。。。好吧。我承认这很不优雅。。。不过兼容性最好。。

对了 kiss2u 是开源项目,你可以直接去看源代码 <-----自买自夸

https://github.com/a-wing/KISS2U

参考文章:

Foreman 可以直接导出 Systemd 配置文件

我用 cap 部署,systemd 监视进程。

我还是喜欢用 god

matrixbirds 回复

god 好多问题,monit 比较省心

cap 问题挺多的…… 直接 scp + ssh 部署也不用写很多代码,而且完全可控,不像 cap 那样想做点什么事情都得把源码挖出来改。

Procfile + Foreman 可以简化部署的命令。另外 Procfile 用 Overmind 而不是 Foreman 启动,能保留 stdin 方便 debug。

monit 功能比 god 更全面点,个人投 monit 一票。

打包 Docker 发布,不需要搞这么多事情了

我想问一下要是修改了 ~/.bashrc 之类的配置文件里面的值的话,用 cap 来重启 Rails 项目貌似不会读取修改后的值啊

coderliu 回复

还有这种东西.jpg

Rei 回复

求安利 capistrano 的优点

ywjno 回复

capistrano 不太会玩。。。。应该是调用 bin/rails 来热重启的吧。。。不更新也是有可能的

a-wing 回复

创建目录、链接文件、运行迁移、重启进程,这些工作总要有工具做啊。

cap 就是个远程执行工具。

我上周刚好写了几行代码,用来部署一个 java 项目,这几行代码让我很开心,因为我再也不用打开 jekins 了,也省了 ssh 到主机 tail log 的麻烦。

docker,自动重启。

说 docker 的说说用什么编排工具啊,总不能一台台上去操作吧。

ywjno 回复

https://github.com/rbenv/rbenv/wiki/unix-shell-initialization 你的问题的答案在这里

我用了 dot-env 避免了这个问题,还有一个好处是可以更好的隔离同一服务器上多个项目的环境变量

学习了很多平时没用到的方法和思路,谢谢楼主。

我自己项目是用 systemd+unicorn。

[Unit]
Description=XXX unicorn server

[Service]
Type=simple
SyslogIdentifier=xxx
WorkingDirectory=/var/www/xxx/
Environment=RAILS_ENV=production
Environment=WEB_CONCURRENCY=1
ExecStart=/usr/local/bin/bundle exec /usr/local/bin/unicorn -c config/unicorn.rb

[Install]
WantedBy=multi-user.target

(不要吐槽为什么用 Unicorn……因为是个有点年头的项目了)

msg7086 回复

我觉得还可以优化一下。。。

[Unit]
Description=Unicorn application server
After=network.target

Service 可以去指定 pid 文件。。。

系统级 systemd,不把他限制在 nobody 用户(或新建用户)下跑?

虽然这种改动没任何性能上的提升 😂

a-wing 回复

嗯。

这台机器只拿来跑这一个东西,somebody 或者 nobody 其实没太大区别。而且 unicorn 配置文件里我其实给 worker 切了用户了,并不是用 root 全程跑的。

swarm mode 小规模挺好用的,100 个左右的容器实例

不用 docker 的话就 mina + god

a-wing 为什么不应该使用 rvm/rbenv,以及替代方案 提及了此话题。 10月29日 10:06

Capistrano 和 systemd 并不冲突,现在看来 Docker 和 capistrano 各有所长,小项目快发布,还是 capistrano 好。

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