<p>My .yaml looks like this:</p>
<pre><code>apiVersion: batch/v1
kind: Job
metadata:
  name: foo
  namespace: bar
spec:
  template:
    spec:
      imagePullSecrets:
        - name: $DOCKERHUB_REGISTRY_SECRET
      containers:
        - name: django
          image: $DOCKERHUB_USER/$DOCKERHUB_IMAGENAME:$VERSION
          command: [ 'python manage.py makemigrations' ]
          :
</code></pre>
<p>However I see a lot of alternatives for <code>command</code>:</p>
<pre><code>          command: [ 'python', 'manage.py', 'makemigrations' ]
</code></pre>
<pre><code>          command: [ '/bin/sh -c', 'python', 'manage.py', 'makemigrations' ]
</code></pre>
<pre><code>          command: [ '/bin/sh', '-c' ]
          args: [ 'python', 'manage.py', 'makemigrations' ]
</code></pre>
<pre><code>          command: [ 'python' ]
          args: [ 'manage.py', 'makemigrations' ]
</code></pre>
<p>etc.</p>
<p>Aesthetically I prefer the last approach, as it clearly separates the command from the arguments.</p>
<p>But I want to check: is there any subtle difference between these versions? And is there any compelling logic to favour one over the others?</p>

<p>The <a href="https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes" rel="noreferrer">K8s documentation</a> is detailed but <strong>not very opinionated</strong> regarding this point. Also, it is essential to understand the behavior of the underlying Container Runtime, e.g. <a href="https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes" rel="noreferrer">Docker</a>, first.</p>
<p>As a good practices, I would recommend the following rules:</p>
<ul>
<li>If possible, <strong>work with image defaults</strong>. If your Docker image is preconfigured with a sensible <code>ENTRYPOINT</code>, there is no need to define a <code>command</code> in K8s configuration. Defining <code>/bin/sh</code> in your K8s configuration should almost always be <strong>unnecessary, if your image is preconfigured properly</strong>.</li>
</ul>
<p>Nevertheless, if you have to overwrite image defaults, I would consider only <strong>two general patterns</strong>:</p>
<ul>
<li><p><strong>Shell pattern</strong>, where your <code>command</code> just provides a shell and your <code>args</code> the actual executable plus its arguments. This makes your configuration easy to read and lends itself to complicated <code>args</code> that use command chaining.</p>
<pre><code>command: [ '/bin/sh', '-c' ]
args: [ 'python manage.py makemigrations' ]
</code></pre>
</li>
<li><p><strong>Exec pattern</strong>, where your <code>command</code> provides the executable and the <code>args</code> the arguments for that executable. This follows the architectural idea behind splitting the configuration in two parts, where users of images typically only have to modify the <code>args</code>.</p>
<pre><code>command: [ 'python' ]
args: [ 'manage.py', 'makemigrations']
</code></pre>
</li>
</ul>
<p>Please note that K8s does <strong>not</strong> permit shell like pattern for the <code>command</code>, e.g. the following is not valid configuration:</p>
<pre><code>  command: [ '/bin/sh -c' ] &lt;&lt; NOT VALID
  args: [ 'python', 'manage.py',  'makemigrations' ]
</code></pre>
