<p>Is there a way to tie a skaffold profile to a namespace? I'd like to make sure that dev, staging and prod deployments always go to the right namespace. I know that I can add a namespace to <code>skaffold run</code> like <code>skaffold run -p dev -n dev</code> but that's a little error prone. I'd like to make my builds even safer by tying profiles to namespaces. </p>

<p>I've tried adding the following to my <code>skaffold.yaml</code> based on the fact that there's a path in <code>skaffold.yaml</code> which is <a href="https://skaffold.dev/docs/references/yaml/" rel="nofollow noreferrer"><code>build/cluster/namespace</code></a> but I suspect I'm misunderstanding the purpose of the cluster spec.</p>

<pre><code>profiles:
- name: local
  patches:
  - op: replace
    path: /build/artifacts/0/cluster/namespace
    value: testing
</code></pre>

<p>but I get the error </p>

<pre><code> ❮❮❮ skaffold render -p local
FATA[0000] creating runner: applying profiles: applying profile local: invalid path: /build/artifacts/0/cluster/namespace
</code></pre>

<p>I've tried other variants of changing the cluster namespace but all of them fail.</p>

<h3>if TL/DR: please go directly to "solution" (the last section)</h3>

<blockquote>
  <p>Is there a way to tie a skaffold profile to a namespace? I'd like to
  make sure that dev, staging and prod deployments always go to the
  right namespace. I know that I can add a namespace to <code>skaffold run</code>
  like <code>skaffold run -p dev -n dev</code> but that's a little error prone. I'd
  like to make my builds even safer by tying profiles to namespaces.</p>
</blockquote>

<p>At the beginning we need to clarify two things, namely if we are talking about <code>namespaces</code> in <code>build</code> or <code>deploy</code> stage of the pipeline. On one hand you write, that you want <em>to make sure that dev, staging and prod <strong>deployments</strong> always go to the right namespace</em> so I'm assuming you're rather interested in setting the appropriate <code>namespace</code> on your <strong>kubernetes cluster</strong> in which built images will be eventually deployed. Hovewer later you mentioned also about <em>making <strong>builds</strong> even safer by tying profiles to namespaces</em>. Please correct me if I'm wrong but my guess is that you rather mean <code>namespaces</code> at the <code>deploy</code> stage.</p>

<p>So answering your question: <strong>yes, it is possible to tie a skaffold profile to a specific namespace</strong>.</p>

<blockquote>
  <p>I've tried adding the following to my <code>skaffold.yaml</code> based on the
  fact that there's a path in <code>skaffold.yaml</code> which is
  <a href="https://skaffold.dev/docs/references/yaml/" rel="nofollow noreferrer">build/cluster/namespace</a> but I suspect I'm misunderstanding the
  purpose of the cluster spec.</p>
</blockquote>

<p>You're right, there is such path in <code>skaffold.yaml</code> but then your example should look as follows:</p>

<pre><code>profiles:
- name: local
  patches:
  - op: replace
    path: /build/cluster/namespace
    value: testing
</code></pre>

<p>Note that <code>cluster</code> element is on the same indentation level as <code>artifacts</code>. As you can read in the <a href="https://skaffold.dev/docs/references/yaml/" rel="nofollow noreferrer">reference</a>:</p>

<pre><code>cluster:    #   beta describes how to do an on-cluster build.
</code></pre>

<p>and as you can see, most of its options are related with <code>kaniko</code>. It can be also <code>patched</code> in the same way as other <code>skaffold.yaml</code> elements in specific <code>profiles</code> but anyway I don't think this is the element you're really concerned about so let's leave it for now.</p>

<p>Btw. you can easily validate your <code>skaffold.yaml</code> syntax by runnig:</p>

<pre><code>skaffold fix
</code></pre>

<p>If every element is properly used, all the indentation levels are correct etc. it will print:</p>

<pre><code>config is already latest version
</code></pre>

<p>otherwise something like the error below:</p>

<pre><code>FATA[0000] creating runner: applying profiles: applying profile prod: invalid path: /build/cluster/namespace
</code></pre>

<hr>

<h1>solution</h1>

<p>You can make sure your deployments go to the right namespace by setting <code>kubectl flags</code>. It assumes you're using <code>docker</code> as <code>builder</code> and <code>kubectl</code> as deployer. As there are plenty of different <code>builders</code> and <code>deployers</code> supported by <code>skaffold</code> the e.g. you deploy with <code>helm</code> the detailed solution may look quite different.</p>

<p><strong>One very important caveat:</strong> the path must be already present in your general config part, otherwise you won't be able to patch it in <code>profiles</code> section e.g.:</p>

<p>if you have in your profiles section following <code>patch</code>:</p>

<pre><code>profiles:
- name: prod
  patches:
  - op: replace
    path: /build/artifacts/0/docker/dockerfile
    value: DifferentNameForDockerfile
</code></pre>

<p>following section must be already present in your <code>skaffold.yaml</code>:</p>

<pre><code>build:
  artifacts:
  - image: skaffold-example
    docker:
      dockerfile: Dockerfile # the pipeline will fail at build stage
</code></pre>

<p>Going back to our <code>namaspaces</code>, first we need to set default values in <code>deploy</code> section:</p>

<pre><code>deploy:
  kubectl:
    manifests:
    - k8s-pod.yaml
    flags:
      global: # additional flags passed on every command.
      - --namespace=default
#     apply: # additional flags passed on creations (kubectl apply).
#     - --namespace=default
#     delete: # additional flags passed on deletions (kubectl delete).
#     - --namespace=default
</code></pre>

<p>I set only <code>global</code> flags but this is also possible to set for <code>apply</code> and <code>delete</code> commands separately.</p>

<p>In next step we need to override our default value (they must be already present, so we can override them) in our <code>profiles</code>:</p>

<pre><code>profiles:
- name: dev
  patches:
  - op: replace
    path: /deploy/kubectl/flags/global/0
    value: --namespace=dev
- name: staging
  patches:
  - op: replace
    path: /deploy/kubectl/flags/global/0
    value: --namespace=staging
- name: prod
  patches:
  - op: replace
    path: /deploy/kubectl/flags/global/0
    value: --namespace=prod
</code></pre>

<p>Then we can run:</p>

<pre><code>skaffold run --render-only --profile=prod
</code></pre>

<p>As we can see our <code>Pod</code> is going to be deployed in <code>prod</code> <code>namespace</code> of our <strong>kubernetes cluster</strong>:</p>

<pre><code>Generating tags...
 - skaffold-example -&gt; skaffold-example:v1.3.1-15-g11d005d-dirty
Checking cache...
 - skaffold-example: Found Locally
apiVersion: v1
kind: Pod
metadata:
  labels:
    app.kubernetes.io/managed-by: skaffold-v1.3.1
    skaffold.dev/builder: local
    skaffold.dev/cleanup: "true"
    skaffold.dev/deployer: kubectl
    skaffold.dev/docker-api-version: "1.39"
    skaffold.dev/profile.0: prod
    skaffold.dev/run-id: b83d48db-aec8-4570-8cb8-dbf9a7795c00
    skaffold.dev/tag-policy: git-commit
    skaffold.dev/tail: "true"
  name: getting-started
  namespace: prod
spec:
  containers:
  - image: skaffold-example:3e4840dfd2ad13c4d32785d73641dab66be7a89b43355eb815b85bc09f45c8b2
    name: getting-started
</code></pre>
