<p>I've seen conflicting information on what all of these things do. For example:</p>
<blockquote>
<p><code>helm install --dry-run --debug</code> or <code>helm template --debug</code>: We've seen this trick already. It's a great way to have the server render your templates, then return the resulting manifest file.</p>
</blockquote>
<p>From: <a href="https://helm.sh/docs/chart_template_guide/debugging/#helm" rel="nofollow noreferrer">https://helm.sh/docs/chart_template_guide/debugging/#helm</a></p>
<p>That implies that <em>both</em> <code>template --debug</code> and the dry run send it to the server. Is that true?</p>
<p>I've also seen some places that if you have a schema, that <code>template --validate</code> will also do linting. Is that true? And does the dry run also lint?</p>
<p>Here's my &quot;guess&quot;:</p>
<ul>
<li><code>helm template</code> calls <code>lint</code> <em>even</em> if you don't add <code>--validate</code>
<ul>
<li>And <code>helm template --debug</code> does <em>not</em> send it to the server, but just prints out more debug info</li>
</ul>
</li>
<li><code>--validate</code> does nothing that isn't done with the regular template call</li>
<li><code>helm install --dry-run</code> will send each YAML generated to K8s with the following command(s): <code>kubectl apply --validate=true --dry-run=true --f myyaml.yaml</code>
<ul>
<li>Is this correct? Is that how Helm does a dry run? (And in helm 3 there's no Tiller)</li>
</ul>
</li>
</ul>

<p>Short answers:</p>
<ol>
<li><code>helm template</code> without <code>--validate</code> doesn't contact the Kubernetes server at all.  <code>helm template --validate</code> and <code>helm install --dry-run</code> do some additional checks that do involve contacting the API server.</li>
<li><code>helm lint</code> is different and neither command runs linking.</li>
</ol>
<p>Under the hood, <a href="https://github.com/helm/helm/blob/master/cmd/helm/install.go" rel="noreferrer"><code>helm install</code></a> and <a href="https://github.com/helm/helm/blob/master/cmd/helm/template.go" rel="noreferrer"><code>helm template</code></a> are very similar: both create an <a href="https://github.com/helm/helm/blob/master/pkg/action/install.go" rel="noreferrer"><code>action.Install</code></a> object and configure it.</p>
<p><code>helm template</code> is always <code>--dry-run</code>.  If you don't specify <code>helm template --validate</code>, then Helm uses a default set of API versions, and in fact renders the chart without contacting a Kubernetes server at all.  If the chart includes custom resource definitions (CRDs), <code>helm template</code> without <code>--validate</code> won't complain that they're not being processed.  The key important effect of <code>helm template --debug</code> is that, if the template produces invalid YAML, it will get printed out anyways.</p>
<p><code>helm install --dry-run --debug</code> and <code>helm install --validate</code> seem extremely similar, in terms of the options they push into the core installer logic.  In both cases they actually render the chart without talking to the Kubernetes server.  After doing the render, they do check with the Kubernetes client that the produced YAML is valid for what objects the cluster supports, and they both check whether any of the created objects currently exist in the cluster.</p>
<p>Helm doesn't actually run <code>kubectl</code>.  It instead directly uses the Kubernetes Go client library.</p>
<p><a href="https://github.com/helm/helm/blob/master/cmd/helm/lint.go" rel="noreferrer"><code>helm lint</code></a> is a totally separate action.  It runs additional checks on the <em>unrendered</em> chart; for example, if there is a file in the <code>templates</code> directory that's not a <code>*.tpl</code>, <code>*.yml</code>, <code>*.yaml</code>, or <code>*.txt</code> file, you'll get a complaint.  None of the install or template paths run it.</p>
