Rails execution¶
Some GitLab settings have no API. The Rails backend reaches them by running code on the instance — which is why it is never chosen for you.
This executes code on your GitLab instance
The Rails backend stages a script on the GitLab host and runs
gitlab-rails runner. Enable it deliberately, scope its credentials
tightly, and prefer the API transports for anything they can serve.
When you need it¶
Only when a resource you want to manage is capable of rails and nothing else.
The capability matrix records which resources
those are.
If a resource is API-capable, it stays on its API transport even with rails
in your preference — adding Rails does not migrate work onto it.
Enabling it¶
Rails is not in the default preference. Add it:
all pairs naturally with compatible mode: you are usually reaching for
Rails because you want maximum surface, and a skip is more useful than a
failure in that situation.
How a run works¶
- Stage the role-owned bulk executor (
files/apply_settings.rb) and one JSON document of pre-planned operations onto the target. - Invoke
gitlab-rails runnerexactly once per apply — one Rails boot regardless of how many operations are in the document. - Remove the staged directory in an
alwaysblock.
Staged directories are mode 0700.
The Ruby executor is a deliberately dumb dispatcher over the same operations the REST backend reconciles. All normalization lives controller-side in one implementation, so the two backends cannot drift apart in behaviour. See ADR-0003.
One boot per apply is why Rails is the structurally fast path for bulk configuration — a Rails boot costs seconds, and the role pays it once rather than per setting.
Strategies¶
Set rails_strategy on the target.
=== "kubernetes_toolbox (default)"
Executes through `kubernetes.core` modules against the GitLab chart's
toolbox pod.
```yaml
gitlab_settings_target:
url: https://gitlab.example.com
auth:
type: personal_access_token
token: "{{ vault_gitlab_token }}"
rails_strategy: kubernetes_toolbox
kubernetes:
context: gitlab-lab
namespace: gitlab
toolbox_selector: app=toolbox,release=gitlab
```
| Field | Purpose |
|---|---|
| `kubeconfig` | Kubeconfig file. Omit to use the environment default. |
| `context` | Kubeconfig context. Omit to use the current context. |
| `namespace` | Namespace of the GitLab chart deployment. Default `gitlab`. |
| `container` | Toolbox container name. Default `toolbox`. |
| `toolbox_selector` | **Required.** Release-specific label selector locating exactly one toolbox pod. |
The role requires exactly one Running, Ready, non-terminating toolbox pod.
Zero or several is an error, not a pick-one situation.
=== "ssh_omnibus"
Executes over SSH against an Omnibus host in your inventory.
```yaml
gitlab_settings_target:
url: https://gitlab.example.com
auth:
type: personal_access_token
token: "{{ vault_gitlab_token }}"
rails_strategy: ssh_omnibus
```
```yaml
gitlab_settings_rails_host: gitlab-primary
gitlab_settings_rails_become: true
```
`gitlab_settings_rails_host` is the inventory hostname of the Omnibus host
and is required for this strategy. SSH connectivity, credentials, jump
hosts, and host keys belong to that host's ordinary inventory
configuration — the role does not reimplement them.
`gitlab_settings_rails_become` escalates privileges to run `gitlab-rails`.
It defaults to `true` because that is what the command normally requires.
Timeouts¶
Covers the whole staged execution, including the Rails boot. Raise it for very large documents rather than splitting the apply — one boot for a big document still beats several boots for small ones.
Check mode¶
Rails cannot prove drift without booting Rails, which is a real action on the instance. The role will not pretend otherwise:
| Mode | --check behaviour |
|---|---|
strict |
The Rails partition fails the run. |
compatible |
Each Rails operation is recorded as an explicit structured skip. |
If you need a meaningful dry run across a mixed surface, use compatible and
read the coverage manifest: the API operations report real drift, and the Rails
operations are listed as skipped rather than silently assumed clean.
Security boundary¶
A label selector is not authorization
For kubernetes_toolbox, use a dedicated Kubernetes principal limited to
pod get/list and pod-exec creation in the GitLab namespace. Isolate
that namespace from principals that could create or relabel a pod to
impersonate the selected toolbox workload — otherwise the selector can be
made to point at something you did not intend.
For ssh_omnibus, the boundary is the SSH principal and its become rights on
the Omnibus host. Both strategies run role-owned code, not code assembled from
your settings, but they run it with real privilege.
Related¶
- Backends and transports — how Rails is selected, and what happens when its channel is unavailable
- Reconciling settings — check mode and coverage across a mixed surface
- The GitLab target — every
rails_strategyandkubernetesfield - Execution controls — the
gitlab_settings_rails_*variables - ADR-0002 and ADR-0003 — why the Rails path exists and why it batches