Rails asset compilation not working in docker compose

597 Views Asked by At

I'm trying to get a test environment set up on buildkite for a Rails app using Docker and docker-compose following the example given by buildkite here

As part of our Dockerfile we're compiling the assets on the app which should compile to public/packs-test/ we can confirm this output in the Dockerfile with the ls in that file below. We see the output of RUN ls /app/public to contain the packs-test directory

When the docker-compose is then run by buildkite through the command docker-compose -f docker-compose.yml run -e RAILS_ENV=test --rm app /bin/sh -e -c 'ls public' however it doesn't include the packs-test directory.

This means that when we do run our specs they're trying to recompile on each container.

If we try this locally however it does contain the expected output so not sure if something potentially stopping this from working on buildkite through the Elastic stack setup they use?

Have we missed a step in our asset precompile to make this directory available in the container via docker compose?

Any insight on this would be much aprreciated

# Dockerfile

FROM ruby:2.5.1

# Lets us use "source"
SHELL ["/bin/bash", "-c"]

EXPOSE 5000

ENV RAILS_ENV=test

# Node/Yarn stuff
ENV NODE_VERSION 10.15.3
ENV YARN_VERSION 1.16.0

# Node, needed for asset pipeline
RUN curl -sSL "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" | tar --strip-components=2 -xJ -C /usr/local/bin/ node-v$NODE_VERSION-linux-x64/bin/node
RUN curl https://www.npmjs.com/install.sh | bash

# Install Yarn
RUN npm install -g "yarn@$YARN_VERSION"

WORKDIR /app

# Install Rubygems first
ADD Gemfile Gemfile.lock /app/
RUN gem install bundler \
    && bundle install -j 4

# Install npm libraries next
ADD package.json yarn.lock /app/
RUN yarn install --frozen-lockfile


# Now add the rest of your code
ADD . /app/

RUN RAILS_ENV="test" bundle exec rails assets:precompile


RUN ls /app/public

CMD ["rails", "server", "-p", "5000"]
#docker-compose.yml
version: '3'

services:
  app:
    build: .
    depends_on:
      - db
      - redis
    # This mounts the current Buildkite build into /app, ensuring any
    # generated files and artifacts are available to the buildkite-agent on
    # the host machine (outside of the Docker Container)
    volumes:
      - "./:/app"
    # env_file:
    #   - ".env.example"
    environment:
      REDIS_URL: redis://redis

    ports:
      - "5000:5000"

  db:
    image: postgres:10

  redis:
    image: redis

1

There are 1 best solutions below

0
On

While your container may include the precompiled assets, you're mounting a volume right over it with this line:

    # This mounts the current Buildkite build into /app, ensuring any
    # generated files and artifacts are available to the buildkite-agent on
    # the host machine (outside of the Docker Container)
    volumes:
      - "./:/app"

So whatever Buildkite supplies is what you have living inside /app. A possible fix is to avoid mounting that directory:

    # This mounts the current Buildkite build into /app, ensuring any
    # generated files and artifacts are available to the buildkite-agent on
    # the host machine (outside of the Docker Container)
    volumes:
      - "./:/app"
      - "/app/public"

You may also want to consider building assets as a step in you testing pipeline, and removing that functionality from your Dockerfile (and creating a production image version which still builds assets)