No prior knowledge of Helm is required.

Time to completion

45-60m

Prerequisites

It is assumed the reader has at least a basic understanding of the following topics and technologies:

  • YAML

  • Docker/OCI images and containers

  • Application deployments in Kubernetes

Software and tools required
  • kubectl or other Kubernetes compatible client (e.g. oc) installed locally

  • Helm installed locally

  • Access to a Kubernetes compatible cluster

This tutorial was written and tested on CRC (aka OpenShift Local), local OKD/OpenShift cluster provided by Red Hat for developer testing, and thus all URL’s in the tutorial will use the wildcard domain *.app-crc.testing; however any Kubernetes compatible cluster will suffice for running the tutorial, as long as internet access is available to pull el-CICD Chart and the test images. You will need to adjust your endpoint URL’s to your own cluster’s wildcard if not using CRC.

The tutorial will mostly focus on deploying the Apache Web Server using Red Hat’s official httpd image and will not deploy Secrets, so that whether you are deploying on vanilla Kubernetes or a more security conscious cluster like OpenShift this tutorial will run smoothly with only basic developer permissions required.

1. Overview

Helm is an excellent package management tool for Kubernetes. Deploying or removing an application on and off a Kubernetes cluster is handled very well by Helm.

Where Helm falls short is when it comes to templating Kubernetes manifests. Creating Helm templates can be difficult to learn let alone master.

This tutorial will demonstrate how the el-CICD Chart can make defining Kubernetes manifests much easier for all involved while still taking advantage of Helm’s package management functionality.

el-CICD Chart embeds its templates inside Helm values.yaml file(s), and writing Helm templates are not required when using el-CICD Chart. In order to avoid confusion with the word "template", el-CICD Chart values.yaml file(s) will be referred to as deployment definitions.

1.1. Starter Helm chart

The following is the starter chart created by Helm when running helm create my-new-chart along with its issues:

