Skip to content

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:

Performance Fix: Certificate Init Container Optimization

⚠️ Critical Performance Issue Resolved

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:

1. New Configuration Flag (values.yaml)

# Enable certificate init containers for custom CA injection
certificates:
  initContainers:
    enabled: true  # Default: true for backwards compatibility

2. Template Logic Enhancement (templates/_helpers.tpl)

{{- $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

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

1. Basic Template Validation VERIFIED

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)

2. Certificate Integration Test (Standalone) VERIFIED

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 empty initContainers: sections (correct behavior)
  • No template errors when certificate structure is present
  • Graceful degradation - certificate helpers remain empty stubs

3. GitLab Chart Integration Test VERIFIED

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

4. Manual Custom CA Test VERIFIED

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

5. Minikube End-to-End Test COMPLETED

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:

  1. Main chart templates (gitlab/templates/_certificates.tpl) override our stub templates
  2. Global certificate configuration automatically flows to all subcharts
  3. 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

Edited by Dmitry Gruzd

Merge request reports

Loading