Rails Docker build 时遇到的 native extension 的问题

Catherine · September 13, 2021 · Last by Catherine replied at September 14, 2021 · 377 hits

先放 Gemfile 和 Dockerfile

# Dockerfile
FROM ruby:3.0.0-alpine

ENV BUNDLER_VERSION=2.2.6

RUN apk --no-cache add postgresql-client \
  vim \
  yarn \
  wget \
  gcc \
  autoconf \
  libc-dev \
  linux-headers \
  make \
  libxml2-dev \
  libressl-dev \
  postgresql-dev \
  libffi-dev \
  readline-dev \
  yaml-dev \
  tzdata \
  git \
  nodejs \
  less \
  curl \
  g++ \
  ca-certificates \
  imagemagick \
  build-base \
  ruby-dev \
  libxslt-dev \
  libcurl

RUN gem install bundler -v 2.2.6

WORKDIR /app

COPY Gemfile Gemfile.lock ./

# Cuz it'd be extremely slow not doing so
RUN gem install sassc --version 2.4.0

RUN bundle config build.nokogiri --use-system-libraries

RUN bundle check || bundle install

COPY package.json yarn.lock ./

RUN yarn install --check-files

COPY . ./

# Gemfile
source "https://rubygems.org"

ruby '3.0.0'

gem 'rails', '~> 6.0.4'
gem 'puma', '~> 4.1'
gem 'sass-rails', '>= 6'
gem 'webpacker', '~> 4.0'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.7'
gem 'bootsnap', '>= 1.4.2', require: false

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  gem 'pry-rails'
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '~> 3.2'
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  gem 'webdrivers'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem 'pg', '~>1.1.3'
gem 'sidekiq', '~>6.0.0'
gem "sidekiq-scheduler"
gem 'react-rails'

在本地 Mac 上打包,一切正常。但是在 ubuntu 的 vps (1G/1C) 上,执行到 bundle install 时,会在 sassc 2.4.0 的 build native extensions 那一步卡的非常非常久。并且 CPU 和内存在这一步的时间段里,基本上占用都是 80% 左右。

但独执行写一行 RUN 来安装 sassc,可以解决这个问题,也可以拿 Mac 上打包好的作为个基础 image 解决问题。

但我有一个问题不太明白。 bundle install 和 gem install 无非是一个用 bundle 来负责安装。bundle 在安装的版本上会做出最兼容的选择,比如 A 和 B 都需要 sassc 的依赖的情况下。但我已经在 Gemfile 中明确指明 2.4 版本,依然在 ubuntu 中失败。既然和版本没关系,为什么:

  1. Mac 中 build 到 bundle 那一步安装 sassc 直接就过了,内存和 CPU 强一点的原因?
  2. 单独加一层 RUN 去用 gem 直接安装 sassc 就成功了。而放在 Dockerfile 中让 bundle 去安装却卡死了,为什么会有这个区别?

我觉得就是 cpu 和内存太小,以前不用 docker 我也碰到过过 1 G 内存在编译 gem 的时候卡死。

构建镜像的机器性能要好一点,生产环境资源少就不要放在生产环境编译了。编译好 push 到 registry,然后生产环境拉镜像。

1c1g 出现这种情况很正常。。。。

先提交 Gemfile.lock 可以利用构建缓存。要不然每次部署都安装就很累。

Reply to pynix

恩,是的。我的问题应该就是 Rei 说的内存太小了。因为我的机子里还挂了一个被 sidekiq 持续修改的文件,以及代理这个文件做显示的 nginx。实际闲置内存可能还少了两三百 MB...巧妇难为无米之炊,钱没给够还让 docker 打包,是有点黑了 哈哈

Reply to Catherine

本地打。。。

Reply to Catherine

我用 API mode 好像不需要依赖这个。。。

Reply to pynix

它是个整合以及压缩 scss 和 sass 的工具,API 模式不存在这些静态资源,自然也就没有了。

You need to Sign in before reply, if you don't have an account, please Sign up first.