Skip to content

Deletion & Retention

This guide describes what happens when you delete a GitlabInstance and how to safely clean up the resources that the operator intentionally retains.

What the operator does on deletion

When a GitlabInstance enters the deletion flow (e.g. kubectl delete gli my-gitlab -n my-gitlab), the operator's finalizer (k8s.bnerd.com/gitlab-finalizer) runs before the object is removed:

  1. Deletes operator-owned Secrets — the Secrets listed in status.secrets (e.g. {instance}-gitlab-registry-storage) are deleted.
  2. Removes the finalizer — allowing the Kubernetes API to garbage-collect the GitlabInstance object.

Resources owned by the GitlabInstance via Kubernetes owner references (the HelmRelease and HelmRepository) are deleted automatically by the API server after the finalizer completes.

What is NOT deleted

Managed backends are retained — this is intentional

Managed PerconaPGCluster, Redis CRs (Redis / RedisReplication / RedisSentinel), and ECK Elasticsearch clusters carry no owner reference to the GitlabInstance. They are never deleted by the operator on instance deletion.

This prevents accidental data loss if an instance CR is deleted by mistake. You must delete these resources manually after verifying the data is no longer needed.

Resource Deleted on instance deletion? By whom
GitlabInstance object Yes Kubernetes API (after finalizer)
HelmRelease Yes Kubernetes GC (owner reference)
HelmRepository Yes Kubernetes GC (owner reference)
Operator-owned Secrets (status.secrets) Yes Operator finalizer
GitLab chart Secrets Yes Kubernetes GC (owned by HelmRelease)
PerconaPGCluster (managed) No Must be deleted manually
Redis CRs (managed) No Must be deleted manually
ECK Elasticsearch (managed) No Must be deleted manually
Secrets you provided (S3, license, SMTP, BYO creds) No Must be deleted manually

Deleting a GitlabInstance

  1. Pre-flight — confirm the instance is safe to delete: no active users, data-retention requirements met, backups verified if needed.

  2. Delete the instance:

    kubectl delete gli my-gitlab -n my-gitlab
    
  3. Monitor the finalizer:

    kubectl get gli my-gitlab -n my-gitlab -w
    # NAME       PHASE   ...
    # my-gitlab  Ready   ...   ← still exists while finalizer runs
    # (disappears once finalizer completes)
    
  4. Verify the HelmRelease is gone:

    kubectl get helmrelease -n my-gitlab
    # No resources found.
    
  5. Verify GitLab pods are gone:

    kubectl get pods -n my-gitlab
    # (only backend pods remain if using managed backends)
    

Cleaning up managed backends

After verifying that the GitLab data is no longer needed:

Delete managed PostgreSQL

# Find the PerconaPGCluster
kubectl get perconapgcluster -n my-gitlab

# Delete it (Percona will clean up PVCs)
kubectl delete perconapgcluster my-gitlab-pg -n my-gitlab

# Wait for Percona to finish (may take several minutes)
kubectl get perconapgcluster my-gitlab-pg -n my-gitlab
# Eventually: NotFound

Delete managed Redis

# Standalone
kubectl delete redis my-gitlab-redis -n my-gitlab

# HA (RedisReplication + RedisSentinel)
kubectl delete redisreplication my-gitlab-redis -n my-gitlab
kubectl delete redissentinel my-gitlab-redis -n my-gitlab

Delete managed Elasticsearch (EE)

kubectl delete elasticsearch my-gitlab-es -n my-gitlab

Delete the namespace

Once all managed backend resources and their PVCs have been removed:

kubectl delete namespace my-gitlab

Wait for Percona finalizers before deleting the namespace

Deleting the namespace while PerconaPGCluster resources are still present may cause the namespace to stall in Terminating due to Percona's own finalizers. Always delete the PerconaPGCluster first and wait for it to fully terminate.

Namespace stuck in Terminating

If the namespace stalls:

# Check what is still present
kubectl get all,pvc,perconapgcluster,redis,redisreplication,redissentinel,elasticsearch \
  -n my-gitlab

# Check for remaining finalizers
kubectl describe namespace my-gitlab | grep -iA3 finalizers

Most commonly, a managed backend CR is still terminating (waiting for Percona or ECK to clean up PVCs). Check the respective operator logs:

# Percona operator logs
kubectl logs -n pgo deploy/percona-postgresql-operator --tail=100

# ECK operator logs
kubectl logs -n elastic-system statefulset/elastic-operator --tail=100