59

i have a cronjob helm chat, i can define many jobs in values.yaml and cronjob.yaml will provision my jobs. I have faced an issue when setting the image tag id in command line, following command throw no errors but it wont update jobs image tag to new one.

helm upgrade cronjobs cronjobs/ --wait --set job.myservice.image.tag=b70d744

cronjobs will run with old image tag how can i resolve this?

here is my cronjobs.yaml

{{- $chart_name := .Chart.Name }}
{{- $chart_version := .Chart.Version | replace "+" "_" }}
{{- $release_name := .Release.Name }}

{{- range $job := .Values.jobs }}
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  namespace: "{{ $job.namespace }}"
  name: "{{ $release_name }}-{{ $job.name }}"
  labels:
    chart: "{{ $chart_name }}-{{ $chart_version }}"
spec:
  concurrencyPolicy: {{ $job.concurrencyPolicy }}
  failedJobsHistoryLimit: {{ $job.failedJobsHistoryLimit }}
  suspend: {{ $job.suspend }}
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: {{ $release_name }}
            cron: {{ $job.name }}
        spec:
          containers:
          - image: "{{ $job.image.repository }}:{{ $job.image.tag }}"
            imagePullPolicy: {{ $job.image.imagePullPolicy }}
            ports:
              - name: http
                containerPort: 80
                protocol: TCP
            name: {{ $job.name }}
            args:
{{ toYaml $job.args | indent 12 }}
            env:
{{ toYaml $job.image.env | indent 12 }}
            volumeMounts:
            - name: nfs
              mountPath: "{{ $job.image.nfslogpath }}"
          restartPolicy: OnFailure
          imagePullSecrets:
            - name: {{ $job.image.secret }}
          volumes:
            - name: nfs
              nfs:
                server: "{{ $job.image.server }}"
                path: "{{ $job.image.nfspath }}"
                readOnly: false
  schedule: {{ $job.schedule | quote }}
  successfulJobsHistoryLimit: {{ $job.successfulJobsHistoryLimit }}
  {{- end }}

here is my values.yaml

jobs:
  - name: myservice
    namespace: default
    image:
      repository: xxx.com/myservice
      tag: fe4544
      pullPolicy: Always
      secret: xxx
      nfslogpath: "/var/logs/"
      nfsserver: "xxx"
      nfspath: "/nfs/xxx/cronjobs/"
      nfsreadonly: false
      env:
    schedule: "*/5 * * * *"
    args:
    failedJobsHistoryLimit: 1
    successfulJobsHistoryLimit: 3
    concurrencyPolicy: Forbid
    suspend: false

  - name: myservice2
    namespace: default
    image:
      repository: xxxx/myservice2
      tag: 1dff39a
      pullPolicy: IfNotPresent
      secret: xxxx
      nfslogpath: "/var/logs/"
      nfsserver: "xxxx"
      nfspath: "/nfs/xxx/cronjobs/"
      nfsreadonly: false
      env:
    schedule: "*/30 * * * *"
    args:
    failedJobsHistoryLimit: 1
    successfulJobsHistoryLimit: 2
    concurrencyPolicy: Forbid
    suspend: false
edbighead
  • 5,607
  • 5
  • 29
  • 35
Jack
  • 1,162
  • 3
  • 12
  • 27

5 Answers5

99

If you need to pass array values you can use curly braces (unix shell require quotes):

--set test={x,y,z}
--set "test={x,y,z}"

Result YAML:

test:
  - x
  - y
  - z

Source: https://helm.sh/docs/intro/using_helm/#the-format-and-limitations-of---set

EDITED : added double-quotes for unix shell like bash

Franklin Piat
  • 3,952
  • 3
  • 32
  • 45
Thiago Falcao
  • 4,463
  • 39
  • 34
  • This does not seem to work, at least as of `2.16` version of helm. It gives `Error: This command needs 2 arguments: release name, chart path` when running something like `helm upgrade opining-frog deploy/traefik/chart --set externalIps={a,b,c} --debug`. Which version of helm are you using? – David Fernandez Dec 03 '19 at 18:33
  • 1
    Have you test with --set first? Example: helm upgrade --set pwd=3jk$o2,z=f\30.e redis ./redis Source: https://v2.helm.sh/docs/helm/#helm-upgrade – Thiago Falcao Dec 03 '19 at 18:53
  • 14
    Thanks a lot, that did not work, but I got it to work by scaping the commas (in case someone else faces same issue): `helm upgrade opining-frog deploy/traefik/chart --set externalIps={a\,b\,c}`. Few hours battling with this. – David Fernandez Dec 04 '19 at 10:00
  • 3
    Thanks David! Seems the following will resolve the stated error as well: `--set "service.ListValue={a,b,c}"` – Feocco Oct 22 '20 at 16:24
