Rails 容器化,你并不需要三个模式 (环境)

nouse · 2017年03月15日 · 最后由 killernova 回复于 2017年03月24日 · 6195 次阅读

最近看到很多文章,很多人在容器里跑 rails 的时候仍然使用开发模式。

我这里要提醒一下,在这样做的时候你是否想过为什么要三个模式(环境)?

区分模式的优势:

  • 开发模式自动 reload 代码,但是偶尔仍然需要手动 reload
  • 某些模式多加载一些 gem,比如 debugger 在开发环境,rspec 在测试环境,或者 unicorn 在生产模式
  • 使用不同的数据库配置,比如测试环境会每次测试完成清理数据库,生产环境也不推荐随便 migrate

既然在用了容器,就应该发挥容器的优势,尽量用环境变量而不是模式来区分系统不同的行为,这里也想听听大家的意见。

同意

不过话说,环境和 docker 是两个不同的概念,用 docker 来区分环境还是有环境。

我不认为在业务代码中根据环境的不同来执行不同的逻辑是一个好的实践。这个只能偶尔用用,并且需要被当做技术债务在将来清理掉。

2 楼 已删除

模式区分是非常棒的一种实践,为啥要去掉?用环境变量指定模式不就行了。

vincent 回复

你这个结论下的太草率了,到底棒在哪里呢?

首先环境区分是有意义的,除了你上面提到的点还有更多,比如支付区分沙盒环境和生产环境等等,不区分会一团糟。

如果这些配置很多,全部通过环境变量传递和使用是一个很大的负担,麻烦而且容易出错,不如和代码放在一起,还可以有完整的版本控制。

不过,的确有一些敏感信息(如密码)基于安全考虑不适合放配置文件里,这种配置可以用环境变量。

没必要为了 docker 削足适履,这是我的看法。

标题先加上在容器里面,避免先入为主的误解

huacnlee 回复

谢谢建议

光自动 reload 代码这一个优势就够了

我没搞过容器里面开发啊,环境变量能统一一次切换?


但我认为分环境是为了让某些非配置化的实现能让环境区分来处理,例如:

if Rails.env.development?
   do_some_thing_just_only_need_in_development
end

以及统一配置化,所有的配置都写好了,在多人开发的时候谁来下来,配置都是相同的,要切换环境,仅需要一个点(RAILS_ENV=xxx) 就能搞定。

huacnlee 回复

容器开发可以用 docker-compose 里面的 envfile 来切换,https://docs.docker.com/compose/environment-variables/#setting-environment-variables-in-containers 不过在 docker-compose 启动的时候不能指定 envfile

分环境容易带来的问题是环境承载了太多东西,比如开发模式下可能会指定不同的数据库,不同的支付网关,而这些原本用环境变量就可以解决。

nouse 回复

配置好了以后,是不是开发的时候直接用线上的镜像,然后改一个环境变量就直接开始开发?

便利带来了可能的风险,因为无法杜绝大家有手误清空线上 DB 的 case;也可以暴露敏感信息。安全大于便利。

正确的方法应该是 docker-compose 也做成三个环境,可以分别使用 git 分支管理,生产环境部署就切换到 docker 的生产环境配置

Rails 包括其他框架的环境是起到 配置分组 的作用,从高层一点来理解,环境是按 使用场景 来分组的,毕竟每个场景所使用的配置项都差不多,指定一个环境名比设置多个环境变量更方便。

少数情况下会出现同类型的使用场景需要不同的配置项,最典型的是数据库等外部服务的配置。这个时候把少数配置抽成环境变量更加灵活。

我们现在都是在容器中跑 Rails,依然是用 RAILS_ENV 环境变量来指定运行环境。

daqing 回复

我们也是这样

luikore 回复

我觉得容器更适合做编译型语言的开发,尤其是做不了热重载的语言

👍 👍 👍

好吧,我也发现了,我本地开发搞个 development 的 docker 一阵子了,但感觉真是没有卵用。不过 staging 容器要有的,我用的生产的数据的拷贝,而且,设置里面,将请求设为本地请求那个参数,设为 true,大家懂的。😜

补充,主要是本地 Linux 已经有环境了,觉得 APP 的 容器有点多余,要在环境隔离,一致性的角度说,开发容器也蛮有用的。不过,你得像我一样,搞个万能的 docker_bash 脚本了,不管容器挂了还是什么异常,你总能进去,毕竟,你不总是改 APP,也会改其他,哦,你还得 mount 一个编辑器进去,你不想吧编辑器放到容器里吧!

好吧,我发觉其实我甚至不需要区分 staging 和 production,就我目前的差别,两个环境变量搞定

我感觉我不需要 Docker。。。在本地开发是我一直倾向于原生(Rails 直接跑在 Windows/MacOS 上),发布时我更倾向于选择可以快速发布的工具(Docker 发布比 Capistrano 慢),跑生产时我倾向于便宜(Docker 好像还是比 VPS 贵)。

虽然我这样说会很打击 Docker,但我觉得 Go 是一门好语言,因为平均工资高。。。

能够用 docker 一键发布,启动所有环境还是很爽的。

ericguo 回复

单人项目当然怎么爽怎么来,没有必要 docker

@luikore 能不能给个具体例子,重启容器需要的时间和 reload code 的时间,代码量太大每次重启时间太长确实不适合容器

基本同意题主,个人和小型项目随意

另外附上本人一些想法:

  • 容器不只有 docker
  • 容器是个好东西!在深入使用之后再下定论并给出对比说明
  • 容器不是高深的技术,另外我们不能仅看容器本身,还有容器背后的生态圈
  • 容器是基于版本、单镜像不同环境的整体发布,很大程度的改变现有开发、部署模式
  • Rails 中的三个模式和容器是两个东西,并且这两个东西和语言无关。 # Rails 中的三个模式是在容器流行之前诞生的,如果把现有的 Rails 项目真的容器化,Rails 中的不同运行模式的实现显得臃肿了些

当然并不是非容器不可,只是觉得这是个好东西😎

daqing 回复

我们也是 而且是在生产环境的 base 镜像中就写入了

nouse 回复

我改了一个文件,reload 它需要的时间是毫秒级的,重启容器就太麻烦了...

适合大规模集群部署,或者厂商提供云服务,不适合开发环境。如果遇到环境问题,我用 vagrant 都比 docker 多。

ericguo 回复

大神说得对!

nouse 为什么不应该使用 rvm/rbenv,以及替代方案 提及了此话题。 10月29日 11:43
需要 登录 后方可回复, 如果你还没有账号请 注册新账号