在我的公司,我们目前有一个主要项目,这是一个大型的单片 Rails 应用程序。部署很容易,我们有几个前端服务器(使用 Puppet 设置),Capistrano 会将其部署到其中/var/www/<hostname>/current
。然后它重新启动 Unicorn(零停机部署!),每个人都很开心。
不幸的是,存在一个问题。应用程序的单片特性开始困扰我们。现在运行所有测试需要 30 多分钟,这减慢了我们的速度。我们希望将其拆分成更小的块并采用更多的 μService 架构。然而,这让我思考我们的部署策略。目前的情况是:
- Rails 应用程序和 Nginx 以
www-data
用户身份运行 - 任何有权访问该框的用户都可以部署(在 Capistrano 中,我们
chown
在部署期间将内容发送给应用程序用户)
这样做的安全性相当低(所有东西都以同一个用户身份运行,每个人都可以访问所有东西)。这也让我想起了我们在之前的公司是如何做的——这是一场噩梦,因为所有应用程序都停留在 Ruby 1.6 上,因为它们共享同一个版本。
我认为我们可以通过安装来改善这一点rbenv
允许每个应用程序运行自己的 Ruby 版本,并让每个应用程序都有用户来提高安全性,从而改善这一点。但我还没有真正看到过任何实际的例子。例如37signals 以同一用户身份运行所有应用程序- 我担心为什么应用程序不应该以不同的用户身份运行。
总结一下:
- 在 μService 风格架构中将多个 Rails 应用程序部署到服务器的最佳方法是什么?
- 隔离每个应用程序的最佳方法是什么(就 Ruby 版本和用户安全而言)?
提前致谢!
答案1
我们有一个类似的配置(尽管我们使用的是 Tomcat 和 Grails,而不是 nginx 和 RoR)。我们为每个 Tomcat 实例设置了单独的用户 ID。我们将用户的 .profile 中的 Java、Grails 和任何其他依赖库的主目录设置为环境变量,因此每个 Tomcat 都可以使用我们安装的任何版本运行。
我们的自动部署软件(Atlassian Bamboo)的 userid 用户是分配给每个 Tomcat 目录的组的成员。
答案2
对于多个 Ruby 实例,我绝对推荐RVM (Ruby 环境管理器)。我发现它比 rbenv 更适合生产环境。
Nginx 仅当以特权用户身份启动时才可以绑定特权端口 (<= 1024)。因此,可能需要反向代理配置来满足您的需求,即由允许的用户将每个 Unicorn 实例作为单独的进程启动。
如果你对在单独的虚拟机上运行每个应用程序的评估是确定的,那么在 GNU/Linux 上隔离每个应用程序的方法是SELinux。SELinux 相当复杂,但提供了允许您安全地分离进程和上下文的功能。