This is a Kubernetes Operator for declarative Helm Chart management, part of the Kloudlite platform. It provides Custom Resource Definitions (CRDs) to manage Helm deployments as Kubernetes resources.
The plugin-helm-chart operator enables declarative management of Helm charts within Kubernetes clusters. It provides two main custom resources:
- HelmChart: For managing individual Helm chart deployments
- HelmPipeline: For orchestrating multiple HelmChart resources in sequence
The operator executes Helm operations securely through Kubernetes Jobs, integrating seamlessly with Kloudlite's plugin system for comprehensive service management.
- go version v1.22.0+
- docker version 17.03+.
- kubectl version v1.11.3+.
- Access to a Kubernetes v1.11.3+ cluster.
# Generate code after API changes (ALWAYS run both together)
make manifests generate
# Run tests
make test # Unit tests with envtest
make test-e2e # E2E tests (requires Kind cluster)
# Lint code
make lint # Check for issues
make lint-fix # Auto-fix issues
# Run controller locally
make run
# CRD management
make install # Install CRDs to cluster
make uninstall # Remove CRDs from cluster
# Deployment
make deploy IMG=<registry>/<image>:<tag>
make undeploy# Run controller with environment variables from .secrets/env
run dev
# Create new API resource
run new:api version=v1 kind=YourResourceName
# Generate manifests and code (wrapper for make commands)
run manifests
# Build operations
run build # Build binary
run image:build image=<registry>/<image> # Multi-arch build
run helm-job-runner tag=<version> # Build helm job runner image# Run tests for a specific controller
go test ./internal/controller/helm_chart/... -v
# Run specific test case with Ginkgo
go test ./internal/controller/helm_chart/... -v -ginkgo.focus="should create a Job"
# Run tests with coverage
go test ./... -coverprofile cover.outBuild and push your image to the location specified by IMG:
make docker-build docker-push IMG=<some-registry>/plugin-helm-chart:tagNOTE: This image ought to be published in the personal registry you specified. And it is required to have access to pull the image from the working environment. Make sure you have the proper permission to the registry if the above commands don't work.
Install the CRDs into the cluster:
make installDeploy the Manager to the cluster with the image specified by IMG:
make deploy IMG=<some-registry>/plugin-helm-chart:tagNOTE: If you encounter RBAC errors, you may need to grant yourself cluster-admin privileges or be logged in as admin.
Create instances of your solution You can apply the samples (examples) from the config/sample:
kubectl apply -k config/samples/NOTE: Ensure that the samples has default values to test it out.
Delete the instances (CRs) from the cluster:
kubectl delete -k config/samples/Delete the APIs(CRDs) from the cluster:
make uninstallUnDeploy the controller from the cluster:
make undeploy# Create a new API resource (uses kubebuilder)
run new:api version=v1 kind=YourResourceName-
HelmChart - Manages individual Helm chart deployments
- Controller:
/internal/controller/helm_chart/helmchart_controller.go - API:
/api/v1/helmchart_types.go - Executes Helm operations via Kubernetes Jobs
- Controller:
-
HelmPipeline - Orchestrates multiple HelmChart resources in sequence
- Controller:
/internal/controller/helm_pipeline/controller.go - API:
/api/v1/helmpipeline_types.go - Creates and manages HelmChart resources for each pipeline step
- Controller:
- Job-based Execution: Helm operations run in Kubernetes Jobs using the helm-job-runner image
- Security: Jobs run with hardened security contexts (non-root, read-only filesystem)
- Plugin Integration: Integrates with Kloudlite's plugin system for service management
- Status Tracking: Uses controller-runtime's status subresource for operation tracking
Both controllers follow the same reconciliation pattern:
- Check resource deletion (handle finalizers)
- Create ServiceAccount, Role, RoleBinding for Job execution
- Create/update Job from embedded templates
- Monitor Job status and update resource status accordingly
- Set appropriate conditions on the resource
# Required for local development (set in .secrets/env)
HELM_JOB_IMAGE=ghcr.io/kloudlite/kloudlite/operator/workers/helm-job-runner:latest
# Optional for tests
PROMETHEUS_INSTALL_SKIP=true # Skip Prometheus in e2e tests
CERT_MANAGER_INSTALL_SKIP=true # Skip cert-manager in e2e tests- Use Ginkgo v2 + Gomega for BDD-style tests
- Use envtest for simulated Kubernetes API
- Tests located next to controllers (e.g.,
helmchart_controller_test.go) - Test helpers available in
internal/controller/test_helpers.go
WaitForJob()- Wait for job creation with specific labelsSimulateJobCompletion()- Mark job as completedSimulateJobFailure()- Mark job as failedCreateHelmChartWithDefaults()- Create test HelmChart with sensible defaultsCreateHelmPipelineWithDefaults()- Create test HelmPipeline with sensible defaultsWaitForHelmChartReady()- Wait for HelmChart to be readyWaitForHelmPipelineReady()- Wait for HelmPipeline to be readyCleanupNamespace()- Clean all test resources from namespace
// Example test structure
var _ = Describe("Controller", func() {
Context("when creating a HelmChart", func() {
It("should create a Job", func() {
// Create resource
hc := testHelpers.CreateHelmChartWithDefaults("test", namespace)
Expect(k8sClient.Create(ctx, hc)).To(Succeed())
// Wait for job
job, err := testHelpers.WaitForJob(namespace, labels, timeout)
Expect(err).NotTo(HaveOccurred())
// Simulate completion
Expect(testHelpers.SimulateJobCompletion(job)).To(Succeed())
// Verify status
Expect(testHelpers.WaitForHelmChartReady(name, namespace, timeout)).To(Succeed())
})
})
})- Update the types in
/api/v1/(e.g.,helmchart_types.go) - Run
make manifests generateto update CRDs and generated code - Update the controller logic to handle the new field
- Add tests for the new functionality
- Check the HelmChart status:
kubectl get helmchart -n <namespace> <name> -o yaml - Look for the Job created by the operator:
kubectl get jobs -n <namespace> - Check Job logs:
kubectl logs -n <namespace> job/<job-name> - Common issues:
- Missing RBAC permissions
- Invalid Helm values
- Chart URL/version issues
- Make changes in
IMAGES/helm-job-runner/ - Build:
run helm-job-runner tag=<new-version> - Update default in
cmd/main.goor set via env var
The project supports both amd64 and arm64 architectures. CI automatically builds for both platforms using GitHub Actions.
Following are the steps to build the installer and distribute this project to users.
- Build the installer for the image built and published in the registry:
make build-installer IMG=<some-registry>/plugin-helm-chart:tagNOTE: The makefile target mentioned above generates an 'install.yaml' file in the dist directory. This file contains all the resources built with Kustomize, which are necessary to install this project without its dependencies.
- Using the installer
Users can just run kubectl apply -f to install the project, i.e.:
kubectl apply -f https://raw.githubusercontent.com/<org>/plugin-helm-chart/<tag or branch>/dist/install.yaml- Use
reconciler.Requestfrom kloudlite toolkit - Set conditions: Ready, JobCreated, JobCompleted
- Always update LastObservedGeneration
- Handle transient errors with requeue
- Each HelmChart gets its own ServiceAccount
- Minimal permissions based on release namespace
- Automatic cleanup with owner references
- Templates use Go text/template
- Access to full HelmChart/Pipeline spec
- Environment variables passed to containers
- Security contexts are hardened by default
- Template files embedded in binary using
go:embed
api/v1/ # CRD API definitions
├── helmchart_types.go # HelmChart CRD
└── helmpipeline_types.go # HelmPipeline CRD
internal/controller/
├── helm_chart/ # HelmChart controller
│ ├── helmchart_controller.go # Main reconciliation logic
│ └── templates/ # Job templates for helm operations
├── helm_pipeline/ # HelmPipeline controller
│ ├── controller.go # Pipeline orchestration logic
│ └── templates/ # Pipeline-specific templates
└── test_helpers.go # Shared test utilities
NOTE: Run make help for more information on all potential make targets
More information can be found via the Kubebuilder Documentation
Copyright 2024.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.