Why Alpine Linux?
When you Dockerize a Rails application, you have to choose which distribution of Linux you want your container to use.
When I first started Dockerizing my applications I used Ubuntu for my containers because that was the distro I was familiar with. Unfortunately I discovered that using Ubuntu results in slow builds, slow running of commands, and large image sizes.
I discovered that Alpine Linux is popular for Docker containers because it affords better performance and smaller images.
Alpine + Capybara problems
Alpine had its own drawback though: I couldn’t run my tests because it wasn’t as straightforward in Alpine to get a Capybara + ChromeDriver configuration working on Alpine.
The evident reason for this is that Alpine can’t run a normal Chrome package the way Ubuntu can. Instead, it’s typical on Alpine to use Chromium, which doesn’t quite play nice with Capybara the way Chrome does.
How to get Alpine + Capyabara working
There are three steps to getting Capybara working on Alpine.
- Use selenium-webdriver instead of webdrivers
- Install chromium, chromium-chromedriver and selenium on your Docker image
- Configure a Capybara driver
Use selenium-webdriver instead of webdrivers
The first step is very simple: if you happen to be using the
webdrivers gem in your
Gemfile, replace it with
Install chromium, chromium-chromedriver and selenium on your Docker image
The next step is to alter your
Dockerfile so that
selenium are installed.
Below is a
Dockerfile from one of my projects (which is based on Mike Rogers’ fantastic Docker-Rails template).
I’ll call out the relevant bits of the file.
chromium chromium-chromedriver python3 python3-dev py3-pip
This line, as you can see, installs
chromium-chromedriver. It also installs
pip3 and its dependencies because we need
pip3 in order to install Selenium. (If you don’t know,
pip3 is a Python package manager.)
Here’s the line that installs Selenium:
RUN pip3 install -U selenium
And here’s the full
FROM ruby:2.7.2-alpine AS builder RUN apk add --no-cache \ build-base libffi-dev \ nodejs yarn tzdata \ postgresql-dev postgresql-client zlib-dev libxml2-dev libxslt-dev readline-dev bash \ # # For testing chromium chromium-chromedriver python3 python3-dev py3-pip \ # # Nice-to-haves git vim \ # # Fixes watch file issues with things like HMR libnotify-dev RUN pip3 install -U selenium FROM builder AS development # Add the current apps files into docker image RUN mkdir -p /usr/src/app WORKDIR /usr/src/app # Install any extra dependencies via Aptfile - These are installed on Heroku # COPY Aptfile /usr/src/app/Aptfile # RUN apk add --update $(cat /usr/src/app/Aptfile | xargs) ENV PATH /usr/src/app/bin:$PATH # Install latest bundler RUN bundle config --global silence_root_warning 1 EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0", "-p", "3000"] FROM development AS production COPY Gemfile /usr/src/app COPY .ruby-version /usr/src/app COPY Gemfile.lock /usr/src/app COPY package.json /usr/src/app COPY yarn.lock /usr/src/app # Install Ruby Gems RUN bundle config set deployment 'true' RUN bundle config set without 'development:test' RUN bundle check || bundle install --jobs=$(nproc) # Install Yarn Libraries RUN yarn install --check-files # Copy the rest of the app COPY . /usr/src/app # Precompile the assets RUN RAILS_SERVE_STATIC_FILES=enabled SECRET_KEY_BASE=secret-key-base RAILS_ENV=production RACK_ENV=production NODE_ENV=production bundle exec rake assets:precompile # Precompile Bootsnap run RAILS_SERVE_STATIC_FILES=enabled SECRET_KEY_BASE=secret-key-base RAILS_ENV=production RACK_ENV=production NODE_ENV=production bundle exec bootsnap precompile --gemfile app/ lib/
The next step is to configure a Capybara driver.
Configure a Capybara driver
Below is the Capybara configuration that I use for one of my projects. This configuration is actually identical to the config I used before I started using Docker, so there’s nothing special here related to Alpine Linux, but the Alpine Linux configuration described in this post won’t work without something like this.
Remember to make sure that the line in
spec/rails_helper that includes files from
spec/support is uncommented so this file gets loaded.