Ruby 使用 Docker 打包 Ruby 项目,关于 Gem 打包的一个坑

ampedxx · 2018年06月13日 · 最后由 edward1992 回复于 2018年06月19日 · 3577 次阅读

虽然目前做微服务的项目大多数都用 go 语言了,但是我们还是想尝试用 ruby 搭建一个微服务的框架。用到的技术或者工具有 ruby + grpc + linkerd + docker + k8s。grpc 的官方网站上有 ruby 版本的例子,linkerd 也支持 grpc 的通讯,docker 和 kubenetes 就是用来部署的。

由于脱离了 rails 框架,出现了很多问题。比如下面这一个

test.rb

require 'mygem'
Mygem.say_hello

Gemfile

gem 'mygem', git: 'some git source url.......'

很简单的例子,自己写了一个 gem 包,名叫 mygem,然后放到 git 上(因为是不公开的,所以没有上传到 rubygems.org)。test.rb 这段代码在本地环境 bundle install 之后运行是没有问题的,于是我们开始下一步——用 docker 把它装起来。

Dockerfile:

FROM ruby:2.4-slim-jessie

something not important......

COPY Gemfile Gemfile.lock ./

RUN bundle install

然后执行 docker build -t test:v1 . docker build 成功了!!,一切看起来都非常顺利,直到我们使用 docker 去执行他。

docker run -t --rm test:v1
/usr/local/lib/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:59:in `require': cannot load such file -- mygem (LoadError)

require 'mygem' 报错了,因为 mygem 这个包没有安装到 docker 环境中。我们检查一下 bundle install 的时候有没有安装 mygem。

Using mygem 0.1.0 from 'ssh:// someurl'
Fetching net-ssh 4.2.0
Installing net-ssh 4.2.0

我发现,只要是在 Gemfile 里面指定 git 源的 gem 包,在 bundle install 时只会 Using,而不会 fetching 和 instaling。这在 rails 框架和本地的环境中都不是什么问题,但是放到 docker 里面,就报错了 OTZ, 目前的解决办法就是放弃指定 git 源的写法, https://gemfury.com/help/install-gems/

source: 'some url' do 
  gem 'mygem'
end

这种写法需要有一个私有的 gem 源,不知道还有没有别的方法了。

我这边几个指向 github 的 gem,并没有遇到你说的问题

而且看上去你在 Gemfile 里仍旧使用着 git://

COPY 完成的那一步有生成一层中间镜像

直接 run 那个镜像,手动去执行下命令,看看到底发生了什么,感觉是你的镜像中却了什么东西

另外,部署用的镜像建议加上 --deployment 或者 --frozen

我这边也没有遇到

我这边一般这么干

FROM ruby:2.5.1-alpine

ADD Gemfile Gemfile.lock ./

RUN \
  apk update && apk add --no-cache git build-base && \
  bundle install --deployment --without development:test:doc && \
  apk del git build-base
4 楼 已删除

docker打包项目,可使用bundlegem同时打包:

1. 缓存gem

bundle cache

命令执行成功后会出现vendor/cache缓存文件夹

注意: 如果gem使用c扩展 (ext),请保证当前环境和docker环境 (如操作系统,32/64 位) 一致

2. 将缓存文件夹和Gemfile.lock复制 (COPYgit等) 到 docker

3. docker从缓存文件夹中安装gem

bundle install --local

本机执行:

bundle install --deployment --without=development

该命令可以把 gem 包打包放在{project_root}/vendor/bundle下面,后面备用 Dockerfile

FROM ruby:alpine
RUN apk add --update --no-cache libstdc++
WORKDIR /app

RUN mkdir -p /usr/local/bundle && echo $'---\nBUNDLE_FROZEN: "true"\nBUNDLE_PATH: "vendor/bundle"\nBUNDLE_WITHOUT: "development"' > /usr/local/bundle/config

COPY . /app/

ENTRYPOINT ["ruby", "run_robot.rb"]

这样就可以了。

8 楼 已删除

exec bash 在运行 CMD 看看

试试看关掉本机的代理?

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