50

Update for Helm 2.5.0

As of Helm 2.5.0, it is possible to access list items using an array index syntax.

For example, --set servers[0].port=80 becomes:

servers:
  - port: 80
brass monkey
  • 5,841
  • 10
  • 36
  • 61
  • @justin.m.chase - don't agree. This is setting an array item to a map. Whilst this is useful, it's not what the question asked. – SiHa Oct 04 '21 at 08:48
8

For the sake of completeness I'll post a more complex example with Helm 3.

Let's say that you have this in your values.yaml file:

extraEnvVars:
- name: CONFIG_BACKEND_URL
  value: "https://api.example.com"
- name: CONFIG_BACKEND_AUTH_USER
  value: "admin"
- name: CONFIG_BACKEND_AUTH_PWD
  value: "very-secret-password"

You can --set just the value for the CONFIG_BACKEND_URL this way:

helm install ... --set "extraEnvVars[0].value=http://172.23.0.1:36241"

The other two variables (i.e. CONFIG_BACKEND_AUTH_USER and CONFIG_BACKEND_AUTH_PWD) will be read from the values.yaml file since we're not overwriting them with a --set. Same for extraEnvVars[0].name which will be CONFIG_BACKEND_URL as per values.yaml.

Source: https://helm.sh/docs/intro/using_helm/#the-format-and-limitations-of---set

Francesco Casula
  • 26,184
  • 15
  • 132
  • 131
7

Since you are using array in your values.yaml file, please see related issue

Alternative solution

  • Your values.yaml is missing values for args and env. I've set them in my example, as well as changed indent to 14

  • Your cronjob.yaml server: "{{ $job.image.server }}" value is null, and I've changed it to .image.nfsserver

Instead of using array, just separate your services like in example below:

values.yaml

jobs:
  myservice:
    namespace: default
    image:
      repository: xxx.com/myservice
      tag: fe4544
      pullPolicy: Always
      secret: xxx
      nfslogpath: "/var/logs/"
      nfsserver: "xxx"
      nfspath: "/nfs/xxx/cronjobs/"
      nfsreadonly: false
      env:
        key: val
    schedule: "*/5 * * * *"
    args:
      key: val
    failedJobsHistoryLimit: 1
    successfulJobsHistoryLimit: 3
    concurrencyPolicy: Forbid
    suspend: false

  myservice2:
    namespace: default
    image:
      repository: xxxx/myservice2
      tag: 1dff39a
      pullPolicy: IfNotPresent
      secret: xxxx
      nfslogpath: "/var/logs/"
      nfsserver: "xxxx"
      nfspath: "/nfs/xxx/cronjobs/"
      nfsreadonly: false
      env:
        key: val
    schedule: "*/30 * * * *"
    args:
      key: val
    failedJobsHistoryLimit: 1
    successfulJobsHistoryLimit: 2
    concurrencyPolicy: Forbid
    suspend: false

In your cronjob.yaml use {{- range $job, $val := .Values.jobs }} to iterate over values.

Use $job where you used {{ $job.name }}.

Access values like suspend with {{ .suspend }} instead of {{ $job.suspend }}

cronjob.yaml

{{- $chart_name := .Chart.Name }}
{{- $chart_version := .Chart.Version | replace "+" "_" }}
{{- $release_name := .Release.Name }}

{{- range $job, $val := .Values.jobs }}
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  namespace: {{ .namespace }} 
  name: "{{ $release_name }}-{{ $job }}"
  labels:
    chart: "{{ $chart_name }}-{{ $chart_version }}"
