Architecture
GDK is a development environment orchestrator written in Ruby, Bash, and Make that sets up and manages a development installation of the GitLab application. It orchestrates over 50 individual services, some of which optional, that make GitLab work.
The following diagram is a rough overview of architectural components:
mindmap root((GDK)) Commands Dependencies Tools: mise Platform: Brew/Apt/... Services Commands Repositories Settings Port management Resource sharing Config templates Runtime Runit Troubleshooting Diagnostics Reports Cell support Data management Sandbox Postgres upgrades
Environments
GDK and all its dependencies are usually installed directly on a user’s machine.
The exception to this are GDK-in-a-box and the unsupported minikube installation method, which is the spiritual predecessor to GDK-in-a-box.
Remote environments, such as via GitLab Workspaces or installation on a remote machine like a GCP VM, aren’t supported but technically possible.
Dependencies
GDK uses mise as tooling manager for tools like Ruby and Postgres. Despite this, GDK still expects subprojects to list their dependencies in a .tool-versions
file for historical reasons.
Platform dependencies that are required to compile dependencies, such as for Ruby gems with native extensions, are managed with Homebrew on macOS and the respective default package managed on Linux.
Directory structure
To use GDK, a user clones the GDK repository, either manually or with the help of the one-line installation. This directory contains all projects that GDK manages, except for system dependencies, such as Ruby or NGINX.
This repository path is often abbreviated as <gdk_root>
or $GDK_ROOT
. From here, GDK clones the GitLab repository to <gdk_root>/gitlab
. Likewise, other subprojects like gitaly
or gitlab-http-router
are cloned to this directory. The root directory also contains directories for persistent data, such as postgresql/data
, repositories/+gitaly
, and redis/dump.rdb
.
These directories are manually excluded from being tracked by Git in the .gitignore
file.
Doctor diagnostics
GDK has a list of health checks, called diagnostics, that looks for common problems affecting GDK installations, such as resource conflicts or a misconfigured system.
Diagnostics are defined in lib/gdk/diagnostic/
and automatically registered. Users run all diagnostics with gdk doctor
. Some failing diagnostics are auto-correctable by running gdk doctor --correct
.
Commands
GDK is available to users via the terminal with the gdk
command.
Commands are defined in lib/gdk/command/
and registered in lib/gdk/command.rb
.
To see an overview of all relevant commands, run gdk help
. These help text entries are generated dynamically from the command definitions.
GDK doesn’t provide any special flags or options like other command frameworks and instead leaves argument handling entirely to commands.
Ruby gem
The gdk
command is available to the user’s command line through the gitlab-development-kit
gem.
The code for the gem is located in gem/
. It is a thin wrapper around the GDK.main
function defined in lib/gdk.rb
. Similar to Git, it detects the <gdk_root>
path based on the .GDK_ROOT
file and allows using the gdk
command from any subdirectory within the root directory.
Services
Services are tightly coupled with the core code of GDK. A service in its minimal form is a command that is run by GDK using runit. Besides that, a service can also have a repository, configuration settings, and config templates. The repository might be shared with other services.
Users manage the service runtime by using GDK’s start
, stop
, restart
, status
, and kill
.
To add a new service, a service owner needs to:
Pick a unique service name, such as
my-service
,Create a Ruby service at
lib/gdk/services/my_service.rb
,Add a
gdk.yml
config setting tolib/gdk/config.rb
with at least the following:settings :my_service do bool(:enabled) { false } end
my_service.enabled
should befalse
, so users can choose to opt in to using the service. Only in rare exceptions should services be enabled by default. This keeps the base installation fast and easy to set up.(Optionally) add setup and update instructions at
support/makefiles/Makefile.my-service.mk
, and then add these tolib/tasks/{update,reconfigure}.rake
andlib/support/rake/{update,reconfigure}.rb
,If a repository is cloned, add the repository name (such as
/my_service
) to.gitignore
,(Optionally) create config templates in
support/templates/my_service/
,If there are templates, register config templates in
lib/gdk/task_helpers/config_tasks.rb
,Add a how-to documentation page at
doc/howto/my_service.md
, and(Optionally) add a troubleshooting page at
doc/troubleshooting/my_service.md
.
Some services might be mentioned in or have dedicated diagnostics. Services can also have a command like gdk psql
for Postgres and gdk bao
for OpenBao, though this is only recommended for commands that are frequently used by users or very cumbersome to set up manually.
Services, which are very complicated to set up, might also get a Rake task that guides users through the initial setup like setup_ai_gateway
.
Commands
Each service consists of a single command that spawns a process, which is managed by runit
.
Previously, service commands were registered in support/templates/Procfile.erb
. Some services, which we call legacy services, are still registered there. New services must be created as Ruby services like lib/gdk/services/vite.rb
.
Config management
Configurations are centrally managed as ERB template files in the support/templates/
directory. They are registered in lib/gdk/task_helpers/config_tasks.rb
.
Updates
When a user runs gdk update
to update GDK, all services that can be updated and are enabled should also be updated. Likewise, when a service is enabled for the first time, both gdk update
and gdk reconfigure
should set up the service.
The command steps to set up and update a service are defined in a service-specific Makefile like support/makefiles/Makefile.gitaly.mk
.
Because GDK is written in Ruby and we’re incrementally moving more auxiliary code to Ruby, these make tasks are defined as Rake tasks in lib/support/rake/{update,reconfigure}.rb
, which are executed in lib/tasks/{update,reconfigure}.rake
.
Cells support
In addition to a primary GitLab instance, GDK can also set up multiple other instances (aka. cells).
These instances are technically just other GDK installations with a reduced feature set.