rails / execjs

Run JavaScript code from Ruby
MIT License
539 stars 283 forks source link

Node interpreted as non-executable in alpine (docker container) and ruby 2.7.8 #144

Closed simoniong closed 1 month ago

simoniong commented 1 month ago

Docker container env & softwares I install:

bash-5.1# ruby -v
ruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [x86_64-linux-musl]

bash-5.1# bundle -v
`/root` is not writable.
Bundler will use `/tmp/bundler/home/unknown' as your home directory temporarily.
Bundler version 1.17.2

bash-5.1# node -v
v16.20.2
bash-5.1# which node
/usr/bin/node
bash-5.1# uname -a
Linux 6b7bd7e5f4b9 4.15.0-197-generic #208-Ubuntu SMP Tue Nov 1 17:23:37 UTC 2022 x86_64 Linux

bash-5.1# file /usr/bin/node
/usr/bin/node: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, stripped

bash-5.1# ruby -e "p File.executable? 'node'"
false
bash-5.1# ruby -e "p File.executable? '/usr/bin/node'"
false
bash-5.1# ruby -e "p File.file? 'node'"
false
bash-5.1# ruby -e "p File.file? '/usr/bin/node'"
true

bash-5.1# bundle list
Gems included by the bundle:
  * aasm (5.1.1)
  * actioncable (6.1.1)
  * actionmailbox (6.1.1)
  * actionmailer (6.1.1)
  * actionpack (6.1.1)
  * actiontext (6.1.1)
  * actionview (6.1.1)
  * active_decorator (1.3.4)
  * active_model_serializers (0.10.12)
  * activejob (6.1.1)
  * activemodel (6.1.1)
  * activerecord (6.1.1)
  * activestorage (6.1.1)
  * activesupport (6.1.1)
  * addressable (2.8.7)
  * autoprefixer-rails (10.4.19.0)
  * aws-eventstream (1.1.0)
  * aws-partitions (1.424.0)
  * aws-sdk-core (3.112.0)
  * aws-sdk-kms (1.42.0)
  * aws-sdk-s3 (1.88.0)
  * aws-sigv4 (1.2.2)
  * axiom-types (0.1.1)
  * bcrypt (3.1.16)
  * bootsnap (1.7.1)
  * bootstrap-sass (3.3.7)
  * breadcrumbs_on_rails (4.0.0)
  * browser (5.3.0)
  * builder (3.2.4)
  * bundler (1.17.2)
  * case_transform (0.2)
  * chronic (0.10.2)
  * chunky_png (1.4.0)
  * coercible (1.0.0)
  * coffee-rails (4.2.2)
  * coffee-script (2.4.1)
  * coffee-script-source (1.12.2)
  * compass (1.0.3)
  * compass-core (1.0.3)
  * compass-import-once (1.0.5)
  * compass-rails (4.0.0)
  * concurrent-ruby (1.1.8)
  * connection_pool (2.2.3)
  * crass (1.0.6)
  * css_parser (1.9.0)
  * descendants_tracker (0.0.4)
  * devise (4.7.3)
  * devise-i18n (1.9.2)
  * down (4.8.1)
  * equalizer (0.0.11)
  * erubi (1.10.0)
  * excon (0.79.0)
  * execjs (2.9.1)
  * faraday (1.10.3)
  * faraday-em_http (1.0.0)
  * faraday-em_synchrony (1.0.0)
  * faraday-excon (1.1.0)
  * faraday-httpclient (1.0.1)
  * faraday-multipart (1.0.4)
  * faraday-net_http (1.0.1)
  * faraday-net_http_persistent (1.2.0)
  * faraday-patron (1.0.0)
  * faraday-rack (1.0.0)
  * faraday-retry (1.0.3)
  * fastimage (2.2.2)
  * ffi (1.14.2)
  * fog-aws (3.8.0)
  * fog-core (2.2.3)
  * fog-json (1.2.0)
  * fog-xml (0.1.3)
  * font-awesome-rails (4.7.0.6 87ce085)
  * formatador (0.2.5)
  * foundation_emails (2.2.1.0)
  * friendly_id (5.1.0)
  * globalid (0.4.2)
  * google_currency (3.4.1)
  * hashie (4.1.0)
  * htmlentities (4.3.4)
  * i18n (1.8.8)
  * ice_nine (0.11.2)
  * image_processing (0.4.5)
  * inky-rb (1.3.8.0)
  * ipaddress (0.8.3)
  * jbuilder (2.11.2)
  * jmespath (1.4.0)
  * jquery-rails (4.4.0)
  * jquery-turbolinks (2.1.0)
  * jsonapi-renderer (0.2.2)
  * jwt (2.2.3)
  * kaminari (1.2.1)
  * kaminari-actionview (1.2.1)
  * kaminari-activerecord (1.2.1)
  * kaminari-core (1.2.1)
  * knock (2.2.0 37e403a)
  * loofah (2.9.0)
  * mail (2.7.1)
  * marcel (0.3.3)
  * meta-tags (2.14.0)
  * method_source (1.0.0)
  * mime-types (3.3.1)
  * mime-types-data (3.2020.1104)
  * mimemagic (0.3.10)
  * mini_magick (4.11.0)
  * mini_mime (1.1.5)
  * mini_portile2 (2.8.7)
  * minitest (5.14.3)
  * money (6.14.0)
  * msgpack (1.7.3)
  * multi_json (1.15.0)
  * multi_xml (0.6.0)
  * multipart-post (2.4.0)
  * newrelic_rpm (6.15.0)
  * nio4r (2.5.5)
  * nokogiri (1.13.10)
  * oauth2 (1.4.4)
  * omniauth (1.9.1)
  * omniauth-facebook (8.0.0)
  * omniauth-oauth2 (1.6.0)
  * orm_adapter (0.5.0)
  * pdf-core (0.5.1)
  * pg (1.2.3)
  * prawn (2.0.0)
  * prawn-table (0.2.2)
  * premailer (1.14.2)
  * premailer-rails (1.11.1)
  * public_suffix (5.1.1)
  * puma (5.2.1)
  * racc (1.8.1)
  * rack (2.2.9)
  * rack-test (2.1.0)
  * rails (6.1.1)
  * rails-controller-testing (1.0.5)
  * rails-dom-testing (2.0.3)
  * rails-html-sanitizer (1.3.0)
  * rails-i18n (6.0.0)
  * railties (6.1.1)
  * rake (13.0.6)
  * rb-fsevent (0.10.4)
  * rb-inotify (0.10.1)
  * redis (3.3.5)
  * responders (3.0.1)
  * roboto (1.0.1)
  * ruby-hmac (0.4.0)
  * ruby2_keywords (0.0.5)
  * sass (3.4.25)
  * sass-rails (5.0.8)
  * sentry-raven (3.1.1)
  * shrine (2.9.0)
  * sidekiq (4.1.2)
  * sitemap_generator (6.1.2)
  * slim (4.1.0)
  * slim-rails (3.2.0)
  * sprockets (3.7.2)
  * sprockets-rails (3.2.2)
  * temple (0.8.2)
  * thor (1.1.0)
  * thread_safe (0.3.6)
  * tilt (2.0.10)
  * timecop (0.9.2)
  * ttfunk (1.4.0)
  * turbolinks (5.2.1)
  * turbolinks-source (5.2.0)
  * twilio-ruby (6.12.1)
  * tzinfo (2.0.4)
  * tzinfo-data (1.2021.1)
  * uglifier (4.2.0)
  * virtus (1.0.5)
  * warden (1.2.9)
  * websocket-driver (0.7.3)
  * websocket-extensions (0.1.5)
  * whenever (1.0.0)
  * zeitwerk (2.4.2)

execjs is latest version 2.9.1, and while i kick start rails, I got this error:

bash-5.1# bin/rails s
Traceback (most recent call last):
    46: from bin/rails:4:in `<main>'
    45: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
    44: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
    43: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
    42: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
    41: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
    40: from /app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.1/lib/rails/commands.rb:18:in `<main>'
    39: from /app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.1/lib/rails/command.rb:50:in `invoke'
    38: from /app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.1/lib/rails/command/base.rb:69:in `perform'
    37: from /app/vendor/bundle/ruby/2.7.0/gems/thor-1.1.0/lib/thor.rb:392:in `dispatch'
    36: from /app/vendor/bundle/ruby/2.7.0/gems/thor-1.1.0/lib/thor/invocation.rb:127:in `invoke_command'
    35: from /app/vendor/bundle/ruby/2.7.0/gems/thor-1.1.0/lib/thor/command.rb:27:in `run'
    34: from /app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.1/lib/rails/commands/server/server_command.rb:135:in `perform'
    33: from /app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.1/lib/rails/commands/server/server_command.rb:135:in `tap'
    32: from /app/vendor/bundle/ruby/2.7.0/gems/railties-6.1.1/lib/rails/commands/server/server_command.rb:138:in `block in perform'
    31: from /app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.1/lib/active_support/dependencies.rb:332:in `require'
    30: from /app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.1/lib/active_support/dependencies.rb:299:in `load_dependency'
    29: from /app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.1/lib/active_support/dependencies.rb:332:in `block in require'
    28: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
    27: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
    26: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
    25: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
    24: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
    23: from /app/config/application.rb:17:in `<main>'
    22: from /usr/local/bundle/gems/bundler-1.17.2/lib/bundler.rb:114:in `require'
    21: from /usr/local/bundle/gems/bundler-1.17.2/lib/bundler/runtime.rb:65:in `require'
    20: from /usr/local/bundle/gems/bundler-1.17.2/lib/bundler/runtime.rb:65:in `each'
    19: from /usr/local/bundle/gems/bundler-1.17.2/lib/bundler/runtime.rb:76:in `block in require'
    18: from /usr/local/bundle/gems/bundler-1.17.2/lib/bundler/runtime.rb:76:in `each'
    17: from /usr/local/bundle/gems/bundler-1.17.2/lib/bundler/runtime.rb:81:in `block (2 levels) in require'
    16: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
    15: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
    14: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
    13: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
    12: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
    11: from /app/vendor/bundle/ruby/2.7.0/gems/uglifier-4.2.0/lib/uglifier.rb:5:in `<main>'
    10: from /app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.1/lib/active_support/dependencies.rb:332:in `require'
     9: from /app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.1/lib/active_support/dependencies.rb:299:in `load_dependency'
     8: from /app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.1/lib/active_support/dependencies.rb:332:in `block in require'
     7: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
     6: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
     5: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
     4: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
     3: from /app/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
     2: from /app/vendor/bundle/ruby/2.7.0/gems/execjs-2.9.1/lib/execjs.rb:4:in `<main>'
     1: from /app/vendor/bundle/ruby/2.7.0/gems/execjs-2.9.1/lib/execjs.rb:5:in `<module:ExecJS>'
/app/vendor/bundle/ruby/2.7.0/gems/execjs-2.9.1/lib/execjs/runtimes.rb:68:in `autodetect': Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)