spec:
  concurrencyPolicy: {{ .concurrencyPolicy }}
  failedJobsHistoryLimit: {{ .failedJobsHistoryLimit }}
  suspend: {{ .suspend }}
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: {{ $release_name }}
            cron: {{ $job }}
        spec:
          containers:
          - image: "{{ .image.repository }}:{{ .image.tag }}"
            imagePullPolicy: {{ .image.imagePullPolicy }}
            ports:
              - name: http
                containerPort: 80
                protocol: TCP
            name: {{ $job }}
            args:
{{ toYaml .args | indent 14 }}
            env:
{{ toYaml .image.env | indent 14 }}
            volumeMounts:
            - name: nfs
              mountPath: "{{ .image.nfslogpath }}"
          restartPolicy: OnFailure
          imagePullSecrets:
            - name: {{ .image.secret }}
          volumes:
            - name: nfs
              nfs:
                server: "{{ .image.nfsserver }}"
                path: "{{ .image.nfspath }}"
                readOnly: false
  schedule: {{ .schedule | quote }}
  successfulJobsHistoryLimit: {{ .successfulJobsHistoryLimit }}
{{- end }}

Passing values using --set :

helm upgrade cronjobs cronjobs/ --wait --set jobs.myservice.image.tag=b70d744

Example:

helm install --debug --dry-run --set jobs.myservice.image.tag=my123tag .

...
HOOKS:
MANIFEST:

---
# Source: foo/templates/cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  namespace: default
  name: "illmannered-iguana-myservice"
  labels:
    chart: "foo-0.1.0"
spec:
  concurrencyPolicy: Forbid
  failedJobsHistoryLimit: 1
  suspend: false
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: illmannered-iguana
            cron: myservice
        spec:
          containers:
          - image: "xxx.com/myservice:my123tag"
            imagePullPolicy:
            ports:
              - name: http
                containerPort: 80
                protocol: TCP
            name: myservice
            args:
              key: val

            env:
              key: val

            volumeMounts:
            - name: nfs
              mountPath: "/var/logs/"
          restartPolicy: OnFailure
          imagePullSecrets:
            - name: xxx
          volumes:
            - name: nfs
              nfs:
                server: "xxx"
                path: "/nfs/xxx/cronjobs/"
                readOnly: false
  schedule: "*/5 * * * *"
  successfulJobsHistoryLimit: 3
---
# Source: foo/templates/cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  namespace: default
  name: "illmannered-iguana-myservice2"
  labels:
    chart: "foo-0.1.0"
spec:
  concurrencyPolicy: Forbid
  failedJobsHistoryLimit: 1
  suspend: false
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: illmannered-iguana
            cron: myservice2
        spec:
          containers:
          - image: "xxxx/myservice2:1dff39a"
            imagePullPolicy:
            ports:
              - name: http
                containerPort: 80
                protocol: TCP
            name: myservice2
            args:
              key: val

            env:
              key: val

            volumeMounts:
            - name: nfs
              mountPath: "/var/logs/"
          restartPolicy: OnFailure
          imagePullSecrets:
            - name: xxxx
          volumes:
            - name: nfs
              nfs:
                server: "xxxx"
                path: "/nfs/xxx/cronjobs/"
                readOnly: false
  schedule: "*/30 * * * *"
  successfulJobsHistoryLimit: 2

Hope that helps!

edbighead
  • 5,607
  • 5
  • 29
  • 35
  • 4
    Passing array is now supported using `--set "test={x,y,z}"` and `--set servers[0].port=80` as explained in other answsers. – Franklin Piat Nov 20 '20 at 15:26
  • i your cronjob.yaml you define $val but never used it, inside the range loop if I try to access .env it returns an error, nill pointer evaluating interface, are you sure this is the right way to access variables inside the loop ? – Elias Ghali Jul 01 '21 at 08:44
  • @edbighead Can you please answer my question here --> https://stackoverflow.com/questions/69173783/setting-up-multiple-cronjob-using-helm My question is relatively easy. – Shailesh Sutar Sep 14 '21 at 18:21
7

On helm 3. This works for me. --set "servers[0].port=80" --set "servers[1].port=8080"

Ammanuel g
  • 151
  • 2
  • 4
  • 3
    This also works for nested elements. An example : `"elements[0].arguments[0].value=firstValue"` `"elements[0].arguments[1].value=secondValue"` – Yann Sep 10 '21 at 10:02