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

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

虽然目前做微服务的项目大多数都用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源,不知道还有没有别的方法了。

共收到 8 条回复

我这边几个指向 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看看

试试看关掉本机的代理?

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