doc/administration/gitaly/configure_gitaly.md
{{< details >}}
{{< /details >}}
Configure Gitaly in one of two ways:
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
/etc/gitlab/gitlab.rb and add or change the Gitaly settings. Refer to the
example Gitaly configuration file. The
settings in the example file must be converted into Ruby.{{< /tab >}}
{{< tab title="Helm chart (Kubernetes)" >}}
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
/home/git/gitaly/config.toml and add or change the Gitaly settings. Refer to the
example Gitaly configuration file.{{< /tab >}}
{{< /tabs >}}
The following configuration options are also available:
The token referred to throughout the Gitaly documentation is just an arbitrary password selected by the administrator. It is unrelated to tokens created for the GitLab API or other similar web API tokens.
By default, Gitaly is run on the same server as Gitaly clients and is configured as described previously. Single-server installations are best served by this default configuration used by:
However, Gitaly can be deployed to its own server, which can benefit GitLab installations that span multiple machines.
[!note] When configured to run on their own servers, Gitaly servers must be upgraded before Gitaly clients in your cluster.
The process for setting up Gitaly on its own server is:
[!note] Disk requirements apply to Gitaly nodes.
The following list depicts the network architecture of Gitaly:
/config/gitlab.yml contains a map from storage names to (Gitaly address, Gitaly token) pairs.storage name -> (Gitaly address, Gitaly token) map in /config/gitlab.yml is the single
source of truth for the Gitaly network topology.(Gitaly address, Gitaly token) corresponds to a Gitaly server.(Gitaly address, Gitaly token) pair as specified in /config/gitlab.yml.The following diagram illustrates communication between Gitaly servers and GitLab Rails showing the default ports for HTTP and HTTPs communication.
[!warning] Gitaly servers must not be exposed to the public internet as Gitaly network traffic is unencrypted by default. The use of firewall is highly recommended to restrict access to the Gitaly server. Another option is to use TLS.
In the following sections, we describe how to configure two Gitaly servers with secret token
abc123secret:
gitaly1.internal.gitaly2.internal.We assume your GitLab installation has three repository storages:
default.storage1.storage2.You can use as few as one server with one repository storage if desired.
Install Gitaly on each Gitaly server using either:
EXTERNAL_URL= value.To configure Gitaly servers, you must:
The git user must be able to read, write, and set permissions on the configured storage path.
To avoid downtime while rotating the Gitaly token, you can temporarily disable authentication using the gitaly['auth_transitioning'] setting. For more information, see
enable auth transitioning mode.
{{< history >}}
token_file introduced in GitLab 18.11.{{< /history >}}
Gitaly and GitLab use two shared secrets for authentication:
0600 or 0400.{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
To configure the Gitaly token, edit /etc/gitlab/gitlab.rb:
When using a token file:
gitaly['configuration'] = {
# ...
auth: {
# ...
token_file: '/etc/gitlab/gitaly_token',
},
}
When specifying the token directly:
gitaly['configuration'] = {
# ...
auth: {
# ...
token: 'abc123secret',
},
}
token and token_file are mutually exclusive.
Configure the GitLab Shell token in one of two ways:
Method 1 (recommended): copy /etc/gitlab/gitlab-secrets.json from the Gitaly client to the same path on the Gitaly
servers and any other Gitaly clients.
Method 2:
On all nodes running GitLab Rails, edit /etc/gitlab/gitlab.rb.
Replace GITLAB_SHELL_SECRET_TOKEN with the real secret:
GitLab 17.5 and later:
gitaly['gitlab_secret'] = 'GITLAB_SHELL_SECRET_TOKEN'
GitLab 17.4 and earlier:
gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
On all nodes running Gitaly, edit /etc/gitlab/gitlab.rb.
Replace GITLAB_SHELL_SECRET_TOKEN with the real secret:
GitLab 17.5 and later:
gitaly['gitlab_secret'] = 'GITLAB_SHELL_SECRET_TOKEN'
GitLab 17.4 and earlier:
gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
After those changes, reconfigure GitLab:
sudo gitlab-ctl reconfigure
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Copy /home/git/gitlab/.gitlab_shell_secret from the Gitaly client to the same path on the
Gitaly servers (and any other Gitaly clients).
On the Gitaly clients, edit /home/git/gitlab/config/gitlab.yml:
gitlab:
gitaly:
token: 'abc123secret'
Save the file and restart GitLab.
On the Gitaly servers, edit /home/git/gitaly/config.toml:
When using a token file:
[auth]
token_file = '/etc/gitaly/token'
When specifying the token directly:
[auth]
token = 'abc123secret'
token and token_file are mutually exclusive.
Save the file and restart GitLab.
{{< /tab >}}
{{< /tabs >}}
Configure Gitaly server.
Gitaly has some RPCs in which it makes a network call to itself using the address provided by the client (such as Rails or Sidekiq).
If Gitaly can't reach itself this way because of your network configuration (for example, Gitaly is behind a load balancer that doesn't support hairpinning connections):
/etc/hosts file of the Gitaly server.127.0.0.1 gitaly.example.com
or <local-ip> gitaly.example.com.{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb:
# Avoid running unnecessary services on the Gitaly server
postgresql['enable'] = false
redis['enable'] = false
nginx['enable'] = false
puma['enable'] = false
sidekiq['enable'] = false
gitlab_workhorse['enable'] = false
gitlab_exporter['enable'] = false
gitlab_kas['enable'] = false
# If you run a separate monitoring node you can disable these services
prometheus['enable'] = false
alertmanager['enable'] = false
# If you don't run a separate monitoring node you can
# enable Prometheus access & disable these extra services.
# This makes Prometheus listen on all interfaces. You must use firewalls to restrict access to this address/port.
# prometheus['listen_address'] = '0.0.0.0:9090'
# prometheus['monitor_kubernetes'] = false
# If you don't want to run monitoring services uncomment the following (not recommended)
# node_exporter['enable'] = false
# Prevent database connections during 'gitlab-ctl reconfigure'
gitlab_rails['auto_migrate'] = false
# Configure the gitlab-shell API callback URL. Without this, `git push` will
# fail. This can be your 'front door' GitLab URL or an internal load
# balancer.
# Don't forget to copy `/etc/gitlab/gitlab-secrets.json` from Gitaly client to Gitaly server.
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
gitaly['configuration'] = {
# ...
#
# Make Gitaly accept connections on all network interfaces. You must use
# firewalls to restrict access to this address/port.
# Comment out following line if you only want to support TLS connections
listen_addr: '0.0.0.0:8075',
auth: {
# ...
#
# Authentication token to ensure only authorized servers can communicate with
# Gitaly server
token: 'AUTH_TOKEN',
},
}
Append the following to /etc/gitlab/gitlab.rb for each respective Gitaly server:
On gitaly1.internal:
gitaly['configuration'] = {
# ...
storage: [
{
name: 'default',
path: '/var/opt/gitlab/git-data/repositories',
},
{
name: 'storage1',
path: '/mnt/gitlab/git-data/repositories',
},
],
}
On gitaly2.internal:
gitaly['configuration'] = {
# ...
storage: [
{
name: 'storage2',
path: '/srv/gitlab/git-data/repositories',
},
],
}
Save the file and reconfigure GitLab.
Confirm that Gitaly can perform callbacks to the GitLab internal API:
sudo -u git -- /opt/gitlab/embedded/bin/gitaly check /var/opt/gitlab/gitaly/config.toml
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /home/git/gitaly/config.toml:
listen_addr = '0.0.0.0:8075'
runtime_dir = '/var/opt/gitlab/gitaly'
[logging]
format = 'json'
level = 'info'
dir = '/var/log/gitaly'
Append the following to /home/git/gitaly/config.toml for each respective Gitaly server:
On gitaly1.internal:
[[storage]]
name = 'default'
path = '/var/opt/gitlab/git-data/repositories'
[[storage]]
name = 'storage1'
path = '/mnt/gitlab/git-data/repositories'
On gitaly2.internal:
[[storage]]
name = 'storage2'
path = '/srv/gitlab/git-data/repositories'
Edit /home/git/gitlab-shell/config.yml:
gitlab_url: https://gitlab.example.com
Save the files and restart GitLab.
Confirm that Gitaly can perform callbacks to the GitLab internal API:
sudo -u git -- /opt/gitlab/embedded/bin/gitaly check /var/opt/gitlab/gitaly/config.toml
{{< /tab >}}
{{< /tabs >}}
[!warning] If directly copying repository data from a GitLab server to Gitaly, ensure that the metadata file, default path
/var/opt/gitlab/git-data/repositories/.gitaly-metadata, is not included in the transfer. Copying this file causes GitLab to use the direct disk access to repositories hosted on the Gitaly server, leading toError creating pipelineandCommit not founderrors, or stale data.
As the final step, you must update Gitaly clients to switch from using local Gitaly service to use the Gitaly servers you just configured.
[!note] GitLab requires a
defaultrepository storage to be configured. Read more about this limitation.
This can be risky because anything that prevents your Gitaly clients from reaching the Gitaly servers causes all Gitaly requests to fail. For example, any sort of network, firewall, or name resolution problems.
Gitaly makes the following assumptions:
gitaly1.internal Gitaly server can be reached at gitaly1.internal:8075 from your Gitaly
clients, and that Gitaly server can read, write, and set permissions on /var/opt/gitlab/git-data and
/mnt/gitlab/git-data.gitaly2.internal Gitaly server can be reached at gitaly2.internal:8075 from your Gitaly
clients, and that Gitaly server can read, write, and set permissions on /srv/gitlab/git-data.gitaly1.internal and gitaly2.internal Gitaly servers can reach each other.You can't define Gitaly servers with some as a local Gitaly server
(without gitaly_address) and some as remote
server (with gitaly_address) unless you use
mixed configuration.
Configure Gitaly clients in one of two ways. These instructions are for unencrypted connections but you can also enable TLS support:
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb:
# Use the same token value configured on all Gitaly servers
gitlab_rails['gitaly_token'] = '<AUTH_TOKEN>'
gitlab_rails['repositories_storages'] = {
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
'storage1' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
}
Alternatively, if each Gitaly server is configured to use a different authentication token:
gitlab_rails['repositories_storages'] = {
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075', 'gitaly_token' => '<AUTH_TOKEN_1>' },
'storage1' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075', 'gitaly_token' => '<AUTH_TOKEN_1>' },
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075', 'gitaly_token' => '<AUTH_TOKEN_2>' },
}
Save the file and reconfigure GitLab.
Run sudo gitlab-rake gitlab:gitaly:check on the Gitaly client (for example, the
Rails application) to confirm it can connect to Gitaly servers.
Tail the logs to see the requests:
sudo gitlab-ctl tail gitaly
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /home/git/gitlab/config/gitlab.yml:
gitlab:
repositories:
storages:
default:
gitaly_address: tcp://gitaly1.internal:8075
gitaly_token: AUTH_TOKEN_1
storage1:
gitaly_address: tcp://gitaly1.internal:8075
gitaly_token: AUTH_TOKEN_1
storage2:
gitaly_address: tcp://gitaly2.internal:8075
gitaly_token: AUTH_TOKEN_2
Save the file and restart GitLab.
Run sudo -u git -H bundle exec rake gitlab:gitaly:check RAILS_ENV=production to confirm the
Gitaly client can connect to Gitaly servers.
Tail the logs to see the requests:
tail -f /home/git/gitlab/log/gitaly.log
{{< /tab >}}
{{< /tabs >}}
When you tail the Gitaly logs on your Gitaly server, you should see requests coming in. One sure way to trigger a Gitaly request is to clone a repository from GitLab over HTTP or HTTPS.
[!warning] If you have server hooks configured, either per repository or globally, you must move these to the Gitaly servers. If you have multiple Gitaly servers, copy your server hooks to all Gitaly servers.
GitLab can reside on the same server as one of many Gitaly servers, but doesn't support configuration that mixes local and remote configuration. The following setup is incorrect, because:
storage1 is assigned a Unix socket for gitaly_address which is
invalid for some of the Gitaly servers.gitlab_rails['repositories_storages'] = {
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
'storage1' => { 'gitaly_address' => 'unix:/var/opt/gitlab/gitaly/gitaly.socket' },
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
}
To combine local and remote Gitaly servers, use an external address for the local Gitaly server. For example:
gitlab_rails['repositories_storages'] = {
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
# Address of the GitLab server that also has Gitaly running on it
'storage1' => { 'gitaly_address' => 'tcp://gitlab.internal:8075' },
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
}
gitaly['configuration'] = {
# ...
#
# Make Gitaly accept connections on all network interfaces
listen_addr: '0.0.0.0:8075',
# Or for TLS
tls_listen_addr: '0.0.0.0:9999',
tls: {
certificate_path: '/etc/gitlab/ssl/cert.pem',
key_path: '/etc/gitlab/ssl/key.pem',
},
storage: [
{
name: 'storage1',
path: '/mnt/gitlab/git-data/repositories',
},
],
}
path can be included only for storage shards on the local Gitaly server.
If it's excluded, default Git storage directory is used for that storage shard.
When adding Gitaly servers to an environment, you might want to replace the original default Gitaly service. However, you can't
reconfigure the GitLab application servers to remove the default storage because GitLab requires a storage called default.
Read more about this limitation.
To work around the limitation:
default. The storage location must have a
Gitaly service running and available to avoid issues with database migrations that expect working storages.default to a weight of zero
to prevent repositories being stored there.If you run Gitaly as a remote service, consider disabling the local Gitaly service that runs on your GitLab server by default, and run it only where required.
Disabling Gitaly on the GitLab instance makes sense only when you run GitLab in a custom cluster configuration, where Gitaly runs on a separate machine from the GitLab instance. Disabling Gitaly on all machines in the cluster is not a valid configuration (some machines much act as Gitaly servers).
Disable Gitaly on a GitLab server in one of two ways:
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb:
gitaly['enable'] = false
Save the file and reconfigure GitLab.
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /etc/default/gitlab:
gitaly_enabled=false
Save the file and restart GitLab.
{{< /tab >}}
{{< /tabs >}}
You can change the interface that Gitaly listens on. You might change the listening interface when you have an external service that must communicate with Gitaly. For example, exact code search that uses Zoekt when exact code search is enabled but the actual service is running on another server.
The gitaly_token must be a secret string because gitaly_token is used for authentication with the Gitaly service.
This secret can be generated with openssl rand -base64 24 to generate a random 32 character string.
For example, to change the Gitaly listening interface to 0.0.0.0:8075:
# /etc/gitlab/gitlab.rb
# Add a shared token for Gitaly authentication
gitlab_shell['secret_token'] = 'your_secure_token_here'
gitlab_rails['gitaly_token'] = 'your_secure_token_here'
# Gitaly configuration
gitaly['gitlab_secret'] = 'your_secure_token_here'
gitaly['configuration'] = {
listen_addr: '0.0.0.0:8075',
auth: {
token: 'your_secure_token_here',
},
storage: [
{
name: 'default',
path: '/var/opt/gitlab/git-data/repositories',
},
]
}
# Tell Rails where to find Gitaly
gitlab_rails['repositories_storages'] = {
'default' => { 'gitaly_address' => 'tcp://ip_address_here:8075' },
}
# Internal API URL (important for multi-server setups)
gitlab_rails['internal_api_url'] = 'http://ip_address_here'
For information on control groups, see Cgroups.
The way data is stored in the object database of a Git repository can become inefficient over time, which slows down Git operations. You can schedule Gitaly to run a daily background task with a maximum duration to clean up these items and improve performance.
[!warning] Background repository optimization can place significant load on the host while running. Make sure to schedule this during off-peak hours and keep the duration short (for example, 30-60 minutes).
Configure background repository optimization in one of two ways:
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb and add:
gitaly['configuration'] = {
# ...
daily_maintenance: {
# ...
start_hour: 4,
start_minute: 30,
duration: '30m',
storages: ['default'],
},
}
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /home/git/gitaly/config.toml and add:
[daily_maintenance]
start_hour = 4
start_minute = 30
duration = '30m'
storages = ["default"]
{{< /tab >}}
{{< /tabs >}}
Rotating credentials in a production environment often requires downtime, causes outages, or both.
However, you can rotate Gitaly credentials without a service interruption. Rotating a Gitaly authentication token involves:
This procedure also works if you are running GitLab on a single server. In that case, the Gitaly server and the Gitaly client refer to the same machine.
Before rotating a Gitaly authentication token, verify that you can monitor the authentication behavior of your GitLab installation using Prometheus.
You can then continue the rest of the procedure.
Temporarily disable Gitaly authentication on the Gitaly servers by putting them into auth transitioning mode as follows:
# in /etc/gitlab/gitlab.rb
gitaly['configuration'] = {
# ...
auth: {
# ...
transitioning: true,
},
}
After you have made this change, your Prometheus query should return something like:
{enforced="false",status="would be ok"} 4424.985419441742
Because enforced="false", it is safe to start rolling out the new token.
To update to a new Gitaly authentication token, on each Gitaly client and Gitaly server:
Update the configuration:
# in /etc/gitlab/gitlab.rb
gitaly['configuration'] = {
# ...
auth: {
# ...
token: '<new secret token>',
},
}
If you are using token_file, update the contents of the referenced file with the new token.
No configuration change is needed. The token file is read on startup.
Restart Gitaly:
gitlab-ctl restart gitaly
If you run your Prometheus query while this change is
being rolled out, you see non-zero values for the enforced="false",status="denied" counter.
After the new token is set, and all services involved have been restarted, you will temporarily see a mix of:
status="would be ok".status="denied".After the new token is picked up by all Gitaly clients and Gitaly servers, the
only non-zero rate should be enforced="false",status="would be ok".
To re-enable Gitaly authentication, disable auth transitioning mode. Update the configuration on your Gitaly servers as follows:
# in /etc/gitlab/gitlab.rb
gitaly['configuration'] = {
# ...
auth: {
# ...
transitioning: false,
},
}
[!warning] Without completing this step, you have no Gitaly authentication.
Refresh your Prometheus query. You should now see a similar result as you did at the start. For example:
{enforced="true",status="ok"} 4424.985419441742
enforced="true" means that authentication is being enforced.
{{< details >}}
{{< /details >}}
Gitaly, the service that provides storage for Git repositories, can be configured to cache a short rolling window of Git fetch responses. This can reduce server load when your server receives lots of CI fetch traffic.
The pack-objects cache wraps git pack-objects, an internal part of
Git that gets invoked indirectly by using the PostUploadPack and
SSHUploadPack Gitaly RPCs. Gitaly runs PostUploadPack when a
user does a Git fetch by using HTTP, or SSHUploadPack when a
user does a Git fetch by using SSH.
When the cache is enabled, anything that uses PostUploadPack or SSHUploadPack can
benefit from it. It is independent of and unaffected by:
The strength of this cache is its ability to deduplicate concurrent identical fetches. It:
The pack-objects cache is a local cache. It:
Using local files has the benefit that the operating system may automatically keep parts of the pack-objects cache files in RAM, making it faster.
Because the pack-objects cache can lead to a significant increase in disk write IO, it is off by default.
These configuration settings are available for the pack-objects cache. Each setting is discussed in greater detail below.
| Setting | Default | Description |
|---|---|---|
enabled | false | Turns on the cache. When off, Gitaly runs a dedicated git pack-objects process for each request. |
dir | <PATH TO FIRST STORAGE>/+gitaly/PackObjectsCache | Local directory where cache files get stored. |
max_age | 5m (5 minutes) | Cache entries older than this get evicted and removed from disk. |
min_occurrences | 1 | Minimum times a key must occur before a cache entry is created. |
In /etc/gitlab/gitlab.rb, set:
gitaly['configuration'] = {
# ...
pack_objects_cache: {
enabled: true,
# The default settings for "dir", "max_age" and "min_occurences" should be fine.
# If you want to customize these, see details below.
},
}
enabled defaults to falseThe cache is disabled by default because in some cases, it can create an extreme increase in the number of bytes written to disk. On GitLab.com, we have verified that our repository storage disks can handle this extra workload, but we felt we cannot assume this is true everywhere.
dirThe cache needs a directory to store its files in. This directory should be:
[!warning] All existing data in the specified directory will be removed. Take care not to use a directory with existing data.
By default, the cache storage directory is set to a subdirectory of the first Gitaly storage defined in the configuration file.
Multiple Gitaly processes can use the same directory for cache storage. Each Gitaly process uses a unique random string as part of the cache filenames it creates. This means:
While the default directory puts the cache files in the same file system as your repository data, this is not requirement. You can put the cache files on a different file system if that works better for your infrastructure.
The amount of IO bandwidth required from the disk depends on:
You can use the gitaly_pack_objects_generated_bytes_total metric as a pessimistic estimate,
pretending your cache hit ratio is 0%.
The amount of space required depends on:
max_age cache eviction window.If your users pull 100 MB/s and you use a 5 minute window, then on average you have
5*60*100 MB = 30 GB of data in your cache directory. This average is an expected average, not
a guarantee. Peak size may exceed this average.
max_ageThe max_age configuration setting lets you control the chance of a
cache hit and the average amount of storage used by cache files.
Entries older than max_age get deleted from the disk.
Eviction does not interfere with ongoing requests. It is OK for max_age to be less than the time it takes to do a
fetch over a slow connection because Unix filesystems do not truly delete a file until all processes that are reading
the deleted file have closed it.
min_occurrencesThe min_occurrences setting controls how often an identical request
must occur before we create a new cache entry. The default value is 1,
meaning that unique requests do not get written into the cache.
If you:
You should set min_occurrences to 1. On GitLab.com,
going from 0 to 1 saved us 50% cache disk space while barely affecting
the cache hit rate.
{{< history >}}
{{< /history >}}
You can observe the cache using Prometheus metrics and log fields.
Gitaly exports the following Prometheus metrics for monitoring the pack-objects cache:
| Metric | Type | Description |
|---|---|---|
gitaly_pack_objects_served_bytes_total | Counter | Total number of bytes of git-pack-objects data served to clients |
gitaly_pack_objects_cache_lookups_total | Counter | Number of cache lookups, with a result label indicating hit or miss |
gitaly_pack_objects_generated_bytes_total | Counter | Total number of bytes generated by running git-pack-objects |
Example Prometheus queries:
Cache hit rate:
sum(rate(gitaly_pack_objects_cache_lookups_total{result="hit"}[5m])) /
sum(rate(gitaly_pack_objects_cache_lookups_total[5m]))
Bytes served from cache per second:
rate(gitaly_pack_objects_served_bytes_total[5m])
Bytes generated (cache misses) per second:
rate(gitaly_pack_objects_generated_bytes_total[5m])
Cache efficiency (bytes served vs bytes generated):
rate(gitaly_pack_objects_served_bytes_total[5m]) /
rate(gitaly_pack_objects_generated_bytes_total[5m])
These logs are part of the gRPC logs and can be discovered when a call is executed.
| Field | Description |
|---|---|
pack_objects_cache.hit | Indicates whether the current pack-objects cache was hit (true or false) |
pack_objects_cache.key | Cache key used for the pack-objects cache |
pack_objects_cache.generated_bytes | Size (in bytes) of the new cache being written |
pack_objects_cache.served_bytes | Size (in bytes) of the cache being served |
pack_objects.compression_statistics | Statistics regarding pack-objects generation |
pack_objects.enumerate_objects_ms | Total time (in ms) spent enumerating objects sent by clients |
pack_objects.prepare_pack_ms | Total time (in ms) spent preparing the packfile before sending it back to the client |
pack_objects.write_pack_file_ms | Total time (in ms) spent sending back the packfile to the client. Highly dependent on the client's internet connection |
pack_objects.written_object_count | Total number of objects Gitaly sends back to the client |
In the case of a:
pack_objects_cache.generated_bytes and pack_objects_cache.served_bytes message. Gitaly also logs some more detailed statistics of
pack-object generation.pack_objects_cache.served_bytes message.Example:
{
"bytes":26186490,
"correlation_id":"01F1MY8JXC3FZN14JBG1H42G9F",
"grpc.meta.deadline_type":"none",
"grpc.method":"PackObjectsHook",
"grpc.request.fullMethod":"/gitaly.HookService/PackObjectsHook",
"grpc.request.glProjectPath":"root/gitlab-workhorse",
"grpc.request.glRepository":"project-2",
"grpc.request.repoPath":"@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35.git",
"grpc.request.repoStorage":"default",
"grpc.request.topLevelGroup":"@hashed",
"grpc.service":"gitaly.HookService",
"grpc.start_time":"2021-03-25T14:57:52.747Z",
"level":"info",
"msg":"finished unary call with code OK",
"peer.address":"@",
"pid":20961,
"span.kind":"server",
"system":"grpc",
"time":"2021-03-25T14:57:53.543Z",
"pack_objects.compression_statistics": "Total 145991 (delta 68), reused 6 (delta 2), pack-reused 145911",
"pack_objects.enumerate_objects_ms": 170,
"pack_objects.prepare_pack_ms": 7,
"pack_objects.write_pack_file_ms": 786,
"pack_objects.written_object_count": 145991,
"pack_objects_cache.generated_bytes": 49533030,
"pack_objects_cache.hit": "false",
"pack_objects_cache.key": "123456789",
"pack_objects_cache.served_bytes": 49533030,
"peer.address": "127.0.0.1",
"pid": 8813,
}
cat-file cacheA lot of Gitaly RPCs need to look up Git objects from repositories.
Most of the time we use git cat-file --batch processes for that. For
better performance, Gitaly can re-use these git cat-file processes
across RPC calls. Previously used processes are kept around in a
git cat-file cache.
To control how much system resources this uses, we have a maximum number of
cat-file processes that can go into the cache.
The default limit is 100 cat-files, which constitute a pair of
git cat-file --batch and git cat-file --batch-check processes. If
you see errors about "too many open files", or an
inability to create new processes, you may want to lower this limit.
Ideally, the number should be large enough to handle standard traffic. If you raise the limit, you should measure the cache hit ratio before and after. If the hit ratio does not improve, the higher limit is probably not making a meaningful difference. Here is an example Prometheus query to see the hit rate:
sum(rate(gitaly_catfile_cache_total{type="hit"}[5m])) / sum(rate(gitaly_catfile_cache_total{type=~"(hit)|(miss)"}[5m]))
Configure the cat-file cache in the Gitaly configuration file.
{{< history >}}
gitaly_gpg_signing. Disabled by default.rotated_signing_keys option introduced in GitLab 16.3.{{< /history >}}
[!flag] On GitLab Self-Managed, by default this feature is available. To hide the feature, an administrator can disable the feature flag named
gitaly_gpg_signing. On GitLab.com, this feature is not available. On GitLab Dedicated, this feature is available.
By default, Gitaly doesn't sign commits made using GitLab UI. For example, commits made using:
When you enable commit signing in Gitaly:
committer_email and committer_name. For example, on GitLab.com these configuration options are set to [email protected] and GitLab.rotated_signing_keys is a list of keys to use for verification only. Gitaly tries to verify a web commit using the configured signing_key, and then uses
the rotated keys one by one until it succeeds. Set the rotated_signing_keys option when either:
Configure Gitaly to sign commits made with the GitLab UI in one of two ways:
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Create a GPG key and export it, or create an SSH key. For optimal performance, use an EdDSA key.
Export GPG key:
gpg --export-secret-keys <ID> > signing_key.gpg
Or create an SSH key (with no passphrase):
ssh-keygen -t ed25519 -f signing_key.ssh
On the Gitaly nodes, copy the key into /etc/gitlab/gitaly/ and ensure the git user has permissions to read the file.
Edit /etc/gitlab/gitlab.rb and configure gitaly['git']['signing_key']:
gitaly['configuration'] = {
# ...
git: {
# ...
committer_name: 'Your Instance',
committer_email: '[email protected]',
signing_key: '/etc/gitlab/gitaly/signing_key.gpg',
rotated_signing_keys: ['/etc/gitlab/gitaly/previous_signing_key.gpg'],
# ...
},
}
Save the file and reconfigure GitLab.
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Create a GPG key and export it, or create an SSH key. For optimal performance, use an EdDSA key.
Export GPG key:
gpg --export-secret-keys <ID> > signing_key.gpg
Or create an SSH key (with no passphrase):
ssh-keygen -t ed25519 -f signing_key.ssh
On the Gitaly nodes, copy the key into /etc/gitlab.
Edit /home/git/gitaly/config.toml and configure signing_key:
[git]
committer_name = "Your Instance"
committer_email = "[email protected]"
signing_key = "/etc/gitlab/gitaly/signing_key.gpg"
rotated_signing_keys = ["/etc/gitlab/gitaly/previous_signing_key.gpg"]
Save the file and restart GitLab.
{{< /tab >}}
{{< /tabs >}}
Gitaly does not read the system or user level Git configuration files. To provide custom Git
configuration on the Gitaly server, use the git.config setting.
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb:
gitaly['configuration'] = {
# ...
git: {
# ...
config: [
{ key: "fsck.badDate", value: "ignore" },
...
],
},
}
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /home/git/gitaly/config.toml:
[[git.config]]
key = "fsck.badDate"
value = "ignore"
{{< /tab >}}
{{< /tabs >}}
Gitaly sets the following Git configuration values, which cannot be overridden using
the git.config setting:
advice.fetchShowForcedUpdatesattr.treebundle.heuristicbundle.modebundle.versioncore.alternateRefsCommandcore.autocrlfcore.bigFileThresholdcore.filesRefLockTimeoutcore.fsynccore.fsyncMethodcore.hooksPathcore.packedRefsTimeoutcore.useReplaceRefsdiff.noprefixfetch.fsck.badTimezonefetch.fsck.missingSpaceBeforeDatefetch.fsck.zeroPaddedFilemodefetch.fsckObjectsfetch.negotiationAlgorithmfetch.recurseSubmodulesfetch.writeCommitGraphfsck.badTimezonefsck.missingSpaceBeforeDatefsck.zeroPaddedFilemodegc.autogrep.threadshttp.<url>.extraHeaderhttp.curloptResolvehttp.extraHeaderhttp.followRedirectsinit.defaultBranchinit.templateDirmaintenance.autopack.allowPackReusepack.islandpack.islandCorepack.threadspack.windowMemorypack.writeBitmapLookupTablepack.writeReverseIndexreceive.advertisePushOptionsreceive.autogcreceive.fsck.badTimezonereceive.fsck.missingSpaceBeforeDatereceive.fsck.zeroPaddedFilemodereceive.hideRefsreceive.procReceiveRefsremote.inmemory.fetchremote.inmemory.urlremote.origin.fetchremote.origin.urlrepack.updateServerInforepack.writeBitmapstransfer.bundleURItransfer.fsckObjectsuploadpack.advertiseBundleURIsuploadpack.allowAnySHA1InWantuploadpack.allowFilteruploadpack.hideRefsYou can generate parts of the Gitaly configuration using an external command. You might do this:
To generate configuration using an external command, you must provide a script that dumps the desired configuration of the Gitaly node in JSON format to its standard output.
For example, the following command configures the HTTP password used to connect to the GitLab internal API using an AWS secret:
#!/usr/bin/env ruby
require 'json'
JSON.generate({"gitlab": {"http_settings": {"password": `aws get-secret-value --secret-id ...`}}})
You must then make the script path known to Gitaly in one of two ways:
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb and configure the config_command:
gitaly['configuration'] = {
config_command: '/path/to/config_command',
}
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /home/git/gitaly/config.toml and configure config_command:
config_command = "/path/to/config_command"
{{< /tab >}}
{{< /tabs >}}
After configuration, Gitaly executes the command on startup and parses its standard output as JSON. The resulting configuration is then merged back into the other Gitaly configuration.
Gitaly fails to start up if either:
{{< history >}}
{{< /history >}}
Repository backups can be configured so that the Gitaly node that hosts each repository is responsible for creating the backup and streaming it to object storage. This helps reduce the network resources required to create and restore a backup.
Each Gitaly node must be configured to connect to object storage for backups.
After configuring server-side backups, you can create a server-side repository backup.
How you configure Azure Blob storage for backups depends on the type of installation you have. For self-compiled installations, you must set
the AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_KEY environment variables outside of GitLab.
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb and configure the go_cloud_url:
gitaly['env'] = {
'AZURE_STORAGE_ACCOUNT' => 'azure_storage_account',
'AZURE_STORAGE_KEY' => 'azure_storage_key' # or 'AZURE_STORAGE_SAS_TOKEN'
}
gitaly['configuration'] = {
backup: {
go_cloud_url: 'azblob://<bucket>'
}
}
{{< /tab >}}
{{< tab title="Helm chart (Kubernetes)" >}}
For Helm-based deployments, see the server-side backup documentation for Gitaly chart.
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /home/git/gitaly/config.toml and configure go_cloud_url:
[backup]
go_cloud_url = "azblob://<bucket>"
{{< /tab >}}
{{< /tabs >}}
Google Cloud storage (GCP) authenticates using Application Default Credentials. Set up Application Default Credentials on each Gitaly server using either:
gcloud auth application-default login command.GOOGLE_APPLICATION_CREDENTIALS environment variable. For self-compiled installations, set the environment
variable outside of GitLab.For more information, see Application Default Credentials.
The destination bucket is configured using the go_cloud_url option.
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb and configure the go_cloud_url:
gitaly['env'] = {
'GOOGLE_APPLICATION_CREDENTIALS' => '/path/to/service.json'
}
gitaly['configuration'] = {
backup: {
go_cloud_url: 'gs://<bucket>'
}
}
{{< /tab >}}
{{< tab title="Helm chart (Kubernetes)" >}}
For Helm-based deployments, see the server-side backup documentation for Gitaly chart.
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /home/git/gitaly/config.toml and configure go_cloud_url:
[backup]
go_cloud_url = "gs://<bucket>"
{{< /tab >}}
{{< /tabs >}}
To configure S3 storage authentication:
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables. For self-compiled installations, set the environment
variables outside of GitLab.For more information, see AWS Session documentation.
The destination bucket and region are configured using the go_cloud_url option.
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb and configure the go_cloud_url:
gitaly['env'] = {
'AWS_ACCESS_KEY_ID' => 'aws_access_key_id',
'AWS_SECRET_ACCESS_KEY' => 'aws_secret_access_key'
}
gitaly['configuration'] = {
backup: {
go_cloud_url: 's3://<bucket>?region=us-west-1'
}
}
{{< /tab >}}
{{< tab title="Helm chart (Kubernetes)" >}}
For Helm-based deployments, see the server-side backup documentation for Gitaly chart.
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /home/git/gitaly/config.toml and configure go_cloud_url:
[backup]
go_cloud_url = "s3://<bucket>?region=us-west-1"
{{< /tab >}}
{{< /tabs >}}
S3-compatible servers are configured similarly to S3 with the addition of the endpoint parameter.
The following parameters are supported:
region: The AWS region.endpoint: The endpoint URL.disabledSSL: A value of true disables SSL.s3ForcePathStyle: A value of true forces path-style addressing.{{< tabs >}}
{{< tab title="Helm chart (Kubernetes)" >}}
For Helm-based deployments, see the server-side backup documentation for Gitaly chart.
{{< /tab >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb and configure the go_cloud_url:
gitaly['env'] = {
'AWS_ACCESS_KEY_ID' => '<your_access_key_id>',
'AWS_SECRET_ACCESS_KEY' => '<your_secret_access_key>'
}
gitaly['configuration'] = {
backup: {
go_cloud_url: 's3://<bucket>?region=us-east-1&endpoint=s3.example.com:9000&disableSSL=true&s3ForcePathStyle=true'
}
}
{{< /tab >}}
{{< tab title="Self-compiled (source)" >}}
Edit /home/git/gitaly/config.toml and configure go_cloud_url:
[backup]
go_cloud_url = "s3://<bucket>?region=us-east-1&endpoint=s3.example.com:9000&disableSSL=true&s3ForcePathStyle=true"
{{< /tab >}}
{{< /tabs >}}