Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auto-apply memberlist ring config when join_members provided #4400

Merged
merged 4 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## Main
* [4400](https://github.com/grafana/loki/pull/4400) **trevorwhitney**: Config: automatically apply memberlist config too all rings when provided

# 2.3.0 (2021/08/06)

Expand Down
4 changes: 4 additions & 0 deletions docs/sources/configuration/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,10 @@ The `memberlist_config` block configures the gossip ring to discover and connect
between distributors, ingesters and queriers. The configuration is unique for all
three components to ensure a single shared ring.

When a `memberlist_config` with least 1 `join_members` is defined, a `kvstore` of type `memberlist` is
automatically configured for the `distributor`, `ingester`, and `ruler` rings unless otherwise specified in
those components specific configuration sections.

```yaml
# Name of the node in memberlist cluster. Defaults to hostname.
# CLI flag: -memberlist.nodename
Expand Down
45 changes: 45 additions & 0 deletions docs/sources/upgrading/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,53 @@ If possible try to stay current and do sequential updates. If you want to skip v

## Master / Unreleased

### Loki

#### Memberlist config now automatically applies to all non-configured rings
PR [4400](https://github.com/grafana/loki/pull/4400) **trevorwhitney**: Config: automatically apply memberlist config too all rings when provided

This change affects the behavior of the ingester, distributor, and ruler rings. Previously, if you wanted to use memberlist for all of these rings, you
had to provide a `memberlist` configuration as well as specify `store: memberlist` for the `kvstore` of each of the rings you wanted to use memberlist.
For example, your configuration might look something like this:

```yaml
memberlist:
join_members:
- loki.namespace.svc.cluster.local
distributor:
ring:
kvstore:
store: memberlist
ingester:
lifecycler:
ring:
kvstore:
store: memberlist
ruler:
ring:
kvstore:
store: memberlist
```

Now, if your provide a `memberlist` configuration with at least one `join_members`, loki will default all rings to use a `kvstore` of type `memberlist`.
You can change this behavior by overriding specific configurations. For example, if you wanted to use `consul` for you `ruler` rings, but `memberlist`
for the `ingester` and `distributor`, you could do so with the following config:

```yaml
memberlist:
join_members:
- loki.namespace.svc.cluster.local
ruler:
ring:
kvstore:
store: consul
consul:
host: consul.namespace.svc.cluster.local:8500
```

-_add changes here which are unreleased_


## 2.3.0

### Loki
Expand Down
17 changes: 17 additions & 0 deletions pkg/loki/config_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ func (c *ConfigWrapper) Clone() flagext.Registerer {
}(*c)
}

const memberlistStr = "memberlist"

// ApplyDynamicConfig satisfies WithCommonCloneable interface, and applies all rules for setting Loki
// config values from the common section of the Loki config file.
// This method's purpose is to simplify Loki's config in an opinionated way so that Loki can be run
Expand All @@ -69,6 +71,21 @@ func (c *ConfigWrapper) ApplyDynamicConfig() cfg.Source {
}
}

applyMemberlistConfig(r)

return nil
}
}

// applyMemberlistConfig will change the default ingester, distributor, and ruler ring configurations to use memberlist
// if the -memberlist.join_members config is provided. The idea here is that if a user explicitly configured the
// memberlist configuration section, they probably want to be using memberlist for all their ring configurations.
// Since a user can still explicitly override a specific ring configuration (for example, use consul for the distributor),
// it seems harmless to take a guess at better defaults here.
func applyMemberlistConfig(r *ConfigWrapper) {
if len(r.MemberlistKV.JoinMembers) > 0 {
r.Ingester.LifecyclerConfig.RingConfig.KVStore.Store = memberlistStr
r.Distributor.DistributorRing.KVStore.Store = memberlistStr
r.Ruler.Ring.KVStore.Store = memberlistStr
}
}
61 changes: 61 additions & 0 deletions pkg/loki/config_wrapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,65 @@ common:
assert.EqualValues(t, "/opt/loki/wal", config.Ingester.WAL.Dir)
})
})

t.Run("common memberlist config", func(t *testing.T) {
// components with rings
// * ingester
// * distributor
// * ruler

t.Run("does not automatically configure memberlist when no top-level memberlist config is provided", func(t *testing.T) {
configFileString := `---`
config, defaults := testContext(configFileString, nil)

assert.EqualValues(t, defaults.Ingester.LifecyclerConfig.RingConfig.KVStore.Store, config.Ingester.LifecyclerConfig.RingConfig.KVStore.Store)
assert.EqualValues(t, defaults.Distributor.DistributorRing.KVStore.Store, config.Distributor.DistributorRing.KVStore.Store)
assert.EqualValues(t, defaults.Ruler.Ring.KVStore.Store, config.Ruler.Ring.KVStore.Store)
})

t.Run("when top-level memberlist join_members are provided, all applicable rings are defaulted to use memberlist", func(t *testing.T) {
configFileString := `---
memberlist:
join_members:
- foo.bar.example.com`

config, _ := testContext(configFileString, nil)

assert.EqualValues(t, memberlistStr, config.Ingester.LifecyclerConfig.RingConfig.KVStore.Store)
assert.EqualValues(t, memberlistStr, config.Distributor.DistributorRing.KVStore.Store)
assert.EqualValues(t, memberlistStr, config.Ruler.Ring.KVStore.Store)
})

t.Run("explicit ring configs provided via config file are preserved", func(t *testing.T) {
configFileString := `---
memberlist:
join_members:
- foo.bar.example.com
distributor:
ring:
kvstore:
store: etcd`

config, _ := testContext(configFileString, nil)

assert.EqualValues(t, "etcd", config.Distributor.DistributorRing.KVStore.Store)

assert.EqualValues(t, memberlistStr, config.Ingester.LifecyclerConfig.RingConfig.KVStore.Store)
assert.EqualValues(t, memberlistStr, config.Ruler.Ring.KVStore.Store)
})

t.Run("explicit ring configs provided via command line are preserved", func(t *testing.T) {
configFileString := `---
memberlist:
join_members:
- foo.bar.example.com`

config, _ := testContext(configFileString, []string{"-ruler.ring.store", "inmemory"})

assert.EqualValues(t, "inmemory", config.Ruler.Ring.KVStore.Store)

assert.EqualValues(t, memberlistStr, config.Ingester.LifecyclerConfig.RingConfig.KVStore.Store)
assert.EqualValues(t, memberlistStr, config.Distributor.DistributorRing.KVStore.Store)
})
})
}