kubernetes-health 2.2.0 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
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