Author a Helm artifact
After this guide, you have a Helm chart and an OCM component constructor ready to validate and publish as a Konfidence artifact. Once the published artifact is included in a vector, the Kubernetes deployer installs the chart in the landscape.
The examples build a service named my-service and push everything to registry.example.com/my-org.
Prerequisites
Before you begin, make sure you have:
- A container build tool such as
dockerand Helm 3.8 or later with Open Container Initiative (OCI) support. - Push access to an OCI registry for the image, the chart, and the artifact.
- The
kdencommand-line tool. See Publish artifacts. - A landscape with a ready
helm.konfidence.cloudtarget. See Configure deployment targets for a landscape. - A service that reads and forwards
X-Vector-ID. See Prepare your application.
Build and push the container image
Create a
Dockerfilein your service directory. The following example copies a prebuilt binary into a small base image. Replace the build with your own toolchain.dockerfileFROM alpine:3.20 COPY my-service /usr/local/bin/my-service EXPOSE 8080 ENTRYPOINT ["my-service"]Build and push the image with the version you plan to release:
bashdocker build -t registry.example.com/my-org/my-service:1.0.0 . docker push registry.example.com/my-org/my-service:1.0.0
The registry lists my-service:1.0.0 afterward.
Create a minimal chart
Create a my-service/ directory for the chart and a templates/ directory inside it:
mkdir -p my-service/templatesCreate the following files inside my-service/. Run the packaging commands from its parent directory. helm create generates a larger chart that follows the same rules.
Create
Chart.yaml:yamlapiVersion: v2 name: my-service version: 1.0.0 appVersion: "1.0.0"Create
values.yamlwith the image reference:yamlimage: repository: registry.example.com/my-org/my-service tag: "1.0.0"Create
templates/deployment.yaml:yamlapiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }} spec: replicas: 1 selector: matchLabels: app.kubernetes.io/instance: {{ .Release.Name }} template: metadata: labels: app.kubernetes.io/instance: {{ .Release.Name }} spec: containers: - name: my-service image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" ports: - containerPort: 8080Create
templates/service.yaml:yamlapiVersion: v1 kind: Service metadata: name: {{ .Release.Name }} spec: selector: app.kubernetes.io/instance: {{ .Release.Name }} ports: - port: 80 targetPort: 8080
The chart renders one Deployment and one Service, both named after the release.
Package and push the chart
Package the chart directory:
bashhelm package ./my-servicePush the package to the registry:
bashhelm push my-service-1.0.0.tgz oci://registry.example.com/my-org/charts
The chart is available as registry.example.com/my-org/charts/my-service:1.0.0. Keep charts and container images in separate registry paths so that pushing a chart does not replace an image tag.
Reference the chart from the artifact component
Create
manifest.jsonwith the Helm type:json{ "type": "helm.konfidence.cloud", "allowReuse": false }Set
allowReusetotrueonly when one running instance can serve several vectors.Create
component-constructor.yamlwith the manifest and the chart as resources:yamlcomponents: - name: github.com/my-org/my-service version: 1.0.0 provider: name: my-org resources: - name: my-service-manifest type: cloud.konfidence.artifact.manifest version: 1.0.0 relation: local input: type: file/v1 path: ./manifest.json - name: my-service-chart type: helmChart version: 1.0.0 relation: external access: type: ociArtifact imageReference: registry.example.com/my-org/charts/my-service:1.0.0The component carries exactly one resource of type
helmChart.
Derive every resource name from the release name
Several vectors deploy the same chart into one landscape namespace. The deployer gives each deployment its own release name. Every resource in the chart must derive metadata.name from that release name, either directly or through the chart's fullname helper. A hard-coded name collides when a second vector deploys the chart.
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configThe fullname helper that helm create generates works as well:
metadata:
name: {{ include "my-service.fullname" . }}Do not hard-code names:
metadata:
name: my-service-configDo not set metadata.namespace in templates. The deployer installs every release into the landscape namespace.
The deployer owns the release itself: its name, its namespace, and its labels. Everything in the chart is duplicated per instance. Deliver resources that must exist once per cluster, such as a CustomResourceDefinition, through a separate delivery path.
Fields the deployer sets on the HelmRelease
The deployer creates one Flux HelmRelease per artifact instance and sets these fields. Your chart cannot override them.
| Field | Value |
|---|---|
metadata.name | The ArtifactDeployment name |
spec.releaseName | The ArtifactDeployment name |
spec.chart.spec.sourceRef | The HelmRepository with the same name |
spec.targetNamespace | The landscape namespace |
spec.storageNamespace | The landscape namespace |
spec.commonMetadata.labels | konfidence.cloud/artifact-deployment=<artifact-deployment-name> |
The release name is deterministic per component, version, allowReuse setting, and VectorDeployment.
Verify the result
Render the chart twice with different release names and compare the resource names. This is the check the deployer relies on.
helm template vector-a ./my-service | grep '^ name:'
helm template vector-b ./my-service | grep '^ name:'Every name in the first output starts with vector-a, and every name in the second output starts with vector-b. A name that appears unchanged in both outputs is hard-coded and must derive from the release name.
Next steps
Use the following guides to publish your artifact and expose its Service:
- Validate and publish the artifact.
- Add deployment results to an artifact to expose the Service to other services in the vector.
- Read Kubernetes deployer for supported manifest types and deployment-result behavior.