Skip to content

Latest commit

 

History

History
215 lines (153 loc) · 12.2 KB

README.md

File metadata and controls

215 lines (153 loc) · 12.2 KB

hnhs/ruby-dev

A fork from alpine-labs/ruby-dev.

The main goal of this project is to have a single Docker image to develop all your Ruby projects, with all dependencies contained inside Docker (like gems, NPM packages or even Ruby itself, that won't pollute your host environment) and without anything specific to the project in the Docker image (the codebase is mounted directly from the host filesystem into the container, thus you'll never have to build the image when you add a gem or change some code).

The Docker container also provides developer-friendly tools and behaviours like persisted Ruby console history (IRB and Pry), shell history, or even auto-installing dependencies (that's right: simply change your Gemfile or package.json and bundle install or yarn install will be run automatically for you and only when necessary). It also provides a few CLI tools to get your hands dirty, but as least as possible: vim, nano, heroku.

The default command (when you just docker-compose up) is to run foreman start, thus starting whatever you put in your Procfile (except the release process, if you have one: it's a reserved process name by Heroku/Dokku). All commands are run inside the container as the same user that owns your codebase (thus probably your host user), which means that any file generated inside the container (think of rails generate, yarn init, or even log files) will be owned by yourself (not by root, like they would with a default Docker configuration).

We try to use sane default conventions so you don't have to think about it, but this image also allows some configuration (e.g. Heroku CLI or Git authentication) and customisation (install extra software inside the container). See the recipes book for more details.

TL;DR 🙄

  • your codebase is 2-way-mounted from your host to /app inside the container
  • Yarn is configured to store installed modules in /app/node_modules
  • Bundler is configured to store installed gems in /bundle
  • Rubygems is configured to store installed gems (using gem install … directly) in /bundle/global
  • everything ran inside the container is done with your host user UID and GID
  • bundle install is run before any command, only if necessary
  • yarn install is run before any command, only if necessary
  • you can customise the image with extra software

Latest images

The latest versions built by the Docker Build workflow are available from Docker Hub and GitHub Container Registry (GHCR). Size badges show the compressed download size for linux/amd64 from Docker Hub.

Docker Hub GitHub Container Registry Size (linux/amd64)
hnhs/ruby-dev:4.0.9 ghcr.io/hicknhack-software/ruby-dev:4.0.9 4.0.9 image size
hnhs/ruby-dev:4.0.9-alpine ghcr.io/hicknhack-software/ruby-dev:4.0.9-alpine 4.0.9-alpine image size
hnhs/ruby-dev:3.4.12 ghcr.io/hicknhack-software/ruby-dev:3.4.12 3.4.12 image size
hnhs/ruby-dev:3.4.12-alpine ghcr.io/hicknhack-software/ruby-dev:3.4.12-alpine 3.4.12-alpine image size
hnhs/ruby-dev:3.3.13 ghcr.io/hicknhack-software/ruby-dev:3.3.13 3.3.13 image size
hnhs/ruby-dev:3.3.13-alpine ghcr.io/hicknhack-software/ruby-dev:3.3.13-alpine 3.3.13-alpine image size

Usage

Setup

Simply create a docker-compose.yml file in your project root directory like this:

version: "3"
volumes:
  bundle:       { driver: local }
  node_modules: { driver: local }
  config:       { driver: local }
services:
  app:
    image: hnhs/ruby-dev
    ports: ["5000:5000"]
    volumes:
      - .:/app
      - bundle:/bundle
      - node_modules:/app/node_modules
      - config:/config

💡 Feel free to use hnhs/ruby-dev:<ruby-version>: we support multiple Ruby versions as Docker tags and Alpine Linux variants (append -alpine to image tag).

If you're on MacOS, you'll very likely want to use Docker Sync too.

⚠️ Use your actual application name suffixed with -sync instead of your_app-sync to prevent conflicts between your projects.

  1. install it with gem install docker-sync

  2. add a docker-sync.yml file:

    version: "3"
    syncs:
      your_app-sync:
        src: ./
        sync_excludes: [log, tmp, .git, .bundle, .idea, node_modules]
  3. add the sync container as external container in docker-compose.yml:

    volumes:
      your_app-sync: { external: true }
  4. use it by replacing - ./:/app with - your_app-sync:/app:nocopy in docker-compose.yml

  5. start the sync with docker-sync start

Run

You can now start your project with:

docker-compose up

Or run any command (like rake, bash, or whatever else) with:

docker-compose run app [rake|bash|...]

💡 Note that you don't need to prefix commands with bundle exec.

You can even bypass dependencies check/auto-install before the command is run by setting the DISABLE_AUTO_INSTALL_DEPS environment variable from the command-line:

docker-compose run -e DISABLE_AUTO_INSTALL_DEPS=1 app bash

Customisation

You can customise this image by building your own image based on this one (or any of its tags, by appending them to the FROM step of the Dockerfile), and install additional software on top of it:

  1. create a Dockerfile in your project root folder, and add a build step that installs the APT package you need (other installation methods work too, but it's out of the scope of this documentation):

    FROM alpinelab/ruby-dev
    
    RUN apt-get update \
     && apt-get install --assume-yes --no-install-recommends --no-install-suggests \
          <INSERT APT PACKAGE NAME HERE> \
     && rm -rf /var/lib/apt/lists/*
  2. change your docker-compose.yml to use this Dockerfile (rather than an upstream image) and to build it on-demand:

    • change this line:

      image: alpinelab/ruby-dev
    • into this line:

      build: .

ℹ️ To temporarily install a package inside the container (e.g. for a one-time debugging session), you can simply:

  1. Run a shell as root in the container (notice the empty entrypoint):

    docker-compose run --entrypoint= app bash
  2. Install the pakckage using APT (any change will be undone when you close the shell):

    apt-get update && apt-get install <your_package>

Known issues

A wild node_modules directory owned by root may appear in your codebase directory. This is due to Docker creating the destination mount point for the bind mount. It should be solved when we will be able to reliably configure Yarn to use an absolute directory (instead of relative node_modules) outside of the codebase, like we do with Bundler.

Unmaintained versions

The following Ruby versions are not maintained anymore:

  • Ruby 2.2 (EOL'd)

⚠️ Note: This fork only contains the latest Ruby versions to minimize the effort. Feel free to open an issue if you need a different Ruby version.

Image updates

The official ruby images do not have a fixed publication time. Docker Library's version-update jobs check every six hours (H H/6 * * *, with Jenkins assigning the actual times). Images are published after changes are reviewed and built, and are also rebuilt when their parent images change. The publication pipeline has several stages, so a source commit or CI completion does not mean an image is available yet.

Our Docker Build workflow checks the published Ruby tags in its matrix every day at 00:37, 06:37, 12:37, and 18:37 UTC. Each scheduled run builds only variants whose linux/amd64 base-image digest or source revision differs from the labels on the corresponding ruby-dev image in either Docker Hub or GHCR. Changes only to other architectures, index annotations, or attestation manifests do not trigger builds. Missing images, missing labels, or an unverifiable downstream image trigger a build; an upstream lookup failure fails the job instead of reporting an unchanged image.

Builds use the exact base digest checked and record it in the org.opencontainers.image.base.digest label, alongside org.opencontainers.image.revision. Comparing both registries also retries partially published builds. Existing images without these labels rebuild once. Pushes to main and manual workflow runs always build, so manual runs can also refresh development packages when the Ruby base is unchanged. Ruby patch versions remain explicitly selected in the workflow matrix.

Run the change-detection tests with:

python3 -m unittest discover -s .github/scripts -p 'test_*.py'

Contributing

Contributions are indeed warmly welcome as pull requests, or issues ❤️

License

This project is developed by Alpine Lab and released under the terms of the MIT license.