Service
apiVersion: v1
kind: Service
metadata:
  name: {{ include "my-new-chart.fullname" . }}
  labels:
    {{- include "my-new-chart.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "my-new-chart.selectorLabels" . | nindent 4 }}
Deployment
kind: Deployment
metadata:
  name: {{ include "my-new-chart.fullname" . }}
  labels:
    {{- include "my-new-chart.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "my-new-chart.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include "my-new-chart.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "my-new-chart.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
Ingress
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "my-new-chart.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
  {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
  {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
  {{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
    {{- include "my-new-chart.labels" . | nindent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
  ingressClassName: {{ .Values.ingress.className }}
  {{- end }}
  {{- if .Values.ingress.tls }}
  tls:
    {{- range .Values.ingress.tls }}
    - hosts:
        {{- range .hosts }}
        - {{ . | quote }}
        {{- end }}
      secretName: {{ .secretName }}
    {{- end }}
  {{- end }}
  rules:
    {{- range .Values.ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
          {{- range .paths }}
          - path: {{ .path }}
            {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
            pathType: {{ .pathType }}
            {{- end }}
            backend:
              {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
              service:
                name: {{ $fullName }}
                port:
                  number: {{ $svcPort }}
              {{- else }}
              serviceName: {{ $fullName }}
              servicePort: {{ $svcPort }}
              {{- end }}
          {{- end }}
    {{- end }}
{{- end }}
values.yaml
# Default values for my-new-chart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: nginx
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: ""

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""

podAnnotations: {}

podSecurityContext: {}
  # fsGroup: 2000

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  className: ""
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #   cpu: 100m
  #   memory: 128Mi
  # requests:
  #   cpu: 100m
  #   memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity: {}
Verbose

The files are verbose, and assume a good understanding of the manifests required to deploy an application on Kubernetes.

Obtuse

Go Template syntax (everything between the double-brackets) and the supporting Sprig library is not very user friendly, but it’s required knowledge to understand and modify Helm templates.

Values used to render the chart are defined in files separate from Helm templates, and structured far differently, which can make understanding what will rendered difficult.

No configuration management

Configuration management is not supported by Helm. Defining charts that can adapts across even a narrowly defined set of different deployments can be challenging.

It’s code

Helm templates are code; it constitutes a separate application. This means Helm charts need to be tested in isolation from the application they are meant to deploy. Helm charts acknowledge this by supporting a built-in testing framework.

1.2. el-CICD Chart

el-CICD Chart was created with the intention of leveraging all the package management goodness Helm has to offer while making defining deployments easier. In particular, the following design goals were set:

Helm centric

No extra scripts or special commands for standard Helm deployments or templating should be needed. el-CICD Chart should be able to be used anywhere Helm can be used, and alongside any other Helm chart either as the main chart or a subchart.

Easier

Defining deployments should be done using plain YAML documents, with no extra language skills or libraries.

More concise

Support the DRY (Don’t Repeat Yourself) Principle aggressively to significantly reduce the amount of copying and pasting of boilerplate YAML. For application developers, support reasonable defaults so deployment definitions are confined as much as possible to the application’s needs.

Support configuration management

Defining different configurations for the same set of deployment manifests (e.g. per locale, region, and/or development environment) should be easy and directly supported.

Extensible

Kubernetes is very extensible, as the abundance of Custom Resource Definitions illustrates. el-CICD Chart should be able to render CRD’s out-of-the-box without requiring new Helm template code.

The following tutorial will demonstrate how el-CICD Chart met each of these goals.

2. Tutorial

This tutorial will demonstrate how el-CICD Chart can make defining and defining Kubernetes deployment definitions easier, more readable, and more concise as well as directly supporting configuration management.

All commands used below will refer to kubectl, but if on OpenShift oc will work just as well.

2.1. Add and update the el-CICD Chart repository

Add and update the el-CICD Chart repository. This will pull the chart from the GitHub repository to your local machine for use.

$ helm repo add elcicd-charts https://elcicd.github.io/el-CICD-deploy/charts/
$ helm repo update
Deploying Helm charts from OCI repositories is better, but GitHub currently makes is easy to serve Helm charts from GitHub pages

+ Output::

"elcicd-charts" has been added to your repositories
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "elcicd-charts" chart repository
Update Complete. ⎈Happy Helming!⎈

2.2. el-CICD Chart Templates

Features demonstrated
  • el-CICD Chart templates.

  • el-CICD Chart helper templates.

  • el-CICD Chart template helper attributes.

  • el-CICD Chart built-in variables.

The el-CICD Chart aims to define basic Kubernetes resources for application deployments out-of-the-box and provide as many reasonable defaults as possible to reduce the amount of boilerplate required by the end user. The el-CICD Chart also aims to do away with the need to write Helm (Go) templates, and instead follows the Helm requirement for values.yaml files be plain YAML.

The example below is purposefully contrived to be more complicated than necessary. In this case the Ingress will be communicating with the Service over port 8081, and the Service will forward incoming requests to Apache Web Server container over the more standard port 8080. The next part of the tutorial will make it clear why we are making this more complicated than necessary.

Create and save the following file as elcicd-demo-1.yaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
elCicdTemplates: (1)
- templateName: deployment (2)
  image: registry.redhat.io/rhel8/httpd-24

- templateName: service (3)
  port: 8081 (4)
  targetPort: 8080 (5)

- templateName: ingress (6)
  host: httpd-$<HELM_RELEASE_NAMESPACE>.apps-crc.testing (7)
  port: 8081 (8)
1 All el-CICD Chart templates are defined in a list called elCicdTemplates.
If you want to spread your el-CICD templates out over multiple values.yaml files, more template lists can be defined as elCicdTemplates-*; e.g. elCicdTemplates-foo.

The suffix is meaningless and only serves to be keep the lists unique from Helm’s perspective. el-CICD Chart will automatically merge the lists into a single, unified list.

2 By convention, there is a one-to-one relation between el-CICD Chart templates and the Kubernetes resources they render.
  1. deployment for a Kubernetes Deployment

  2. service for a Kubernetes Service

  3. ingress for a Kubernetes Ingress

  4. el-CICD Chart templates are all named by convention with lowerCamelCase.

3 Helper attributes are el-CICD Chart template top level keys; e.g. some standard el-CICD attributes every template has:
  1. templateName: the name of the el-CICD Chart template to render.

  2. objName: maps directly metadata.name.

  3. template: custom el-CICD template definitions when built-in templates aren’t used.

4 $<HELM_RELEASE_NAMESPACE> references a built-in el-CICD Chart variable.
  1. In a Helm template this corresponds to .Release.Namespace; i.e. the namespace a Helm chart is deployed in.

    The release namespace is not necessarily the same as the Kubernetes resources being deployed.
  2. el-CICD Chart variables are referenced using the syntax $<VARIABLE_NAME>.

  3. el-CICD Chart conventions define variables using UPPER_SNAKE_CASE, similar to Shell.

Tutorial steps

What to expect
  • A Deployment, Service, and Ingress will be deployed on the cluster using el-CICD Chart.

  • An httpd Pod will be created from the Deployment and accessible in the browser from outside the cluster.

  • The httpd server’s test page will be reachable and visible in the browser.

  1. Install the elcicd-chart-demo release in the elcicd-chart-demo namespace using the el-CICD Chart:

    $ helm upgrade --install --atomic -n elcicd-chart-demo --create-namespace -f elcicd-demo-1.yaml elcicd-chart-demo elcicd-charts/elcicd-chart
    Output
    Release "elcicd-chart-demo" does not exist. Installing it now.
    NAME: elcicd-chart-demo
    LAST DEPLOYED: Tue Jul 16 16:47:02 2024
    NAMESPACE: elcicd-chart-demo
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
  2. View the manifests that generated by el-CICD Chart from the helm upgrade --install command:

    $ helm get manifest -n elcicd-chart-demo elcicd-chart-demo
    Output
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      selector:
        elcicd.io/selector: elcicd-chart-demo
      ports:
      - name: elcicd-chart-demo-port
        port: 8081
        targetPort: 8080
        protocol: TCP
    # Rendered el-CICD Chart Template -> "service" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      revisionHistoryLimit: 0
      selector:
        matchExpressions:
        - key: elcicd.io/selector
          operator: Exists
        matchLabels:
          elcicd.io/selector: elcicd-chart-demo
      template:
        metadata:
          labels:
            app.kubernetes.io/instance: elcicd-chart-demo
            app.kubernetes.io/managed-by: Helm
            elcicd.io/selector: elcicd-chart-demo
            helm.sh/chart: elcicd-chart-0.1.0
          name: elcicd-chart-demo
          namespace: elcicd-chart-demo
        spec:
          containers:
          - name: elcicd-chart-demo
            image: registry.redhat.io/rhel8/httpd-24
            imagePullPolicy: Always
            ports:
            - name: default-port
              containerPort: 8080
              protocol: TCP
            resources:
              limits: {}
              requests: {}
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
          imagePullSecrets: []
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
    # Rendered el-CICD Chart Template -> "deployment" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.allow-http: "false"
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      rules:
      - host: httpd-elcicd-chart-demo.apps-crc.testing
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: elcicd-chart-demo
                port:
                  number: 8081
      tls:
      - secretName:
    # Rendered el-CICD Chart Template -> "ingress" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    # Profiles: []
  3. View the running elcicd-chart-demo resources in the cluster:

    $ kubectl get -n elcicd-chart-demo -l elcicd.io/selector deploy,rs,pod,cm,service,ingress
    Output
    NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/elcicd-chart-demo   1/1     1            1           3m29s
    
    NAME                                           DESIRED   CURRENT   READY   AGE
    replicaset.apps/elcicd-chart-demo-6c6fd69cb7   1         1         1       3m29s
    
    NAME                                     READY   STATUS    RESTARTS   AGE
    pod/elcicd-chart-demo-6c6fd69cb7-xtk5k   1/1     Running   0          3m29s
    
    NAME                        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
    service/elcicd-chart-demo   ClusterIP   10.217.5.104   <none>        8081/TCP   3m29s
    
    NAME                                          CLASS    HOSTS                                      ADDRESS                           PORTS     AGE
    ingress.networking.k8s.io/elcicd-chart-demo   <none>   httpd-elcicd-chart-demo.apps-crc.testing   router-default.apps-crc.testing   80, 443   3m29s
  4. Get the value of the host from the Ingress, and verify the Apache Web Server is reachable:

    $ kubectl get ingress -n elcicd-chart-demo --no-headers -o custom-columns=:.spec.rules[*].host
    Output
    httpd-elcicd-chart-demo.apps-crc.testing
    If not using CRC, run the kubectl get command above to get the correct host.
    rhel test page screenshot
  5. Uninstall the chart.

    $ helm uninstall -n elcicd-chart-demo elcicd-chart-demo
    Output
    release "elcicd-chart-demo" uninstalled

2.3. Compound el-CICD Chart Templates

Features demonstrated
  • Defining compound templates.

  • Reducing boilerplate YAML using common el-CICD Chart templates helper attributes.

In el-CICD Chart Templates, we demonstrated the conciseness and modularity el-CICD Chart templates. We will now show how to combine multiple, related el-CICD Chart templates into a single compound template for even more concise deployment definitions.

Any el-CICD Chart built-in template can be compounded into a single template definition as long as any common helper attributes refer to the same, basic data.

Create and save the following file as elcicd-demo-2.yaml

1
2
3
4
5
6
elCicdTemplates:
- templateNames: [deployment, service, ingress] (1)
  image: registry.redhat.io/rhel8/httpd-24
  host: httpd-$<HELM_RELEASE_NAMESPACE>.apps-crc.testing
  port: 8081 (2)
  targetPort: 8080 (3)

YAML is a superset of JSON; thus YAML will interpret both [deployment, service, ingress] and

1
2
3
4
templateNames:
- deployment
- service
- ingress

as lists.

1 Compound templates are defined as a list under the templateNames attribute, versus templateName for a single template.
2 In compound templates, all helper attributes are shared among the el-CICD templates.
  1. image is unique to the deployment template.

  2. host is unique to the ingress el-CICD Chart template.

  3. port is shared and used by all three listed el-CICD Chart templates.

  4. targetPort is shared by the service and deployment templates, and take precedence over the port attribute when defined.

In the first part of the tutorial, el-CICD Chart Templates, we promised to explain why we contrived a different port and target port, and it was to better demonstrate how shared helper attributes would behave in compound templates.

Tutorial steps

What to expect
  • A Deployment, Service, Ingress, and ConfigMap will be deployed on the cluster using el-CICD Chart.

  • An httpd Pod will be created from the Deployment and accessible in the browser from outside the cluster.

  • The httpd server’s test page will be reachable and visible in the browser.

  1. Install the elcicd-chart-demo release in the elcicd-chart-demo namespace using the el-CICD Chart:

    $ helm upgrade --install --atomic -n elcicd-chart-demo --create-namespace -f elcicd-demo-2.yaml elcicd-chart-demo elcicd-charts/elcicd-chart
    Output
    Release "elcicd-chart-demo" does not exist. Installing it now.
    NAME: elcicd-chart-demo
    LAST DEPLOYED: Tue Jul 16 16:47:02 2024
    NAMESPACE: elcicd-chart-demo
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
  2. View the manifests that generated by el-CICD Chart from the helm upgrade --install command:

    $ helm get manifest -n elcicd-chart-demo elcicd-chart-demo
    Output
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      selector:
        elcicd.io/selector: elcicd-chart-demo
      ports:
      - name: elcicd-chart-demo-port
        port: 8081
        targetPort: 8080
        protocol: TCP
    # Rendered el-CICD Chart Template -> "service" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      revisionHistoryLimit: 0
      selector:
        matchExpressions:
        - key: elcicd.io/selector
          operator: Exists
        matchLabels:
          elcicd.io/selector: elcicd-chart-demo
      template:
        metadata:
          labels:
            app.kubernetes.io/instance: elcicd-chart-demo
            app.kubernetes.io/managed-by: Helm
            elcicd.io/selector: elcicd-chart-demo
            helm.sh/chart: elcicd-chart-0.1.0
          name: elcicd-chart-demo
          namespace: elcicd-chart-demo
        spec:
          containers:
          - name: elcicd-chart-demo
            image: registry.redhat.io/rhel8/httpd-24
            imagePullPolicy: Always
            ports:
            - name: default-port
              containerPort: 8080
              protocol: TCP
            resources:
              limits: {}
              requests: {}
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
          imagePullSecrets: []
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
    # Rendered el-CICD Chart Template -> "deployment" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.allow-http: "false"
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      rules:
      - host: httpd-elcicd-chart-demo.apps-crc.testing
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: elcicd-chart-demo
                port:
                  number: 8081
      tls:
      - secretName:
    # Rendered el-CICD Chart Template -> "ingress" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    # Profiles: []
  3. View the running elcicd-chart-demo resources in the cluster:

    $ kubectl get -n elcicd-chart-demo -l elcicd.io/selector deploy,rs,pod,cm,service,ingress
    Output
    NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/elcicd-chart-demo   1/1     1            1           4m55s
    
    NAME                                           DESIRED   CURRENT   READY   AGE
    replicaset.apps/elcicd-chart-demo-6c6fd69cb7   1         1         1       4m55s
    
    NAME                                     READY   STATUS    RESTARTS   AGE
    pod/elcicd-chart-demo-6c6fd69cb7-xtk5k   1/1     Running   0          4m55s
    
    NAME                        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
    service/elcicd-chart-demo   ClusterIP   10.217.5.104   <none>        8081/TCP   4m55s
    
    NAME                                          CLASS    HOSTS                                      ADDRESS                           PORTS     AGE
    ingress.networking.k8s.io/elcicd-chart-demo   <none>   httpd-elcicd-chart-demo.apps-crc.testing   router-default.apps-crc.testing   80, 443   4m55s
  4. Get the value of the host from the Ingress, and verify the Apache Web Server is reachable:

    $ kubectl get ingress -n elcicd-chart-demo --no-headers -o custom-columns=:.spec.rules[*].host
    Output
    httpd-elcicd-chart-demo.apps-crc.testing
    If not using CRC, run the kubectl get command above to get the correct host.
    rhel test page screenshot
  5. Uninstall the chart.

    $ helm uninstall -n elcicd-chart-demo elcicd-chart-demo
    Output
    release "elcicd-chart-demo" uninstalled

2.4. User-defined Variables

Features demonstrated
  • User-defined el-CICD Chart variables in deployment definitions.

  • Using el-CICD Chart variables as YAML templates.

  • Easily mounting ConfigMaps in Pods with the projectedVolumes helper attribute.

Both el-CICD Chart Templates and Compound el-CICD Chart Templates made use of el-CICD Chart’s built-in variables to help define their host domain. This part of the tutorial will focus on user-defined variables.

A fundamental goal of el-CICD Chart is to eliminate the need for Helm templates and instead let the user define their deployment manifests as plain YAML documents. Another goal is to remove the need for copying and pasting boilerplate YAML as much as possible when defining manifests. User-defined el-CICD Chart variables support these goals.

Create and save the following file as elcicd-demo-3.yaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
elCicdDefs: (1)
  INDEX_HTML_NAME: index.html
  DEFAULT_PAGE_CONTENT: <h1>Howdy from $<OBJ_NAME> in release $<HELM_RELEASE_NAME>!<h1>
  PAGE_CONTENT: $<DEFAULT_PAGE_CONTENT>
  HTML_PAGE: <!DOCTYPE html><html><body>$<PAGE_CONTENT></body></html>

  INDEX_HTML_NAME: index.html
  PAGE_CONTENT: <h1>Howdy from $<OBJ_NAME> in release $<HELM_RELEASE_NAME>!<h1>
  HTML_PAGE: |-
    <!DOCTYPE html>
    <html>
      <body>
        <h1>$<PAGE_CONTENT></h1>
      </body>
    </html>

elCicdTemplates:
- templateNames: [deployment, service, ingress]
  image: registry.redhat.io/rhel8/httpd-24
  host: httpd-$<NAME_SPACE>.apps-crc.testing
  projectedVolumes: (2)
  - name: $<HELM_RELEASE_NAME> (3)
    mountPath: /var/www/html/
    configMaps:
      $<INDEX_HTML_NAME>: {}

- templateName: configMap
  objName: $<INDEX_HTML_NAME> (4)
  data:
    $<OBJ_NAME>: $<HTML_PAGE> (5)
1 All el-CICD Chart variables are defined under elCicdDefs maps.
  1. Keys in the elCicdDefs map are el-CICD Chart variables.

  2. elCicdDefs maps can be any valid YAML; i.e. valid keys and values for YAML maps.

  3. By convention, variable names use UPPER_SNAKE_CASE.

  4. Variables are referenced using the syntax $<VARIABLE_NAME>.

  5. Variables can references other variables.

    1. The order variables are defined is irrelevant; i.e. a variable can reference another variable that is defined later.

    2. Variable names and references can be defined and used dynamically; e.g.:

      given FOO: howdy and howdy_BAR: welcome, $<$<FOO>_BAR> ultimately resolves to welcome.

2 projectedVolumes is a helper attribute for generating projectedVolumes.
  1. This helper attribute obviates the need for a separate volume and volumeMount definition.

  2. In this example it will mount the ConfigMap $<INDEX_HTML_NAME> (index.html) as a projected volume in the Deployment, along with it’s associated volumeMount.

3 $<HELM_RELEASE_NAME> is another built-in el-CICD Chart variable that corresponds to .Release.Name in a Helm template.
4 objName is a helper attribute that will render as the name of a resource or resources; i.e.metadata.name.
  1. objName must follow the same naming rules as metadata.name.

  2. $<OBJ_NAME> is another built-in el-CICD Chart variable referring to the el-CICD Chart template’s objName.

  3. objName and OBJ_NAME will default to the chart’s release name, $<HELM_RELEASE_NAME> if left undefined by the user.

Tutorial steps

What to expect
  • A Deployment, Service, Ingress, and ConfigMap will be deployed on the cluster using el-CICD Chart.

  • An httpd Pod will be created from the Deployment and accessible in the browser from outside the cluster.

  • The ConfigMap will contain an index.html web page that was generated from multiple el-CICD Chart variables.

  • The ConfigMap will be mounted inside the httpd Pod, and and the index.html page will become the server’s home page.

  1. Install the elcicd-chart-demo release in the elcicd-chart-demo namespace using the el-CICD Chart:

    $ helm upgrade --install --atomic -n elcicd-chart-demo --create-namespace -f elcicd-demo-3.yaml elcicd-chart-demo elcicd-charts/elcicd-chart
    Output
    Release "elcicd-chart-demo" does not exist. Installing it now.
    NAME: elcicd-chart-demo
    LAST DEPLOYED: Tue Jul 16 16:47:02 2024
    NAMESPACE: elcicd-chart-demo
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
  2. View the manifests that generated by el-CICD Chart from the helm upgrade --install command:

    $ helm get manifest -n elcicd-chart-demo elcicd-chart-demo
    Output
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: index.html
        helm.sh/chart: elcicd-chart-0.1.0
      name: index.html
      namespace: elcicd-chart-demo
    data:
      index.html: |-
        <!DOCTYPE html>
        <html>
          <body>
            <h1><h1>Howdy from index.html in release elcicd-chart-demo!<h1></h1>
          </body>
        </html>
    # Rendered el-CICD Chart Template -> "configMap" index.html
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      selector:
        elcicd.io/selector: elcicd-chart-demo
      ports:
      - name: elcicd-chart-demo-port
        port: 8080
        protocol: TCP
    # Rendered el-CICD Chart Template -> "service" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      revisionHistoryLimit: 0
      selector:
        matchExpressions:
        - key: elcicd.io/selector
          operator: Exists
        matchLabels:
          elcicd.io/selector: elcicd-chart-demo
      template:
        metadata:
          labels:
            app.kubernetes.io/instance: elcicd-chart-demo
            app.kubernetes.io/managed-by: Helm
            elcicd.io/selector: elcicd-chart-demo
            helm.sh/chart: elcicd-chart-0.1.0
          name: elcicd-chart-demo
          namespace: elcicd-chart-demo
        spec:
          containers:
          - name: elcicd-chart-demo
            image: registry.redhat.io/rhel8/httpd-24
            imagePullPolicy: Always
            ports:
            - name: default-port
              containerPort: 8080
              protocol: TCP
            resources:
              limits: {}
              requests: {}
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
            volumeMounts:
            - mountPath: /var/www/html/
              name: elcicd-chart-demo
              readOnly: false
          imagePullSecrets: []
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          volumes:
          - name: elcicd-chart-demo
            projected:
              sources:
              - configMap:
                  name: index.html
    # Rendered el-CICD Chart Template -> "deployment" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.allow-http: "false"
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      rules:
      - host: httpd-elcicd-chart-demo.apps-crc.testing
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: elcicd-chart-demo
                port:
                  number: 8080
      tls:
      - secretName:
    # Rendered el-CICD Chart Template -> "ingress" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    # Profiles: []
  3. View the running elcicd-chart-demo resources in the cluster:

    $ kubectl get -n elcicd-chart-demo -l elcicd.io/selector deploy,rs,pod,cm,service,ingress
    Output
    NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/elcicd-chart-demo   1/1     1            1           3m17s
    
    NAME                                          DESIRED   CURRENT   READY   AGE
    replicaset.apps/elcicd-chart-demo-878f4b9d5   1         1         1       3m17s
    
    NAME                                    READY   STATUS    RESTARTS   AGE
    pod/elcicd-chart-demo-878f4b9d5-x88mg   1/1     Running   0          3m17s
    
    NAME                                 DATA   AGE
    configmap/index.html                 1      3m17s
    
    NAME                        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
    service/elcicd-chart-demo   ClusterIP   10.217.5.87   <none>        8080/TCP   3m17s
    
    NAME                                          CLASS    HOSTS                                      ADDRESS                           PORTS     AGE
    ingress.networking.k8s.io/elcicd-chart-demo   <none>   httpd-elcicd-chart-demo.apps-crc.testing   router-default.apps-crc.testing   80, 443   3m17s
  4. Get the value of the host from the Ingress, and verify the Apache Web Server is reachable:

    $ kubectl get ingress -n elcicd-chart-demo --no-headers -o custom-columns=:.spec.rules[*].host
    Output
    httpd-elcicd-chart-demo.apps-crc.testing
    If not using CRC, run the kubectl get command above to get the correct host.
    user defined variables screenshot
  5. Uninstall the chart.

    $ helm uninstall -n elcicd-chart-demo elcicd-chart-demo
    Output
    release "elcicd-chart-demo" uninstalled

2.5. Deployment Profiles

Features demonstrated
  • Defining and deploying with arbitrary el-CICD Chart deployment profiles.

  • elCicdDefs-* variable map definitions.

  • Using el-CICD Chart matrices to further reduce copying and pasting boilerplate Kubernetes resource definitions.

In User-defined Variables, we demonstrated how to define and reference your own variables. In this part of the tutorial you’ll learn about deployment profiles. While the previous parts of the tutorial have focused on el-CICD Chart’s strengths with regards to templating, readability, and conciseness, it’s the deployment profiles that give el-CICD Chart its true power. This feature makes it much, much easier for users to manage the same, basic deployment definitions across numerous environments with minimal configuration changes.

Example use cases for deployment profiles
  • The software development lifecycle (SDLC).

    Development, test, and production are rarely configured the same way.

  • Different geographical jurisdictions

    Regulatory and/or language requirements almost always differ between geographical jurisdictions.

  • High availability and persistence options

    One or more services of an an application need to be deployed as highly available and/or data persistence options, either in production or for testing purposes.

Deployment profiles are most useful whenever a resource needs to be deployed differently depending on the situation or environment.

Create and save the following file as elcicd-demo-4.yaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
elCicdDefs:
  MULTI_LINGUAL_PROFILE: MULTI_LINGUAL
  INDEX_HTML_NAME: index.html
  DEFAULT_PAGE_CONTENT: <h1>Howdy from $<OBJ_NAME> in release $<HELM_RELEASE_NAME>!<h1>
  PAGE_CONTENT: $<DEFAULT_PAGE_CONTENT>
  HTML_PAGE: <!DOCTYPE html><html><body>$<PAGE_CONTENT></body></html>

elCicdDefs-$<MULTI_LINGUAL_PROFILE>: (1)
  PAGE_CONTENT: <h1><a href="$<ENGLISH>">English</a>&nbsp;<a href="$<ESPANOL>">Español</a></h1>
  ENGLISH: english.html
  ESPANOL: espanol.html

elCicdTemplates:
- templateNames: [deployment, service, ingress]
  image: registry.redhat.io/rhel8/httpd-24
  host: httpd-$<NAME_SPACE>.apps-crc.testing
  projectedVolumes:
  - name: $<HELM_RELEASE_NAME>
    mountPath: /var/www/html/
    configMaps:
      $<INDEX_HTML_NAME>: {}
      $<ENGLISH>: {} (2)
      $<ESPANOL>: {}

- templateName: configMap
  objName: $<INDEX_HTML_NAME>
  data:
    $<OBJ_NAME>: $<HTML_PAGE>

- templateName: configMap
  objNames: (3)
  - $<ENGLISH>
  - $<ESPANOL>
  mustHaveAnyProfile:
  - $<MULTI_LINGUAL_PROFILE> (4)
  elCicdDefs-$<ENGLISH>: (5)
    PAGE_CONTENT:  $<DEFAULT_PAGE_CONTENT>
  elCicdDefs-$<ESPANOL>:
    PAGE_CONTENT: <h1>¡Hola desde $<OBJ_NAME> en el lanzamiento $<HELM_RELEASE_NAME>!<h1>
  data:
    $<OBJ_NAME>: $<HTML_PAGE>
1 Deployment profiles are defined whenever an el-CICD Chart template and/or elCicdDefs variable map is marked for them.
  1. Deployment profiles must consist of upper case alphanumeric characters, '_', or '.', and must start and end with an alphanumeric characters; ([_.][A-Z0-9])*

    This naming standard was chosen so that resource names, which must follow Kubernetes naming standards, and deployment profiles could never be confused.
  2. elCicdDefs-$<MULTI_LINGUAL_PROFILE> declares the $<MULTI_LINGUAL_PROFILE> (MULTI_LINGUAL) profile.

    1. el-CICD Chart template discriminators define whether or not a template should be rendered based on the active profile(s).

2 If keys in maps or values in maps or lists evaluate to empty or null values after processing, they will be removed.
  1. If the MULTI_LINGUAL deployment profile is inactive, the keys evaluate to null, and each member of the configMaps list will not be rendered after processing.

3 objNames is one of two el-CICD Chart matrices (namespaces being the other).
  1. Matrices are lists that will tell el-CICD Chart to generate a copy of the template for each element in the list.

  2. objName will be assigned for each copy corresponding to an element in the objNames list used to generate it.

  3. The matrix definition defines two ConfigMaps, $<ENGLISH> (english.html) and `$<ESPANOL> (espanol.html).

4 mustHaveAnyProfile is a template discriminator
  1. Discriminators can also define profiles.

  2. The el-CICD Chart template defines multiple ConfigMaps via the objNames matrix, but they will only be rendered if the MULTI_LINGUAL profiles is active.

5 el-Cicd Chart variables maps can be defined for a specific template.
  1. elCicdDefs variable maps can be declared for specific profiles, a particular objName, and/or under specific el-CICD Chart templates.

    1. objName and/or profiles can be appended to elCicdDefs using a - as a delimiter; e.g.

      1. elCicdDefs-foo for objName foo, which declares variables only for objects named "foo".

      2. elCicdDefs-BAR for deployment profile BAR, which declares variables only when the BAR profile is active.

      3. elCicdDefs-foo-BAR or elCicdDefs-BAR-foo, which declares variables only for objects named "foo" when the BAR profile is active.

      4. Discriminators in elCicdDefs declarations can be dynamic; e.g. elCicdDefs-$<FOO>

      5. If an elCicdDefs-* map ends in just a dash, or has two dashes within it because a variable used to define it is empty, it will be ignored.

2.5.1. Deploy the httpd server without an active deployment profile

Deploying without a deployment profile with the above deployment definition will look identical to the User-defined Variables demonstration in every way. The lack of a proper active profile in this deployment means all the additions made to the deployment definition in elcicd-demo-4.yaml compared to elcicd-demo-3.yaml will be ignored.

Tutorial steps

What to expect
  • A Deployment, Service, Ingress, and ConfigMap will be deployed on the cluster using el-CICD Chart.

  • An httpd Pod will be created from the Deployment and accessible in the browser from outside the cluster.

  • The ConfigMap will contain an index.html web page that was generated from multiple el-CICD Chart variables.

  • The ConfigMap will be mounted inside the httpd Pod, and and the index.html page will become the server’s home page.

  1. Install the elcicd-chart-demo release in the elcicd-chart-demo namespace using the el-CICD Chart:

    $ helm upgrade --install --atomic -n elcicd-chart-demo --create-namespace -f elcicd-demo-4.yaml elcicd-chart-demo elcicd-charts/elcicd-chart
    Output
    Release "elcicd-chart-demo" does not exist. Installing it now.
    NAME: elcicd-chart-demo
    LAST DEPLOYED: Tue Jul 16 16:47:02 2024
    NAMESPACE: elcicd-chart-demo
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
  2. View the manifests that generated by el-CICD Chart from the helm upgrade --install command:

    $ helm get manifest -n elcicd-chart-demo elcicd-chart-demo
    Output
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: index.html
        helm.sh/chart: elcicd-chart-0.1.0
      name: index.html
      namespace: elcicd-chart-demo
    data:
      index.html: <!DOCTYPE html><html><body><h1>Howdy from index.html in release elcicd-chart-demo!<h1></body></html>
    # Rendered el-CICD Chart Template -> "configMap" index.html
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      selector:
        elcicd.io/selector: elcicd-chart-demo
      ports:
      - name: elcicd-chart-demo-port
        port: 8080
        protocol: TCP
    # Rendered el-CICD Chart Template -> "service" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      revisionHistoryLimit: 0
      selector:
        matchExpressions:
        - key: elcicd.io/selector
          operator: Exists
        matchLabels:
          elcicd.io/selector: elcicd-chart-demo
      template:
        metadata:
          labels:
            app.kubernetes.io/instance: elcicd-chart-demo
            app.kubernetes.io/managed-by: Helm
            elcicd.io/selector: elcicd-chart-demo
            helm.sh/chart: elcicd-chart-0.1.0
          name: elcicd-chart-demo
          namespace: elcicd-chart-demo
        spec:
          containers:
          - name: elcicd-chart-demo
            image: registry.redhat.io/rhel8/httpd-24
            imagePullPolicy: Always
            ports:
            - name: default-port
              containerPort: 8080
              protocol: TCP
            resources:
              limits: {}
              requests: {}
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
            volumeMounts:
            - mountPath: /var/www/html/
              name: elcicd-chart-demo
              readOnly: false
          imagePullSecrets: []
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          volumes:
          - name: elcicd-chart-demo
            projected:
              sources:
              - configMap:
                  name: index.html
    # Rendered el-CICD Chart Template -> "deployment" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.allow-http: "false"
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      rules:
      - host: httpd-elcicd-chart-demo.apps-crc.testing
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: elcicd-chart-demo
                port:
                  number: 8080
      tls:
      - secretName:
    # Rendered el-CICD Chart Template -> "ingress" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    # Profiles: []
    # EXCLUDED BY PROFILES: configMap -> objNames: [$<ENGLISH> $<ESPANOL>]
  3. View the running elcicd-chart-demo resources in the cluster:

    $ kubectl get -n elcicd-chart-demo -l elcicd.io/selector deploy,rs,pod,cm,service,ingress
    Output
    NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/elcicd-chart-demo   1/1     1            1           3m49s
    
    NAME                                          DESIRED   CURRENT   READY   AGE
    replicaset.apps/elcicd-chart-demo-878f4b9d5   1         1         1       3m49s
    
    NAME                                    READY   STATUS    RESTARTS   AGE
    pod/elcicd-chart-demo-878f4b9d5-ng28g   1/1     Running   0          3m49s
    
    NAME                                 DATA   AGE
    configmap/index.html                 1      3m49s
    
    NAME                        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
    service/elcicd-chart-demo   ClusterIP   10.217.5.142   <none>        8080/TCP   3m49s
    
    NAME                                          CLASS    HOSTS                                      ADDRESS                           PORTS     AGE
    ingress.networking.k8s.io/elcicd-chart-demo   <none>   httpd-elcicd-chart-demo.apps-crc.testing   router-default.apps-crc.testing   80, 443   3m49s
  4. Get the value of the host from the Ingress, and verify the Apache Web Server is reachable:

    $ kubectl get ingress -n elcicd-chart-demo --no-headers -o custom-columns=:.spec.rules[*].host
    Output
    httpd-elcicd-chart-demo.apps-crc.testing
    If not using CRC, run the kubectl get command above to get the correct host.
    deployment profiles default screenshot
  5. Uninstall the chart.

    $ helm uninstall -n elcicd-chart-demo elcicd-chart-demo
    Output
    release "elcicd-chart-demo" uninstalled

2.5.2. Install the httpd server with the MULTI_LINGUAL deployment profile

el-CICD Chart deployment profiles are defined in elCicdProfiles as a list. The helm update --install command is modified to apply deployment profile --set elCicdProfiles='{MULTI_LINGUAL}' clause. If more than one deployment profile is specified, the order of precedence is from least to greatest in determining the values of variables; e.g. given elCicdProfiles={FOO,BAR}, all conflicting variable definitions defined in the BAR profile would take precedence over FOO.

This part of the demonstration will change the server’s home page to display a pair of links that will take you to either English or Spanish versions of the "Howdy!" message.

Tutorial steps

What to expect
  • A Deployment, Service, Ingress, and ConfigMap will be deployed on the cluster using el-CICD Chart.

  • An httpd Pod will be created from the Deployment and accessible in the browser from outside the cluster.

  • An index.html, english.html, and spanish.html web page will be generated from multiple el-CICD Chart variables.

  • Three ConfigMaps, each containing the generated web pages, will be deployed to the cluster, and mounted inside the httpd Pod.

  • The index.html page will contain links to the english.html and spanish.html pages.

  1. Install the elcicd-chart-demo release in the elcicd-chart-demo namespace using the el-CICD Chart:

    $ helm upgrade --install --atomic -n elcicd-chart-demo --create-namespace --set elCicdProfiles='{MULTI_LINGUAL}' -f elcicd-demo-4.yaml elcicd-chart-demo elcicd-charts/elcicd-chart
    Output
    Release "elcicd-chart-demo" does not exist. Installing it now.
    NAME: elcicd-chart-demo
    LAST DEPLOYED: Tue Jul 16 16:47:02 2024
    NAMESPACE: elcicd-chart-demo
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
  2. View the manifests that generated by el-CICD Chart from the helm upgrade --install command:

    $ helm get manifest -n elcicd-chart-demo elcicd-chart-demo
    Output
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: index.html
        helm.sh/chart: elcicd-chart-0.1.0
      name: index.html
      namespace: elcicd-chart-demo
    data:
      index.html: <!DOCTYPE html><html><body><h1><a href="english.html">English</a>&nbsp;<a
        href="espanol.html">Español</a></h1></body></html>
    # Rendered el-CICD Chart Template -> "configMap" index.html
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: english.html
        helm.sh/chart: elcicd-chart-0.1.0
      name: english.html
      namespace: elcicd-chart-demo
    data:
      english.html: <!DOCTYPE html><html><body><h1>Howdy from english.html in release elcicd-chart-demo!<h1></body></html>
    # Rendered el-CICD Chart Template -> "configMap" english.html
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: espanol.html
        helm.sh/chart: elcicd-chart-0.1.0
      name: espanol.html
      namespace: elcicd-chart-demo
    data:
      espanol.html: <!DOCTYPE html><html><body><h1>¡Hola desde espanol.html en el lanzamiento
        elcicd-chart-demo!<h1></body></html>
    # Rendered el-CICD Chart Template -> "configMap" espanol.html
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      selector:
        elcicd.io/selector: elcicd-chart-demo
      ports:
      - name: elcicd-chart-demo-port
        port: 8080
        protocol: TCP
    # Rendered el-CICD Chart Template -> "service" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      revisionHistoryLimit: 0
      selector:
        matchExpressions:
        - key: elcicd.io/selector
          operator: Exists
        matchLabels:
          elcicd.io/selector: elcicd-chart-demo
      template:
        metadata:
          labels:
            app.kubernetes.io/instance: elcicd-chart-demo
            app.kubernetes.io/managed-by: Helm
            elcicd.io/selector: elcicd-chart-demo
            helm.sh/chart: elcicd-chart-0.1.0
          name: elcicd-chart-demo
          namespace: elcicd-chart-demo
        spec:
          containers:
          - name: elcicd-chart-demo
            image: registry.redhat.io/rhel8/httpd-24
            imagePullPolicy: Always
            ports:
            - name: default-port
              containerPort: 8080
              protocol: TCP
            resources:
              limits: {}
              requests: {}
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
            volumeMounts:
            - mountPath: /var/www/html/
              name: elcicd-chart-demo
              readOnly: false
          imagePullSecrets: []
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          volumes:
          - name: elcicd-chart-demo
            projected:
              sources:
              - configMap:
                  name: english.html
              - configMap:
                  name: espanol.html
              - configMap:
                  name: index.html
    # Rendered el-CICD Chart Template -> "deployment" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.allow-http: "false"
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo
      namespace: elcicd-chart-demo
    spec:
      rules:
      - host: httpd-elcicd-chart-demo.apps-crc.testing
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: elcicd-chart-demo
                port:
                  number: 8080
      tls:
      - secretName:
    # Rendered el-CICD Chart Template -> "ingress" elcicd-chart-demo
    ---
    # Source: elcicd-chart/templates/render.yaml
    # Profiles: [MULTI-LINGUAL]
  3. View the running elcicd-chart-demo resources in the cluster:

    $ kubectl get -n elcicd-chart-demo -l elcicd.io/selector deploy,rs,pod,cm,service,ingress
    Output
    NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/elcicd-chart-demo   1/1     1            1           5m23s
    
    NAME                                           DESIRED   CURRENT   READY   AGE
    replicaset.apps/elcicd-chart-demo-58494f8c55   1         1         1       5m23s
    
    NAME                                     READY   STATUS    RESTARTS   AGE
    pod/elcicd-chart-demo-58494f8c55-5tp6x   1/1     Running   0          5m23s
    
    NAME                                 DATA   AGE
    configmap/english.html               1      5m23s
    configmap/espanol.html               1      5m23s
    configmap/index.html                 1      5m23s
    
    NAME                        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
    service/elcicd-chart-demo   ClusterIP   10.217.5.97   <none>        8080/TCP   5m23s
    
    NAME                                          CLASS    HOSTS                                      ADDRESS                           PORTS     AGE
    ingress.networking.k8s.io/elcicd-chart-demo   <none>   httpd-elcicd-chart-demo.apps-crc.testing   router-default.apps-crc.testing   80, 443   5m23s
  4. Get the value of the host from the Ingress, and verify the Apache Web Server is reachable:

    $ kubectl get ingress -n elcicd-chart-demo --no-headers -o custom-columns=:.spec.rules[*].host
    Output
    httpd-elcicd-chart-demo.apps-crc.testing
    If not using CRC, run the kubectl get command above to get the correct host.
    deployment profiles multi lingual screenshot
  5. Uninstall the chart.

    $ helm uninstall -n elcicd-chart-demo elcicd-chart-demo
    Output
    release "elcicd-chart-demo" uninstalled

2.6. Free Form Templates

Features demonstrated
  • Defining free form templates.

  • Using el-CICD Chart matrices to deploy copies of the same el-CICD template across namespaces.

So far this tutorial has focused on the easy deployments of services using built-in helper el-CICD Chart templates. Unfortunately, because Kubernetes has many dozens of resources, and it is infinitely extensible with Custom Resource Definitions (CRD), creating helper templates for every resource deployable to a Kubernetes cluster is not feasible.

To address this, el-CICD Chart supports templating any arbitrary YAML as an el-CICD Chart template, including Kubernetes resources. Rather than using a named helper template with templateName(s), the full YAML of the resource is written under the template key. While more verbose than their helper template counterparts, they still allow for the use of el-CICD Chart variables, deployment profiles, and matrices; thus, they will still be able to take advantage of the most powerful features of the el-CICD Chart.

Example use cases for free form templates
  • Any default Kubernetes resource without a corresponding el-CICD Chart helper template

  • Custom Resource Definitions

    Many Kubernetes add-ons have CRD’s and will therefore not have corresponding el-CICD Chart helper templates.

  • General YAML templating

    Some use cases involve YAML that does not represent a Kubernetes object directly.

    • Third party chart integration

      Converting an already working Helm chart into a el-CICD Chart compatible chart may not be feasible and/or is probably not worth the time. el-CICD Chart can be used as a general YAML templating tool to generate values.yaml files for other Helm charts via Helm post-renderering.

    • Dynamic Kustomizations

      kustomization.yaml files only support statically declared data. If you need a more dynamic solution, kustomization.yaml files can be templated using el-CICD Chart, and kustomize applied during Helm post-rendering.

Create and save the following file as elcicd-demo-5.yaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
elCicdDefs:
  ENGLISH_JOB: job-en
  ESPANOL_JOB: job-es
  OBJ_NAMES:
  - $<ENGLISH_JOB>
  - $<ESPANOL_JOB>
  ENV:
  - name: WELCOME_MSG
    value: $<WELCOME_MSG>
  JOB_NAMESPACE_2: elcicd-chart-demo-2
  NAMESPACES: (1)
  - $<HELM_RELEASE_NAMESPACE>
  - $<JOB_NAMESPACE_2>
  COMMAND: ["bash", "-c"]
  JOB_SCRIPT:
  - for COUNTER in {1..5};
    do
        echo ${WELCOME_MSG};
    done

elCicdDefs-$<ENGLISH_JOB>:
  WELCOME_MSG: 'Howdy from $<OBJ_NAME> in release $<HELM_RELEASE_NAME>!'

elCicdDefs-$<ESPANOL_JOB>:
  WELCOME_MSG: '¡Hola desde $<OBJ_NAME> en el lanzamiento $<HELM_RELEASE_NAME>!'

elCicdTemplates:
- templateName: namespace
  objName: $<JOB_NAMESPACE_2>

- templateName: job
  objNames: $<OBJ_NAMES>
  namespaces: $<NAMESPACES>
  objName: $<>-helper (2)
  image: quay.io/centos/centos:stream9-minimal
  command: $<COMMAND>
  args: $<JOB_SCRIPT>
  env: $<ENV>

- objNames: $<OBJ_NAMES>
  namespaces: $<NAMESPACES>
  objName: $<>-raw
  template: (3)
    apiVersion: batch/v1
    kind: Job
    spec:
      template:
        spec:
          containers:
          - name: $<OBJ_NAME>
            image: quay.io/centos/centos:stream9-minimal
            command: $<COMMAND>
            args: $<JOB_SCRIPT>
            env: $<ENV> (4)
          restartPolicy: Never
1 Like objNames, namespaces is an el-CICD Chart matrix.

Each element in the namespaces list will generate a copy of the el-CICD Chart template, and assign the value to .metadata.namespace.

2 Both objNames and namespaces can use patterns to further decorate each final matrix value.
  1. $<> refers each element in the matrix; e.g. job-en or job-es.

  2. $<#> refers to the index of the element in the matrix; e.g. the pattern $<>-$<#> would generate job-en-1 and job-en-2.

  3. In the deployment definition above, the base name is decorated with either -helper or -raw so the pods generated from either the helper template or the raw YAML templates are clearly identified.

  4. In templates generated from matrices with patterns, use $<BASE_OBJ_NAME> to refer to the undecorated element from the matrix’s list that generated $<OBJ_NAME>.

3 The template helper attribute contains the free form YAML definition.
  1. Matrices, variables, and deployment profiles can be used as usual with free form el-CICD Chart template.

  2. The metadata section can optionally defined directly in.

    1. el-CICD Chart will attempt generate a metadata automatically if it is missing.

    2. Any fields defined in metadata sections will always take precedence over values defined in helper attributes.

    3. If kubeObject: false is set on the el-CICD Chart template, the metadata section will not be generated if missing.

4 Defining environment variables in a container is the same whether using helper or raw templates.
There is rarely if ever a reason to use a raw template when cl-CICD Chart helper templates exist. This example is for demonstration purposes only.

Tutorial steps

What to expect
  • A second namespace will be created from a namespace helper template, and managed by Helm.

  • Using a job el-CICD Chart helper template, four Jobs (two per namespace) will be deployed on the cluster, based on two objNames and two namespaces.

  • Using a job el-CICD Chart free form template, four Jobs (two per namespace) will be deployed on the cluster, based on two objNames and two namespaces.

  • All Job containers will be created from a simple CentOS 9 Stream minimal image.

  • The manifests between all eight Jobs deployed will be identical except for metadata.name, metadata.namespace, and the WELCOME_MSG value.

  • Each Job Pod will log a few welcome messages based on the environment variable set in the Pod before completing, either in English or Spanish, based on their object names.

  1. Install the elcicd-chart-demo release in the elcicd-chart-demo namespace using the el-CICD Chart:

    $ helm upgrade --install --atomic -n elcicd-chart-demo --create-namespace -f elcicd-demo-5.yaml elcicd-chart-demo elcicd-charts/elcicd-chart
    Output
    Release "elcicd-chart-demo" does not exist. Installing it now.
    NAME: elcicd-chart-demo
    LAST DEPLOYED: Tue Jul 16 16:47:02 2024
    NAMESPACE: elcicd-chart-demo
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
  2. View the manifests that generated by el-CICD Chart from the helm upgrade --install command:

    $ helm get manifest -n elcicd-chart-demo elcicd-chart-demo
    Output
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: elcicd-chart-demo-2
        helm.sh/chart: elcicd-chart-0.1.0
      name: elcicd-chart-demo-2
      namespace: elcicd-chart-demo
    # Rendered el-CICD Chart Template -> "namespace" elcicd-chart-demo-2
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: job-en-helper
        helm.sh/chart: elcicd-chart-0.1.0
      name: job-en-helper
      namespace: elcicd-chart-demo
    spec:
      template:
        metadata:
          labels:
            app.kubernetes.io/instance: elcicd-chart-demo
            app.kubernetes.io/managed-by: Helm
            elcicd.io/selector: job-en-helper
            helm.sh/chart: elcicd-chart-0.1.0
          name: job-en-helper
          namespace: elcicd-chart-demo
        spec:
          containers:
          - name: job-en-helper
            image: quay.io/centos/centos:stream9-minimal
            imagePullPolicy: Always
            ports:
            - name: default-port
              containerPort: 8080
              protocol: TCP
            resources:
              limits: {}
              requests: {}
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
            args:
            - for COUNTER in {1..5}; do echo ${WELCOME_MSG}; done
            command:
            - bash
            - -c
            env:
            - name: WELCOME_MSG
              value: Howdy from job-en-helper in release elcicd-chart-demo!
          imagePullSecrets: []
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          restartPolicy: "Never"
    # Rendered el-CICD Chart Template -> "job" job-en-helper
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: job-en-helper
        helm.sh/chart: elcicd-chart-0.1.0
      name: job-en-helper
      namespace: elcicd-chart-demo-2
    spec:
      template:
        metadata:
          labels:
            app.kubernetes.io/instance: elcicd-chart-demo
            app.kubernetes.io/managed-by: Helm
            elcicd.io/selector: job-en-helper
            helm.sh/chart: elcicd-chart-0.1.0
          name: job-en-helper
          namespace: elcicd-chart-demo-2
        spec:
          containers:
          - name: job-en-helper
            image: quay.io/centos/centos:stream9-minimal
            imagePullPolicy: Always
            ports:
            - name: default-port
              containerPort: 8080
              protocol: TCP
            resources:
              limits: {}
              requests: {}
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
            args:
            - for COUNTER in {1..5}; do echo ${WELCOME_MSG}; done
            command:
            - bash
            - -c
            env:
            - name: WELCOME_MSG
              value: Howdy from job-en-helper in release elcicd-chart-demo!
          imagePullSecrets: []
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          restartPolicy: "Never"
    # Rendered el-CICD Chart Template -> "job" job-en-helper
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: job-es-helper
        helm.sh/chart: elcicd-chart-0.1.0
      name: job-es-helper
      namespace: elcicd-chart-demo
    spec:
      template:
        metadata:
          labels:
            app.kubernetes.io/instance: elcicd-chart-demo
            app.kubernetes.io/managed-by: Helm
            elcicd.io/selector: job-es-helper
            helm.sh/chart: elcicd-chart-0.1.0
          name: job-es-helper
          namespace: elcicd-chart-demo
        spec:
          containers:
          - name: job-es-helper
            image: quay.io/centos/centos:stream9-minimal
            imagePullPolicy: Always
            ports:
            - name: default-port
              containerPort: 8080
              protocol: TCP
            resources:
              limits: {}
              requests: {}
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
            args:
            - for COUNTER in {1..5}; do echo ${WELCOME_MSG}; done
            command:
            - bash
            - -c
            env:
            - name: WELCOME_MSG
              value: ¡Hola desde job-es-helper en el lanzamiento elcicd-chart-demo!
          imagePullSecrets: []
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          restartPolicy: "Never"
    # Rendered el-CICD Chart Template -> "job" job-es-helper
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: job-es-helper
        helm.sh/chart: elcicd-chart-0.1.0
      name: job-es-helper
      namespace: elcicd-chart-demo-2
    spec:
      template:
        metadata:
          labels:
            app.kubernetes.io/instance: elcicd-chart-demo
            app.kubernetes.io/managed-by: Helm
            elcicd.io/selector: job-es-helper
            helm.sh/chart: elcicd-chart-0.1.0
          name: job-es-helper
          namespace: elcicd-chart-demo-2
        spec:
          containers:
          - name: job-es-helper
            image: quay.io/centos/centos:stream9-minimal
            imagePullPolicy: Always
            ports:
            - name: default-port
              containerPort: 8080
              protocol: TCP
            resources:
              limits: {}
              requests: {}
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
            args:
            - for COUNTER in {1..5}; do echo ${WELCOME_MSG}; done
            command:
            - bash
            - -c
            env:
            - name: WELCOME_MSG
              value: ¡Hola desde job-es-helper en el lanzamiento elcicd-chart-demo!
          imagePullSecrets: []
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          restartPolicy: "Never"
    # Rendered el-CICD Chart Template -> "job" job-es-helper
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: job-en-raw
        helm.sh/chart: elcicd-chart-0.1.0
      name: job-en-raw
      namespace: elcicd-chart-demo
    spec:
      template:
        spec:
          containers:
          - args:
            - for COUNTER in {1..5}; do echo ${WELCOME_MSG}; done
            command:
            - bash
            - -c
            env:
            - name: WELCOME_MSG
              value: Howdy from job-en-raw in release elcicd-chart-demo!
            image: quay.io/centos/centos:stream9-minimal
            name: job-en-raw
          restartPolicy: Never
    # Rendered YAML Template -> kind: "Job" name: "job-en-raw"
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: job-en-raw
        helm.sh/chart: elcicd-chart-0.1.0
      name: job-en-raw
      namespace: elcicd-chart-demo-2
    spec:
      template:
        spec:
          containers:
          - args:
            - for COUNTER in {1..5}; do echo ${WELCOME_MSG}; done
            command:
            - bash
            - -c
            env:
            - name: WELCOME_MSG
              value: Howdy from job-en-raw in release elcicd-chart-demo!
            image: quay.io/centos/centos:stream9-minimal
            name: job-en-raw
          restartPolicy: Never
    # Rendered YAML Template -> kind: "Job" name: "job-en-raw"
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: job-es-raw
        helm.sh/chart: elcicd-chart-0.1.0
      name: job-es-raw
      namespace: elcicd-chart-demo
    spec:
      template:
        spec:
          containers:
          - args:
            - for COUNTER in {1..5}; do echo ${WELCOME_MSG}; done
            command:
            - bash
            - -c
            env:
            - name: WELCOME_MSG
              value: ¡Hola desde job-es-raw en el lanzamiento elcicd-chart-demo!
            image: quay.io/centos/centos:stream9-minimal
            name: job-es-raw
          restartPolicy: Never
    # Rendered YAML Template -> kind: "Job" name: "job-es-raw"
    ---
    # Source: elcicd-chart/templates/render.yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      labels:
        app.kubernetes.io/instance: elcicd-chart-demo
        app.kubernetes.io/managed-by: Helm
        elcicd.io/selector: job-es-raw
        helm.sh/chart: elcicd-chart-0.1.0
      name: job-es-raw
      namespace: elcicd-chart-demo-2
    spec:
      template:
        spec:
          containers:
          - args:
            - for COUNTER in {1..5}; do echo ${WELCOME_MSG}; done
            command:
            - bash
            - -c
            env:
            - name: WELCOME_MSG
              value: ¡Hola desde job-es-raw en el lanzamiento elcicd-chart-demo!
            image: quay.io/centos/centos:stream9-minimal
            name: job-es-raw
          restartPolicy: Never
    # Rendered YAML Template -> kind: "Job" name: "job-es-raw"
    ---
    # Source: elcicd-chart/templates/render.yaml
    # Profiles: []
  3. View the running elcicd-chart-demo resources in the cluster:

    $ kubectl get -n elcicd-chart-demo jobs,pods
    Output
    NAME                      STATUS     COMPLETIONS   DURATION   AGE
    job.batch/job-en-helper   Complete   1/1           11s        23s
    job.batch/job-en-raw      Complete   1/1           12s        23s
    job.batch/job-es-helper   Complete   1/1           11s        23s
    job.batch/job-es-raw      Complete   1/1           12s        23s
    
    NAME                      READY   STATUS      RESTARTS   AGE
    pod/job-en-helper-vx985   0/1     Completed   0          23s
    pod/job-en-raw-zx24g      0/1     Completed   0          23s
    pod/job-es-helper-t9b5v   0/1     Completed   0          23s
    pod/job-es-raw-lbr42      0/1     Completed   0          23s
  4. View the running elcicd-chart-demo-2 resources in the cluster:

    $ kubectl get -n elcicd-chart-demo-2 jobs,pods
    Output
    NAME                      STATUS     COMPLETIONS   DURATION   AGE
    job.batch/job-en-helper   Complete   1/1           12s        44s
    job.batch/job-en-raw      Complete   1/1           13s        44s
    job.batch/job-es-helper   Complete   1/1           12s        44s
    job.batch/job-es-raw      Complete   1/1           12s        44s
    
    NAME                      READY   STATUS      RESTARTS   AGE
    pod/job-en-helper-8r6pg   0/1     Completed   0          44s
    pod/job-en-raw-ww6z9      0/1     Completed   0          44s
    pod/job-es-helper-vtlqj   0/1     Completed   0          44s
    pod/job-es-raw-r8ftk      0/1     Completed   0          44s
  5. Check the logs of the Jobs:

    Only two of the eight jobs are displayed for brevity.
    $ oc logs -f -n elcicd-chart-demo job-es-helper-t9b5v
    Output
    Howdy from job-en-helper in release elcicd-chart-demo!
    Howdy from job-en-helper in release elcicd-chart-demo!
    Howdy from job-en-helper in release elcicd-chart-demo!
    Howdy from job-en-helper in release elcicd-chart-demo!
    Howdy from job-en-helper in release elcicd-chart-demo!
    $ oc logs -f -n elcicd-chart-demo-2 job-en-helper-8r6pg
    Output
    ¡Hola desde job-es-helper en el lanzamiento elcicd-chart-demo!
    ¡Hola desde job-es-helper en el lanzamiento elcicd-chart-demo!
    ¡Hola desde job-es-helper en el lanzamiento elcicd-chart-demo!
    ¡Hola desde job-es-helper en el lanzamiento elcicd-chart-demo!
    ¡Hola desde job-es-helper en el lanzamiento elcicd-chart-demo!
  6. Uninstall the chart.

    $ helm uninstall -n elcicd-chart-demo elcicd-chart-demo
    Output
    release "elcicd-chart-demo" uninstalled

2.7. Remove the el-CICD Chart repository

$ helm repo remove elcicd-charts
Output
"elcicd-charts" has been removed from your repositories

This concludes the el-CICD Chart tutorial.