Search code examples
kuberneteskubernetes-helm

Helm 3 Deployment Order of Kubernetes Service Catalog Resources


I am using Helm v3.3.0, with a Kubernetes 1.16.

The cluster has the Kubernetes Service Catalog installed, so external services implementing the Open Service Broker API spec can be instantiated as K8S resources - as ServiceInstances and ServiceBindings.

ServiceBindings reflect as K8S Secrets and contain the binding information of the created external service. These secrets are usually mapped into the Docker containers as environment variables or volumes in a K8S Deployment.

Now I am using Helm to deploy my Kubernetes resources, and I read here that...

The [Helm] install order of Kubernetes types is given by the enumeration InstallOrder in kind_sorter.go

In that file, the order does neither mention ServiceInstance nor ServiceBinding as resources, and that would mean that Helm installs these resource types after it has installed any of its InstallOrder list - in particular Deployments. That seems to match the output of helm install --dry-run --debug run on my chart, where the order indicates that the K8S Service Catalog resources are applied last.

Question: What I cannot understand is, why my Deployment does not fail to install with Helm. After all my Deployment resource seems to be deployed before the ServiceBinding is. And it is the Secret generated out of the ServiceBinding that my Deployment references. I would expect it to fail, since the Secret is not there yet, when the Deployment is getting installed. But that is not the case.

Is that just a timing glitch / lucky coincidence, or is this something I can rely on, and why?

Thanks!


Solution

  • As said in the comment I posted:

    In fact your Deployment is failing at the start with Status: CreateContainerConfigError. Your Deployment is created before Secret from the ServiceBinding. It's only working as it was recreated when the Secret from ServiceBinding was available.

    I wanted to give more insight with example of why the Deployment didn't fail.

    What is happening (simplified in order):

    • Deployment -> created and spawned a Pod
    • Pod -> failing pod with status: CreateContainerConfigError by lack of Secret
    • ServiceBinding -> created Secret in a background
    • Pod gets the required Secret and starts

    Previously mentioned InstallOrder will leave ServiceInstace and ServiceBinding as last by comment on line 147.


    Example

    Assuming that:

    • There is a working Kubernetes cluster
    • Helm3 installed and ready to use

    Following guides:

    There is a Helm chart with following files in templates/ directory:

    • ServiceInstance
    • ServiceBinding
    • Deployment

    Files:

    ServiceInstance.yaml:

    apiVersion: servicecatalog.k8s.io/v1beta1
    kind: ServiceInstance
    metadata:
      name: example-instance
    spec:
      clusterServiceClassExternalName: redis
      clusterServicePlanExternalName: 5-0-4
    

    ServiceBinding.yaml:

    apiVersion: servicecatalog.k8s.io/v1beta1
    kind: ServiceBinding
    metadata:
      name: example-binding
    spec:
      instanceRef:
        name: example-instance
    

    Deployment.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ubuntu
    spec:
      selector:
        matchLabels:
          app: ubuntu
      replicas: 1
      template:
        metadata:
          labels:
            app: ubuntu
        spec:
          containers:
          - name: ubuntu
            image: ubuntu
            command:
            - sleep 
            - "infinity" 
            # part below responsible for getting secret as env variable
            env: 
            - name: DATA
              valueFrom: 
                secretKeyRef:
                  name: example-binding
                  key: host
    

    Applying above resources to check what is happening can be done in 2 ways:

    • First method is to use timestamp from $ kubectl get RESOURCE -o yaml
    • Second method is to use $ kubectl get RESOURCE --watch-only=true

    First method

    As said previously the Pod from the Deployment couldn't start as Secret was not available when the Pod tried to spawn. After the Secret was available to use, the Pod started.

    The statuses this Pod had were the following:

    • Pending
    • ContainerCreating
    • CreateContainerConfigError
    • Running

    This is a table with timestamps of Pod and Secret:

    |                  Pod                      |                Secret                     |
    |-------------------------------------------|-------------------------------------------|
    | creationTimestamp: "2020-08-23T19:54:47Z" |                   -                       |
    |                   -                       | creationTimestamp: "2020-08-23T19:54:55Z" |
    | startedAt: "2020-08-23T19:55:08Z"         |                   -                       |
    

    You can get this timestamp by invoking below commands:

    • $ kubectl get pod pod_name -n namespace -o yaml
    • $ kubectl get secret secret_name -n namespace -o yaml

    You can also get get additional information with:

    • $ kubectl get event -n namespace
    • $ kubectl describe pod pod_name -n namespace

    Second method

    This method requires preparation before running Helm chart. Open another terminal window (for this particular case 2) and run:

    • $ kubectl get pod -n namespace --watch-only | while read line ; do echo -e "$(gdate +"%H:%M:%S:%N")\t $line" ; done
    • $ kubectl get secret -n namespace --watch-only | while read line ; do echo -e "$(gdate +"%H:%M:%S:%N")\t $line" ; done

    After that apply your Helm chart.

    Disclaimer!

    Above commands will watch for changes in resources and display them with a timestamp from the OS. Please remember that this command is only for example purposes.

    The output for Pod:

    21:54:47:534823000   NAME                      READY   STATUS                       RESTARTS    AGE
    21:54:47:542107000   ubuntu-65976bb789-l48wz   0/1     Pending                      0           0s
    21:54:47:553799000   ubuntu-65976bb789-l48wz   0/1     Pending                      0           0s
    21:54:47:655593000   ubuntu-65976bb789-l48wz   0/1     ContainerCreating            0           0s
    -> 21:54:52:001347000    ubuntu-65976bb789-l48wz   0/1     CreateContainerConfigError   0           4s
    21:55:09:205265000   ubuntu-65976bb789-l48wz   1/1     Running                      0           22s
    

    The output for Secret:

    21:54:47:385714000   NAME                            TYPE                 DATA   AGE
    21:54:47:393145000   sh.helm.release.v1.example.v1   helm.sh/release.v1   1      0s
    21:54:47:719864000   sh.helm.release.v1.example.v1   helm.sh/release.v1   1      0s
    21:54:51:182609000   understood-squid-redis          Opaque               1      0s
    21:54:52:001031000   understood-squid-redis          Opaque               1      0s
    -> 21:54:55:686461000    example-binding                 Opaque               6      0s
    

    Additional resources: