Automatic CRD Upgrades in VirtRigaud Helm Chart¶
Overview¶
VirtRigaud Helm chart now supports automatic CRD upgrades during helm upgrade. This eliminates the need for manual CRD management and provides a seamless upgrade experience.
The Problem¶
By default, Helm has a limitation: - CRDs are installed during helm install - CRDs are NOT upgraded during helm upgrade
This means users had to manually apply CRD updates before upgrading, which was: - Error-prone - Easy to forget - Breaks GitOps workflows - Causes version drift between chart and CRDs
The Solution¶
VirtRigaud uses Helm Hooks with a Kubernetes Job to automatically apply CRDs during both install and upgrade:
kubectl Image¶
VirtRigaud builds and publishes its own kubectl image as part of the release process. This image:
- Based on Alpine Linux for minimal size (~50MB)
- Includes kubectl 1.32.0 binary from official Kubernetes releases
- Includes bash and shell for scripting support
- Runs as non-root user (UID 65532)
- Verified with SHA256 checksums
- Signed with Cosign and includes SBOM
- Security scanned but uses official kubectl binary (vulnerabilities tracked upstream)
The image is automatically built and tagged to match each VirtRigaud release version, ensuring version consistency across all components.
Image Location: ghcr.io/projectbeskar/virtrigaud/kubectl:<version>
How It Works¶
- Pre-Upgrade Hook: Before the main upgrade starts, a Job is created
- CRD Application: The Job applies all CRDs using
kubectl apply --server-side - Safe Upgrades: Server-side apply handles conflicts gracefully
- Automatic Cleanup: Job is deleted after successful completion
Architecture¶
helm upgrade virtrigaud
↓
[Pre-Upgrade Hook -10]
↓
ConfigMap with CRDs created
↓
[Pre-Upgrade Hook -5]
↓
ServiceAccount + RBAC created
↓
[Pre-Upgrade Hook 0]
↓
Job applies CRDs via kubectl
↓
[Standard Helm Resources]
↓
Manager & Providers deployed
↓
[Hook Cleanup]
↓
Job & Hook resources deleted
Features¶
Enabled by Default¶
No configuration needed - just works:
Server-Side Apply¶
Uses kubectl apply --server-side for: - Safe conflict resolution - Field management - No ownership conflicts
GitOps Compatible¶
Works seamlessly with: - ArgoCD: Helm hooks execute properly - Flux: Compatible with HelmRelease CRD upgrades - Terraform: Helm provider handles hooks
Configurable¶
Customize the upgrade behavior:
crdUpgrade:
enabled: true # Enable/disable automatic upgrades
image:
repository: ghcr.io/projectbeskar/virtrigaud/kubectl # VirtRigaud kubectl image
tag: "v0.2.0" # Auto-updated to match release version
backoffLimit: 3
ttlSecondsAfterFinished: 300
waitSeconds: 5
resources:
limits:
cpu: 100m
memory: 128Mi
Usage Examples¶
Standard Upgrade (Automatic CRDs)¶
# CRDs are automatically upgraded
helm upgrade virtrigaud virtrigaud/virtrigaud \
-n virtrigaud-system
Disable Automatic CRD Upgrade¶
# Disable if you manage CRDs separately
helm upgrade virtrigaud virtrigaud/virtrigaud \
-n virtrigaud-system \
--set crdUpgrade.enabled=false
Manual CRD Management¶
# Apply CRDs manually before upgrade
kubectl apply -f charts/virtrigaud/crds/
# Then upgrade without CRD management
helm upgrade virtrigaud virtrigaud/virtrigaud \
-n virtrigaud-system \
--set crdUpgrade.enabled=false
Skip CRDs Entirely¶
# Skip CRDs during upgrade (for external CRD management)
helm upgrade virtrigaud virtrigaud/virtrigaud \
-n virtrigaud-system \
--skip-crds \
--set crdUpgrade.enabled=false
GitOps Integration¶
ArgoCD¶
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: virtrigaud
spec:
source:
chart: virtrigaud
targetRevision: 0.2.2
helm:
values: |
crdUpgrade:
enabled: true # Automatic upgrades work!
syncPolicy:
automated:
prune: true
selfHeal: true
Note: ArgoCD executes Helm hooks properly, so CRDs will be upgraded automatically.
Flux¶
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: virtrigaud
spec:
chart:
spec:
chart: virtrigaud
version: 0.2.2
values:
crdUpgrade:
enabled: true # Automatic upgrades work!
install:
crds: CreateReplace
upgrade:
crds: CreateReplace
Note: Flux's crds: CreateReplace works alongside our hook-based upgrades for maximum compatibility.
Troubleshooting¶
Check CRD Upgrade Job¶
# View job status
kubectl get jobs -n virtrigaud-system -l app.kubernetes.io/component=crd-upgrade
# View job logs
kubectl logs -n virtrigaud-system -l app.kubernetes.io/component=crd-upgrade
# View job details
kubectl describe job -n virtrigaud-system -l app.kubernetes.io/component=crd-upgrade
Common Issues¶
1. RBAC Permissions¶
Symptom: Job fails with "forbidden" errors
Solution: Ensure the ServiceAccount has CRD permissions:
kubectl get clusterrole -l app.kubernetes.io/component=crd-upgrade
kubectl describe clusterrole <role-name>
2. Image Pull Failures¶
Symptom: Job fails to start, ImagePullBackOff
Solution: Check image configuration:
crdUpgrade:
image:
repository: ghcr.io/projectbeskar/virtrigaud/kubectl
tag: "v0.2.2-rc1" # Use matching VirtRigaud version
pullPolicy: IfNotPresent
3. CRD Conflicts¶
Symptom: Apply errors about field conflicts
Solution: Server-side apply handles this automatically, but you can force:
4. Job Not Cleaning Up¶
Symptom: Old jobs remain after upgrade
Solution: Adjust TTL or manually clean:
Debug Mode¶
Enable verbose logging:
Migration Guide¶
Migrating from Manual CRD Management¶
If you were previously managing CRDs manually:
-
Enable automatic upgrades:
-
Verify CRDs are upgraded:
-
Remove manual steps from your upgrade process
Migrating to External CRD Management¶
If you want to manage CRDs externally (e.g., separate Helm chart):
-
Disable automatic upgrades:
-
Extract CRDs:
-
Manage CRDs separately:
Technical Details¶
Hook Weights¶
The upgrade process uses weighted hooks for proper ordering:
| Weight | Resource | Purpose |
|---|---|---|
-10 | ConfigMap | Store CRD content |
-5 | RBAC | Create permissions |
0 | Job | Apply CRDs |
Resource Requirements¶
The CRD upgrade job is lightweight:
Security¶
- Runs as non-root user (65532)
- Read-only root filesystem
- No privilege escalation
- Minimal RBAC (only CRD permissions)
- Automatic cleanup after completion
Compatibility¶
- Kubernetes: 1.25+
- Helm: 3.8+
- kubectl: 1.24+ (in Job image)
Best Practices¶
- Use Automatic Upgrades: Enable by default for best UX
- Monitor Job Logs: Check logs during first upgrade
- Test in Dev First: Verify upgrades in non-production
- Backup CRDs: Keep backups before major upgrades
- Review Changelogs: Check for breaking CRD changes
FAQ¶
Q: Will this delete my existing resources?¶
A: No. CRD upgrades are additive and preserve existing Custom Resources.
Q: What happens if the job fails?¶
A: Helm upgrade will fail, leaving your cluster in the previous state. Fix the issue and retry.
Q: Can I use this with ArgoCD?¶
A: Yes! ArgoCD properly executes Helm hooks.
Q: Does this work with Flux?¶
A: Yes! Flux HelmRelease handles hooks correctly.
Q: How do I roll back?¶
A: Use helm rollback. CRDs are not rolled back (Kubernetes limitation).
Q: Can I customize the kubectl image?¶
A: Yes, via crdUpgrade.image.repository and crdUpgrade.image.tag. The default uses the official Kubernetes kubectl image from registry.k8s.io.