Customizing the Docker Build
We've already seen the standard way to configure Kuby's Docker component (i.e. the
docker do ... end section), but there's a lot more you can do.
app_root String: Set your application's root directory. This is useful if the app lives in a separate folder, eg. is a demo app for a gem, etc.
All the other Docker build options are described in the sections below.
Installing Additional Packages
Kuby officially supports the Debian and Alpine distros of Linux for Docker images.
Let's install imagemagick as an example. First, we'll need to register the imagemagick package with Kuby. It just so happens both the Debian and Alpine Linux distros use the same name for their imagemagick package, meaning we can define using just its name.
Next, we tell Kuby to install imagemagick in the
docker section of our Kuby config:
If the package we want to install has a different name under each of the Linux distros, register it using a hash instead. Let's say we want to install the
dig command-line utility. In Debian, we'd need to install the
dnsutils package, but in Alpine we'd need
Kuby.register_package(:dig, debian: 'dnsutils', alpine: 'bind-tools')
Finally, some packages are more complicated to install. In such cases, define a Ruby class that responds to
install_on_alpine, and register it with Kuby.
class WatchmanPackage < Kuby::Docker::Packages::Package
git clone --no-checkout https://github.com/facebook/watchman.git \
&& cd watchman \
&& git checkout v4.7.0 \
&& ./autogen.sh \
&& ./configure \
&& make && make install
# alpine-specific statements
Selecting a Different Package Version
Some Kuby packages like Yarn and NodeJS support installing specific versions. For example, to install a specific version of NodeJS for your app, first remove the
:nodejs package and then add it back again using the version you want:
Kuby builds Docker images in 8 build phases. The options available in the various phases are documented below.
The setup phase defines the Docker base image (eg. ruby:2.6.3, ruby:2.6.3-alpine, etc), sets the working directory, and defines the
RAILS_ENV environment variables.
setup_phase.base_image = String: Sets the Docker base image on top of which your application's image will be built. Defaults to the official Ruby image for the version of Ruby currently running the
setup_phase.working_dir = String: Sets the working directory for the Docker image's filesystem. Application code will be copied into this directory and commands like
bundle installexecuted within it. Defaults to /usr/src/app.
setup_phase.rails_env = String: Sets
RAILS_ENV. Defaults to the current Kuby env, which is either the value passed to the Kuby CLI tool via the
kuby -e production ...), or the value of the
The package phase installs packages via the operating system's package manager, eg.
yum, etc. Popular packages include things like database drivers (eg. postgresql-client, sqlite3-dev), and image processing libraries (eg. imagemagick, graphicsmagick).
package_phase.add(package_name: Symbol): Adds a package by its name. Packages must be registered ahead of time (see above).
package_phase.remove(package_name: Symbol): Removes a package by its name.
The Bundler phase installs all the Ruby dependencies listed in your app's Gemfile via Bundler.
bundler_phase.version = String: Sets the version of Bundler to use. Defaults to the current version of Bundler being used to run the
bundler_phase.gemfile = String: Sets the path to the Gemfile.
bundler_phase.without = Array[String]: Sets the array of Bundler groups to be ignored during installation.
bundler_phase.executable = String: Sets the path to the Bundler executable. Defaults to
bundler_phase.gemfiles(gemfiles: Array[String]): Specifies additional Gemfiles to be copied into the Docker image before installation. Useful if your main Gemfile references other Gemfiles, eg. via the
The copy phase copies your app's source code into the Docker image.
copy_phase << String: Adds an additional path to copy into the image. Defaults to the current directory (eg: ./)
The app phase allows setting environment variables. These variables will be available to any commands run afterwards in the
docker build process, but will also be accessible to your application via Ruby's
app_phase.env(key: String, value: String): Adds an environment variable.
The assets phase compiles static assets managed by both the asset pipeline and Webpacker.
The webserver phase instructs the Docker image to use a webserver to run your app. Currently only the Rails default, Puma, is supported (including puma in your Gemfile is all you need to do - no other configuration is necessary).
webserver_phase.port = Integer: Sets the port the webserver should listen on.
webserver_phase.webserver = Symbol: Sets the webserver to use. Must be
:puma. Additional webservers may be supported in the future if there is demand. The only reason to set this field manually is if Kuby can't detect Puma in your Gemfile for some reason.
Creating A Custom Build Phase
Phases are just Ruby classes that respond to the
apply_to(dockerfile) method. It's possible to define your own custom phases and insert them into the build process. To do so, create a Ruby class and define the appropriate method. Then, insert your new phase. For example, let's define a phase that writes a file into the image that contains the current git commit ID (it can be handy to know which version of your code your image contains). We assume the current git commit is passed as a Docker build argument, since it won't be available to Docker otherwise (in other words, the .git folder won't and shouldn't be copied into the image).
dockerfile.run('echo $GIT_COMMIT > GIT_COMMIT')
insert :git_commit_phase, GitCommitPhase.new, after: :copy_phase
Kuby::Docker::Dockerfile objects respond to the following methods, which are mapped 1:1 to Dockerfile instructions:
from(image_url, as: nil)
argis a string of the form
copy(source, dest, from: nil)
Custom build phases can also be inserted inline, without the need to define a class:
insert :git_commit_phase, after: :copy_phase do |dockerfile|
dockerfile.run('echo $GIT_COMMIT > GIT_COMMIT')
Removing Build Phases
Build phases can be removed entirely. For example, if your app is API-only and doesn't have any static assets, then you may want to remove the asset compilation phase entirely:
It is possible to pass additional build args to
kuby build via the
--arg) flag. For example, here's how to pass a build arg containing the current Git commit SHA:
bundle exec kuby build -a SOURCE_COMMIT=$(git rev-parse HEAD)
NOTE: The example above assumes the
SOURCE_COMMIT build arg has been added via a custom build phase. To be able to access the value of the arg from the Rails app, it must also be exposed as an environment variable. To accomplish both goals, try something like this:
insert :git_commit_arg, after: :setup_phase do |dockerfile|
Building Specific Images
kuby build builds all the registered Docker images. Sometimes it's useful to build a specific one instead. To do so, pass the
bundle exec kuby build --only app # only build the app image
The value for the
--only option is an image identifier. A list of all registered images and their identifiers can be obtained via the
kuby images command.
A similar option is available for the
dockerfiles commands, e.g.,
kuby push --only app.
docker build Options
It is also possible to pass arbitrary options to the
docker build command:
bundle exec kuby build -- [options]
For example, to specify a custom build target, try this:
bundle exec kuby build -- --output type=tar,dest=out.tar
The options given after the
-- will be appended verbatim to the
docker build command.