kubernetes-health 2.2.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +60 -28
- data/Rakefile +30 -4
- data/kubernetes-health.gemspec +2 -0
- data/lib/kubernetes/health/config.rb +11 -2
- data/lib/kubernetes/health/rack_on_migrate.rb +1 -1
- data/lib/kubernetes/health/version.rb +1 -1
- data/lib/puma/kubernetes/app.rb +39 -0
- data/lib/puma/kubernetes/dsl.rb +7 -0
- data/lib/puma/kubernetes/parser.rb +45 -0
- data/lib/puma/plugin/kubernetes.rb +34 -0
- metadata +35 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7237a6079afe249dc00d6f75a99b30c6ed594cc090f25d43b9677a63aee28f3
|
4
|
+
data.tar.gz: ec385cbc59cb999647c85d5ac1813585a55ffa283b9922f32dc2eceb55313d7d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be3c95a034f79708968f24808656961f611819e6d559d6f24549fb497e99224d94369787911467886ca1f0ae2b5d2040ec42acd8b6b735d8b80bad5c1a790b02
|
7
|
+
data.tar.gz: 85cbe5b9902df2cbfa154fb642f3878fcd203ad1e6a3da05adb78c4f50974ebbc3844fe6018e5aae8115f281c0dbc92ccee5e134fd332096e49756ed7486c503
|
data/README.md
CHANGED
@@ -3,8 +3,10 @@
|
|
3
3
|
This gem allows kubernetes monitoring your app while it is running migrates and after it started.
|
4
4
|
|
5
5
|
# Features
|
6
|
-
- add routes `/_readiness
|
7
|
-
-
|
6
|
+
- add routes `/_readiness`, `/_liveness` on rails stack.
|
7
|
+
- add routes `/_readiness`, `/_liveness` and `/_metrics` as a puma plugin.
|
8
|
+
- metrics are prometheus compatible (code copied from `puma-metrics` gem).
|
9
|
+
- allow custom checks for `/_readiness` and `/_liveness`.
|
8
10
|
- add routes `/_readiness` and `/_liveness` while `rake db:migrate` runs. (optional)
|
9
11
|
- add support to avoid parallel running of `rake db:migrate` while keep kubernetes waiting. (optional)
|
10
12
|
|
@@ -13,7 +15,49 @@ This gem allows kubernetes monitoring your app while it is running migrates and
|
|
13
15
|
Add this line to your application's Gemfile:
|
14
16
|
|
15
17
|
```ruby
|
16
|
-
gem 'kubernetes-health', '~>
|
18
|
+
gem 'kubernetes-health', '~> 3.0'
|
19
|
+
```
|
20
|
+
|
21
|
+
## Enabling puma plugin
|
22
|
+
|
23
|
+
add in `config/puma.rb`
|
24
|
+
```
|
25
|
+
plugin 'kubernetes'
|
26
|
+
kubernetes_url 'tcp://0.0.0.0:9393'
|
27
|
+
```
|
28
|
+
|
29
|
+
In Kubernetes you need to configure your deployment `readinessProbe` and `livenessProbe` like this:
|
30
|
+
|
31
|
+
```
|
32
|
+
livenessProbe:
|
33
|
+
httpGet:
|
34
|
+
path: /_liveness
|
35
|
+
port: 9393
|
36
|
+
initialDelaySeconds: 30
|
37
|
+
timeoutSeconds: 5
|
38
|
+
failureThreshold: 3
|
39
|
+
successThreshold: 1
|
40
|
+
readinessProbe:
|
41
|
+
httpGet:
|
42
|
+
path: /_readiness
|
43
|
+
port: 9393
|
44
|
+
initialDelaySeconds: 30
|
45
|
+
timeoutSeconds: 5
|
46
|
+
failureThreshold: 3
|
47
|
+
successThreshold: 1
|
48
|
+
```
|
49
|
+
|
50
|
+
Setting `failureThreshold` is import to avoid problems when app finish migrates and is starting the web process.
|
51
|
+
|
52
|
+
## Enabling prometheus metrics
|
53
|
+
|
54
|
+
```
|
55
|
+
template:
|
56
|
+
metadata:
|
57
|
+
annotations:
|
58
|
+
prometheus.io/path: '/_metrics'
|
59
|
+
prometheus.io/port: '9393'
|
60
|
+
prometheus.io/scrape: 'true'
|
17
61
|
```
|
18
62
|
|
19
63
|
## Enabling monitoring while `rake db:migrate` runs
|
@@ -29,27 +73,13 @@ or add in your `application.rb`.
|
|
29
73
|
Kubernetes::Health::Config.enable_rack_on_migrate = true
|
30
74
|
```
|
31
75
|
|
32
|
-
In Kubernetes you need to configure your deployment `readinessProbe` like this:
|
33
|
-
|
34
|
-
```
|
35
|
-
livenessProbe:
|
36
|
-
httpGet:
|
37
|
-
path: /_liveness
|
38
|
-
port: 80
|
39
|
-
initialDelaySeconds: 10
|
40
|
-
timeoutSeconds: 5
|
41
|
-
readinessProbe:
|
42
|
-
httpGet:
|
43
|
-
path: /_readiness
|
44
|
-
port: 80
|
45
|
-
initialDelaySeconds: 10
|
46
|
-
timeoutSeconds: 5
|
47
|
-
```
|
48
|
-
|
49
76
|
### How `rake db:migrate` monitoring works
|
50
77
|
It will run a RACK server for `/_readiness` and `/_liveness` routes while `rake db:migrate` is running.
|
51
78
|
|
52
|
-
##
|
79
|
+
## Avoiding migrations running in parallel and making kubernetes happy.
|
80
|
+
Rails already avoid migrations running in parallel, but it raise exceptions. This gem will just wait for other migrations without exit.
|
81
|
+
If you enable `rack_on_migrate` together with this, kubernetes will just wait, avoiding erros.
|
82
|
+
|
53
83
|
|
54
84
|
Add `KUBERNETES_HEALTH_ENABLE_LOCK_ON_MIGRATE=true` environment variable.
|
55
85
|
|
@@ -76,22 +106,24 @@ Kubernetes::Health::Config.unlock = lambda {
|
|
76
106
|
|
77
107
|
It only works for routes in rails stack, they are not executed while `rake db:migrate` runs.
|
78
108
|
|
79
|
-
|
109
|
+
I prefer do nothing else on `liveness` to avoid unnecessary `CrashLoopBackOff` status. `params` is optional.
|
80
110
|
|
81
111
|
```
|
82
|
-
Kubernetes::Health::Config.
|
83
|
-
|
112
|
+
Kubernetes::Health::Config.live_if = lambda {
|
113
|
+
true
|
84
114
|
}
|
85
|
-
```
|
86
115
|
|
87
116
|
```
|
88
|
-
|
89
|
-
|
117
|
+
Ex. Check if PostgreSQL is reachable on `readiness`. `params` is optional.
|
118
|
+
```
|
119
|
+
Kubernetes::Health::Config.ready_if = lambda { |params|
|
120
|
+
ActiveRecord::Base.connection.execute("SELECT 1").cmd_tuples != 1
|
90
121
|
}
|
91
122
|
```
|
92
123
|
|
93
124
|
## Customizing routes
|
94
125
|
```
|
95
126
|
Kubernetes::Health::Config.route_liveness = '/liveness'
|
96
|
-
Kubernetes::Health::Config.route_readiness = '/readiness
|
127
|
+
Kubernetes::Health::Config.route_readiness = '/readiness'
|
128
|
+
Kubernetes::Health::Config.route_metrics = '/metrics'
|
97
129
|
```
|
data/Rakefile
CHANGED
@@ -1,6 +1,32 @@
|
|
1
|
-
|
2
|
-
require
|
1
|
+
task :default => :spec
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rake/testtask'
|
3
4
|
|
4
|
-
|
5
|
+
Rake::TestTask.new(:test) do |t|
|
6
|
+
t.libs << 'test'
|
7
|
+
t.libs << 'lib'
|
8
|
+
t.test_files = FileList['test/**/test_*.rb']
|
9
|
+
end
|
5
10
|
|
6
|
-
task :
|
11
|
+
task :server do
|
12
|
+
require 'puma'
|
13
|
+
require 'puma/configuration'
|
14
|
+
require 'puma/events'
|
15
|
+
require 'puma/plugin/kubernetes.rb'
|
16
|
+
|
17
|
+
configuration = Puma::Configuration.new do |config|
|
18
|
+
config.bind 'tcp://127.0.0.1:0'
|
19
|
+
config.kubernetes_url 'tcp://127.0.0.1:9494'
|
20
|
+
config.plugin 'kubernetes'
|
21
|
+
config.workers 1
|
22
|
+
config.app do |_env|
|
23
|
+
[200, {}, ['hello world']]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
events = Puma::Events.new STDOUT, STDERR
|
28
|
+
launcher = Puma::Launcher.new(configuration, events: events)
|
29
|
+
launcher.run
|
30
|
+
end
|
31
|
+
|
32
|
+
task default: :test
|
data/kubernetes-health.gemspec
CHANGED
@@ -3,10 +3,11 @@ module Kubernetes
|
|
3
3
|
class Config
|
4
4
|
@@live_if = lambda { true }
|
5
5
|
@@ready_if = lambda { true }
|
6
|
-
@@enable_lock_on_migrate =
|
7
|
-
@@enable_rack_on_migrate =
|
6
|
+
@@enable_lock_on_migrate = [true, 'true'].include? ENV['KUBERNETES_HEALTH_ENABLE_LOCK_ON_MIGRATE']
|
7
|
+
@@enable_rack_on_migrate = [true, 'true'].include? ENV['KUBERNETES_HEALTH_ENABLE_RACK_ON_MIGRATE']
|
8
8
|
@@route_liveness = '/_liveness'
|
9
9
|
@@route_readiness = '/_readiness'
|
10
|
+
@@route_metrics = '/_metrics'
|
10
11
|
@@lock_or_wait = lambda { ActiveRecord::Base.connection.execute 'select pg_advisory_lock(123456789123456789);' }
|
11
12
|
@@unlock = lambda { ActiveRecord::Base.connection.execute 'select pg_advisory_unlock(123456789123456789);' }
|
12
13
|
|
@@ -42,6 +43,14 @@ module Kubernetes
|
|
42
43
|
@@enable_rack_on_migrate = value
|
43
44
|
end
|
44
45
|
|
46
|
+
def self.route_metrics
|
47
|
+
@@route_metrics
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.route_metrics=(value)
|
51
|
+
@@route_metrics = value
|
52
|
+
end
|
53
|
+
|
45
54
|
def self.route_liveness
|
46
55
|
@@route_liveness
|
47
56
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "kubernetes/health/config"
|
2
|
+
require 'prometheus/client/formats/text'
|
3
|
+
require 'puma/kubernetes/parser'
|
4
|
+
require 'rack'
|
5
|
+
|
6
|
+
module Puma
|
7
|
+
module Kubernetes
|
8
|
+
class App
|
9
|
+
def initialize(launcher)
|
10
|
+
@launcher = launcher
|
11
|
+
clustered = (@launcher.options[:workers] || 0) > 0
|
12
|
+
@parser = Parser.new clustered
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(_env)
|
16
|
+
req = ::Rack::Request.new(_env)
|
17
|
+
type = {}
|
18
|
+
content = []
|
19
|
+
case req.path_info
|
20
|
+
when ::Kubernetes::Health::Config.route_readiness
|
21
|
+
i_am_live = ::Kubernetes::Health::Config.live_if.arity == 0 ? ::Kubernetes::Health::Config.live_if.call : ::Kubernetes::Health::Config.live_if.call(req.params)
|
22
|
+
http_code = i_am_live ? 200 : 503
|
23
|
+
when ::Kubernetes::Health::Config.route_liveness
|
24
|
+
i_am_ready = ::Kubernetes::Health::Config.ready_if.arity == 0 ? ::Kubernetes::Health::Config.ready_if.call : ::Kubernetes::Health::Config.ready_if.call(req.params)
|
25
|
+
http_code = i_am_ready ? 200 : 503
|
26
|
+
when ::Kubernetes::Health::Config.route_metrics
|
27
|
+
http_code = 200
|
28
|
+
@parser.parse JSON.parse(@launcher.stats)
|
29
|
+
type = { 'Content-Type' => 'text/plain' }
|
30
|
+
content = [Prometheus::Client::Formats::Text.marshal(Prometheus::Client.registry)]
|
31
|
+
else
|
32
|
+
http_code = 404
|
33
|
+
end
|
34
|
+
Rails.logger.info "Kubernetes Health: Rack on Migrate - Request: Path: #{req.path_info} / Params: #{req.params} / HTTP Code: #{http_code}" rescue nil
|
35
|
+
[http_code, type, content]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'prometheus/client'
|
2
|
+
|
3
|
+
module Puma
|
4
|
+
module Kubernetes
|
5
|
+
class Parser
|
6
|
+
def initialize(clustered = false)
|
7
|
+
register_default_kubernetes
|
8
|
+
register_clustered_kubernetes if clustered
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse(stats, labels = {})
|
12
|
+
stats.each do |key, value|
|
13
|
+
value.each { |s| parse(s, labels.merge(index: s['index'])) } if key == 'worker_status'
|
14
|
+
parse(value, labels) if key == 'last_status'
|
15
|
+
update_metric(key, value, labels)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def register_clustered_kubernetes
|
22
|
+
registry.gauge(:puma_booted_workers, 'Number of booted workers').set({}, 1)
|
23
|
+
registry.gauge(:puma_old_workers, 'Number of old workers').set({}, 0)
|
24
|
+
end
|
25
|
+
|
26
|
+
def register_default_kubernetes
|
27
|
+
registry.gauge(:puma_backlog, 'Number of established but unaccepted connections in the backlog', index: 0)
|
28
|
+
registry.gauge(:puma_running, 'Number of running worker threads', index: 0)
|
29
|
+
registry.gauge(:puma_pool_capacity, 'Number of allocatable worker threads', index: 0)
|
30
|
+
registry.gauge(:puma_max_threads, 'Maximum number of worker threads', index: 0)
|
31
|
+
registry.gauge(:puma_workers, 'Number of configured workers').set({}, 1)
|
32
|
+
end
|
33
|
+
|
34
|
+
def registry
|
35
|
+
Prometheus::Client.registry
|
36
|
+
end
|
37
|
+
|
38
|
+
def update_metric(key, value, labels)
|
39
|
+
return if registry.get("puma_#{key}").nil?
|
40
|
+
|
41
|
+
registry.get("puma_#{key}").set(labels, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'puma/kubernetes/dsl'
|
2
|
+
|
3
|
+
Puma::Plugin.create do
|
4
|
+
# rubocop:disable Kubernetes/MethodLength, Kubernetes/AbcSize
|
5
|
+
def start(launcher)
|
6
|
+
str = launcher.options[:kubernetes_url] || 'tcp://0.0.0.0:9393'
|
7
|
+
|
8
|
+
require 'puma/kubernetes/app'
|
9
|
+
|
10
|
+
app = Puma::Kubernetes::App.new launcher
|
11
|
+
uri = URI.parse str
|
12
|
+
|
13
|
+
kubernetes = Puma::Server.new app, launcher.events
|
14
|
+
kubernetes.min_threads = 0
|
15
|
+
kubernetes.max_threads = 1
|
16
|
+
|
17
|
+
case uri.scheme
|
18
|
+
when 'tcp'
|
19
|
+
launcher.events.log "* Starting kubernetes-healh server on #{str}"
|
20
|
+
kubernetes.add_tcp_listener uri.host, uri.port
|
21
|
+
else
|
22
|
+
launcher.events.error "Invalid control URI: #{str}"
|
23
|
+
end
|
24
|
+
|
25
|
+
launcher.events.register(:state) do |state|
|
26
|
+
if %i[halt restart stop].include?(state)
|
27
|
+
kubernetes.stop(true) unless kubernetes.shutting_down?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
kubernetes.run
|
32
|
+
end
|
33
|
+
# rubocop:enable Kubernetes/MethodLength, Kubernetes/AbcSize
|
34
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kubernetes-health
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wagner Caixeta
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: prometheus-client
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.8'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.8'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: puma
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
83
111
|
description: "\n This gem allows kubernetes monitoring your app while it is running
|
84
112
|
migrates and after it started.\n Features:\n * add routes /_readiness and
|
85
113
|
/_liveness on rails stack by default;\n * allow custom checks for /_readiness
|
@@ -110,6 +138,10 @@ files:
|
|
110
138
|
- lib/kubernetes/health/rack_on_migrate.rb
|
111
139
|
- lib/kubernetes/health/railtie.rb
|
112
140
|
- lib/kubernetes/health/version.rb
|
141
|
+
- lib/puma/kubernetes/app.rb
|
142
|
+
- lib/puma/kubernetes/dsl.rb
|
143
|
+
- lib/puma/kubernetes/parser.rb
|
144
|
+
- lib/puma/plugin/kubernetes.rb
|
113
145
|
homepage: https://github.com/platbr/kubernetes-health
|
114
146
|
licenses: []
|
115
147
|
metadata: {}
|
@@ -128,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
160
|
- !ruby/object:Gem::Version
|
129
161
|
version: '0'
|
130
162
|
requirements: []
|
131
|
-
rubygems_version: 3.0.
|
163
|
+
rubygems_version: 3.0.3
|
132
164
|
signing_key:
|
133
165
|
specification_version: 4
|
134
166
|
summary: This gem allows kubernetes monitoring your app while it is running migrates
|