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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4425830e42d12960033f406ddb4e3da9d33e7d4f2836362cfad272b2aefa7aee
4
- data.tar.gz: 72ea97e57b9100f0e465abf1e1e17168a8706f8eeb85f9d14b3e4f5d5660d6ed
3
+ metadata.gz: e7237a6079afe249dc00d6f75a99b30c6ed594cc090f25d43b9677a63aee28f3
4
+ data.tar.gz: ec385cbc59cb999647c85d5ac1813585a55ffa283b9922f32dc2eceb55313d7d
5
5
  SHA512:
6
- metadata.gz: 779947240739615102d287539e8f9542c1e73c2af1c5cc4d2d11d2760c866b5b6669d4482a881518844d028be4e53e930549d80b41bbfb6af3136ea6207ad84f
7
- data.tar.gz: 16127f3a04957449a1c731ff2649e5b480b88486c1d2d94d572c80c162cfdd802e05c8db36a722b7435624d4b604d5d4deae151281702468182cc3a2b95390ed
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` and `/_liveness` on rails stack by default.
7
- - allow custom checks for `/_readiness` and `/_liveness` on rails stack.
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', '~> 2.1'
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
- ## Avoid `rake db:migrate` parallel running.
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
- Ex. Check if PostgreSQL is reachable. `params` is optional.
109
+ I prefer do nothing else on `liveness` to avoid unnecessary `CrashLoopBackOff` status. `params` is optional.
80
110
 
81
111
  ```
82
- Kubernetes::Health::Config.ready_if = lambda { |params|
83
- ActiveRecord::Base.connection.execute("SELECT 1").cmd_tuples != 1
112
+ Kubernetes::Health::Config.live_if = lambda {
113
+ true
84
114
  }
85
- ```
86
115
 
87
116
  ```
88
- Kubernetes::Health::Config.live_if = lambda { |params|
89
- ActiveRecord::Base.connection.execute("SELECT 1").cmd_tuples != 1
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
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ task :default => :spec
2
+ require 'bundler/gem_tasks'
3
+ require 'rake/testtask'
3
4
 
4
- RSpec::Core::RakeTask.new(:spec)
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 :default => :spec
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
@@ -31,4 +31,6 @@ Gem::Specification.new do |spec|
31
31
  spec.add_development_dependency "rspec", "~> 3.0"
32
32
  spec.add_dependency "rack"
33
33
  spec.add_dependency "rails"
34
+ spec.add_runtime_dependency 'prometheus-client', '~> 0.8'
35
+ spec.add_runtime_dependency 'puma', '~> 3.0'
34
36
  end
@@ -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 = ActiveRecord::Type::Boolean.new.cast(ENV['KUBERNETES_HEALTH_ENABLE_LOCK_ON_MIGRATE']) || false
7
- @@enable_rack_on_migrate = ActiveRecord::Type::Boolean.new.cast(ENV['KUBERNETES_HEALTH_ENABLE_RACK_ON_MIGRATE']) || false
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
@@ -2,7 +2,7 @@ module Kubernetes
2
2
  module Health
3
3
  class RackOnMigrate
4
4
  def call(env)
5
- req = Rack::Request.new(env)
5
+ req = ::Rack::Request.new(env)
6
6
  case req.path_info
7
7
  when Kubernetes::Health::Config.route_readiness
8
8
  http_code = 503
@@ -1,5 +1,5 @@
1
1
  module Kubernetes
2
2
  module Health
3
- VERSION = "2.2.0"
3
+ VERSION = "3.0.2"
4
4
  end
5
5
  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,7 @@
1
+ module Puma
2
+ class DSL
3
+ def kubernetes_url(url)
4
+ @options[:kubernetes_url] = url
5
+ end
6
+ end
7
+ 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: 2.2.0
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-04-24 00:00:00.000000000 Z
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.1
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