{"id":1122,"date":"2023-02-21T16:56:00","date_gmt":"2023-02-21T16:56:00","guid":{"rendered":"https:\/\/www.aviator.co\/blog\/?p=1122"},"modified":"2025-09-25T14:00:39","modified_gmt":"2025-09-25T14:00:39","slug":"dependencies-for-helm-releases-in-fluxcd","status":"publish","type":"post","link":"https:\/\/www.aviator.co\/blog\/dependencies-for-helm-releases-in-fluxcd\/","title":{"rendered":"Dependencies for Helm releases in FluxCD"},"content":{"rendered":"\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/helm-fluxcd-1024x576.jpeg\" alt=\"\" class=\"wp-image-1124\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/helm-fluxcd-1024x576.jpeg 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/helm-fluxcd-300x169.jpeg 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/helm-fluxcd-768x432.jpeg 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/helm-fluxcd-1536x864.jpeg 1536w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/helm-fluxcd.jpeg 1920w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>FluxCD is a popular CNCF-graduated GitOps tool that allows you to automate and manage your Kubernetes deployments in an automated process.<\/p>\n\n\n\n<p>In this post, we will look at an example of a dependency between a backend service and a Redis service and how to set up and configure FluxCD to manage dependencies between Helm Releases.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/docs.aviator.co\/mergequeue\" target=\"_blank\" rel=\" noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"264\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-1024x264.png\" alt=\"MergeQueue CTA\" class=\"wp-image-4921\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-1024x264.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-300x77.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-768x198.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1-1536x396.png 1536w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-documentation-cta-photo-min-1.png 1940w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Prerequisites<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Kubernetes Cluster<\/li>\n\n\n\n<li>Helm v3<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>HelmRelease dependencies<\/strong><\/h2>\n\n\n\n<p>Let\u2019s consider an example scenario where the apps have the dependency: <strong>Backend service \u2192 Redis Service.<\/strong><\/p>\n\n\n\n<p>If the backend service starts without the Redis pod being ready, it will not be able to read requested data in Redis and starts to throw errors like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"msg\":\"cache server is offline\",\"error\":\"dial tcp redis:6379: connect: connection refused\"<\/code><\/pre>\n\n\n\n<p>Here, we\u2019ll use <a href=\"https:\/\/github.com\/stefanprodan\/podinfo\">podinfo<\/a> as our Backend service and Redis as a cache service.<\/p>\n\n\n\n<p>One can define a dependency between Helm Releases using the below parameter in the helm Release manifest :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  dependsOn:\n    - name: &lt;release name&gt;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Steps<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Configure flux<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Install the Flux CLI using the below command :<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -s https:\/\/fluxcd.io\/install.sh | sudo bash<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Install flux controllers in our cluster which will manage helm releases :<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>flux install \n--namespace=flux-system \n--components=source-controller,helm-controller<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Configure apps<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Add Bitnami Helm repository to the cluster via Flux required for Redis service :<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>flux create source helm bitnami \n--namespace=default \n--url=https:\/\/charts.bitnami.com\/bitnami \n--interval=15m<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Add backend service\u2019s Helm repository to the cluster via Flux required for backend service :<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>flux create source helm backend \n--namespace=default \n--url=https:\/\/stefanprodan.github.io\/podinfo \n--interval=15m<\/code><\/pre>\n\n\n\n<p>This will create a resource type <code>HelmRepository<\/code> and it will fetch the latest helm chart releases every 15 min.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get helmrepository\nNAME      URL                                      AGE   READY  STATUS\nbackend   https:\/\/stefanprodan.github.io\/podinfo   2m   True    stored artifact for revision 'fd69a2'\nbitnami   https:\/\/charts.bitnami.com\/bitnami       2m   True    stored artifact for revision '423580'<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Let&#8217;s create the <code>HelmRelease<\/code> YAML for backend service :<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>cat &lt;&lt;EOF &gt; backend-release.yaml\napiVersion: helm.toolkit.fluxcd.io\/v2beta1\nkind: HelmRelease\nmetadata:\n  name: backend\n  namespace: default\nspec:\n  interval: 5m\n  chart:\n    spec:\n      chart: podinfo\n      version: 6.2.2\n      sourceRef:\n        kind: HelmRepository\n        name: backend\n  dependsOn:\n    - name: redis\n  values:\n    cache: \"tcp:\/\/redis-master:6379\"\nEOF\n<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Now, create the <code>HelmRelease<\/code> YAML for Redis service :<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>cat &lt;&lt;EOF &gt; redis-release.yaml\napiVersion: helm.toolkit.fluxcd.io\/v2beta1\nkind: HelmRelease\nmetadata:\n  name: redis\n  namespace: default\nspec:\n  interval: 5m\n  chart:\n    spec:\n      chart: redis\n      version: 17.3.14\n      sourceRef:\n        kind: HelmRepository\n        name: bitnami\n  values:\n    architecture: standalone\n    auth:\n      enabled: false\nEOF<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In the above manifest, we\u2019re installing backend service and Redis helm charts from the Helm repository which we created earlier in Flux using <code>Source<\/code> definition.<\/li>\n\n\n\n<li>We have kept the sync \/ reconcile interval to be <code>5m<\/code>.<\/li>\n\n\n\n<li>We\u2019ve also applied a few custom helm values like Redis service\u2019s address in the backend service and installing Redis as a standalone master instead of Master-Slave architecture.<\/li>\n\n\n\n<li>Finally, we\u2019ve defined that the backend service depends on Redis using <code>dependsOn<\/code>, which means Backend will be reconciled when the Redis service release status is READY.<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Apply both the helm release manifest files :<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f redis-release.yaml -f backend-release.yaml<\/code><\/pre>\n\n\n\n<p>Let\u2019s check the status of releases :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flux get helmreleases -n default\n\nNAME    REVISION        SUSPENDED       READY   MESSAGE\nbackend 6.2.2           False           True    Release reconciliation succeeded\nredis   17.3.14         False           True    Release reconciliation succeeded<\/code><\/pre>\n\n\n\n<p>We can also see from <em>Helm controller<\/em> pod\u2019s log that the backend service got deployed after Redis got ready :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"level\":\"info\",\"msg\":\"all dependencies are ready, \nproceeding with release\",\"HelmRelease\":\"name\":\"backend\",\"namespace\":\"default\"<\/code><\/pre>\n\n\n\n<p>Note: By default. Flux follows Helm\u2019s&#8211;wait. By using this, Helm will wait until all pods of the deployment are in a ready state before marking the release as successful. Read more from the Helm doc <a href=\"https:\/\/helm.sh\/docs\/intro\/using_helm\/#helpful-options-for-installupgraderollback\">here<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Release failure<\/h3>\n\n\n\n<p>In case of release failure, for example, if Redis release has a failure and the pod is not ready, the backend service will not be deployed.<\/p>\n\n\n\n<p>To test this, uninstall both the helm release using the below command ;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl delete -f redis-release.yaml -f backend-release.yaml<\/code><\/pre>\n\n\n\n<p>Update the Redis Manifest with the image tag to a non-existent one so that pod will be in Crash Loop.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>values:\n    architecture: standalone\n    auth:\n      enabled: false\n    image:\n      tag: 1.0<\/code><\/pre>\n\n\n\n<p>Apply the Helm release and check the release status :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get helmreleases\n\nNAME      AGE   READY   STATUS\nbackend   6m   False   dependency 'default\/redis' is not ready\nredis     6m   False   install retries exhausted<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Cross namespace and multi-release dependency<\/h3>\n\n\n\n<p>You can also define multiple Helm releases name in the dependency block, as the <code>dependsOn<\/code> property is an array of Helm release names that the current Helm release depends on.<\/p>\n\n\n\n<p>For example :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  dependsOn:\n    - name: redis\n    - name: mysql<\/code><\/pre>\n\n\n\n<p>To reference the Helm release in different namespace, use the following syntax : <code>&lt;namespace&gt;\/&lt;name&gt;<\/code>, for example :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  dependsOn:\n    - name: monitoring\/prometheus<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Avoid dependency death loop<\/h2>\n\n\n\n<p>Circular dependencies between <code>HelmRelease<\/code> resources must be avoided, otherwise, the interdependent <code>HelmRelease<\/code> resources will never be reconciled.<\/p>\n\n\n\n<p>To understand this, I\u2019ll update the Backend service\u2019s YAML and add the dependency config which will turn into:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"484\" height=\"234\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/app-dependency.png\" alt=\"\" class=\"wp-image-1123\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/app-dependency.png 484w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/app-dependency-300x145.png 300w\" sizes=\"(max-width: 484px) 100vw, 484px\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Once I apply the manifests, let\u2019s check the status of helm releases :<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>flux get helmreleases -n default\n\nNAME    REVISION        SUSPENDED       READY   MESSAGE\nbackend                 False           False   dependency 'default\/redis' is not ready\nredis                   False           False   dependency 'default\/backend' is not ready<\/code><\/pre>\n\n\n\n<p>Let&#8217;s check Kubernetes events to see the reason for the helm release to be not ready. Alternatively, you can describe the <code>helmrelease<\/code> too.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>info  HelmChart 'default\/default-redis' is not ready\ninfo  dependencies do not meet ready condition (dependency 'default\/backend' is not ready)\ninfo  HelmChart 'default\/default-backend' is not ready\ninfo  dependencies do not meet ready condition (dependency 'default\/redis' is not ready)<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>As you can see, this dependency loop will never get resolved as each release is dependent on the other.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">References :<\/h3>\n\n\n\n<p><a href=\"https:\/\/github.com\/fluxcd\/flux2\/blob\/1e67d75848e85d420f2bffdd4e13fabeed654f06\/internal\/utils\/utils.go#L230\">Flux: utils.go#L230<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/fluxcd.io\/flux\/components\/#helmrelease-dependencies\">https:\/\/fluxcd.io\/flux\/components\/#helmrelease-dependencies<\/a><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/www.aviator.co\/\" target=\"_blank\" rel=\"noreferrer noopener\">Aviator<\/a>: Automate your cumbersome merge processes<\/h2>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/www.aviator.co\/\" target=\"_blank\" rel=\"noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"727\" src=\"https:\/\/blog.aviator.co\/wp-content\/uploads\/2022\/08\/blog-cta-1024x727.png\" alt=\"\" class=\"wp-image-57\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-1024x727.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-300x213.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-768x545.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-1536x1090.png 1536w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2022\/08\/blog-cta-2048x1454.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Aviator automates tedious developer workflows by managing git Pull Requests (PRs) and continuous integration test (CI) runs to help your team avoid broken builds, streamline cumbersome merge processes, manage cross-PR dependencies, and handle flaky tests while maintaining their security compliance.<\/p>\n\n\n\n<p>There are 4 key components to Aviator:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>MergeQueue<\/strong>&nbsp;\u2013 an automated queue that manages the merging workflow for your GitHub repository to help protect important branches from broken builds. The Aviator bot uses GitHub Labels to identify Pull Requests (PRs) that are ready to be merged, validates CI checks, processes semantic conflicts, and merges the PRs automatically.<\/li>\n\n\n\n<li><strong>ChangeSets<\/strong>&nbsp;\u2013 workflows to synchronize validating and merging multiple PRs within the same repository or multiple repositories. Useful when your team often sees groups of related PRs that need to be merged together, or otherwise treated as a single broader unit of change.<\/li>\n\n\n\n<li><strong>FlakyBot<\/strong>&nbsp;\u2013 a tool to automatically detect, take action on, and process results from flaky tests in your CI infrastructure.<\/li>\n\n\n\n<li><strong>Stacked PRs CLI<\/strong>&nbsp;\u2013 a command line tool that helps developers manage cross-PR dependencies. This tool also automates syncing and merging of stacked PRs. Useful when your team wants to promote a culture of smaller, incremental PRs instead of large changes, or when your workflows involve keeping multiple, dependent PRs in sync.<\/li>\n<\/ol>\n\n\n\n<p><a href=\"https:\/\/www.aviator.co\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Try it for free.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>An example of a dependency between a backend service and a Redis service and how to set up and configure FluxCD to manage dependencies between Helm releases<\/p>\n","protected":false},"author":11,"featured_media":1124,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[302],"tags":[45,21],"class_list":["post-1122","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tooling-integrations"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":6}},"acf":[],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2023\/02\/helm-fluxcd.jpeg","post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/1122","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/comments?post=1122"}],"version-history":[{"count":5,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/1122\/revisions"}],"predecessor-version":[{"id":4969,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/1122\/revisions\/4969"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/media\/1124"}],"wp:attachment":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/media?parent=1122"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/categories?post=1122"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/tags?post=1122"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}