<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Deploy Grafana Mimir with Jsonnet and Tanka on Grafana Labs</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/</link><description>Recent content in Deploy Grafana Mimir with Jsonnet and Tanka on Grafana Labs</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/index.xml" rel="self" type="application/rss+xml"/><item><title>Deploy Grafana Mimir with Jsonnet and Tanka</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/deploy/</link><pubDate>Thu, 14 Aug 2025 18:42:07 +0000</pubDate><guid>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/deploy/</guid><content><![CDATA[&lt;h1 id=&#34;deploy-grafana-mimir-with-jsonnet-and-tanka&#34;&gt;Deploy Grafana Mimir with Jsonnet and Tanka&lt;/h1&gt;
&lt;p&gt;You can use &lt;a href=&#34;https://tanka.dev/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Tanka&lt;/a&gt; and &lt;a href=&#34;https://github.com/jsonnet-bundler/jsonnet-bundler&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;jsonnet-bundler&lt;/a&gt; to generate Kubernetes YAML manifests from the jsonnet files.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;code&gt;tanka&lt;/code&gt; and &lt;code&gt;jb&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;Follow the steps at &lt;a href=&#34;https://tanka.dev/install&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;https://tanka.dev/install&lt;/a&gt;. If you have &lt;code&gt;go&lt;/code&gt; installed locally you can also use:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;console&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-console&#34;&gt;# make sure to be outside of GOPATH or a go.mod project
go install github.com/grafana/tanka/cmd/tk@latest
go install github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set up a Jsonnet project, based on the example that follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Initialize Tanka&lt;/li&gt;
&lt;li&gt;Install Grafana Mimir and Kubernetes Jsonnet libraries&lt;/li&gt;
&lt;li&gt;Set up an environment&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- prettier-ignore-start --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;sh&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-sh&#34;&gt;#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-only

set -e

# Initialise the Tanka.
mkdir jsonnet-example &amp;amp;&amp;amp; cd jsonnet-example
tk init --k8s=1.29

# Install Mimir jsonnet.
jb install github.com/grafana/mimir/operations/mimir@main

# Use the provided example.
cp vendor/mimir/mimir-manifests.jsonnet.example environments/default/main.jsonnet

# Generate the YAML manifests.
export PAGER=cat
tk show environments/default&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate the Kubernetes YAML manifests and store them in the &lt;code&gt;./manifests&lt;/code&gt; directory:&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;sh&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-sh&#34;&gt;# Generate the YAML manifests:
export PAGER=cat
tk show environments/default
tk export manifests environments/default&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the environment specification file at &lt;code&gt;environments/default/spec.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To learn about how to use Tanka and to configure the &lt;code&gt;spec.json&lt;/code&gt; file, see &lt;a href=&#34;https://tanka.dev/tutorial/jsonnet&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Using Jsonnet: Creating a new project&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the manifests to a Kubernetes cluster, in one of two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use the &lt;code&gt;tk apply&lt;/code&gt; command&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Tanka supports commands to show the &lt;code&gt;diff&lt;/code&gt; and &lt;code&gt;apply&lt;/code&gt; changes to a Kubernetes cluster:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;sh&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-sh&#34;&gt;# Show the difference between your Jsonnet definition and your Kubernetes cluster:
tk diff environments/default

# Apply changes to your Kubernetes cluster:
tk apply environments/default&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use the &lt;code&gt;kubectl apply&lt;/code&gt; command&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You generated the Kubernetes manifests and stored them in the &lt;code&gt;./manifests&lt;/code&gt; directory in the previous step.&lt;/p&gt;
&lt;p&gt;You can run the following command to directly apply these manifests to your Kubernetes cluster:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;sh&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-sh&#34;&gt;# Review the changes that will apply to your Kubernetes cluster:
kubectl apply --dry-run=client -k manifests/

# Apply the changes to your Kubernetes cluster:
kubectl apply -k manifests/&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;The generated Kubernetes manifests create resources in the &lt;code&gt;default&lt;/code&gt; namespace.
To use a different namespace, change the &lt;code&gt;namespace&lt;/code&gt; configuration option in the &lt;code&gt;environments/default/main.jsonnet&lt;/code&gt; file, and re-generate the Kubernetes manifests.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;



