Should dependencies between Helm charts reflect dependencies between microservices?

3/9/2019

Given a following scheme of services and their dependencies I would like to engineer a set of Helm charts.

  • API Gateway calls Service A and Service C
  • Service A calls Service B
  • Service B calls Database
  • Service C calls Service B and Service D

At the moment I see two alternatives:

  1. Each of the 6 components in a diagram below is a single chart and each arrow in a diagram is a single dependency.

  2. There's an Umbrella chart that has a dependency on all other charts. The Database chart is a dependency of Service B chart.

Helm documentation suggest going with option 2. I am however more keen towards option 1 due to an ease of local development and CI/CD pipeline.

Example scenario: developer is refactoring Service C and he wants to run the code he changed and test it.

  • Option 1. Developer installs a Service C chart only.
  • Option 2: Developer would have to either:
    • install an Umbrella chart which leads to waste of a CPU and memory resources because of running unneeded services like Service A or API Gateway, which doesn't scale well with the complexity of the system;
    • install Service C, then Service B and then Service D, which also doesn't scale well with the complexity of the system because it requires to perform many manual actions and also require from developer to be faimiliar with the architecture of the system in order to know what charts needs to be installed.

I would like to make an educated decision on which alternative to take. I am more keen towards option 1, but Helm docs and also few examples I was able to find on the Internet (link) are also going with option 2, so I think I might be missing something.

-- Tomasz Bekas
kubernetes
kubernetes-helm

1 Answer

3/10/2019

I would recommend one chart per service, with the additional simplification of making the "service B" chart depend on its database. I would make these charts independent: none of the services depend on any other.

The place where Helm dependencies work well is where you have a service that embeds/hides specific single other parts. The database behind B is an implementation detail, for example, and nothing outside B needs to know about it. So B can depend on stable/postgres or some such, and this works well in Helm.

There's one specific mechanical problem that causes problems for the umbrella-chart approach. Say service D also depended on a database, and it was the same "kind" of database (both use PostgreSQL, say). Operationally you want these two databases to be separate. Helm will see the two paths umbrella > B > database and umbrella > D > database, and only install one copy of the database chart, so you'll wind up with the two services sharing a database. You probably don't want that.

The other mechanical issue you'll encounter using Helm dependencies here is that most resources are named some variant of {{ .Release.Name }}-{{ .Chart.Name }}. In your option 1, say you do just install service C; you'd wind up with Deployments like service-C-C, service-C-B, service-C-database. If you then wanted to deploy service A alongside it, that would introduce its own service-A-B and service-A-database, which again isn't what you want.

I'm not aware of a great high-level open-source solution to this problem. A Make-based solution is hacky, but can work:

# -*- gnu-make -*-
all: api-proxy.deployed

%.deployed:
        helm upgrade --install --name $* -f values.yaml ./charts/$*
        touch $@

api-proxy.deployed: a.deployed c.deployed
a.deployed: b.deployed
c.deployed: b.deployed d.deployed
-- David Maze
Source: StackOverflow