Object Storage¶
GitLab uses S3-compatible object storage for nearly all persistent data (git LFS, CI artifacts, uploads, packages, registry, etc.). The operator consumes an hq-provided Secret that contains both the S3 connection parameters and a per-bucket mapping.
The S3 credentials Secret¶
hq creates the RGW user and all required buckets, then writes a single Secret in the instance namespace. The operator reads this Secret and validates that all required bucket-class keys are present.
apiVersion: v1
kind: Secret
metadata:
name: my-gitlab-s3-credentials
namespace: my-gitlab
stringData:
accessKey: <rgw-access-key>
secretKey: <rgw-secret-key>
endpoint: https://rgw.bnerd.com
region: default
# One key per GitLab storage class:
bucket.registry: my-gitlab-registry
bucket.lfs: my-gitlab-lfs
bucket.artifacts: my-gitlab-artifacts
bucket.uploads: my-gitlab-uploads
bucket.packages: my-gitlab-packages
bucket.mr-diffs: my-gitlab-mr-diffs
bucket.terraform: my-gitlab-terraform
bucket.ci-secure-files: my-gitlab-ci-secure-files
bucket.dependency-proxy: my-gitlab-dependency-proxy
bucket.backups: my-gitlab-backups
bucket.pages: my-gitlab-pages
Reference it from the GitlabInstance:
Required bucket classes¶
The operator validates that the Secret contains all of the following bucket.<class> keys. If any key is missing, the instance enters phase: Failed with condition S3BucketsIncomplete.
| Key | GitLab storage class | What is stored |
|---|---|---|
bucket.registry |
registry |
Container image layers |
bucket.lfs |
lfs |
Git LFS objects |
bucket.artifacts |
artifacts |
CI/CD job artifacts |
bucket.uploads |
uploads |
User-uploaded attachments |
bucket.packages |
packages |
Package registry (npm, pip, etc.) |
bucket.mr-diffs |
mr-diffs |
Merge request diff storage |
bucket.terraform |
terraform |
Terraform state files |
bucket.ci-secure-files |
ci-secure-files |
CI secure files |
bucket.dependency-proxy |
dependency-proxy |
Dependency proxy cache |
bucket.backups |
backups |
GitLab backup tarballs |
bucket.pages |
pages |
GitLab Pages content |
All keys required even if the feature is unused
hq must supply all eleven bucket.<class> keys. A key being present does not enable the feature — it just satisfies the operator's validation. If backups or Pages are not used, the corresponding bucket can be empty but the key must exist in the Secret.
How the operator wires S3 to the chart¶
The operator translates the Secret into Helm values for the upstream GitLab chart:
global.minio.enabled: false— disables bundled MinIOglobal.appConfig.object_store— global S3 connection block referencing the credentials Secret- Per-bucket entries under
global.appConfig.{lfs,artifacts,uploads,packages,...} global.registry.bucket— the registry bucket nameglobal.pages.objectStore— the Pages object store blockregistry.storage— the docker-registry S3 driver config (via an operator-owned Secret)
GitLab 19 mandate¶
External object storage is mandatory on GitLab 19+ (chart 10+)
GitLab 19 (chart 10) removed the bundled MinIO sub-chart. If you deploy GitLab 19 or later without spec.objectStorage.credentialsSecret set and validated, the chart install will fail.
Before upgrading from 18.x to 19.x, ensure your S3 credentials Secret exists and passes validation (all eleven bucket-class keys present). See Version Management for the upgrade sequence.
What the operator does NOT do¶
- The operator never creates or modifies RGW users or buckets.
- The operator never deletes the S3 Secret or any bucket data on instance deletion.
- If
spec.objectStorage.credentialsSecretis empty, S3 wiring is skipped entirely (valid for GitLab 18 and earlier in non-production setups that use the in-chart defaults).
Backup object storage¶
The backup schedule and destination are configured separately on the GitlabInstance:
spec:
backups:
schedule: "30 2 * * *"
objectStorage:
credentialsSecret: my-gitlab-s3-credentials # same Secret as main S3
The backups.objectStorage.credentialsSecret may point at the same Secret as spec.objectStorage.credentialsSecret, or a different one (e.g. a dedicated backup user with narrower permissions).
Backup job wiring is a follow-up item
As of v0.1.0-beta, spec.backups.schedule is stored and validated but the backup job wiring to the chart is not yet complete. The field is accepted without error; the actual backup cron is a planned follow-up.