Docker Community Forums

Share and learn in the Docker community.

Why is Yarn not working during dockerization?

UPDATE: I got Yarn to work in dockerizing my RoR app. But, now when the docker image is set to up, bundler fails in setting puma.

Here is my new Dockerfile

# Use Ruby 2.6.2 version.
FROM ruby:2.6.2

# Optionally set a maintainer name to let people know who made this image.
LABEL maintainer="The Christian Chain <webmaster@thechristianchain.org>"

# Install dependencies:
# - build-essential: To ensure certain gems can be compiled
# - nodejs: Compile assets
# - libpq-dev: Communicate with postgres through the postgres gem

RUN apt-get update && apt-get install -qq -y --no-install-recommends \
build-essential libpq-dev nodejs

# Set an environment variable to store where the app is installed to inside
# of the Docker image. The name matches the project name out of convention only.

ENV INSTALL_PATH /heis_soma
RUN mkdir -p $INSTALL_PATH

# This sets the context of where commands will be ran in and is documented
# on Docker's website extensively.

WORKDIR $INSTALL_PATH

# Download Node and Yarn

RUN curl https://deb.nodesource.com/setup_12.x | bash
RUN curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

# Install Node.js and Yarn
RUN apt-get update && apt-get install -y nodejs yarn

# This is because I get an error in testing stating that the yarn file is not 
# up-to-date, though it still says that after running this so I have to turn off the
# integrity check.

RUN yarn install --check-files

RUN gem update --system

# Ensure gems are cached and only get updated when they change. This will
# drastically increase build times when your gems do not change.

COPY Gemfile Gemfile

# We want binstubs to be available so we can directly call sidekiq and
# potentially other binaries as command overrides without depending on
# bundle exec.

RUN bundle install --binstubs

# Copy in the application code from your work station at the current directory
# over to the working directory.

COPY . .

# Provide a dummy DATABASE_URL to Rails so it can pre-compile assets.

RUN bundle exec rake RAILS_ENV=production DATABASE_URL=postgresql://user:pass@127.0.0.1/dbname SECRET_TOKEN=dummytoken assets:precompile

# Ensure the static assets are exposed through a volume so that nginx can read
# in these values later.

VOLUME ["$INSTALL_PATH/public"]

# The default command that gets ran will be to start the Puma server.

CMD bundle exec puma -C config/puma.rb

Errors that cause dbs to shut down. First is the main db:

[6] Puma starting in cluster mode...
heis_soma_1  | [6] * Version 4.2.1 (ruby 2.6.2-p47), codename: Distant Airhorns
heis_soma_1  | [6] * Min threads: 5, max threads: 5
heis_soma_1  | [6] * Environment: development
heis_soma_1  | [6] * Process workers: 1
heis_soma_1  | [6] * Preloading application
heis_soma_1  | bundler: failed to load command: puma (/usr/local/bundle/ruby/2.6.0/bin/puma)
heis_soma_1  | Errno::EPERM: Operation not permitted - bs_fetch:open_cache_file:open
heis_soma_1  | [6] ! Unable to load application: Errno::EPERM: Operation not permitted - bs_fetch:open_cache_file:open
heis_soma_heis_soma_1 exited with code 1

Second is the sidekiq instance which exits with the same issue.

Now, these exit randomly. If I go to the MacOS Docker Desktop and start up the heis_soma_heis_soma, sometimes it runs, but then in the browser at localhost:8000 I get this error:

