How to install a different ruby version on a php container

Problem

In a php/node/… application container you sometimes also need ruby. By default, the version we install is 2.3.3 but it could be you need a different version

Goal

This article describes how to install a different ruby version in your application container. Note that this only applies to application container which are not ruby containers. For ruby containers, simply change the container type as described in the documentation https://docs.platform.sh/languages/ruby.html

0. Platform.Sh project

We need a Platform.Sh project to work with. But I’m assuming you already have that set up.

1. Installing ruby

We are going to leverage brew.sh to save us the hassle of compiling it ourselves.

Create a file install-ruby.sh and commit it to your repository.

run() {
    # Run the compilation process.
    cd $PLATFORM_CACHE_DIR || exit 1;

    if [ ! -d "${PLATFORM_CACHE_DIR}/.linuxbrew/opt/ruby@$1" ]; then
        echo "Ruby not found in cache, installing"
        install_brew
        install_ruby $1
        copy_lib_to_cache
    else
        copy_lib_from_cache
    fi

    write_profile $1

}

copy_lib_to_cache() {
    echo "Copy to cache..."
    rsync -ahr $PLATFORM_APP_DIR/.linuxbrew $PLATFORM_CACHE_DIR
}

copy_lib_from_cache() {
    echo "Copy from cache..."
    rsync -ahr $PLATFORM_CACHE_DIR/.linuxbrew $PLATFORM_APP_DIR
}

write_profile() {
    touch ~/.environment
    echo "export PATH=\"/app/.linuxbrew/bin:/app/.linuxbrew/opt/ruby@$1/bin:$PATH\"" >> ~/.environment
    echo 'eval $(/app/.linuxbrew/bin/brew shellenv)' >>~/.environment
    ruby_dir=$(ls ~/.linuxbrew/Cellar/ruby@$1)
    echo "export LD_LIBRARY_PATH=/app/.linuxbrew/Cellar/ruby@$1/$ruby_dir/lib/" >> ~/.environment
}

install_brew() {
    echo "Installing homebrew"
    mkdir -p /app/.linuxbrew

    echo "Downloading tarball from master repository"
    curl -SsL https://github.com/Homebrew/brew/tarball/master -o brew.tar.gz
    
    echo "Unpacking into .linuxbrew folder"
    tar xzf brew.tar.gz --strip-components 1 -C /app/.linuxbrew/
    rm brew.tar.gz

    eval $(/app/.linuxbrew/bin/brew shellenv)
    brew analytics off

}

install_ruby() {
    echo "Installing ruby with command: brew install ruby@$1"
    brew install ruby@"$1"
    rename 's/.reinstall//' /app/.linuxbrew/Cellar/ruby@$1/*.reinstall
}

ensure_environment() {
    # If not running in a Platform.sh build environment, do nothing.
    if [ -z "${PLATFORM_CACHE_DIR}" ]; then
        echo "Not running in a Platform.sh build environment.  Aborting installation."
        exit 0;
    fi
}

ensure_arguments() {
    # If no version was specified, don't try to guess.
    if [ -z $1 ]; then
        echo "No version specified. You must specify a tagged version on the command line."
        exit 1;
    fi
    echo "Version was specified as $1"
}

ensure_environment
ensure_arguments "$1"
run "$1"

3. Add the install to the build hook

We can now call the bash script from our build hook. You have to pass in the version you want to install to the script.

# The hooks executed at various points in the life cycle of the application.
hooks:
    build: |
        set -e
        bash install-ruby.sh 2.6

4. Verify installation

platform ssh 'ruby -v'

This should return something like this:

ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-linux]

Build cache

The building of ruby and brew is fairly slow. But the script utilizes the platform_build_cache to speed subsequent builds up. If you decide to upgrade the version, run platform project:clear-build-cache

Conclusion

It’s a bit of work to get it working, but since this case is not common, the extra work is justified.