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:

  1. Pick a unique service name, such as my-service,

  2. Create a Ruby service at lib/gdk/services/my_service.rb,

  3. Add a gdk.yml config setting to lib/gdk/config.rb with at least the following:

    settings :my_service do  bool(:enabled) { false } end

    my_service.enabled should be false, 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.

  4. (Optionally) add setup and update instructions at support/makefiles/Makefile.my-service.mk, and then add these to lib/tasks/{update,reconfigure}.rake and lib/support/rake/{update,reconfigure}.rb,

  5. If a repository is cloned, add the repository name (such as /my_service) to .gitignore,

  6. (Optionally) create config templates in support/templates/my_service/,

  7. If there are templates, register config templates in lib/gdk/task_helpers/config_tasks.rb,

  8. Add a how-to documentation page at doc/howto/my_service.md, and

  9. (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.

Last updated on