Puma caught this error: Failed to open TCP connection to localhost:35729 (Cannot assign requested address - connect(2) for "localhost" port 35729) (Errno::EADDRNOTAVAIL)
/usr/local/lib/ruby/2.6.0/net/http.rb:949:in `rescue in block in connect'
/usr/local/lib/ruby/2.6.0/net/http.rb:946:in `block in connect'
/usr/local/lib/ruby/2.6.0/timeout.rb:93:in `block in timeout'
/usr/local/lib/ruby/2.6.0/timeout.rb:103:in `timeout'
/usr/local/lib/ruby/2.6.0/net/http.rb:945:in `connect'
/usr/local/lib/ruby/2.6.0/net/http.rb:930:in `do_start'
/usr/local/lib/ruby/2.6.0/net/http.rb:919:in `start'
/usr/local/lib/ruby/2.6.0/net/http.rb:1470:in `request'
/usr/local/lib/ruby/2.6.0/net/http.rb:1450:in `send_request'
/usr/local/bundle/ruby/2.6.0/gems/rack-livereload-0.3.17/lib/rack/livereload/body_processor.rb:50:in `use_vendored?'
/usr/local/bundle/ruby/2.6.0/gems/rack-livereload-0.3.17/lib/rack/livereload/body_processor.rb:101:in `livereload_source'
(erb):14:in `block (2 levels) in process!'
/usr/local/lib/ruby/2.6.0/erb.rb:901:in `eval'
/usr/local/lib/ruby/2.6.0/erb.rb:901:in `result'
/usr/local/bundle/ruby/2.6.0/gems/rack-livereload-0.3.17/lib/rack/livereload/body_processor.rb:78:in `block (2 levels) in process!'
/usr/local/bundle/ruby/2.6.0/gems/activesupport-6.0.2.2/lib/active_support/core_ext/string/output_safety.rb:283:in `block in gsub!'
/usr/local/bundle/ruby/2.6.0/gems/activesupport-6.0.2.2/lib/active_support/core_ext/string/output_safety.rb:281:in `gsub!'
/usr/local/bundle/ruby/2.6.0/gems/activesupport-6.0.2.2/lib/active_support/core_ext/string/output_safety.rb:281:in `gsub!'
/usr/local/bundle/ruby/2.6.0/gems/rack-livereload-0.3.17/lib/rack/livereload/body_processor.rb:78:in `block in process!'
/usr/local/bundle/ruby/2.6.0/gems/rack-livereload-0.3.17/lib/rack/livereload/body_processor.rb:76:in `each'
/usr/local/bundle/ruby/2.6.0/gems/rack-livereload-0.3.17/lib/rack/livereload/body_processor.rb:76:in `process!'
/usr/local/bundle/ruby/2.6.0/gems/rack-livereload-0.3.17/lib/rack/livereload.rb:28:in `_call'
/usr/local/bundle/ruby/2.6.0/gems/rack-livereload-0.3.17/lib/rack/livereload.rb:14:in `call'
/usr/local/bundle/ruby/2.6.0/gems/actionpack-6.0.2.2/lib/action_dispatch/middleware/static.rb:126:in `call'
/usr/local/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/sendfile.rb:110:in `call'
/usr/local/bundle/ruby/2.6.0/gems/actionpack-6.0.2.2/lib/action_dispatch/middleware/host_authorization.rb:83:in `call'
/usr/local/bundle/ruby/2.6.0/gems/webpacker-4.0.7/lib/webpacker/dev_server_proxy.rb:29:in `perform_request'
/usr/local/bundle/ruby/2.6.0/gems/rack-proxy-0.6.5/lib/rack/proxy.rb:57:in `call'
/usr/local/bundle/ruby/2.6.0/gems/railties-6.0.2.2/lib/rails/engine.rb:526:in `call'
/usr/local/bundle/ruby/2.6.0/gems/puma-4.2.1/lib/puma/configuration.rb:228:in `call'
/usr/local/bundle/ruby/2.6.0/gems/puma-4.2.1/lib/puma/server.rb:667:in `handle_request'
/usr/local/bundle/ruby/2.6.0/gems/puma-4.2.1/lib/puma/server.rb:470:in `process_client'
/usr/local/bundle/ruby/2.6.0/gems/puma-4.2.1/lib/puma/server.rb:328:in `block in run'
/usr/local/bundle/ruby/2.6.0/gems/puma-4.2.1/lib/puma/thread_pool.rb:134:in `block in spawn_thread'

Any ideas would be helpful.


OLD Issue:

Ok, so my development team and I have been pulling our hair out because we can’t figure this out. We have a Ruby on Rails application that we are trying to dockerize so that we can deploy it to either AWS or Azure.

Ruby v --> 2.7.0
Rails v --> 6.0.2.2

When we run the docker-compose up command everything runs smoothly until the bundle exec rake where it fails because Yarn executable was not detected in the system.

If I install yarn by RUN curl -o- -L https://yarnpkg.com/install.sh | bash then it fails even earlier at the line RUN bundle install --binstubs because it can’t find bundler and asks me to install it. If I try to install bundler it says that gem is not found. So, it looks like by installing yarn I get kicked out of where ruby and my gems were installed? I even tried to install yarn prior to my code of FROM ruby:2.7.0. That didn’t seem to work. It goes back to saying that yarn is not installed, even though I get a confirmation that it was.

To be honest, this is the first time I have tried to use Docker and I walked through a Udemy course, which is 4 years out of date so the versions are all different and webpacker and yarn weren’t required with the teacher’s versions.

Does anyone have information to help us? I am including our ‘Dockerfile’ and ‘docker-compose.yml’ file code below.

Dockerfile

FROM node:12.19.0
RUN curl -o- -L https://yarnpkg.com/install.sh | bash

# Use Ruby 2.7.0 version.
FROM ruby:2.7.0

