Building Docker images usually takes a long time. This repo contains base images with preinstalled dependencies for Ruby on Rails, so building a production image will be 2-3 times faster.
When using the official Ruby image, building a Docker image for a typical Rails application requires lots of time for installing dependencies - mainly OS packages, Ruby gems, Ruby gems with native extensions (Nokogiri etc.) and Node modules. This is required every time the app needs to be deployed to production.
In order to reduce this time, we can use these base images that contain most of the dependencies used in an applications.
As much as possible is moved from the app-specific Dockerfile into the base image by using ONBUILD triggers. This makes the Dockerfile small and simple.
Compare building times using a typical Rails application. This is the result on a local machine:
As you can see, using DockerRailsBase is more than 2 times faster compared to the official Ruby image. It saves nearly 3min on every build.
Note: Before the author started timing, the base image was not available on their machine, so it was downloaded first, which took some time. If the base image is already available, the building time is only 1:18min (3 times faster).
This repo is based on the following assumptions:
It uses multi-stage building to build a very small production image. There are two Dockerfiles in this repo, one for the first stage (called Builder) and one for the resulting stage (called Final).
The Builder stage installs Ruby gems and Node modules. It also includes Git, Node.js and some build tools - all we need to compile assets.
The Final stage builds the production image, which includes just the bare minimum.
Builder stageUsing Dependabot, every updated Ruby gem or Node module results in an updated image.
FROM mileszim/rails-base-builder:3.0.0-alpine AS Builder
FROM mileszim/rails-base-final:3.0.0-alpine
USER app
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
Yes, this is the complete Dockerfile of the Rails app. It's simple because the work is done by ONBUILD triggers.
Now build the image:
$ docker build .
BuildKit requires a little workaround to trigger the ONBUILD statements. Add a COPY statement to the Dockerfile:
FROM mileszim/rails-base-builder:3.0.0-alpine AS Builder
FROM mileszim/rails-base-final:3.0.0-alpine
# Workaround to trigger Builder's ONBUILDs to finish:
COPY --from=Builder /etc/alpine-release /tmp/dummy
USER app
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
Now you can build the image with BuildKit:
docker buildx build .
You can use private npm/Yarn packages by mounting the config file:
docker buildx build --secret id=npmrc,src=$HOME/.npmrc .
or
docker buildx build --secret id=yarnrc,src=$HOME/.yarnrc.yml .
Example to build the application's image with GitHub Actions and push it to the GitHub Container Registry:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Login to GitHub Container Registry
run: echo ${{ secrets.CR_PAT }} | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin
- name: Build the image
run: |
export COMMIT_TIME=$(git show -s --format=%ci ${GITHUB_SHA})
export COMMIT_SHA=${GITHUB_SHA}
docker build --build-arg COMMIT_TIME --build-arg COMMIT_SHA -t ghcr.io/user/repo:latest .
- name: Push the image
run: docker push ghcr.io/user/repo:latest
Docker supports layer caching, so for building images it performs just the needed steps: If there is a layer from a former build and nothing has changed, it will be used. But for dependencies, this means: If a single Ruby gem in the application was updated or added, the step with bundle install is run again, so all gems will be installed again.
Using a prebuilt image improves installing dependencies a lot, because only the different/updated dependencies will be installed - all existing ones will be reused.
This doesn't matter:
apk add inside your app's Dockerfile.rails assets:precompile via the ONBUILD trigger.bundle install via the ONBUILD trigger.No. In the build stage there is a bundle clean --force, which uninstalls all gems not referenced in the app's Gemfile.
Content type
Image
Digest
Size
339.6 MB
Last updated
over 5 years ago
docker pull mileszim/rails-base-builder