Search code examples
kubernetesskaffold

Tie skaffold profile to cluster


Building off another one of my questions about tying profiles to namespaces, is there a way to tie profiles to clusters?

I've found a couple times now that I accidentally run commands like skaffold run -p local -n skeleton when my current kubernetes context is pointing to docker-desktop. I'd like to prevent myself and other people on my team from committing the same mistake.

I found that there's a way of specifying contexts but that doesn't play nicely if developers use custom contexts like kubeclt set-context custom --user=custom --cluster=custom. I've also found a cluster field in the skaffold.yaml reference but it seems that doesn't satisfy my need because it doesn't let me specify a cluster name.


Solution

  • After digging through the skaffold documentation and performing several tests I finally managed to find at least partial solution of your problem, maybe not the most elegant one, but still functional. If I find a better way I will edit my answer.

    Let's start from the beginning:

    As we can read here:

    When interacting with a Kubernetes cluster, just like any other Kubernetes-native tool, Skaffold requires a valid Kubernetes context to be configured. The selected kube-context determines the Kubernetes cluster, the Kubernetes user, and the default namespace. By default, Skaffold uses the current kube-context from your kube-config file.

    This is quite important point as we are actually starting from kube-context and based on it we are able to trigger specific profile, never the oposite.

    important to remember: kube-context is not activated based on the profile but the opposite is true: the specific profile is triggered based on the current context (selected by kubectl config use-context).

    Although we can overwrite default settings from our skaffold.yaml config file by patching (compare related answer), it's not possible to overwrite the current-context based on slected profile e.g. manually as in your command:

    skaffold -p prod
    

    Here you are manually selecting specific profile. This way you bypass automatic profile triggering. As the documentation says:

    Activations in skaffold.yaml: You can auto-activate a profile based on

    • kubecontext (could be either a string or a regexp: prefixing with ! will negate the match)
    • environment variable value
    • skaffold command (dev/run/build/deploy)

    Let's say we want to activate our profile based on current kube-context only to make it simple however we can join different conditions together by AND and OR like in the example here.

    solution

    I want to make sure that if I run skaffold -p prod skaffold will fail if my kubecontext points to a cluster other than my production cluster.

    I'm affraid it cannot be done this way. If you've already manually selected prod profile by -p prod you're bypassing selection of profile based on current context therefore you already chosen what can be done no matter how where it can be done is set (currently selected kube-context). In this situation skaffold doesn't have any mechanisms that would prevent you from running something on wrong cluster. In other words you're forcing this way certain behaviour of your pipeline. You already agree to it by selecting the profile. If you gave up using -p or --profile flags, certain profiles will never be triggerd unless currently selected kube-context does it automatically. skaffold just won't let that happen.

    Let's look at the following example showing how to make it work:

    apiVersion: skaffold/v2alpha3
    kind: Config
    metadata:
      name: getting-started
    build:
      artifacts:
      - image: skaffold-example
        docker:
          dockerfile: NonExistingDockerfile # the pipeline will fail at build stage
      cluster:
    deploy:
      kubectl:
        manifests:
        - k8s-pod.yaml
        flags:
          global: # additional flags passed on every command.
          - --namespace=default
      kubeContext: minikube
    profiles:
    - name: prod
      patches:
      - op: replace
        path: /build/artifacts/0/docker/dockerfile
        value: Dockerfile
      - op: replace
        path: /deploy/kubectl/flags/global/0
        value: --namespace=prod
      activation:
      - kubeContext: minikube
        command: run 
      - kubeContext: minikube
        command: dev 
    

    In general part of our skaffold.yaml config we configured:

    dockerfile: NonExistingDockerfile # the pipeline will fail at build stage
    

    Untill we name our Dockerfile - "NonExistingDockerfile" every pipeline will fail at its build stage. So by default all builds, no matter what kube-context is selected are destined to fail. Hovewer we can override this default behaviour by patching specific fragment of the skaffold.yaml in our profile section and setting again Dockerfile to its standard name. This way every:

    skaffold run
    

    or

    skaffold dev
    

    command will succeed only if the current kube-context is set to minikube. Otherwise it will fail.

    We can check it with:

    skaffold run --render-only
    

    previously setting our current kube-context to the one that matches what is present in the activation section of our profile definition.

    I've found a couple times now that I accidentally run commands like skaffold run -p local -n skeleton when my current kubernetes context is pointing to docker-desktop. I'd like to prevent myself and other people on my team from committing the same mistake.

    I understand your point that it would be nice to have some built-in mechanism that prevents overriding this automatic profile activation configured in skaffold.yaml by command line options, but it looks like currently it isn't possible. If you don't specify -p local, skaffold will always choose the correct profile based on the current context. Well, it looks like good material for feature request.