I have no idea why Node can't interprited as a executable. can anyone help?

casperisfine commented 1 month ago

Can you share a dockefile that reproduce the issue?

File.executable? is riddled with issues, so we might want to stop using it and just try running something like node --version or whatever.

simoniong commented 1 month ago

This is the Dockerfile

FROM ruby:2.7.8-alpine as builder

ARG SSH_PRIVATE_KEY

RUN apk add --no-cache git openssh-client tzdata postgresql-dev
RUN apk add --no-cache nodejs yarn build-base shared-mime-info gcompat
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts

WORKDIR /app

ENV RAILS_ENV=production
ENV NODE_ENV=production

COPY Gemfile Gemfile.lock /app/
RUN gem install bundler:1.17.2
RUN gem install nokogiri:1.13.10
RUN --mount=type=ssh bundle install --jobs 4 --without development:test --deployment

# COPY package.json yarn.lock /app/
COPY yarn.lock /app/
RUN yarn install

COPY . /app/

RUN --mount=type=ssh bin/rails assets:precompile aws_access_key=xxx aws_secret_key=yyy aws_bucket=bubu secret_key_base=xxx
##############################################################
FROM ruby:2.7.8-alpine

RUN apk add --no-cache bash tzdata postgresql-dev file imagemagick nodejs shared-mime-info gcompat && \
    cp /usr/share/zoneinfo/Asia/Hong_Kong /etc/localtime

