Skip to content

Commit 3d13dd9

Browse files
authored
Add prometheus reporting for replicas scaled (#1)
* Add prometheus reporting for replicas scaled * Bump rake version to address a CVE
1 parent a518e9a commit 3d13dd9

File tree

8 files changed

+162
-12
lines changed

8 files changed

+162
-12
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
/pkg/
77
/spec/reports/
88
/tmp/
9-
Gemfile.lock
109
.env
1110
scaltainer.yml
1211
scaltainer.yml.state

Gemfile.lock

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
PATH
2+
remote: .
3+
specs:
4+
scaltainer (0.3.0)
5+
docker-api
6+
dotenv
7+
excon (>= 0.47.0)
8+
kubeclient
9+
prometheus-client
10+
11+
GEM
12+
remote: https://rubygems.org/
13+
specs:
14+
addressable (2.7.0)
15+
public_suffix (>= 2.0.2, < 5.0)
16+
coderay (1.1.1)
17+
coveralls (0.8.21)
18+
json (>= 1.8, < 3)
19+
simplecov (~> 0.14.1)
20+
term-ansicolor (~> 1.3)
21+
thor (~> 0.19.4)
22+
tins (~> 1.6)
23+
diff-lcs (1.3)
24+
docile (1.1.5)
25+
docker-api (1.34.2)
26+
excon (>= 0.47.0)
27+
multi_json
28+
domain_name (0.5.20190701)
29+
unf (>= 0.0.5, < 1.0.0)
30+
dotenv (2.7.5)
31+
excon (0.73.0)
32+
ffi (1.12.2)
33+
ffi-compiler (1.0.1)
34+
ffi (>= 1.0.0)
35+
rake
36+
http (4.4.1)
37+
addressable (~> 2.3)
38+
http-cookie (~> 1.0)
39+
http-form_data (~> 2.2)
40+
http-parser (~> 1.2.0)
41+
http-accept (1.7.0)
42+
http-cookie (1.0.3)
43+
domain_name (~> 0.5)
44+
http-form_data (2.3.0)
45+
http-parser (1.2.1)
46+
ffi-compiler (>= 1.0, < 2.0)
47+
json (2.1.0)
48+
kubeclient (4.6.0)
49+
http (>= 3.0, < 5.0)
50+
recursive-open-struct (~> 1.0, >= 1.0.4)
51+
rest-client (~> 2.0)
52+
mime-types (3.3.1)
53+
mime-types-data (~> 3.2015)
54+
mime-types-data (3.2020.0425)
55+
multi_json (1.14.1)
56+
netrc (0.11.0)
57+
prometheus-client (2.0.0)
58+
public_suffix (4.0.4)
59+
rake (13.0.1)
60+
recursive-open-struct (1.1.1)
61+
rest-client (2.1.0)
62+
http-accept (>= 1.7.0, < 2.0)
63+
http-cookie (>= 1.0.2, < 2.0)
64+
mime-types (>= 1.16, < 4.0)
65+
netrc (~> 0.8)
66+
rspec (3.6.0)
67+
rspec-core (~> 3.6.0)
68+
rspec-expectations (~> 3.6.0)
69+
rspec-mocks (~> 3.6.0)
70+
rspec-core (3.6.0)
71+
rspec-support (~> 3.6.0)
72+
rspec-expectations (3.6.0)
73+
diff-lcs (>= 1.2.0, < 2.0)
74+
rspec-support (~> 3.6.0)
75+
rspec-mocks (3.6.0)
76+
diff-lcs (>= 1.2.0, < 2.0)
77+
rspec-support (~> 3.6.0)
78+
rspec-support (3.6.0)
79+
simplecov (0.14.1)
80+
docile (~> 1.1.0)
81+
json (>= 1.8, < 3)
82+
simplecov-html (~> 0.10.0)
83+
simplecov-html (0.10.0)
84+
term-ansicolor (1.6.0)
85+
tins (~> 1.0)
86+
thor (0.19.4)
87+
tins (1.13.2)
88+
unf (0.1.4)
89+
unf_ext
90+
unf_ext (0.0.7.7)
91+
92+
PLATFORMS
93+
ruby
94+
95+
DEPENDENCIES
96+
bundler (~> 1.15)
97+
coderay (~> 1.1)
98+
coveralls (~> 0.8)
99+
rake (>= 12.3.3)
100+
rspec (~> 3.5)
101+
scaltainer!
102+
103+
BUNDLED WITH
104+
1.17.3

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ specify the wait time between repetitions using the `-w` parameter in seconds:
5555

5656
This will repeatedly call scaltainer every 60 seconds, sleeping in-between.
5757

58+
If you would like to monitor the changes in scaling out and in. You can install
59+
Prometheus and add a configuration parameter pointing to its Push Gateway:
60+
61+
scaltainer -g prometheus-pushgateway.monitoring.svc.cluster.local:9091
62+
63+
Where `prometheus-pushgateway.monitoring.svc.cluster.local:9091` is the address
64+
of the push gateway. For Kubernetes environments the above denotes the gateway service
65+
name (`prometheus-pushgateway`), where it is installed in the namespace called
66+
`monitoring`. Scaltainer will report the following metrics to Prometheus:
67+
68+
- `rayyan_controller_replicas`: number of replicas scaled (or untouched thereof).
69+
This is labeled by the namespace and controller name, both matching the scaltainer
70+
configuration file.
71+
- `rayyan_scaltainer_ticks`: iterations scaltainer has performed (if `-w` is used)
72+
5873
## Configuration
5974

6075
### Environment variables
@@ -121,7 +136,7 @@ The configuration file (determined by `-f FILE` command line parameter) should b
121136

122137
# to get worker metrics
123138
endpoint: https://your-app.com/hirefire/$HIREFIRE_TOKEN/info
124-
# optional docker swarm stack name or kubernetes namespace
139+
# optional docker swarm stack name or kubernetes namespace (useful if having push gateway)
125140
namespace: mynamespace
126141
# list of web services to monitor
127142
web_services:

exe/scaltainer

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
require 'scaltainer'
44

55
begin
6-
configfile, statefile, logger, wait, orchestrator = Scaltainer::Command.parse ARGV
7-
Scaltainer::Runner.new configfile, statefile, logger, wait, orchestrator
6+
configfile, statefile, logger, wait, orchestrator, pushgateway = Scaltainer::Command.parse ARGV
7+
Scaltainer::Runner.new configfile, statefile, logger, wait, orchestrator, pushgateway
88
rescue => e
99
$stderr.puts e.message
1010
$stderr.puts e.backtrace

lib/scaltainer/command.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
module Scaltainer
55
class Command
66
def self.parse(args)
7-
configfile, statefile, wait, orchestrator = 'scaltainer.yml', nil, 0, :swarm
7+
configfile, statefile, wait, orchestrator, pushgateway = 'scaltainer.yml', nil, 0, :swarm, nil
88
OptionParser.new do |opts|
99
opts.banner = "Usage: scaltainer [options]"
1010
opts.on("-f", "--conf-file FILE", "Specify configuration file (default: scaltainer.yml)") do |file|
@@ -19,6 +19,9 @@ def self.parse(args)
1919
opts.on("-o", "--orchestrator swarm:kubernetes", [:swarm, :kubernetes], "Specify orchestrator type (default: swarm)") do |o|
2020
orchestrator = o
2121
end
22+
opts.on("-g", "--prometheus-push-gateway ADDRESS", "Specify prometheus push gateway address in the form of host:port") do |gw|
23+
pushgateway = gw
24+
end
2225
opts.on("-v", "--version", "Show version and exit") do
2326
puts Scaltainer::VERSION
2427
exit 0
@@ -55,7 +58,7 @@ def self.parse(args)
5558
logger = Logger.new(STDOUT)
5659
logger.level = %w(debug info warn error fatal unknown).find_index((ENV['LOG_LEVEL'] || '').downcase) || 1
5760

58-
return configfile, statefile, logger, wait, orchestrator
61+
return configfile, statefile, logger, wait, orchestrator, pushgateway
5962
end
6063

6164
private

lib/scaltainer/runner.rb

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
require "yaml"
2+
require 'prometheus/client'
3+
require 'prometheus/client/push'
24

35
module Scaltainer
46
class Runner
5-
def initialize(configfile, statefile, logger, wait, orchestrator)
7+
def initialize(configfile, statefile, logger, wait, orchestrator, pushgateway)
68
@orchestrator = orchestrator
79
@logger = logger
810
@default_service_config = {
@@ -19,18 +21,20 @@ def initialize(configfile, statefile, logger, wait, orchestrator)
1921
endpoint = config["endpoint"]
2022
service_type_web = ServiceTypeWeb.new(endpoint)
2123
service_type_worker = ServiceTypeWorker.new(endpoint)
24+
register_pushgateway(pushgateway) if pushgateway
25+
namespace = config["namespace"] || config["stack_name"]
2226
loop do
23-
run config, state, service_type_web, service_type_worker
27+
run config, state, service_type_web, service_type_worker, namespace
2428
save_state statefile, state
29+
sync_pushgateway(namespace, state) if pushgateway
2530
sleep wait
2631
break if wait == 0
2732
end
2833
end
2934

3035
private
3136

32-
def run(config, state, service_type_web, service_type_worker)
33-
namespace = config["namespace"] || config["stack_name"]
37+
def run(config, state, service_type_web, service_type_worker, namespace)
3438
iterate_services config["web_services"], namespace, service_type_web, state
3539
iterate_services config["worker_services"], namespace, service_type_worker, state
3640
end
@@ -82,9 +86,11 @@ def process_service(service_name, config, state, namespace, type, metrics)
8286
adjusted_replicas = type.adjust_desired_replicas(desired_replicas, config)
8387
@logger.debug "Desired number of replicas for #{service.type} #{service.name} is adjusted to #{adjusted_replicas}"
8488
replica_diff = adjusted_replicas - current_replicas
89+
state["replicas"] = current_replicas
8590
type.yield_to_scale(replica_diff, config, state, metric,
8691
service.name, @logger) do
8792
scale_out service, current_replicas, adjusted_replicas
93+
state["replicas"] = adjusted_replicas
8894
end
8995
end
9096

@@ -113,5 +119,27 @@ def scale_out(service, current_replicas, desired_replicas)
113119
end
114120
end
115121

122+
def register_pushgateway(pushgateway)
123+
@registry = Prometheus::Client.registry
124+
@replicas_gauge = @registry.gauge(:rayyan_controller_replicas, docstring: 'Rayyan replicas', labels: [:controller, :namespace])
125+
@ticks_counter = @registry.counter(:rayyan_scaltainer_ticks, docstring: 'Rayyan Scaltainer ticks', labels: [:namespace])
126+
127+
@pushgateway = Prometheus::Client::Push.new("scaltainer", "scaltainer", "http://#{pushgateway}")
128+
end
129+
130+
def sync_pushgateway(namespace, state)
131+
@logger.debug("Now syncing state #{state} in namespace #{namespace}")
132+
state.each do |service, state|
133+
@replicas_gauge.set(state["replicas"], labels: {namespace: namespace, controller: service}) if state["replicas"]
134+
end
135+
@ticks_counter.increment(labels: {namespace: namespace})
136+
begin
137+
@pushgateway.add(@registry)
138+
rescue => e
139+
@logger.warn "[#{e.class}] Error pushing metrics to the configured Prometheus Push Gateway: #{e.message}"
140+
end
141+
@logger.info "Pushed metrics successfully to the configured Prometheus Push Gateway"
142+
end
143+
116144
end # class
117145
end # module

lib/scaltainer/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module Scaltainer
2-
VERSION = "0.2.0"
2+
VERSION = "0.3.0"
33
end

scaltainer.gemspec

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
2323
spec.require_paths = ["lib"]
2424

2525
spec.add_development_dependency "bundler", "~> 1.15"
26-
spec.add_development_dependency "rake", "~> 10.0"
26+
spec.add_development_dependency "rake", ">= 12.3.3"
2727
spec.add_development_dependency 'rspec', '~> 3.5'
2828
spec.add_development_dependency 'coderay', '~> 1.1'
2929
spec.add_development_dependency 'coveralls', '~> 0.8'
@@ -32,4 +32,5 @@ Gem::Specification.new do |spec|
3232
spec.add_runtime_dependency "docker-api"
3333
spec.add_runtime_dependency "kubeclient"
3434
spec.add_runtime_dependency "dotenv"
35+
spec.add_runtime_dependency "prometheus-client"
3536
end

0 commit comments

Comments
 (0)