Add custom certificates support [Attempt 2]
What does this MR do and why?
This merge request updates the GitLab Zoekt helm chart from version 3.4.0 to 3.5.0, adding flexible container customization capabilities.
Note
This is the second attempt after resolving the issue discovered in gitlab-com/gl-infra/delivery#21528 (closed). The original MR was reverted in Revert "Merge branch 'add-custom-cert-escape-ha... (!130 - merged)
The main enhancement allows users to add their own custom containers, storage volumes, and initialization scripts to the deployment. This includes support for:
- Extra init containers - containers that run before the main application starts (useful for setup tasks like updating security certificates)
- Extra volumes - additional storage that can be mounted from secrets or configuration files
- Extra volume mounts - ways to attach the extra storage to specific locations in containers
- Extra containers - additional containers that run alongside the main application (like log shipping or monitoring tools)
The changes include comprehensive test coverage that verifies these new features work correctly both individually and when combined together. The tests cover scenarios like adding custom certificate authority updates, configuration management, and log shipping containers.
The implementation follows GitLab's standard patterns for container customization, making it consistent with other GitLab components. This gives users much more flexibility to customize their Zoekt search deployments for specific security, monitoring, or operational requirements without modifying the core chart templates.
Issues addressed:
- zoekt-indexer failed to verify webservice certi... (#28 - closed)
- Support Custom Certificate Authorities with Zoe... (#23 - closed)
Performance Fix: Certificate Init Container Optimization
After the initial implementation, we discovered that the certificate init container integration was causing severe performance issues in GitLab.com deployments:
- Problem: Deployment times increased from ~15 minutes to 40+ minutes starting September 9th, 2025
- Root cause: Certificate init containers were being added to all 36 Zoekt pods during rolling updates, even though Zoekt doesn't need Gitaly/Praefect TLS certificates
- Impact: 35 minutes of the total deployment time was spent on Zoekt pod rolling updates
Solution Implemented
Added semantic control to prevent unnecessary certificate init containers:
values.yaml
)
1. New Configuration Flag (# Enable certificate init containers for custom CA injection
certificates:
initContainers:
enabled: true # Default: true for backwards compatibility
templates/_helpers.tpl
)
2. Template Logic Enhancement ({{- $certificateInitContainersEnabled := .Values.certificates.initContainers.enabled | default true -}}
{{- $hasCertificates := (and $certificateInitContainersEnabled .Values.global .Values.global.certificates .Values.global.certificates.customCAs (gt (len .Values.global.certificates.customCAs) 0)) -}}
3. GitLab Chart Integration
Updated GitLab chart values to disable certificate init containers for Zoekt:
gitlab-zoekt:
certificates:
initContainers:
enabled: false # Prevents Gitaly/Praefect certificates from affecting Zoekt
- GSTG: [GSTG] Disable gitlab-zoekt.certificates.initCo... (gitlab-com/gl-infra/k8s-workloads/gitlab-com!4767 - merged)
- GPRD: [GPRD] Disable gitlab-zoekt.certificates.initCo... (gitlab-com/gl-infra/k8s-workloads/gitlab-com!4768 - merged)
✅
Validation Results Template Verification:
helm template . --set certmanager-issuer.email=email@example.com --set gitlab-zoekt.install=true --set gitlab-zoekt.replicas=3
Results:
-
✅ No certificate init containers in gitlab-zoekt pods when flag is disabled -
✅ Certificate volumes still available for manual certificate scenarios via extraInitContainers -
✅ Zero breaking changes - existing functionality preserved -
✅ Backwards compatible - flag defaults to enabled
Expected Performance Impact
- Deployment time reduction: ~25 minutes (from 40+ back to ~15 minutes)
- Rolling update optimization: Certificate processing eliminated from all 36 Zoekt pods
- Resource efficiency: Reduced container startup overhead during deployments
How to set up and validate locally
✅ VERIFIED
1. Basic Template Validation helm template test . -f tmp/test-basic-values.yaml
helm lint -f tmp/test-basic-values.yaml
Results:
-
✅ All templates render correctly -
✅ No linting errors (only expected warnings for missing values)
✅ VERIFIED
2. Certificate Integration Test (Standalone) helm template test . -f tmp/test-custom-cert-values.yaml
Configuration:
global:
certificates:
customCAs:
- secret: company-internal-ca
keys: [company-ca.crt]
- configMap: additional-ca-certs
Results:
-
✅ Templates render with emptyinitContainers:
sections (correct behavior) -
✅ No template errors when certificate structure is present -
✅ Graceful degradation - certificate helpers remain empty stubs
✅ VERIFIED
3. GitLab Chart Integration Test Test Command:
cd /Users/dgruzd/projects/gitlab-chart
helm template gitlab . -f test-global-custom-ca.yaml | grep -A 20 -B 5 "gitlab-zoekt"
Results:
-
✅ Certificate init container: Automatically included with proper image -
✅ Custom CA volumes: Projected volumes properly configured -
✅ Template override: GitLab templates properly override our stubs -
✅ Certificate processing: Full GitLab certificate infrastructure working
✅ VERIFIED
4. Manual Custom CA Test helm template test . -f tmp/test-manual-ca-values.yaml
Configuration:
extraInitContainers: |
- name: custom-ca-injector
image: alpine:3.18
command: ["/bin/sh", "-c"]
args:
- |
cp /etc/ssl/certs/ca-certificates.crt /shared-ca-certs/
cat /custom-ca/company-ca.crt >> /shared-ca-certs/ca-certificates.crt
extraVolumes: |
- name: custom-ca-certs
secret:
secretName: company-internal-ca
- name: shared-ca-certs
emptyDir: {}
extraVolumeMounts: |
- name: shared-ca-certs
mountPath: /etc/ssl/certs/ca-certificates.crt
subPath: ca-certificates.crt
Results:
-
✅ Custom CA init container: Properly rendered in both deployment and statefulset -
✅ Extra volumes: Secret and emptyDir volumes configured correctly -
✅ Volume mounts: All containers have custom CA certificate access -
✅ Manual injection: Escape hatch works for standalone custom CA scenarios
✅ COMPLETED
5. Minikube End-to-End Test Environment Setup:
# Create test certificates
openssl genrsa -out tmp/certs/company-ca-key.pem 2048
openssl req -new -x509 -key tmp/certs/company-ca-key.pem -out tmp/certs/company-ca.crt -days 365 \
-subj "/CN=Test Company Internal CA/O=Test Company/C=US"
# Create Kubernetes secrets
kubectl create namespace gitlab-zoekt-test
kubectl create secret generic company-internal-ca --from-file=tmp/certs/company-ca.crt -n gitlab-zoekt-test
kubectl create secret generic test-gitlab-shell-secret --from-literal=secret="test-secret-value" -n gitlab-zoekt-test
✅
Standalone Deployment Results helm install gitlab-zoekt-standalone . -f tmp/minikube-standalone-values.yaml -n gitlab-zoekt-test
-
✅ Deployment Success: Both statefulset (3/3) and deployment (1/1) pods running -
✅ Custom CA Processing: Init container processed 151 certificates (149 base + 2 custom) -
✅ Certificate Integration: Custom CAs available in all containers -
✅ Log Verification: "Installing custom CAs... Custom CAs installed. Total certificates: 151"
✅
GitLab Subchart Deployment Results cd /Users/dgruzd/projects/gitlab-chart
helm install gitlab-chart-test . -f /path/to/minikube-gitlab-values.yaml -n gitlab-test --timeout 15m
-
✅ Deployment Success: GitLab Zoekt pods running as part of GitLab chart -
✅ Certificate Init Container: GitLab's certificates container processed 148 certificates -
✅ Custom CA Files: Our custom CA available as/etc/ssl/certs/company-ca.pem
-
✅ Certificate Validation:openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/company-ca.pem
returns "OK" -
✅ Template Override: GitLab templates properly override our certificate helper stubs
Technical Details
Template Override Architecture
When used as GitLab subchart:
-
Main chart templates (
gitlab/templates/_certificates.tpl
) override our stub templates - Global certificate configuration automatically flows to all subcharts
-
Manual escape hatch still available via
extraInitContainers
patterns
Reusable Template Helper
- Centralized logic: Single source of truth for certificate and extra init container conditions
- Nil-safe: Proper defensive checking prevents template rendering failures
- Flexible: Works for both deployment and statefulset with different additional requirements
- Maintainable: Changes to common logic only need to be made in one place
Expected Results
-
✅ Templates render correctly: No more nil pointer errors or template failures -
✅ Dual compatibility: Works standalone AND as GitLab subchart seamlessly -
✅ Certificate Integration:- Standalone: Graceful degradation with empty certificate helpers
- GitLab subchart: Full certificate processing via template override
- Manual: Escape hatch via extraInitContainers for standalone custom CAs
-
✅ Real Minikube Deployment: End-to-end validation with actual Kubernetes clusters -
✅ Certificate Processing Verified:- Standalone: 151 certificates (149 base + 2 custom via manual injection)
- GitLab subchart: 148 certificates via GitLab's certificate infrastructure
-
✅ Production Ready: Validated with real certificates and cluster deployments -
✅ Zero Regressions: All existing functionality preserved, all tests pass
Migration Notes
No Breaking Changes:
- All existing functionality preserved
- No changes to values.yaml structure required
- Same template rendering results for existing configurations
- Additional certificate integration capabilities when used as GitLab subchart
Backwards Compatibility:
- Standalone deployments continue to work exactly as before
- GitLab subchart integration enhanced but not changed
- Manual certificate injection via extraInitContainers unchanged