ENV RAILS_ENV=production

WORKDIR /app

COPY . /app/
COPY --from=builder /usr/local/bundle/config /usr/local/bundle/config
COPY --from=builder /app/vendor/bundle/ /app/vendor/bundle/
COPY --from=builder /app/public/ /app/public/

RUN gem install bundler:1.17.2

EXPOSE 3000
CMD ["bin/rails", "server"]
casperisfine commented 1 month ago

I'm not able to reproduce, I reduced your Dockefile to just:

FROM ruby:2.7.8-alpine as builder

RUN apk add --no-cache git openssh-client tzdata postgresql-dev
RUN apk add --no-cache nodejs yarn build-base shared-mime-info gcompat

# WORKDIR /app
#
# ENV RAILS_ENV=production
# ENV NODE_ENV=production
#
# COPY Gemfile Gemfile.lock /app/
# RUN gem install bundler:1.17.2
# RUN gem install nokogiri:1.13.10
# RUN --mount=type=ssh bundle install --jobs 4 --without development:test --deployment
#
# # COPY package.json yarn.lock /app/
# COPY yarn.lock /app/
# RUN yarn install
#
# COPY . /app/
#
# RUN --mount=type=ssh bin/rails assets:precompile aws_access_key=xxx aws_secret_key=yyy aws_bucket=bubu secret_key_base=xxx
# ##############################################################
FROM ruby:2.7.8-alpine

