Skip to content

Commit b83af95

Browse files
authored
Added integrated monitoring. (#5)
Signed-off-by: Bartlomiej Plotka <bwplotka@gmail.com>
1 parent e5dbc3c commit b83af95

29 files changed

Lines changed: 1265 additions & 134 deletions

File tree

README.md

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,25 @@ Let's go through an example leveraging `go test` flow:
2525

2626
1. Implement the workload by embedding`e2e.Runnable` or `*e2e.InstrumentedRunnable`. Or you can use existing ones in [e2edb](db/) package. For example implementing Thanos Querier with our desired configuration could look like this:
2727

28-
```go mdox-exec="sed -n '47,64p' examples/thanos/standalone.go"
28+
```go mdox-exec="sed -n '49,67p' examples/thanos/standalone.go"
2929
func newThanosSidecar(env e2e.Environment, name string, prom e2e.Linkable) *e2e.InstrumentedRunnable {
3030
ports := map[string]int{
3131
"http": 9090,
3232
"grpc": 9091,
3333
}
34-
return e2e.NewInstrumentedRunnable(env, name, ports, "http", e2e.StartOptions{
35-
Image: "quay.io/thanos/thanos:v0.21.1",
36-
Command: e2e.NewCommand("sidecar", e2e.BuildArgs(map[string]string{
37-
"--debug.name": name,
38-
"--grpc-address": fmt.Sprintf(":%d", ports["grpc"]),
39-
"--http-address": fmt.Sprintf(":%d", ports["http"]),
40-
"--prometheus.url": "http://" + prom.InternalEndpoint(e2edb.AccessPortName),
41-
"--log.level": "info",
42-
})...),
43-
Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200),
44-
User: strconv.Itoa(os.Getuid()),
45-
})
34+
return e2e.NewInstrumentedRunnable(env, name, ports, "http").Init(
35+
e2e.StartOptions{
36+
Image: "quay.io/thanos/thanos:v0.21.1",
37+
Command: e2e.NewCommand("sidecar", e2e.BuildArgs(map[string]string{
38+
"--debug.name": name,
39+
"--grpc-address": fmt.Sprintf(":%d", ports["grpc"]),
40+
"--http-address": fmt.Sprintf(":%d", ports["http"]),
41+
"--prometheus.url": "http://" + prom.InternalEndpoint(e2edb.AccessPortName),
42+
"--log.level": "info",
43+
})...),
44+
Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200),
45+
User: strconv.Itoa(os.Getuid()),
46+
})
4647
}
4748
```
4849

@@ -119,6 +120,30 @@ Let's go through an example leveraging `go test` flow:
119120
}
120121
```
121122

123+
### Monitoring
124+
125+
Each instrumented workload have programmatic access to latest metrics with `WaitSumMetricsWithOptions` methods family. Yet, especially for standalone mode it's often useful to query yourself and visualisate metrics provided by your workloads and environment. In order to do so just start monitoring from `e2emontioring` package:
126+
127+
```go
128+
mon, err := e2emonitoring.Start(e)
129+
if err != nil {
130+
return err
131+
}
132+
```
133+
134+
This will start Prometheus with automatic discovery for every new and old instrumented runnables being scraped. It also runs cadvisor that monitors docker itself if `env.DockerEnvironment` is started. Run `OpenUserInterfaceInBrowser()` to open Prometheus UI in browser.
135+
136+
```go
137+
// Open monitoring page with all metrics.
138+
if err := mon.OpenUserInterfaceInBrowser(); err != nil {
139+
return err
140+
}
141+
```
142+
143+
To see how it works in practice run our example code in [standalone.go](examples/thanos/standalone.go) by running `make run-example`. At the end two UI should show in your browser. Thanos one and monitoring one. You can then e.g query docker container metrics using `sum(container_memory_working_set_bytes{name!=""}) by (name)` metric e.g:
144+
145+
![mem metric](monitoring.png)
146+
122147
## Credits
123148

