Dependency ordering

Kapps (applications) often need installing in a particular order, especially if you’re creating a cluster from scratch. You’d need to create public hosted zones before you could create public DNS entries for your services, or perhaps create a shared database before installing your web applications.

To enable Sugarkube to install and delete kapps in the correct order, you need to tell it about each kapp’s dependencies, which it uses to build a dependency graph or Directed Acyclic Graph – a DAG for short. If you’re not familiar with them, our DAG basically says which things need to be installed or deleted before something else can be installed or deleted.

Wordpress Dependencies

In the above DAG, wordpress:site1 will only be installed once bootstrap:nginx1 and shared-data:site1-db have both been installed. This is what we need because a database must exist before we can install Wordpress. The two shared databases can be installed in parallel once bootstrap:tiller has completed since the databases don’t depend on each other. Similarly, bootstrap:nginx1 will only be deleted once both the wordpress sites have been deleted, which can be done in parallel since they have no children.

The algorithms to install or delete kapps using the DAG are simple:

  • A kapp will only be installed if it either has no parents, or if all its parents have been installed.
  • A kapp will only be deleted if it either has no children, or if all its children have been deleted.

All the sugarkube kapps <subcommand> subcommands build a DAG and traverse it when performing operations. You can generate a visualisation of a DAG by using the sugarkube kapps graphs command.

Declaring dependencies

The simplest way to declare dependencies between kapps is by adding a depends_on block to the kapp’s config. Dependencies are defined as follows:

  • id - The ID of a dependency
  • conditions - a list of entries that must all evaluate to true for the dependency to apply

You may want to declare different dependencies for a kapp depending on the target cluster’s provider. E.g. in our sample ops cluster tiller only depends on a private hosted zone if we’re creating a private kops cluster.

Here’s an example of declaring dependencies:

# manifests/manifest1.yaml
kapps:
  - id: jenkins
    state: present
    sources:
      - uri: git@github.com:sugarkube/kapps.git//incubator/jenkins#master    
    depends_on:   
      - id: bootstrap:cert-manager
      - id: bootstrap:nginx-ingress

This tells Sugarkube that the jenkins kapp can only be installed after both bootstrap:cert-manager and bootstrap:nginx-ingress have been installed.

As a shortcut for when all kapps in a manifest need to be installed sequentially – and therefore each depends on the previous kapp in the manifest – define the option sequential: true for the whole manifest, e.g.:

# manifests/manifest2.yaml
options:
  sequential: true      
kapps:
  # ... define your kapps here

Within a manifest, kapps can be referred to by its naked ID, e.g. jenkins in the first example above. To declare a dependency on a kapp in another manifest you need to use the fully-qualified kapp ID, which is of the form <manifest ID>:<kapp ID>.

As with all kapp configs, values for dependencies can be defined in various places. Here’s a longer example that declares default dependencies for all kapps in the manifest as well as dependencies within the manifest itself.

# manifests/web.yaml
defaults:
  depends_on:       # defaults for all kapps in this manifest
  - id: routing:load-balancer

kapps:
- id: database
  state: present
  sources: 
  # ...
  
- id: memcached
  state: present
  sources: 
  # ...
  
- id: wordpress
  state: present
  sources: 
  # ...
  depends_on:   # defining this replaces the defaults, so this
  - id: database    # kapp doesn't directly depend on the
  - id: memcached   # routing:load-balancer kapp 

- id: analytics
  state: present
  sources: 
  # ...

In this definition, the database, memcached and analytics kapps can all be installed in parallel once the routing:load-balancer kapp in the routing manifest has been installed. The wordpress kapp will only be installed once the database and memcached kapps have been installed. The advantage of declaring kapps this way is that it allows them to be installed in parallel once their dependencies have been met.

Selecting subsets of the DAG

The DAG encapsulates the global set of dependencies between kapps in a target stack. Sometimes though you just want to work with a subset of the DAG, e.g. to install or delete one or two specific kapps. This is possible with selectors.

Selectors are simply the fully-qualified ID of a kapp, which is of the form <manifest ID>:<kapp ID>. They can be used to include (with the -i flag) or exclude (-x) kapps from being operated on. The flag can be passed multiple times to include or exclude multiple kapps, e.g.:

sugarkube kapps install -i web:analytics -i web:wordpress

You can also use the wildcard symbol * to select all kapps in a manifest, e.g. web:* (make sure to quote this on the command line though to prevent tripping up your shell):

sugarkube kapps delete -i 'web:*'

Internally Sugarkube first builds a DAG from the global set of dependencies, then extracts a subgraph containing just the parents of the selected kapps.

Visualising the DAG

A textual representation of a graph isn’t very intuitive to understand. To create an SVG image of a DAG like we showed above, simply run the sugarkube kapps graph command. It’ll generate an SVG and open it in the default application associated with SVGs on your computer. This command also supports selectors like -i/-x to include or exclude only certain kapps in your stack. Note: Generating SVGs requires graphviz.

For a walkthrough of how to use the kapps graph command, see the Wordpress on Minikube tutorial.