&lt;div class=&#34;admonition admonition-warning&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Warning&lt;/p&gt;&lt;p&gt;A Jsonnet-based installation uses etcd for the HA tracker by default.
The Jsonnet-based installation creates the etcd using the &lt;a href=&#34;https://github.com/coreos/etcd-operator&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;etcd-operator&lt;/a&gt;.
Before applying the &lt;code&gt;tk apply&lt;/code&gt; or &lt;code&gt;kubectl apply&lt;/code&gt; command, make sure that you have the etcd-operator running in your Kubernetes cluster.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ol&gt;
]]></content><description>&lt;h1 id="deploy-grafana-mimir-with-jsonnet-and-tanka">Deploy Grafana Mimir with Jsonnet and Tanka&lt;/h1>
&lt;p>You can use &lt;a href="https://tanka.dev/" target="_blank" rel="noopener noreferrer">Tanka&lt;/a> and &lt;a href="https://github.com/jsonnet-bundler/jsonnet-bundler" target="_blank" rel="noopener noreferrer">jsonnet-bundler&lt;/a> to generate Kubernetes YAML manifests from the jsonnet files.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Install &lt;code>tanka&lt;/code> and &lt;code>jb&lt;/code>:&lt;/p></description></item><item><title>Configure Grafana Mimir to use low resources with Jsonnet</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-low-resources/</link><pubDate>Thu, 14 Aug 2025 18:42:07 +0000</pubDate><guid>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-low-resources/</guid><content><![CDATA[&lt;h1 id=&#34;configure-grafana-mimir-to-use-low-resources-with-jsonnet&#34;&gt;Configure Grafana Mimir to use low resources with Jsonnet&lt;/h1&gt;
&lt;p&gt;This page describes how to configure Jsonnet to deploy Grafana Mimir in a Kubernetes cluster with low CPU and memory resources available.&lt;/p&gt;
&lt;h2 id=&#34;anti-affinity&#34;&gt;Anti-affinity&lt;/h2&gt;
&lt;p&gt;Given the distributed nature of Mimir, both performance and reliability are improved when pods are spread across different nodes.
For example, losing multiple ingesters can cause data loss, so it&amp;rsquo;s better to distribute them across different nodes.&lt;/p&gt;
&lt;p&gt;For this reason, by default, anti-affinity rules are applied to some Kubernetes Deployments and StatefulSets.
These anti-affinity rules can become an issue when playing with Mimir in a single-node Kubernetes cluster.
You can disable anti-affinity by setting the configuration values &lt;code&gt;_config.&amp;lt;component&amp;gt;_allow_multiple_replicas_on_same_node&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;example-disable-anti-affinity&#34;&gt;Example: disable anti-affinity&lt;/h3&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;local mimir = import &amp;#39;mimir/mimir.libsonnet&amp;#39;;

mimir {
  _config&amp;#43;:: {
    ingester_allow_multiple_replicas_on_same_node: true,
    store_gateway_allow_multiple_replicas_on_same_node: true,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;resources&#34;&gt;Resources&lt;/h2&gt;
&lt;p&gt;Default scaling of Mimir components in the provided Jsonnet is opinionated and based on engineers’ years of experience running it at Grafana Labs.
The default resource requests and limits are also fine-tuned for the provided alerting rules.
For more information, see &lt;a href=&#34;/docs/mimir/manage/monitor-grafana-mimir&#34;&gt;Monitor Grafana Mimir&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, there are use cases where you might want to change the default resource requests, their limits, or both.
For example, if you are just testing Mimir and you want to run it on a small (possibly one-node) Kubernetes cluster, and you do not have tens of gigabytes of memory or multiple cores to schedule the components, consider overriding the scaling requirements as follows:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;local k = import &amp;#39;github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet&amp;#39;,
      deployment = k.apps.v1.deployment,
      statefulSet = k.apps.v1.statefulSet;
local mimir = import &amp;#39;mimir/mimir.libsonnet&amp;#39;;

mimir {
  _config&amp;#43;:: {
    // ... configuration values
  },

  compactor_container&amp;#43;: k.util.resourcesRequests(&amp;#39;100m&amp;#39;, &amp;#39;128Mi&amp;#39;),
  compactor_statefulset&amp;#43;: statefulSet.mixin.spec.withReplicas(1),

  distributor_container&amp;#43;: k.util.resourcesRequests(&amp;#39;100m&amp;#39;, &amp;#39;128Mi&amp;#39;),
  distributor_deployment&amp;#43;: deployment.mixin.spec.withReplicas(2),

  ingester_container&amp;#43;: k.util.resourcesRequests(&amp;#39;100m&amp;#39;, &amp;#39;128Mi&amp;#39;),
  ingester_statefulset&amp;#43;: statefulSet.mixin.spec.withReplicas(3),

  querier_container&amp;#43;: k.util.resourcesRequests(&amp;#39;100m&amp;#39;, &amp;#39;128Mi&amp;#39;),
  querier_deployment&amp;#43;: deployment.mixin.spec.withReplicas(2),

  query_frontend_container&amp;#43;: k.util.resourcesRequests(&amp;#39;100m&amp;#39;, &amp;#39;128Mi&amp;#39;),
  query_frontend_deployment&amp;#43;: deployment.mixin.spec.withReplicas(2),

  store_gateway_container&amp;#43;: k.util.resourcesRequests(&amp;#39;100m&amp;#39;, &amp;#39;128Mi&amp;#39;),
  store_gateway_statefulset&amp;#43;: statefulSet.mixin.spec.withReplicas(1),

  local smallMemcached = {
    cpu_requests:: &amp;#39;100m&amp;#39;,
    memory_limit_mb:: 64,
    memory_request_overhead_mb:: 8,
    statefulSet&amp;#43;: statefulSet.mixin.spec.withReplicas(1),
  },

  memcached_chunks&amp;#43;: smallMemcached,
  memcached_frontend&amp;#43;: smallMemcached,
  memcached_index_queries&amp;#43;: smallMemcached,
  memcached_metadata&amp;#43;: smallMemcached,
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="configure-grafana-mimir-to-use-low-resources-with-jsonnet">Configure Grafana Mimir to use low resources with Jsonnet&lt;/h1>
&lt;p>This page describes how to configure Jsonnet to deploy Grafana Mimir in a Kubernetes cluster with low CPU and memory resources available.&lt;/p></description></item><item><title>Configure the Grafana Mimir object storage backend with Jsonnet</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-object-storage-backend/</link><pubDate>Thu, 14 Aug 2025 18:42:07 +0000</pubDate><guid>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-object-storage-backend/</guid><content><![CDATA[&lt;h1 id=&#34;configure-the-grafana-mimir-object-storage-backend-with-jsonnet&#34;&gt;Configure the Grafana Mimir object storage backend with Jsonnet&lt;/h1&gt;
&lt;p&gt;You can configure the object storage backend for all Mimir components from a single place.
The minimum Jsonnet code required for this is:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    storage_backend: &amp;#39;gcs&amp;#39;,
    blocks_storage_bucket_name: &amp;#39;blocks-bucket&amp;#39;,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;storage_backend&lt;/code&gt; option must be one of either &lt;code&gt;azure&lt;/code&gt;, &lt;code&gt;gcs&lt;/code&gt;, or &lt;code&gt;s3&lt;/code&gt;.
Additional configuration options are available for each one of these providers.&lt;/p&gt;
&lt;h2 id=&#34;amazon-s3-s3-storage-configuration-options&#34;&gt;Amazon S3 (&lt;code&gt;s3&lt;/code&gt;) storage configuration options&lt;/h2&gt;
&lt;p&gt;Amazon S3 storage can be accessed without credentials when &lt;a href=&#34;https://aws.amazon.com/premiumsupport/knowledge-center/s3-private-connection-no-authentication/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;using Amazon VPC&lt;/a&gt;.
In this case, &lt;code&gt;storage_s3_secret_access_key&lt;/code&gt; and &lt;code&gt;storage_s3_access_key_id&lt;/code&gt; are optional and can be left null, as in the following example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    storage_backend: &amp;#39;s3&amp;#39;,
    blocks_storage_bucket_name: &amp;#39;blocks-bucket&amp;#39;,
    aws_region: &amp;#39;af-south-1&amp;#39;,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If credentials are required, it is a good practice to keep them in secrets. In that case environment variable interpolation can be used:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    storage_backend: &amp;#39;s3&amp;#39;,
    storage_s3_access_key_id: &amp;#39;$(BLOCKS_STORAGE_S3_ACCESS_KEY_ID)&amp;#39;,
    storage_s3_secret_access_key: &amp;#39;$(BLOCKS_STORAGE_S3_SECRET_ACCESS_KEY)&amp;#39;,
    aws_region: &amp;#39;af-south-1&amp;#39;,
    blocks_storage_bucket_name: &amp;#39;blocks-bucket&amp;#39;,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;azure-azure-storage-configuration-options&#34;&gt;Azure (&lt;code&gt;azure&lt;/code&gt;) storage configuration options&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://learn.microsoft.com/en-us/azure/storage/blobs/data-lake-storage-namespace&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Hierarchical namespace&lt;/a&gt; must be disabled in Azure Blob Storage.
Otherwise, Grafana Mimir will leave empty directories behind after deleting blocks.&lt;/p&gt;
&lt;p&gt;The Azure storage client requires the &lt;code&gt;storage_azure_account_name&lt;/code&gt; and &lt;code&gt;storage_azure_account_key&lt;/code&gt; to be configured.
It is a good practice to keep them in secrets. In that case environment variable interpolation can be used:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    storage_backend: &amp;#39;azure&amp;#39;,
    storage_azure_account_name: &amp;#39;$(STORAGE_AZURE_ACCOUNT_NAME)&amp;#39;,
    storage_azure_account_key: &amp;#39;$(STORAGE_AZURE_ACCOUNT_KEY)&amp;#39;,
    blocks_storage_bucket_name: &amp;#39;blocks-bucket&amp;#39;,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;google-cloud-storage-gcs-storage-configuration-options&#34;&gt;Google Cloud Storage (&lt;code&gt;gcs&lt;/code&gt;) storage configuration options&lt;/h2&gt;
&lt;p&gt;There are multiple &lt;a href=&#34;/docs/mimir/configure/configuration-parameters/#gcs_storage_backend&#34;&gt;ways to configure Google Cloud Storage client&lt;/a&gt;.
If you run Mimir on Google Cloud Platform it is possible that &lt;a href=&#34;https://cloud.google.com/storage/docs/authentication#libauth&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;the environment already has the credentials configured&lt;/a&gt;,
in that case the minimum jsonnet configuration is valid:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    storage_backend: &amp;#39;gcs&amp;#39;,
    blocks_storage_bucket_name: &amp;#39;blocks-bucket&amp;#39;,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can use the &lt;code&gt;storage_gcs_service_account&lt;/code&gt; configuration key to provide the service account when authentication is needed.
It is a good practice to keep credentials in secrets, so environment variable interpolation can be used:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    storage_backend: &amp;#39;gcs&amp;#39;,
    storage_gcs_service_account: &amp;#39;$(STORAGE_GCS_SERVICE_ACCOUNT)&amp;#39;,
    blocks_storage_bucket_name: &amp;#39;blocks-bucket&amp;#39;,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively, you can set the &lt;code&gt;GOOGLE_APPLICATION_CREDENTIALS&lt;/code&gt; environment variable to point to the service account file mounted from a secret.&lt;/p&gt;
]]></content><description>&lt;h1 id="configure-the-grafana-mimir-object-storage-backend-with-jsonnet">Configure the Grafana Mimir object storage backend with Jsonnet&lt;/h1>
&lt;p>You can configure the object storage backend for all Mimir components from a single place.
The minimum Jsonnet code required for this is:&lt;/p></description></item><item><title>Configure the Grafana Mimir ruler with Jsonnet</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-ruler/</link><pubDate>Thu, 14 Aug 2025 18:42:07 +0000</pubDate><guid>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-ruler/</guid><content><![CDATA[&lt;h1 id=&#34;configure-the-grafana-mimir-ruler-with-jsonnet&#34;&gt;Configure the Grafana Mimir ruler with Jsonnet&lt;/h1&gt;
&lt;p&gt;The ruler is an optional component and is therefore not deployed by default when using Jsonnet.
For more information about the ruler, see &lt;a href=&#34;/docs/mimir/references/architecture/components/ruler&#34;&gt;Grafana Mimir ruler&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To enable it, add the following Jsonnet code to the &lt;code&gt;_config&lt;/code&gt; section:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    ruler_enabled: true,
    ruler_storage_bucket_name: &amp;#39;ruler-bucket-name&amp;#39;,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;By default, the object storage backend used for the ruler will be the one set by the &lt;code&gt;$._config.storage_backend&lt;/code&gt; option.
If desired, you can override it by setting the &lt;code&gt;$._config.ruler_storage_backend&lt;/code&gt; option.
The &lt;code&gt;ruler_storage_backend&lt;/code&gt; option must be one of either &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;azure&lt;/code&gt;, &lt;code&gt;gcs&lt;/code&gt;, or &lt;code&gt;s3&lt;/code&gt;.
For more information about the options available for storing ruler state, see &lt;a href=&#34;/docs/mimir/references/architecture/components/ruler/#state&#34;&gt;Grafana Mimir ruler: State&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To get started, use the &lt;code&gt;local&lt;/code&gt; client type for initial testing:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    ruler_enabled: true,
    ruler_storage_backend: &amp;#39;local&amp;#39;,
    ruler_local_directory: &amp;#39;/path/to/local/directory&amp;#39;,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you are using object storage, you must set &lt;code&gt;ruler_storage_bucket_name&lt;/code&gt; to the name of the bucket that you want to use.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;If ruler object storage credentials differ from the ones defined in the common section, you need to manually provide them by using additional command line arguments.
For more information, refer to &lt;a href=&#34;/docs/mimir/configure/configuration-parameters/#ruler_storage&#34;&gt;Grafana Mimir configuration parameters: ruler_storage&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;operational-modes&#34;&gt;Operational modes&lt;/h2&gt;
&lt;p&gt;The ruler has two operational modes: &lt;em&gt;internal&lt;/em&gt; and &lt;em&gt;remote&lt;/em&gt;. By default, the Jsonnet deploys the ruler by using the internal operational mode.
For more information about these modes, see &lt;a href=&#34;/docs/mimir/references/architecture/components/ruler/#operational-modes&#34;&gt;Operational modes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To enable the remote operational mode, add the following code to the Jsonnet:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {n
    ruler_remote_evaluation_enabled: true,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;To support the &lt;em&gt;remote&lt;/em&gt; operational mode, the configuration includes three additional Kubernetes Deployments as a separate query path.&lt;/p&gt;
&lt;p&gt;These are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ruler-query-frontend&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ruler-query-scheduler&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ruler-querier&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;migrate-to-remote-evaluation&#34;&gt;Migrate to remote evaluation&lt;/h3&gt;
&lt;p&gt;To perform a zero downtime migration from internal to remote rule evaluation, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Deploy the following changes to enable remote evaluation in migration mode.
Doing so causes the three new and previously listed Kubernetes deployments to start. However, they will not reconfigure the ruler to use them just yet.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
 _config&amp;#43;:: {
   ruler_remote_evaluation_enabled: true,
   ruler_remote_evaluation_migration_enabled: true,
 },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check that all of pods for the following deployments have successfully started before moving to the next step:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ruler-query-frontend&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ruler-query-scheduler&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ruler-querier&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reconfigure the ruler pods to perform remote evaluation, by deploying the following changes:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    ruler_remote_evaluation_enabled: true,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
]]></content><description>&lt;h1 id="configure-the-grafana-mimir-ruler-with-jsonnet">Configure the Grafana Mimir ruler with Jsonnet&lt;/h1>
&lt;p>The ruler is an optional component and is therefore not deployed by default when using Jsonnet.
For more information about the ruler, see &lt;a href="/docs/mimir/references/architecture/components/ruler">Grafana Mimir ruler&lt;/a>.&lt;/p></description></item><item><title>Configure Grafana Mimir autoscaling with Jsonnet</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-autoscaling/</link><pubDate>Thu, 14 Aug 2025 18:42:07 +0000</pubDate><guid>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-autoscaling/</guid><content><![CDATA[&lt;h1 id=&#34;configure-grafana-mimir-autoscaling-with-jsonnet&#34;&gt;Configure Grafana Mimir autoscaling with Jsonnet&lt;/h1&gt;
&lt;p&gt;Mimir Jsonnet supports autoscaling for the following components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/docs/mimir/references/architecture/components/ruler&#34;&gt;Ruler Querier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/mimir/references/architecture/components/querier&#34;&gt;Querier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/mimir/references/architecture/components/distributor&#34;&gt;Distributor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Autoscaling, which is based on Prometheus metrics and &lt;a href=&#34;https://keda.sh&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Kubernetes-based Event Driven Autoscaler (KEDA)&lt;/a&gt;, uses Kubernetes&amp;rsquo; Horizontal Pod Autoscaler (HPA).&lt;/p&gt;
&lt;p&gt;HPA is not configured directly in Jsonnet but it&amp;rsquo;s created and updated by KEDA.
KEDA is an operator, running in the Kubernetes cluster, which is responsible to simplify the setup of HPA with custom metrics (Prometheus in our case).&lt;/p&gt;


&lt;div class=&#34;admonition admonition-warning&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Warning&lt;/p&gt;&lt;p&gt;Do not use the same Mimir or Grafana Enterprise Metrics cluster for storing and querying autoscaling metrics. Using the same cluster can create a dangerous feedback loop:&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t use the same Mimir or Grafana Enterprise Metrics cluster for storing and querying autoscaling metrics. Using the same cluster can create a dangerous feedback loop.&lt;/p&gt;
&lt;p&gt;For instance, if the Mimir or GEM cluster becomes unavailable, autoscaling stops working, because it cannot query the metrics. This prevents the cluster from automatically scaling up during high load or recovery. This inability to scale further exacerbates the cluster&amp;rsquo;s unavailability, which might, in turn, prevent the cluster from recovering.&lt;/p&gt;
&lt;p&gt;Instead, use a separate Prometheus instance or a different metrics backend for autoscaling metrics.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;how-keda-works&#34;&gt;How KEDA works&lt;/h2&gt;
&lt;p&gt;KEDA is a Kubernetes operator aiming to simplify the wiring between HPA and Prometheus.&lt;/p&gt;
&lt;p&gt;Kubernetes HPA, out of the box, is not capable of autoscaling based on metrics scraped by Prometheus, but it allows to configure a custom metrics API server which proxies metrics from a data source (e.g. Prometheus) to Kubernetes.
Setting up the custom metrics API server for Prometheus in a Kubernetes can be a tedious operation, so KEDA offers an operator to set it up automatically.
KEDA supports proxying metrics for a variety of sources, including Prometheus.&lt;/p&gt;
&lt;h3 id=&#34;keda-in-a-nutshell&#34;&gt;KEDA in a nutshell&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Runs an operator and an external metrics server.&lt;/li&gt;
&lt;li&gt;The metrics server supports proxying for many metric sources, including Prometheus.&lt;/li&gt;
&lt;li&gt;The operator watches for &lt;code&gt;ScaledObject&lt;/code&gt; custom resource definition (CRD), defining the minimum and maximum replicas, and scaling trigger metrics of a Deployment or StatefulSet, and then configures the related HPA resource. You don&amp;rsquo;t create the HPA resource in Kubernetes, but the operator creates it for you whenever a &lt;code&gt;ScaledObject&lt;/code&gt; CRD is created (and keeps it updated for its whole lifecycle).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Refers to &lt;a href=&#34;https://keda.sh&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;KEDA documentation&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h3 id=&#34;what-happens-if-keda-is-unhealthy&#34;&gt;What happens if KEDA is unhealthy&lt;/h3&gt;
&lt;p&gt;The autoscaling of deployments is always managed by HPA, which is a native Kubernetes feature.
KEDA, as we use it, never changes the number of replicas of Mimir Deployments or StatefulSets.&lt;/p&gt;
&lt;p&gt;However, if KEDA is not running successfully, there are consequences for Mimir autoscaling too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;keda-operator&lt;/code&gt; is down (critical): as the operator is the single point of truth, it will not request the metrics when &lt;code&gt;keda-operator-metrics-apiserver&lt;/code&gt; requests them. Changes to &lt;code&gt;ScaledObject&lt;/code&gt; CRD will not be reflected to the HPA until the operator is back online. The deployment (e.g. queriers) will keep working but, if there is a surge of traffic, HPA will not be able to detect it due to a lack of metrics and so will not scale up.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keda-operator-metrics-apiserver&lt;/code&gt; is down (critical): HPA is not able to fetch updated metrics and it will stop scaling the deployment until metrics will be back. The deployment (e.g. queriers) will keep working but, if there is a surge of traffic, HPA will not be able to detect it due to a lack of metrics and so will not scale up.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keda-admission-webhooks&lt;/code&gt; is down (not critical): CRD validation will not be executed. Based on KEDA&amp;rsquo;s configuration, this can block changes on CRDs until the service is restored. HPA functionality is not affected.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;Use a &lt;a href=&#34;https://keda.sh/docs/latest/operate/cluster/#high-availability&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;high availability&lt;/a&gt; KEDA configuration if autoscaling is critical for your use case.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href=&#34;/docs/mimir/manage/monitor-grafana-mimir&#34;&gt;alert &lt;code&gt;MimirAutoscalerNotActive&lt;/code&gt;&lt;/a&gt; fires if HPA is unable to scale the deployment for any reason (e.g. unable to scrape metrics from KEDA metrics API server).&lt;/p&gt;
&lt;h2 id=&#34;how-kubernetes-hpa-works&#34;&gt;How Kubernetes HPA works&lt;/h2&gt;
&lt;p&gt;Refer to Kubernetes &lt;a href=&#34;https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Horizontal Pod Autoscaling&lt;/a&gt; documentation to have a full understanding of how HPA works.&lt;/p&gt;
&lt;h2 id=&#34;how-to-enable-autoscaling&#34;&gt;How to enable autoscaling&lt;/h2&gt;
&lt;p&gt;The following Jsonnet configuration snippet shows an example of how to enable Mimir autoscaling with Jsonnet:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;local mimir = import &amp;#39;mimir/mimir.libsonnet&amp;#39;;

mimir {
    _config&amp;#43;:: {
        autoscaling_prometheus_url: &amp;#39;http://prometheus.default:9090/prometheus&amp;#39;,
        // Enable queriers autoscaling.
        autoscaling_querier_enabled: true,
        autoscaling_querier_min_replicas: 10,
        autoscaling_querier_max_replicas: 40,
        // Enable ruler queriers autoscaling.
        autoscaling_ruler_querier_enabled: true,
        autoscaling_ruler_querier_min_replicas: 10,
        autoscaling_ruler_querier_max_replicas: 40,
        // Enable distributor autoscaling.
        autoscaling_distributor_enabled: true,
        autoscaling_distributor_min_replicas: 10,
        autoscaling_distributor_max_replicas: 40,
    }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;The Mimir Jsonet doesn&amp;rsquo;t install KEDA.&lt;/p&gt;
&lt;p&gt;To install KEDA, follow the instructions in &lt;a href=&#34;https://keda.sh/docs/latest/deploy/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Deploying KEDA&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;how-to-disable-autoscaling&#34;&gt;How to disable autoscaling&lt;/h2&gt;
&lt;p&gt;There are two options to disable autoscaling in a Mimir cluster:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set minimum replicas = maximum replicas.&lt;/li&gt;
&lt;li&gt;Decommission HPA.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;set-minimum-replicas--maximum-replicas&#34;&gt;Set minimum replicas = maximum replicas&lt;/h3&gt;
&lt;p&gt;If KEDA and Kubernetes HPA work correctly but the HPA configuration (metric and threshold) are not giving the expected results (e.g. not scaling up when required), a simple solution to bypass the autoscaling algorithm is to set the minimum and maximum replicas to the same value. (e.g. &lt;code&gt;autoscaling_querier_min_replicas: 40&lt;/code&gt; and &lt;code&gt;autoscaling_querier_max_replicas: 40&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;decommission-hpa&#34;&gt;Decommission HPA&lt;/h3&gt;
&lt;p&gt;To fully decommission HPA in a Mimir cluster you have to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Disable the relevant autoscaler (e.g. &lt;code&gt;autoscaling_querier_enabled: false&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Manually set the expected number of replicas for the given Mimir component.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The following example shows how to disable querier autoscaler and configure querier Deployment with 10 replicas:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;local k = import &amp;#39;github.com/grafana/jsonnet-libs/ksonnet-util/kausal.libsonnet&amp;#39;;
local deployment = k.apps.v1.deployment;

mimir {
    _config&amp;#43;:: {
        autoscaling_querier_enabled: false,
    },

    querier_deployment&amp;#43;: deployment.mixin.spec.withReplicas(10),
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="configure-grafana-mimir-autoscaling-with-jsonnet">Configure Grafana Mimir autoscaling with Jsonnet&lt;/h1>
&lt;p>Mimir Jsonnet supports autoscaling for the following components:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="/docs/mimir/references/architecture/components/ruler">Ruler Querier&lt;/a>&lt;/li>
&lt;li>&lt;a href="/docs/mimir/references/architecture/components/querier">Querier&lt;/a>&lt;/li>
&lt;li>&lt;a href="/docs/mimir/references/architecture/components/distributor">Distributor&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Autoscaling, which is based on Prometheus metrics and &lt;a href="https://keda.sh" target="_blank" rel="noopener noreferrer">Kubernetes-based Event Driven Autoscaler (KEDA)&lt;/a>, uses Kubernetes&amp;rsquo; Horizontal Pod Autoscaler (HPA).&lt;/p></description></item><item><title>Configure deployment mode</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-deployment-mode/</link><pubDate>Thu, 14 Aug 2025 18:42:07 +0000</pubDate><guid>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/configure-deployment-mode/</guid><content><![CDATA[&lt;h1 id=&#34;configure-deployment-mode&#34;&gt;Configure deployment mode&lt;/h1&gt;
&lt;p&gt;Grafana Mimir supports multiple &lt;a href=&#34;/docs/mimir/references/architecture/deployment-modes&#34;&gt;deployment modes&lt;/a&gt;. By default, the provided Jsonnet deploys in microservices mode. Monolithic mode is not supported in Jsonnet.&lt;/p&gt;
&lt;h2 id=&#34;use-read-write-deployment-mode&#34;&gt;Use Read-Write deployment mode&lt;/h2&gt;


&lt;div class=&#34;admonition admonition-warning&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Warning&lt;/p&gt;&lt;p&gt;Read-Write deployment mode is experimental.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;requirements&#34;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;Read-write deployment mode requires that you use multi-zone ingesters and multi-zone store gateways. Additionally, rule evaluation is performed within &lt;code&gt;mimir-backend&lt;/code&gt;, so you must disable ruler remote evaluation.&lt;/p&gt;
&lt;p&gt;You can set the deployment mode via the &lt;code&gt;deployment_mode&lt;/code&gt; configuration variable:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    deployment_mode: &amp;#39;read-write&amp;#39;,

    mimir_write_replicas: 15,
    mimir_read_replicas: 6,
    mimir_backend_replicas: 9,

    // Requirements.
    multi_zone_ingester_enabled: true,
    multi_zone_store_gateway_enabled: true,
    ruler_remote_evaluation_enabled: false,

    // Disable microservices autoscaling.
    autoscaling_querier_enabled: false,
    autoscaling_ruler_querier_enabled: false,
  }

}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can configure autoscaling for the read path:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    autoscaling_mimir_read_enabled: true,
    autoscaling_mimir_read_min_replicas: 2,
    autoscaling_mimir_read_max_replicas: 20,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;CLI flags for read-write components are inherited from the microservices. For example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    // This change also applies to mimir-backend.
    store_gateway_args&amp;#43;:: {
      &amp;#39;blocks-storage.bucket-store.sync-interval&amp;#39;: &amp;#39;5m&amp;#39;,
    },
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;⚠️ Pitfall: Kubernetes resources’ overrides are not inherited. Remember to apply overrides to both microservices and read-write components, if you make changes to any of the following items:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Container specification, for example environment variables&lt;/li&gt;
&lt;li&gt;Deployment&lt;/li&gt;
&lt;li&gt;StatefulSet&lt;/li&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;li&gt;PodDisruptionBudget&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    // This change will NOT be applied to mimir-write too.
    ingester_container&amp;#43;::
      container.withEnvMixin(
        [envVar.new(&amp;#39;GOGC&amp;#39;, &amp;#39;50&amp;#39;)]
      ),

    mimir_write_container&amp;#43;::
      container.withEnvMixin(
        [envVar.new(&amp;#39;GOGC&amp;#39;, &amp;#39;50&amp;#39;)]
      ),
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="configure-deployment-mode">Configure deployment mode&lt;/h1>
&lt;p>Grafana Mimir supports multiple &lt;a href="/docs/mimir/references/architecture/deployment-modes">deployment modes&lt;/a>. By default, the provided Jsonnet deploys in microservices mode. Monolithic mode is not supported in Jsonnet.&lt;/p>
&lt;h2 id="use-read-write-deployment-mode">Use Read-Write deployment mode&lt;/h2>
&lt;div class="admonition admonition-warning">&lt;blockquote>&lt;p class="title text-uppercase">Warning&lt;/p></description></item><item><title>Migrate from Consul to memberlist KV store for hash rings without downtime</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/migrate-from-consul-to-memberlist/</link><pubDate>Thu, 14 Aug 2025 18:42:07 +0000</pubDate><guid>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/migrate-from-consul-to-memberlist/</guid><content><![CDATA[&lt;h1 id=&#34;migrate-from-consul-to-memberlist-kv-store-for-hash-rings-without-downtime&#34;&gt;Migrate from Consul to memberlist KV store for hash rings without downtime&lt;/h1&gt;
&lt;p&gt;Mimir Jsonnet uses memberlist as KV store for hash rings since Mimir 2.2.0.&lt;/p&gt;
&lt;p&gt;Memberlist can be disabled by using the following configuration:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    memberlist_ring_enabled: false
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you are running Mimir hash rings with Consul and would like to migrate to memberlist without any downtime, you can follow instructions in this document.&lt;/p&gt;
&lt;h2 id=&#34;step-1-enable-memberlist-and-multi-kv-store&#34;&gt;Step 1: Enable memberlist and multi KV store.&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    memberlist_ring_enabled: true,
    multikv_migration_enabled: true,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Step 1 configures components to use &lt;code&gt;multi&lt;/code&gt; KV store, with &lt;code&gt;consul&lt;/code&gt; as primary and memberlist as secondary stores.
This step requires rollout of all Mimir components.
After applying this step all Mimir components will expose &lt;a href=&#34;/docs/mimir/references/http-api/#memberlist-cluster&#34;&gt;&lt;code&gt;/memberlist&lt;/code&gt;&lt;/a&gt; page on HTTP admin interface, which can be used to check health of memberlist cluster.&lt;/p&gt;
&lt;h2 id=&#34;step-2-enable-kv-store-mirroring&#34;&gt;Step 2: Enable KV store mirroring&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    memberlist_ring_enabled: true,
    multikv_migration_enabled: true,
    multikv_mirror_enabled: true,  // Changed in this step.
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this step we enable writes to primary KV store (Consul) to be mirrored into secondary store (memberlist).
Applying this change will not cause restart of Mimir components.&lt;/p&gt;
&lt;p&gt;You can monitor following metrics to check if mirroring was enabled on all components and if it works correctly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cortex_multikv_mirror_enabled&lt;/code&gt; – shows which components have KV store mirroring enabled. All Mimir components should start mirroring to secondary KV store reloading runtime configuration.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rate(cortex_multikv_mirror_writes_total[1m])&lt;/code&gt; – shows rate of writes to secondary KV store in writes per second.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rate(cortex_multikv_mirror_write_errors_total[1m])&lt;/code&gt; – shows rate of write errors to secondary KV store, in errors per second.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After mirroring is enabled, you should see a key for each Mimir hash ring in the &lt;a href=&#34;/docs/mimir/references/http-api/#memberlist-cluster&#34;&gt;Memberlist cluster information&lt;/a&gt; admin page.
See &lt;a href=&#34;/docs/mimir/references/architecture/hash-ring&#34;&gt;list of components that use hash ring&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;step-3-switch-primary-and-secondary-store&#34;&gt;Step 3: Switch Primary and Secondary store&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    memberlist_ring_enabled: true,
    multikv_migration_enabled: true,
    multikv_mirror_enabled: true,
    multikv_switch_primary_secondary: true,  // Changed in this step.
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This change will switch primary and secondary stores as used by &lt;code&gt;multi&lt;/code&gt; KV.
From this point on Mimir components will use memberlist as primary KV store, and they will mirror updates to Consul.
This step does not require restart of Mimir components.&lt;/p&gt;
&lt;p&gt;To see if all components started to use memberlist as primary store, please watch &lt;code&gt;cortex_multikv_primary_store&lt;/code&gt; metric.&lt;/p&gt;
&lt;h2 id=&#34;step-4-disable-mirroring-to-consul&#34;&gt;Step 4: Disable mirroring to Consul&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    memberlist_ring_enabled: true,
    multikv_migration_enabled: true,
    multikv_mirror_enabled: false,  // Changed in this step.
    multikv_switch_primary_secondary: true,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This step does not require restart of any Mimir component. After applying the change components will stop writing ring updates to Consul, and will only use memberlist.
You can watch &lt;code&gt;cortex_multikv_mirror_enabled&lt;/code&gt; metric to see if all components have picked up updated configuration.&lt;/p&gt;
&lt;h2 id=&#34;step-5-disable-multi-kv-store&#34;&gt;Step 5: Disable &lt;code&gt;multi&lt;/code&gt; KV Store&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    memberlist_ring_enabled: true,
    multikv_migration_enabled: false,  // Changed in this step.
    multikv_mirror_enabled: false,
    multikv_switch_primary_secondary: true,
    multikv_migration_teardown: true,  // Added in this step.
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This configuration change will cause a new rollout of all components.
After the restart components will no longer use &lt;code&gt;multi&lt;/code&gt; KV store and will be configured to use memberlist only.
We use &lt;code&gt;multikv_migration_teardown&lt;/code&gt; to preserve runtime configuration for &lt;code&gt;multi&lt;/code&gt; KV store for components that haven&amp;rsquo;t restarted yet.&lt;/p&gt;
&lt;p&gt;All &lt;code&gt;cortex_multikv_*&lt;/code&gt; metrics are only exposed by components that use &lt;code&gt;multi&lt;/code&gt; KV store. As components restart, these metrics will disappear.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;Setting &lt;code&gt;multikv_migration_enabled: false&lt;/code&gt; while keeping &lt;code&gt;memberlist_ring_enabled: true&lt;/code&gt; removes the Consul workload.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s expected, since Consul isn&amp;rsquo;t used anymore—you disabled mirroring to it in step 4.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;If you need to keep consul running, you can explicitly set &lt;code&gt;consul_enabled: true&lt;/code&gt; in &lt;code&gt;_config&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;step-6-cleanup&#34;&gt;Step 6: Cleanup&lt;/h2&gt;
&lt;p&gt;We have successfully migrated Mimir cluster from using Consul to memberlist without any downtime!
As a final step, we can remove all migration-related config options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;multikv_migration_enabled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;multikv_mirror_enabled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;multikv_switch_primary_secondary&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;multikv_migration_teardown&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our final memberlist configuration will be:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    memberlist_ring_enabled: true,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will not trigger new restart of Mimir components. After applying this change, you are finished.&lt;/p&gt;
]]></content><description>&lt;h1 id="migrate-from-consul-to-memberlist-kv-store-for-hash-rings-without-downtime">Migrate from Consul to memberlist KV store for hash rings without downtime&lt;/h1>
&lt;p>Mimir Jsonnet uses memberlist as KV store for hash rings since Mimir 2.2.0.&lt;/p></description></item><item><title>Migrate from microservices to read-write mode without downtime</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/migrate-from-microservices-to-read-write/</link><pubDate>Thu, 14 Aug 2025 18:42:07 +0000</pubDate><guid>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/migrate-from-microservices-to-read-write/</guid><content><![CDATA[&lt;h1 id=&#34;migrate-from-microservices-to-read-write-mode-without-downtime&#34;&gt;Migrate from microservices to read-write mode without downtime&lt;/h1&gt;


&lt;div class=&#34;admonition admonition-warning&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Warning&lt;/p&gt;&lt;p&gt;Read-Write mode, and migrating between modes, is experimental.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;At a high level, the steps involved are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deploy read-write components alongside microservices; they both join the same ring.&lt;/li&gt;
&lt;li&gt;Switch over end points in your ingress.&lt;/li&gt;
&lt;li&gt;Decommission microservices.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Steps can be applied vice-versa for migrating from read-write mode to microservices.&lt;/p&gt;
&lt;h2 id=&#34;step-1-configure-prerequisite-zone-awareness&#34;&gt;Step 1: Configure prerequisite zone-awareness&lt;/h2&gt;
&lt;p&gt;Read-write mode requires that you enable &lt;a href=&#34;/docs/mimir/configure/configure-zone-aware-replication/#enabling-zone-awareness-via-the-grafana-mimir-jsonnet&#34;&gt;multi-zone ingesters and store-gateways&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    multi_zone_ingester_enabled: true,
    multi_zone_store_gateway_enabled: true,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&#34;/docs/mimir/v2.17.x/set-up/configure-ruler/#operational-modes&#34;&gt;Ruler remote evaluation&lt;/a&gt; is also required to be disabled, however this is done later in the migration process if you are presently using it in microservices.&lt;/p&gt;
&lt;h2 id=&#34;step-2-deploy-read-write-components-with-0-replicas&#34;&gt;Step 2: Deploy read-write components with 0 replicas&lt;/h2&gt;
&lt;p&gt;By setting the &lt;code&gt;deployment_mode&lt;/code&gt; to &lt;code&gt;migration&lt;/code&gt;, jsonnet will configure the components for both read-write and microservices. To begin with we want to set their replicas to 0.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    deployment_mode: &amp;#39;migration&amp;#39;,

    mimir_write_replicas: 0,
    mimir_read_replicas: 0,
    mimir_backend_replicas: 0,
    autoscaling_mimir_read_enabled: false,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;optionally-double-check-configuration&#34;&gt;Optionally double check configuration&lt;/h3&gt;
&lt;p&gt;Optionally at this point you may like to compare the component configuration between microservice and read-write modes.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;# Export all of the Kubernetes objects to yaml:

kubectl get -o yaml deployment distributor &amp;gt; distributor.yaml; yq eval -i &amp;#39;.spec&amp;#39; distributor.yaml
kubectl get -o yaml deployment overrides-exporter &amp;gt; overrides-exporter.yaml; yq eval -i &amp;#39;.spec&amp;#39; overrides-exporter.yaml
kubectl get -o yaml deployment querier &amp;gt; querier.yaml; yq eval -i &amp;#39;.spec&amp;#39; querier.yaml
kubectl get -o yaml deployment query-frontend &amp;gt; query-frontend.yaml; yq eval -i &amp;#39;.spec&amp;#39; query-frontend.yaml
kubectl get -o yaml deployment query-scheduler &amp;gt; query-scheduler.yaml; yq eval -i &amp;#39;.spec&amp;#39; query-scheduler.yaml
kubectl get -o yaml deployment ruler &amp;gt; ruler.yaml; yq eval -i &amp;#39;.spec&amp;#39; ruler.yaml
kubectl get -o yaml deployment ruler-querier &amp;gt; ruler-querier.yaml; yq eval -i &amp;#39;.spec&amp;#39; ruler-querier.yaml
kubectl get -o yaml deployment ruler-query-frontend &amp;gt; ruler-query-frontend.yaml; yq eval -i &amp;#39;.spec&amp;#39; ruler-query-frontend.yaml
kubectl get -o yaml deployment ruler-query-scheduler &amp;gt; ruler-query-scheduler.yaml; yq eval -i &amp;#39;.spec&amp;#39; ruler-query-scheduler.yaml
kubectl get -o yaml deployment mimir-read &amp;gt; mimir-read.yaml; yq eval -i &amp;#39;.spec&amp;#39; mimir-read.yaml
kubectl get -o yaml statefulset compactor &amp;gt; compactor.yaml; yq eval -i &amp;#39;.spec&amp;#39; compactor.yaml
kubectl get -o yaml statefulset ingester-zone-a &amp;gt; ingester-zone-a.yaml; yq eval -i &amp;#39;.spec&amp;#39; ingester-zone-a.yaml
kubectl get -o yaml statefulset ingester-zone-b &amp;gt; ingester-zone-b.yaml; yq eval -i &amp;#39;.spec&amp;#39; ingester-zone-b.yaml
kubectl get -o yaml statefulset ingester-zone-c &amp;gt; ingester-zone-c.yaml; yq eval -i &amp;#39;.spec&amp;#39; ingester-zone-c.yaml
kubectl get -o yaml statefulset store-gateway-zone-a &amp;gt; store-gateway-zone-a.yaml; yq eval -i &amp;#39;.spec&amp;#39; store-gateway-zone-a.yaml
kubectl get -o yaml statefulset store-gateway-zone-b &amp;gt; store-gateway-zone-b.yaml; yq eval -i &amp;#39;.spec&amp;#39; store-gateway-zone-b.yaml
kubectl get -o yaml statefulset store-gateway-zone-c &amp;gt; store-gateway-zone-c.yaml; yq eval -i &amp;#39;.spec&amp;#39; store-gateway-zone-c.yaml
kubectl get -o yaml statefulset mimir-write-zone-a &amp;gt; mimir-write-zone-a.yaml; yq eval -i &amp;#39;.spec&amp;#39; mimir-write-zone-a.yaml
kubectl get -o yaml statefulset mimir-write-zone-b &amp;gt; mimir-write-zone-b.yaml; yq eval -i &amp;#39;.spec&amp;#39; mimir-write-zone-b.yaml
kubectl get -o yaml statefulset mimir-write-zone-c &amp;gt; mimir-write-zone-c.yaml; yq eval -i &amp;#39;.spec&amp;#39; mimir-write-zone-c.yaml
kubectl get -o yaml statefulset mimir-backend-zone-a &amp;gt; mimir-backend-zone-a.yaml; yq eval -i &amp;#39;.spec&amp;#39; mimir-backend-zone-a.yaml
kubectl get -o yaml statefulset mimir-backend-zone-b &amp;gt; mimir-backend-zone-b.yaml; yq eval -i &amp;#39;.spec&amp;#39; mimir-backend-zone-b.yaml
kubectl get -o yaml statefulset mimir-backend-zone-c &amp;gt; mimir-backend-zone-c.yaml; yq eval -i &amp;#39;.spec&amp;#39; mimir-backend-zone-c.yaml

# Diff deployments and statefulsets:

## Write
diff --color=always distributor.yaml mimir-write-zone-a.yaml
diff --color=always ingester-zone-a.yaml mimir-write-zone-a.yaml
diff --color=always ingester-zone-b.yaml mimir-write-zone-b.yaml
diff --color=always ingester-zone-c.yaml mimir-write-zone-c.yaml

## Read
diff --color=always query-frontend.yaml mimir-read.yaml
diff --color=always querier.yaml mimir-read.yaml
diff --color=always ruler-query-frontend.yaml mimir-read.yaml
diff --color=always ruler-querier.yaml mimir-read.yaml

## Backend
diff --color=always overrides-exporter.yaml mimir-backend-zone-a.yaml
diff --color=always query-scheduler.yaml mimir-backend-zone-a.yaml
diff --color=always ruler-query-scheduler.yaml mimir-backend-zone-a.yaml
diff --color=always ruler.yaml mimir-backend-zone-a.yaml
diff --color=always compactor.yaml mimir-backend-zone-a.yaml
diff --color=always store-gateway-zone-a.yaml mimir-backend-zone-a.yaml
diff --color=always store-gateway-zone-b.yaml mimir-backend-zone-b.yaml
diff --color=always store-gateway-zone-c.yaml mimir-backend-zone-c.yaml&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;step-3-migrate-read-path-to-read-write-service&#34;&gt;Step 3: Migrate read-path to read-write service&lt;/h2&gt;
&lt;h3 id=&#34;step-31-scale-up-read-component&#34;&gt;Step 3.1: Scale up read component&lt;/h3&gt;
&lt;p&gt;Scale up the Mimir read component using either the autoscaler or explicitly setting the number of replicas. (Keep the current microservices at their present level of replicas or autoscaling).&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    deployment_mode: &amp;#39;migration&amp;#39;,

    mimir_write_replicas: 0,
    mimir_read_replicas: 3,
    mimir_backend_replicas: 0,
    autoscaling_mimir_read_enabled: false,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    deployment_mode: &amp;#39;migration&amp;#39;,

    mimir_write_replicas: 0,
    mimir_backend_replicas: 0,
    autoscaling_mimir_read_enabled: true,
    autoscaling_mimir_read_min_replicas: 3,
    autoscaling_mimir_read_max_replicas: 30,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The Read-write querier at this point will start running queries from the &lt;code&gt;query-scheduler&lt;/code&gt; (as they share the same ring).&lt;/p&gt;
&lt;h3 id=&#34;step-32-check-mimir-read-is-working&#34;&gt;Step 3.2: Check mimir-read is working&lt;/h3&gt;
&lt;p&gt;Perform a test query by port-forwarding to &lt;code&gt;mimir-read&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ensure &lt;code&gt;mimir-read&lt;/code&gt; is running queries:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sum by (pod) (rate(cortex_querier_request_duration_seconds_count{job=~&amp;quot;.*mimir-read.*&amp;quot;, route=~&amp;quot;(prometheus|api_prom)_api_v1_.&#43;&amp;quot;}[1m]))&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;step-33-route-traffic-to-mimir-read&#34;&gt;Step 3.3: Route traffic to mimir-read&lt;/h3&gt;
&lt;p&gt;Configure your load-balancer to route read requests to &lt;code&gt;mimir-read&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ensure the &lt;code&gt;query-frontend&lt;/code&gt; microservice is no longer getting requests:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sum by(pod) (rate(cortex_query_frontend_queries_total{pod!~&amp;quot;ruler-query-frontend.*&amp;quot;}[1m]))&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;step-4-migrate-backend-components-to-backend-service&#34;&gt;Step 4: Migrate backend components to backend service&lt;/h2&gt;
&lt;h3 id=&#34;step-41-scale-up-backend-component&#34;&gt;Step 4.1: Scale up backend component&lt;/h3&gt;
&lt;p&gt;Scale up the Mimir backend component.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    mimir_backend_replicas: 3,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;step-42-check-mimir-backend-is-working&#34;&gt;Step 4.2: Check mimir-backend is working&lt;/h3&gt;
&lt;p&gt;Check the following rings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query-scheduler ring should include both microservices and read-write components.&lt;/li&gt;
&lt;li&gt;Store-gateway ring should include both microservices and read-write components.&lt;/li&gt;
&lt;li&gt;Compactor ring should include both microservices and read-write components.&lt;/li&gt;
&lt;li&gt;Ruler ring should include both microservices and read-write components.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Run a few test queries on long-term data.&lt;/p&gt;
&lt;h3 id=&#34;step-43-route-traffic-to-mimir-backend&#34;&gt;Step 4.3: Route traffic to mimir-backend&lt;/h3&gt;
&lt;p&gt;Configure your load-balancer to route &lt;code&gt;compactor&lt;/code&gt; and &lt;code&gt;ruler&lt;/code&gt; endpoints to &lt;code&gt;mimir-backend&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;step-5-scale-down-microservice-read-and-backend-components&#34;&gt;Step 5: Scale down microservice read and backend components&lt;/h2&gt;
&lt;p&gt;Now that we have &lt;code&gt;mimir-read&lt;/code&gt; and &lt;code&gt;mimir-backend&lt;/code&gt; scaled up and receiving traffic, we can safely decommission the microservices on those paths.&lt;/p&gt;
&lt;p&gt;First though, configure the microservice &lt;code&gt;store-gateway&lt;/code&gt; to leave the ring:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  // Configure microservices store-gateway to leave the ring.
  store_gateway_args&amp;#43;:: {
    &amp;#39;store-gateway.sharding-ring.unregister-on-shutdown&amp;#39;: true,
  },

  mimir_backend_args&amp;#43;:: {
    &amp;#39;store-gateway.sharding-ring.unregister-on-shutdown&amp;#39;: false,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then scale down the replicas for all components:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    multi_zone_store_gateway_replicas: 0,
    autoscaling_querier_enabled: false,
  },

  query_frontend_deployment&amp;#43;:
    deployment.mixin.spec.withReplicas(0),

  query_scheduler_deployment&amp;#43;:
    deployment.mixin.spec.withReplicas(0),

  querier_deployment&amp;#43;:
    deployment.mixin.spec.withReplicas(0),

  ruler_deployment&amp;#43;:
    deployment.mixin.spec.withReplicas(0),

  overrides_exporter_deployment&amp;#43;:
    deployment.mixin.spec.withReplicas(0),

  compactor_statefulset&amp;#43;:
    statefulSet.mixin.spec.withReplicas(0),
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ensure backend components (&lt;code&gt;query-scheduler&lt;/code&gt;, &lt;code&gt;compactor&lt;/code&gt;, &lt;code&gt;ruler&lt;/code&gt;, &lt;code&gt;store-gateway&lt;/code&gt;) correctly left their respective rings (Query-scheduler, Compactor, Ruler, Store-gateway).&lt;/p&gt;
&lt;p&gt;It is now safe to disable &lt;a href=&#34;/docs/mimir/v2.17.x/set-up/configure-ruler/#operational-modes&#34;&gt;ruler remote evaluation&lt;/a&gt;. (This needs to be done after the microservices ruler has been scaled down, otherwise rule evaluations may fail).&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    ruler_remote_evaluation_enabled: false,
    autoscaling_ruler_querier_enabled: false,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;step-6-migrate-write-path-to-read-write-deployment&#34;&gt;Step 6: Migrate write path to read-write deployment&lt;/h2&gt;
&lt;h3 id=&#34;step-61-scale-up-write-component&#34;&gt;Step 6.1: Scale up write component&lt;/h3&gt;
&lt;p&gt;Scale up &lt;code&gt;mimir-write&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    mimir_write_replicas: 3,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;step-62-route-traffic-to-mimir-write&#34;&gt;Step 6.2: Route traffic to mimir-write&lt;/h3&gt;
&lt;p&gt;Configure your load-balancer to route write requests to &lt;code&gt;mimir-write&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ensure the microservice distributor is no longer receiving write requests:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sum by (job) (rate(cortex_request_duration_seconds_count{job=~&amp;quot;.*distributor.*&amp;quot;, route=~&amp;quot;/distributor.Distributor/Push|/httpgrpc.*|api_(v1|prom)_push|otlp_v1_metrics&amp;quot;}[1m]))&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;step-7-scale-down-write-microservices&#34;&gt;Step 7: Scale down write microservices&lt;/h2&gt;
&lt;h3 id=&#34;step-71-scale-down-distributors&#34;&gt;Step 7.1: Scale down distributors&lt;/h3&gt;
&lt;p&gt;Set &lt;code&gt;distributor&lt;/code&gt; replicas to &lt;code&gt;0&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  distributor_deployment&amp;#43;:
    deployment.mixin.spec.withReplicas(0),
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Wait the next TSDB head compaction for ingesters (2 hours).&lt;/p&gt;
&lt;h3 id=&#34;step-72-scale-down-ingesters&#34;&gt;Step 7.2: Scale down ingesters&lt;/h3&gt;


&lt;div class=&#34;admonition admonition-warning&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Warning&lt;/p&gt;&lt;p&gt;You must follow the shutdown ingester procedure to avoid data loss.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;Follow the procedure for &lt;a href=&#34;/docs/mimir/manage/run-production-environment/scaling-out/#scaling-down-ingesters&#34;&gt;shutting down ingesters&lt;/a&gt; in &lt;code&gt;ingester-zone-a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Scale down zone-a replicas (this can be done before waiting for step 4 in the shutdown procedure):&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  ingester_zone_a_statefulset&amp;#43;:
    statefulSet.mixin.spec.withReplicas(0),
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Wait the required amount of time as per step 4 in the shutdown procedure.&lt;/p&gt;
&lt;p&gt;Repeat shutting down and scaling down ingesters for zone-b and zone-c waiting the required amount of time between each zone.&lt;/p&gt;
&lt;h2 id=&#34;step-8-final-cleanup&#34;&gt;Step 8: Final cleanup&lt;/h2&gt;
&lt;p&gt;Now that migration is complete you can clean up your deployment and jsonnet.&lt;/p&gt;
&lt;p&gt;Changing &lt;code&gt;deployment_mode&lt;/code&gt; to the final state of &lt;code&gt;read-write&lt;/code&gt; will remove all of the microservice Kubernetes objects.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    deployment_mode: &amp;#39;read-write&amp;#39;,
  },
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As the objects such as &lt;code&gt;query_frontend_deployment&lt;/code&gt; are no longer defined, you&amp;rsquo;ll also need to remove the scaling that we did for those components. This is a good time to remove any other left over scaling or microservice configuration you may have set.&lt;/p&gt;
&lt;p&gt;Lastly you can remove and release any now unused volumes from microservices. For example, to get a list of unused PVC&amp;rsquo;s:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl get pvc --no-headers | grep -E &#39;(ingester|store-gateway|compactor)&#39; | awk &#39;{print $1}&#39;&lt;/code&gt;&lt;/p&gt;
]]></content><description>&lt;h1 id="migrate-from-microservices-to-read-write-mode-without-downtime">Migrate from microservices to read-write mode without downtime&lt;/h1>
&lt;div class="admonition admonition-warning">&lt;blockquote>&lt;p class="title text-uppercase">Warning&lt;/p>&lt;p>Read-Write mode, and migrating between modes, is experimental.&lt;/p>&lt;/blockquote>&lt;/div>
&lt;p>At a high level, the steps involved are as follows:&lt;/p></description></item><item><title>Migrate query-scheduler from DNS-based to ring-based service discovery</title><link>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/migrate-query-scheduler-from-dns-to-ring-based-service-discovery/</link><pubDate>Thu, 14 Aug 2025 18:42:07 +0000</pubDate><guid>https://grafana.com/docs/enterprise-metrics/v2.17.x/set-up/jsonnet/migrate-query-scheduler-from-dns-to-ring-based-service-discovery/</guid><content><![CDATA[&lt;h1 id=&#34;migrate-query-scheduler-from-dns-based-to-ring-based-service-discovery&#34;&gt;Migrate query-scheduler from DNS-based to ring-based service discovery&lt;/h1&gt;
&lt;p&gt;The query-scheduler supports two service discovery mechanisms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/docs/mimir/references/architecture/components/query-scheduler/#dns-based-service-discovery&#34;&gt;DNS-based service discovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/mimir/references/architecture/components/query-scheduler/#ring-based-service-discovery&#34;&gt;Ring-based service discovery&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To migrate the query-scheduler from DNS-based to ring-based service discovery when your Mimir cluster is deployed using Jsonnet:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Configure the query-scheduler instances to join a ring, but keep the querier and query-frontend instances discovering query-schedulers via DNS:

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    query_scheduler_service_discovery_mode: &amp;#39;ring&amp;#39;,
    query_scheduler_service_discovery_ring_read_path_enabled: false,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Wait until query-scheduler changes have been applied.&lt;/li&gt;
&lt;li&gt;Open the &lt;a href=&#34;/docs/mimir/references/http-api/#query-scheduler-ring-status&#34;&gt;query-scheduler ring status&lt;/a&gt; page and ensure all query-scheduler instances are registered to the ring.&lt;/li&gt;
&lt;li&gt;Configure query-frontend and querier instances to discover query-schedulers via the ring:

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;jsonnet&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-jsonnet&#34;&gt;{
  _config&amp;#43;:: {
    query_scheduler_service_discovery_mode: &amp;#39;ring&amp;#39;,
    query_scheduler_service_discovery_ring_read_path_enabled: true,
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
]]></content><description>&lt;h1 id="migrate-query-scheduler-from-dns-based-to-ring-based-service-discovery">Migrate query-scheduler from DNS-based to ring-based service discovery&lt;/h1>
&lt;p>The query-scheduler supports two service discovery mechanisms:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="/docs/mimir/references/architecture/components/query-scheduler/#dns-based-service-discovery">DNS-based service discovery&lt;/a>&lt;/li>
&lt;li>&lt;a href="/docs/mimir/references/architecture/components/query-scheduler/#ring-based-service-discovery">Ring-based service discovery&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>To migrate the query-scheduler from DNS-based to ring-based service discovery when your Mimir cluster is deployed using Jsonnet:&lt;/p></description></item></channel></rss>