RUN apk add --no-cache bash tzdata postgresql-dev file imagemagick nodejs shared-mime-info gcompat && \
    cp /usr/share/zoneinfo/Asia/Hong_Kong /etc/localtime

# ENV RAILS_ENV=production

# WORKDIR /app

# COPY . /app/
# COPY --from=builder /usr/local/bundle/config /usr/local/bundle/config
# COPY --from=builder /app/vendor/bundle/ /app/vendor/bundle/
# COPY --from=builder /app/public/ /app/public/

# RUN gem install bundler:1.17.2
#
# EXPOSE 3000
# CMD ["bin/rails", "server"]

And node is seen as executable:

>> File.executable? '/usr/bin/node'
=> true
simoniong commented 1 month ago

It's weird, while I try to build it from my MacBookPro, and run it within my MacBookPro, the result is the same as yours, and I could use irb.

> docker run -it d7e62f6e54d3 bash
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
> irb
irb(main):001:0> File.executable? '/usr/bin/node'
=> true
irb(main):002:0> File.executable? 'node'
=> false
irb(main):003:0>
> ruby -e "p File.executable? '/usr/bin/node'"
true
> docker -v
Docker version 27.2.0, build 3ab4256

but while I try to remote access(ssh) to my VPS, use the same images, I can't really run irb at all.

> docker exec -it 948aa4879c72 bash
> irb
Traceback (most recent call last):
    6: from /usr/local/bin/irb:23:in `<main>'
    5: from /usr/local/bin/irb:23:in `load'
    4: from /usr/local/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
    3: from /usr/local/lib/ruby/2.7.0/irb.rb:393:in `start'
    2: from /usr/local/lib/ruby/2.7.0/irb/init.rb:18:in `setup'
    1: from /usr/local/lib/ruby/2.7.0/irb/init.rb:121:in `init_error'
/usr/local/lib/ruby/2.7.0/irb/locale.rb:121:in `load': No such file to load -- irb/error.rb (LoadError)
> ruby -e "p File.executable? '/usr/bin/node'"
false
> docker -v
Docker version 19.03.8, build afacb8b7f0
simoniong commented 1 month ago

It seems the root cause to be my docker version too low, and after upgrade to latest one, it is okay now.