# Install dependencies:
# - build-essential: To ensure certain gems can be compiled
# - nodejs: Compile assets
# - libpq-dev: Communicate with postgres through the postgres gem

RUN apt-get update && apt-get install -qq -y --no-install-recommends \
                     build-essential nodejs libpq-dev

# Set an environment variable to store where the app is installed to inside
# of the Docker image. The name matches the project name out of convention only.

ENV INSTALL_PATH /heis_soma
RUN mkdir -p $INSTALL_PATH

# This sets the context of where commands will be ran in and is documented
# on Docker's website extensively.

WORKDIR $INSTALL_PATH

# Ensure gems are cached and only get updated when they change. This will
# drastically increase build times when your gems do not change.

COPY Gemfile Gemfile

# We want binstubs to be available so we can directly call sidekiq and
# potentially other binaries as command overrides without depending on
# bundle exec.

RUN bundle install --binstubs

# Copy in the application code from your work station at the current directory
# over to the working directory.

COPY . .

# Provide a dummy DATABASE_URL to Rails so it can pre-compile assets.

RUN bundle exec rake RAILS_ENV=production DATABASE_URL=postgresql://user:pass@127.0.0.1/dbname SECRET_TOKEN=dummytoken assets:precompile

# Ensure the static assets are exposed through a volume so that nginx can read
# in these values later.

VOLUME ["$INSTALL_PATH/public"]

# The default command that gets ran will be to start the Puma server.

CMD bundle exec puma -C config/puma.rb

docker-compose.yml

version: '2'

services:
  postgres:
    image: postgres:12.4
    environment:
      POSTGRES_USER: heis_soma
      POSTGRES_PASSWORD: yourpassword
    ports:
      - '5432:5432'
    volumes:
      - postgres:/var/lib/postgresql/data

  redis:
    image: redis:6.0.8
    ports:
      - '6379:6379'
    volumes:
      - redis:/var/lib/redis/data

  heis_soma:
    build: .
    ports:
      - '8000:8000'
    volumes:
      - .:/heis_soma
    env_file:
      - .heis_soma.env

  sidekiq:
    build: .
    command: bundle exec sidekiq
    volumes:
      - .:/heis_soma
    env_file:
      - .heis_soma.env

volumes:
  redis:
  postgres:

Thank you so much in advance for your assistance. I am sorry if this was posted in the wrong spot. I did try to find the right forum.

Your problem is that you are expecting the environment files to be passed to your docker build. While there is nothing like that happening. The environment that you define is only passed to image at run-time as run-time environment.

So you need to either use build arguments or set these environments in your image

Passing environments

##############################

Building Environment

##############################

Building environment set.

FROM base AS builder

Run yarn to install.

RUN yarn

Copy source code.

COPY ./src/ /home/node/app/src/
COPY ./public/ /home/node/app/public/

Run the build.

ENV SASS_PATH=node_modules:src/components:src/assets/styles:src/assets/fonts REACT_NODE_PATH=src/assets/styles/pages:src/assets/images
RUN yarn run build
Or you need to use build args

##############################

Building Environment

##############################

Building environment set.

FROM base AS builder

Run yarn to install.

RUN yarn

Copy source code.

COPY ./src/ /home/node/app/src/
COPY ./public/ /home/node/app/public/

Run the build.

ARG SASS_PATH
ARG REACT_NODE_PATH
ENV SASS_PATH={SASS_PATH} ENV REACT_NODE_PATH={REACT_NODE_PATH}
RUN yarn run build
And update your compose file like

version: “3.7”
services:
##############################

Front-End Container

##############################
frontend:
container_name: {PROJECT_NAME}_frontend build: context: ./frontend/ target: production args: - REACT_NODE_PATH={REACT_NODE_PATH}
- SASS_PATH={SASS_PATH} restart: always environment: - PROJECT_NAME={PROJECT_NAME}
- NODE_PATH={REACT_NODE_PATH} - NODE_PORT={NODE_PORT}
- SASS_PATH=${SASS_PATH}
- NODE_ENV=production
- DOCKER_BUILDKIT=1
command: /bin/ash -c “envsubst < /etc/nginx/conf.d/nginx.template > /etc/nginx/conf.d/default.conf && exec nginx -g ‘daemon off;’”
expose:
- “80”
ports:
- “80:80”

Thank you for your assistance. One question though: Is your solution for a Ruby on Rails application? It looks to be more of a Node.js application.

FYI, I was unable to figure it out, but hired an expert from Amazon’s AWS Expert Service. After 3 days of playing around with it, he was finally able to get it to work and deploy. I have no idea how he did it so I can’t update this here. But, if anyone knows and wants to update for future readers, and for my sanity to know how this magic is done :slight_smile: , Please do.