124149
* Initial Authors: [@pracucci](https://github.com/pracucci), [@bwplotka](https://github.com/bwplotka), [@pstibrany](https://github.com/pstibrany)

db/db.go

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func NewMinio(env e2e.Environment, name, bktName string, opts ...Option) *e2e.In
6161
"MINIO_KMS_KES_CERT_FILE=" + "root.cert",
6262
"MINIO_KMS_KES_KEY_NAME=" + "my-minio-key",
6363
}
64-
f := e2e.NewFutureInstrumentedRunnable(env, name, ports, AccessPortName)
64+
f := e2e.NewInstrumentedRunnable(env, name, ports, AccessPortName)
6565
return f.Init(
6666
e2e.StartOptions{
6767
Image: o.image,
@@ -87,11 +87,7 @@ func NewConsul(env e2e.Environment, name string, opts ...Option) *e2e.Instrument
8787
}
8888

8989
e2e.MergeFlags()
90-
return e2e.NewInstrumentedRunnable(
91-
env,
92-
name,
93-
map[string]int{AccessPortName: 8500},
94-
AccessPortName,
90+
return e2e.NewInstrumentedRunnable(env, name, map[string]int{AccessPortName: 8500}, AccessPortName).Init(
9591
e2e.StartOptions{
9692
Image: o.image,
9793
// Run consul in "dev" mode so that the initial leader election is immediate.
@@ -107,11 +103,7 @@ func NewDynamoDB(env e2e.Environment, name string, opts ...Option) *e2e.Instrume
107103
opt(&o)
108104
}
109105

110-
return e2e.NewInstrumentedRunnable(
111-
env,
112-
name,
113-
map[string]int{AccessPortName: 8000},
114-
AccessPortName,
106+
return e2e.NewInstrumentedRunnable(env, name, map[string]int{AccessPortName: 8000}, AccessPortName).Init(
115107
e2e.StartOptions{
116108
Image: o.image,
117109
Command: e2e.NewCommand("-jar", "DynamoDBLocal.jar", "-inMemory", "-sharedDb"),
@@ -127,11 +119,7 @@ func NewBigtable(env e2e.Environment, name string, opts ...Option) *e2e.Instrume
127119
opt(&o)
128120
}
129121

130-
return e2e.NewInstrumentedRunnable(
131-
env,
132-
name,
133-
nil,
134-
AccessPortName,
122+
return e2e.NewInstrumentedRunnable(env, name, nil, AccessPortName).Init(
135123
e2e.StartOptions{
136124
Image: o.image,
137125
},
@@ -144,11 +132,7 @@ func NewCassandra(env e2e.Environment, name string, opts ...Option) *e2e.Instrum
144132
opt(&o)
145133
}
146134

147-
return e2e.NewInstrumentedRunnable(
148-
env,
149-
name,
150-
map[string]int{AccessPortName: 9042},
151-
AccessPortName,
135+
return e2e.NewInstrumentedRunnable(env, name, map[string]int{AccessPortName: 9042}, AccessPortName).Init(
152136
e2e.StartOptions{
153137
Image: o.image,
154138
// Readiness probe inspired from https://github.com/kubernetes/examples/blob/b86c9d50be45eaf5ce74dee7159ce38b0e149d38/cassandra/image/files/ready-probe.sh
@@ -163,11 +147,7 @@ func NewSwiftStorage(env e2e.Environment, name string, opts ...Option) *e2e.Inst
163147
opt(&o)
164148
}
165149

166-
return e2e.NewInstrumentedRunnable(
167-
env,
168-
name,
169-
map[string]int{AccessPortName: 8080},
170-
AccessPortName,
150+
return e2e.NewInstrumentedRunnable(env, name, map[string]int{AccessPortName: 8080}, AccessPortName).Init(
171151
e2e.StartOptions{
172152
Image: o.image,
173153
Readiness: e2e.NewHTTPReadinessProbe(AccessPortName, "/", 404, 404),
@@ -181,9 +161,7 @@ func NewMemcached(env e2e.Environment, name string, opts ...Option) e2e.Runnable
181161
opt(&o)
182162
}
183163

184-
return env.Runnable(
185-
name,
186-
map[string]int{AccessPortName: 11211},
164+
return env.Runnable(name).WithPorts(map[string]int{AccessPortName: 11211}).Init(
187165
e2e.StartOptions{
188166
Image: o.image,
189167
Readiness: e2e.NewTCPReadinessProbe(AccessPortName),
@@ -197,14 +175,7 @@ func NewETCD(env e2e.Environment, name string, opts ...Option) *e2e.Instrumented
197175
opt(&o)
198176
}
199177

200-
return e2e.NewInstrumentedRunnable(
201-
env,
202-
name,
203-
map[string]int{
204-
AccessPortName: 2379,
205-
"metrics": 9000,
206-
},
207-
"metrics",
178+
return e2e.NewInstrumentedRunnable(env, name, map[string]int{AccessPortName: 2379, "metrics": 9000}, "metrics").Init(
208179
e2e.StartOptions{
209180
Image: o.image,
210181
Command: e2e.NewCommand("/usr/local/bin/etcd", "--listen-client-urls=http://0.0.0.0:2379", "--advertise-client-urls=http://0.0.0.0:2379", "--listen-metrics-urls=http://0.0.0.0:9000", "--log-level=error"),

db/prometheus.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func NewPrometheus(env e2e.Environment, name string, opts ...Option) *Prometheus
2626

2727
ports := map[string]int{"http": 9090}
2828

29-
f := e2e.NewFutureInstrumentedRunnable(env, name, ports, "http")
29+
f := e2e.NewInstrumentedRunnable(env, name, ports, "http")
3030
config := fmt.Sprintf(`
3131
global:
3232
external_labels:

db/thanos.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func NewThanosQuerier(env e2e.Environment, name string, endpointsAddresses []str
3838
args = e2e.MergeFlagsWithoutRemovingEmpty(args, o.flagOverride)
3939
}
4040

41-
return e2e.NewInstrumentedRunnable(env, name, ports, "http", e2e.StartOptions{
41+
return e2e.NewInstrumentedRunnable(env, name, ports, "http").Init(e2e.StartOptions{
4242
Image: o.image,
4343
Command: e2e.NewCommand("query", e2e.BuildKingpinArgs(args)...),
4444
Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200),
@@ -68,7 +68,7 @@ func NewThanosSidecar(env e2e.Environment, name string, prom e2e.Linkable, opts
6868
args = e2e.MergeFlagsWithoutRemovingEmpty(args, o.flagOverride)
6969
}
7070

71-
return e2e.NewInstrumentedRunnable(env, name, ports, "http", e2e.StartOptions{
71+
return e2e.NewInstrumentedRunnable(env, name, ports, "http").Init(e2e.StartOptions{
7272
Image: o.image,
7373
Command: e2e.NewCommand("sidecar", e2e.BuildKingpinArgs(args)...),
7474
Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200),
@@ -87,7 +87,7 @@ func NewThanosStore(env e2e.Environment, name string, bktConfigYaml []byte, opts
8787
"grpc": 9091,
8888
}
8989

90-
f := e2e.NewFutureInstrumentedRunnable(env, name, ports, "http")
90+
f := e2e.NewInstrumentedRunnable(env, name, ports, "http")
9191
args := map[string]string{
9292
"--debug.name": name,
9393
"--grpc-address": fmt.Sprintf(":%d", ports["grpc"]),

env.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,31 @@ func WithVerbose() EnvironmentOption {
4242

4343
// Environment defines how to run Runnable in isolated area e.g via docker in isolated docker network.
4444
type Environment interface {
45+
// SharedDir returns host directory that will be shared with all runnables.
4546
SharedDir() string
46-
// Runnable returns instance of runnable which can be started and stopped within this environment.
47-
Runnable(name string, Ports map[string]int, opts StartOptions) Runnable
48-
// FutureRunnable returns instance of runnable which can be started and stopped within this environment.
49-
FutureRunnable(name string, Ports map[string]int) FutureRunnable
50-
// Close shutdowns isolated environment and cleans it's resources.
47+
// Runnable returns runnable builder which can build runnables that can be started and stopped within this environment.
48+
Runnable(name string) RunnableBuilder
49+
// AddListener registers given listener to be notified on environment runnable changes.
50+
AddListener(listener EnvironmentListener)
51+
// Close shutdowns isolated environment and cleans its resources.
5152
Close()
5253
}
5354

55+
type EnvironmentListener interface {
56+
OnRunnableChange(started []Runnable) error
57+
}
58+
5459
type StartOptions struct {
5560
Image string
5661
EnvVars map[string]string
5762
User string
5863
Command Command
5964
Readiness ReadinessProbe
60-
// WaitReadyBackoff represents backoff used for WaitReady.
65+
// WaitReadyBackofff represents backoff used for WaitReady.
6166
WaitReadyBackoff *backoff.Config
67+
Volumes []string
68+
UserNs string
69+
Privileged bool
6270
}
6371

6472
// Linkable is the entity that one can use to link runnable to other runnables before started.
@@ -84,8 +92,24 @@ type FutureRunnable interface {
8492
Init(opts StartOptions) Runnable
8593
}
8694

95+
type RunnableBuilder interface {
96+
WithPorts(map[string]int) RunnableBuilder
97+
WithConcreteType(r Runnable) RunnableBuilder
98+
99+
// Future returns future runnable
100+
Future() FutureRunnable
101+
// Init returns runnable.
102+
Init(opts StartOptions) Runnable
103+
}
104+
105+
type identificable interface {
106+
id() uintptr
107+
}
108+
87109
// Runnable is the entity that environment returns to manage single instance.
88110
type Runnable interface {
111+
identificable
112+
89113
Linkable
90114

91115
// IsRunning returns if runnable was started.

0 commit comments

Comments
 (0)