Add a Helm Service to the Community Repo
Purpose: Shows how to add a new Helm-based platform service to the openCenter-gitops-base community repo under applications/base/services/, covering directory structure, HelmRelease configuration, and testing.
Prerequisites
-
Git access to openCenter-gitops-base repository
-
kubectl access to a test cluster
-
FluxCD CLI installed (
flux version) -
Basic understanding of Helm and Kustomize
Steps
1. Create service directory structure
cd openCenter-gitops-base/applications/base/services/
# Create service directory
mkdir -p my-service/helm-values
# Create required files
touch my-service/kustomization.yaml
touch my-service/namespace.yaml
touch my-service/source.yaml
touch my-service/helmrelease.yaml
touch my-service/README.md
2. Define namespace
Create my-service/namespace.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: my-service
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
3. Configure Helm repository source
Create my-service/source.yaml:
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: my-service
namespace: flux-system
spec:
interval: 15m
url: https://charts.example.com/
timeout: 1m
For OCI registries:
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: my-service
namespace: flux-system
spec:
interval: 15m
type: oci
url: oci://registry.example.com/charts
4. Create base Helm values
Create my-service/helm-values/values-v<chart-version>.yaml:
# Base configuration for my-service
replicaCount: 2
image:
repository: registry.example.com/my-service
tag: "1.0.0"
pullPolicy: IfNotPresent
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
service:
type: ClusterIP
port: 8080
5. Create HelmRelease
Create my-service/helmrelease.yaml:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: my-service
namespace: my-service
spec:
interval: 5m
timeout: 10m
releaseName: my-service
chart:
spec:
chart: my-service
version: "1.0.0"
sourceRef:
kind: HelmRepository
name: my-service
namespace: flux-system
interval: 15m
driftDetection:
mode: enabled
install:
crds: CreateReplace
remediation:
retries: 3
remediateLastFailure: true
upgrade:
crds: CreateReplace
remediation:
retries: 0
remediateLastFailure: false
valuesFrom:
- kind: Secret
name: my-service-values-base
valuesKey: values.yaml
- kind: Secret
name: my-service-values-override
valuesKey: override.yaml
optional: true
6. Configure Kustomization
Create my-service/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: my-service
resources:
- namespace.yaml
- source.yaml
- helmrelease.yaml
secretGenerator:
- name: my-service-values-base
files:
- values.yaml=helm-values/values-v<chart-version>.yaml
options:
disableNameSuffixHash: true
generatorOptions:
disableNameSuffixHash: true
7. Document the service
Create my-service/README.md:
# My Service
## Purpose
Brief description of what this service does.
## Version
- Chart: 1.0.0
- App: 1.0.0
## Dependencies
- None (or list dependencies)
## Configuration
### Base Values
Located in `helm-values/values-v<chart-version>.yaml`.
### Override Values
Create in the cluster repo, for example `applications/overlays/<cluster>/services/my-service/helm-values/override-values.yaml` if your consumer layout keeps service overrides under `services/<service>/helm-values/`.
## Resources
- CPU: 100m request, 500m limit
- Memory: 128Mi request, 512Mi limit
## Observability
- Metrics: Exposed on port 8080 at /metrics
- Logs: JSON format to stdout
- Traces: OTLP to OpenTelemetry collector
## Security
- Runs as non-root user (UID 1000)
- Read-only root filesystem
- All capabilities dropped
8. Validate locally
# Build Kustomization
kustomize build applications/base/services/my-service
# Check for errors
echo $? # Should be 0
9. Test in cluster
# Create test namespace
kubectl create namespace flux-system --dry-run=client -o yaml | kubectl apply -f -
# Apply service manifests
kustomize build applications/base/services/my-service | kubectl apply -f -
# Check HelmRelease status
kubectl get helmrelease -n my-service my-service
# View reconciliation
flux reconcile helmrelease my-service -n my-service
# Check logs
flux logs --kind=HelmRelease --name=my-service --namespace=my-service
Verification
After FluxCD reconciles:
# Check GitRepository sync
flux get sources git
# Check HelmRelease status
flux get helmreleases -n my-service
# Verify service is running
kubectl get all -n my-service
Expected output:
-
HelmRelease shows "Ready" status
-
Pods are running
-
Service endpoint is accessible