Search code examples
kubernetes-helm

Provide multiple args to a container command in helm


I've got a helm chart for cron jobs which has been working as expected until now when I've got to pass multiple arguments to a command and want to break the args over multiple lines.

My attempts to break the arguments over multiple lines so far have resulted in the command not receiving the required arguments at all (perhaps a new line problem) or syntax problems from helm with errors such as:

json: cannot unmarshal string into Go struct field

As a simple example, my command would be ran from bash like so;

python -m django scale_workloads --appserver-reg 1 --appserver-up 2 --nginx-reg 1 --nginx-up 2

Usually for this, my helm templates would do:

containers:
  - name: word-check
    image: {{ .Values.gke_registry }}/my_image:{{ .Values.global.build }}
    command: ["/bin/sh","-c"]
    args: ["python -m django word_check --log-all --wordlist /etc/words.txt"]

I've tried many different formats for splitting the arguments over multiple lines, checking yaml syntax as well.

Some things I've tried;

command: [ "/bin/sh","-c" ]
args: [
  "python -m django scale_workloads",
  "--appserver-reg={{ .Values.pods.appserver.minReplicas }}",
  "--appserver-up={{ .Values.pods.appserver.minReplicasUp }}",
  "--nginx-reg={{ .Values.pods.nginx.minReplicas }}",
  "--nginx-up={{ .Values.pods.nginx.minReplicasUp }}"
]
command: [ "/bin/sh","-c" ]
args: |
  python -m django scale_workloads
  --appserver-reg={{ .Values.pods.appserver.minReplicas }}
  --appserver-up={{ .Values.pods.appserver.minReplicasUp }}
  --nginx-reg={{ .Values.pods.nginx.minReplicas }}
  --nginx-up={{ .Values.pods.nginx.minReplicasUp }}
command: [ "/bin/sh","-c" ]
args: >-
  python -m django scale_workloads
  --appserver-reg={{ .Values.pods.appserver.minReplicas }}
  --appserver-up={{ .Values.pods.appserver.minReplicasUp }}
  --nginx-reg={{ .Values.pods.nginx.minReplicas }}
  --nginx-up={{ .Values.pods.nginx.minReplicasUp }}

Solution

  • I suspect the syntax you're looking for is

    command: ["/bin/sh", "-c"]
    args:
      - >-
          python -m django scale_workloads
          --appserver-reg={{ .Values.pods.appserver.minReplicas }}
          ...
    

    At a data model level, args: must be a list, and each item in the list must be a string. Starting a new line with indented - introduces a list item. The >- introduces YAML block scalar syntax; the following indented lines are joined together with single spaces, and there is not a leading or trailing new line.

    As an alternative, your first attempt makes args: explicitly a list. This isn't compatible with sh -c which expects a single command word, but on the other hand you're not using any shell features (variable expansion, pipelines, redirects). If args: or command: is a list, then each shell word needs to be its own list item. You could also use this approach with Helm (and Kubernetes more generally)

    command:
      - python
      - -m
      - django
      - scale_workloads
      - --appserver-reg={{ .Values.pods.appserver.minReplicas }}
      - ...
    

    Here note I don't have a sh -c wrapper, and I haven't tried to split the word list into separate command: and args: (they just get combined together).