kuby-core 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/kuby-core.gemspec +7 -3
  4. data/lib/kuby.rb +9 -7
  5. data/lib/kuby/definition.rb +0 -8
  6. data/lib/kuby/docker/cli.rb +32 -0
  7. data/lib/kuby/docker/errors.rb +1 -0
  8. data/lib/kuby/docker/layer.rb +4 -4
  9. data/lib/kuby/docker/metadata.rb +11 -7
  10. data/lib/kuby/docker/package_phase.rb +2 -2
  11. data/lib/kuby/docker/spec.rb +11 -11
  12. data/lib/kuby/docker/timestamp_tag.rb +6 -3
  13. data/lib/kuby/environment.rb +6 -2
  14. data/lib/kuby/kubernetes.rb +0 -2
  15. data/lib/kuby/kubernetes/deploy_task.rb +0 -1
  16. data/lib/kuby/kubernetes/deployer.rb +7 -7
  17. data/lib/kuby/kubernetes/minikube_provider.rb +4 -0
  18. data/lib/kuby/kubernetes/provider.rb +5 -5
  19. data/lib/kuby/kubernetes/spec.rb +8 -8
  20. data/lib/kuby/plugin.rb +59 -0
  21. data/lib/kuby/plugins.rb +6 -0
  22. data/lib/kuby/plugins/nginx_ingress.rb +71 -0
  23. data/lib/kuby/plugins/rails_app.rb +18 -0
  24. data/lib/kuby/plugins/rails_app/asset_copy_task.rb +117 -0
  25. data/lib/kuby/plugins/rails_app/assets.rb +347 -0
  26. data/lib/kuby/plugins/rails_app/database.rb +75 -0
  27. data/lib/kuby/{kubernetes/plugins → plugins}/rails_app/generators/kuby.rb +0 -0
  28. data/lib/kuby/plugins/rails_app/mysql.rb +155 -0
  29. data/lib/kuby/plugins/rails_app/plugin.rb +398 -0
  30. data/lib/kuby/plugins/rails_app/postgres.rb +143 -0
  31. data/lib/kuby/plugins/rails_app/rewrite_db_config.rb +11 -0
  32. data/lib/kuby/plugins/rails_app/sqlite.rb +32 -0
  33. data/lib/kuby/{kubernetes/plugins → plugins}/rails_app/tasks.rake +10 -2
  34. data/lib/kuby/tasks.rb +28 -9
  35. data/lib/kuby/tasks/kuby.rake +1 -1
  36. data/lib/kuby/version.rb +1 -1
  37. data/spec/docker/timestamp_tag_spec.rb +11 -0
  38. data/spec/spec_helper.rb +102 -0
  39. metadata +50 -27
  40. data/lib/ext/krane/kubernetes_resource.rb +0 -16
  41. data/lib/kuby/kubernetes/plugin.rb +0 -55
  42. data/lib/kuby/kubernetes/plugins.rb +0 -8
  43. data/lib/kuby/kubernetes/plugins/nginx_ingress.rb +0 -73
  44. data/lib/kuby/kubernetes/plugins/rails_app.rb +0 -16
  45. data/lib/kuby/kubernetes/plugins/rails_app/database.rb +0 -79
  46. data/lib/kuby/kubernetes/plugins/rails_app/mysql.rb +0 -154
  47. data/lib/kuby/kubernetes/plugins/rails_app/plugin.rb +0 -379
  48. data/lib/kuby/kubernetes/plugins/rails_app/postgres.rb +0 -142
  49. data/lib/kuby/kubernetes/plugins/rails_app/rewrite_db_config.rb +0 -13
  50. data/lib/kuby/kubernetes/plugins/rails_app/sqlite.rb +0 -30
@@ -1,16 +0,0 @@
1
- require 'krane/kubernetes_resource'
2
-
3
- # See: https://github.com/Shopify/krane/pull/720
4
- module Krane
5
- class KubernetesResource
6
- class << self
7
- def class_for_kind(kind)
8
- if Krane.const_defined?(kind, false)
9
- Krane.const_get(kind, false)
10
- end
11
- rescue NameError
12
- nil
13
- end
14
- end
15
- end
16
- end
@@ -1,55 +0,0 @@
1
- module Kuby
2
- module Kubernetes
3
- class Plugin
4
- attr_reader :definition
5
-
6
- def initialize(definition)
7
- @definition = definition
8
- after_initialize
9
- end
10
-
11
- def configure(&block)
12
- # do nothing by default
13
- end
14
-
15
- def setup
16
- # do nothing by default
17
- end
18
-
19
- def resources
20
- []
21
- end
22
-
23
- # called after all plugins have been configured
24
- def after_configuration
25
- # do nothing by default
26
- end
27
-
28
- # called before any plugins have been setup
29
- def before_setup
30
- # do nothing by default
31
- end
32
-
33
- # called after all plugins have been setup
34
- def after_setup
35
- # do nothing by default
36
- end
37
-
38
- # called before deploying any resources
39
- def before_deploy(manifest)
40
- # do nothing by default
41
- end
42
-
43
- # called after deploying all resources
44
- def after_deploy(manifest)
45
- # do nothing by default
46
- end
47
-
48
- private
49
-
50
- def after_initialize
51
- # override this in derived classes
52
- end
53
- end
54
- end
55
- end
@@ -1,8 +0,0 @@
1
- module Kuby
2
- module Kubernetes
3
- module Plugins
4
- autoload :NginxIngress, 'kuby/kubernetes/plugins/nginx_ingress'
5
- autoload :RailsApp, 'kuby/kubernetes/plugins/rails_app'
6
- end
7
- end
8
- end
@@ -1,73 +0,0 @@
1
- require 'kube-dsl'
2
-
3
- module Kuby
4
- module Kubernetes
5
- module Plugins
6
- class NginxIngress < Plugin
7
- class Config
8
- extend ::KubeDSL::ValueFields
9
-
10
- value_fields :provider
11
- end
12
-
13
- VERSION = '0.27.1'.freeze
14
- DEFAULT_PROVIDER = 'cloud-generic'.freeze
15
- NAMESPACE = 'ingress-nginx'.freeze
16
- SERVICE_NAME = 'ingress-nginx'.freeze
17
-
18
- SETUP_RESOURCES = [
19
- "https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-#{VERSION}/deploy/static/mandatory.yaml",
20
- "https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-#{VERSION}/deploy/static/provider/%{provider}.yaml"
21
- ].freeze
22
-
23
- def configure(&block)
24
- @config.instance_eval(&block) if block
25
- end
26
-
27
- def setup
28
- Kuby.logger.info('Deploying nginx ingress resources')
29
-
30
- if already_deployed?
31
- Kuby.logger.info('Nginx ingress already deployed, skipping')
32
- return
33
- end
34
-
35
- SETUP_RESOURCES.each do |uri|
36
- uri = uri % { provider: @config.provider || DEFAULT_PROVIDER }
37
- kubernetes_cli.apply_uri(uri)
38
- end
39
-
40
- Kuby.logger.info('Nginx ingress resources deployed!')
41
- rescue => e
42
- Kuby.logger.fatal(e.message)
43
- raise
44
- end
45
-
46
- def namespace
47
- NAMESPACE
48
- end
49
-
50
- def service_name
51
- SERVICE_NAME
52
- end
53
-
54
- private
55
-
56
- def already_deployed?
57
- kubernetes_cli.get_object('Service', 'ingress-nginx', 'ingress-nginx')
58
- true
59
- rescue KubernetesCLI::GetResourceError
60
- return false
61
- end
62
-
63
- def after_initialize
64
- @config = Config.new
65
- end
66
-
67
- def kubernetes_cli
68
- definition.kubernetes.provider.kubernetes_cli
69
- end
70
- end
71
- end
72
- end
73
- end
@@ -1,16 +0,0 @@
1
- module Kuby
2
- module Kubernetes
3
- module Plugins
4
- module RailsApp
5
- autoload :Database, 'kuby/kubernetes/plugins/rails_app/database'
6
- autoload :MySQL, 'kuby/kubernetes/plugins/rails_app/mysql'
7
- autoload :Plugin, 'kuby/kubernetes/plugins/rails_app/plugin'
8
- autoload :Postgres, 'kuby/kubernetes/plugins/rails_app/postgres'
9
- autoload :RewriteDbConfig, 'kuby/kubernetes/plugins/rails_app/rewrite_db_config'
10
- autoload :Sqlite, 'kuby/kubernetes/plugins/rails_app/sqlite'
11
- end
12
- end
13
- end
14
- end
15
-
16
- load File.expand_path(File.join('rails_app', 'tasks.rake'), __dir__)
@@ -1,79 +0,0 @@
1
- require 'erb'
2
- require 'yaml'
3
-
4
- module Kuby
5
- module Kubernetes
6
- module Plugins
7
- module RailsApp
8
- class UnsupportedDatabaseError < StandardError; end
9
-
10
- class Database
11
- ADAPTER_MAP = {
12
- 'sqlite3' => Sqlite,
13
- 'mysql2' => MySQL,
14
- 'postgresql' => Postgres
15
- }.freeze
16
-
17
- def self.get(rails_app)
18
- if rails_app.manage_database?
19
- new(rails_app).database
20
- end
21
- end
22
-
23
- def self.get_adapter(adapter)
24
- ADAPTER_MAP.fetch(adapter) do
25
- raise UnsupportedDatabaseError, "Kuby does not support the '#{adapter}' "\
26
- 'database adapter'
27
- end
28
- end
29
-
30
- attr_reader :rails_app
31
-
32
- def initialize(rails_app)
33
- @rails_app = rails_app
34
- end
35
-
36
- def database
37
- @database ||= self.class
38
- .get_adapter(adapter)
39
- .new(rails_app, environment, db_configs)
40
- end
41
-
42
- private
43
-
44
- def adapter
45
- db_config['adapter']
46
- end
47
-
48
- def db_config
49
- @db_config ||= db_configs[environment]
50
- end
51
-
52
- def environment
53
- @environment ||= rails_app.definition.environment.name
54
- end
55
-
56
- def db_configs
57
- @db_configs ||= YAML.load(ERB.new(File.read(db_config_path)).result)
58
- end
59
-
60
- def db_config_path
61
- @db_config_path ||= begin
62
- db_config_paths.first or
63
- raise "Couldn't find database config at #{rails_app.root}"
64
- end
65
- end
66
-
67
- def db_config_paths
68
- @db_config_paths ||=
69
- Dir.glob(
70
- File.join(
71
- rails_app.root, 'config', 'database.{yml,erb,yml.erb,yaml,yaml.erb}'
72
- )
73
- )
74
- end
75
- end
76
- end
77
- end
78
- end
79
- end
@@ -1,154 +0,0 @@
1
- require 'kube-dsl'
2
- require 'kuby/kube-db'
3
-
4
- module Kuby
5
- module Kubernetes
6
- module Plugins
7
- module RailsApp
8
- class MySQL < Kuby::Kubernetes::Plugin
9
- ROLE = 'web'.freeze
10
-
11
- attr_reader :definition, :environment, :configs
12
-
13
- def initialize(definition, environment, configs)
14
- @definition = definition
15
- @environment = environment
16
- @configs = configs
17
-
18
- user(config['username'])
19
- password(config['password'])
20
- end
21
-
22
- def resources
23
- @resources ||= [secret, database]
24
- end
25
-
26
- def after_configuration
27
- definition.docker.package_phase.add(:mysql_dev)
28
- definition.docker.package_phase.add(:mysql_client)
29
- end
30
-
31
- def host
32
- # host is the same as the name thanks to k8s DNS
33
- @host ||= database.metadata.name
34
- end
35
-
36
- def rewritten_configs
37
- # deep dup
38
- @rewritten_configs ||= Marshal.load(Marshal.dump(configs)).tap do |new_configs|
39
- new_configs[environment]['host'] = host
40
- end
41
- end
42
-
43
- def user(user)
44
- secret do
45
- data do
46
- set :user, user
47
- end
48
- end
49
- end
50
-
51
- def password(password)
52
- secret do
53
- data do
54
- set :password, password
55
- end
56
- end
57
- end
58
-
59
- def storage(amount)
60
- database do
61
- spec do
62
- storage do
63
- resources do
64
- requests do
65
- set :storage, amount
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end
72
-
73
- def secret(&block)
74
- context = self
75
-
76
- @secret ||= KubeDSL.secret do
77
- metadata do
78
- name "#{context.base_name}-mysql-secret"
79
- namespace context.kubernetes.namespace.metadata.name
80
- end
81
-
82
- type 'Opaque'
83
- end
84
-
85
- @secret.instance_eval(&block) if block
86
- @secret
87
- end
88
-
89
- def database(&block)
90
- context = self
91
-
92
- @database ||= Kuby::KubeDB.my_sql do
93
- api_version 'kubedb.com/v1alpha1'
94
-
95
- metadata do
96
- name "#{context.base_name}-mysql"
97
- namespace context.kubernetes.namespace.metadata.name
98
- end
99
-
100
- spec do
101
- database_secret do
102
- secret_name context.secret.metadata.name
103
- end
104
-
105
- version '5.7-v2'
106
- storage_type 'Durable'
107
-
108
- storage do
109
- storage_class_name context.kubernetes.provider.storage_class_name
110
- access_modes ['ReadWriteOnce']
111
-
112
- resources do
113
- requests do
114
- add :storage, '10Gi'
115
- end
116
- end
117
- end
118
-
119
- termination_policy 'DoNotTerminate'
120
- end
121
- end
122
-
123
- @database.instance_eval(&block) if block
124
- @database
125
- end
126
-
127
- def base_name
128
- @base_name ||= "#{kubernetes.selector_app}-#{ROLE}"
129
- end
130
-
131
- def kubernetes
132
- definition.kubernetes
133
- end
134
-
135
- private
136
-
137
- def config
138
- configs[environment]
139
- end
140
- end
141
- end
142
- end
143
- end
144
- end
145
-
146
- Kuby.register_package(:mysql_client,
147
- debian: 'default-mysql-client',
148
- alpine: 'mariadb-client'
149
- )
150
-
151
- Kuby.register_package(:mysql_dev,
152
- debian: 'default-libmysqlclient-dev',
153
- alpine: 'mariadb-dev'
154
- )
@@ -1,379 +0,0 @@
1
- require 'kube-dsl'
2
- require 'kuby/cert-manager'
3
-
4
- module Kuby
5
- module Kubernetes
6
- module Plugins
7
- module RailsApp
8
- class Plugin < Kuby::Kubernetes::Plugin
9
- extend ::KubeDSL::ValueFields
10
-
11
- WEB_ROLE = 'web'.freeze
12
- MASTER_KEY_VAR = 'RAILS_MASTER_KEY'.freeze
13
- ENV_SECRETS = [MASTER_KEY_VAR].freeze
14
- ENV_EXCLUDE = ['RAILS_ENV'].freeze
15
-
16
- value_field :root, default: '.'
17
- value_fields :hostname, :tls_enabled
18
- value_fields :manage_database, :database, :replicas
19
-
20
- alias_method :manage_database?, :manage_database
21
-
22
- def initialize(definition)
23
- @definition = definition
24
- @tls_enabled = true
25
- @replicas = 1
26
- @manage_database = true
27
- end
28
-
29
- def configure(&block)
30
- instance_eval(&block) if block
31
- end
32
-
33
- def after_configuration
34
- if @database = Database.get(self)
35
- definition.kubernetes.plugins[database] = @database
36
- definition.kubernetes.add_plugin(:kube_db)
37
-
38
- definition.docker do
39
- insert :rewrite_db_config, RewriteDbConfig.new, after: :copy_phase
40
- end
41
- end
42
-
43
- # do we always want this?
44
- definition.kubernetes.add_plugin(:nginx_ingress)
45
-
46
- if @tls_enabled
47
- context = self
48
-
49
- definition.kubernetes.add_plugin(:cert_manager) do
50
- email context.definition.docker.credentials.email
51
- end
52
- end
53
- end
54
-
55
- def before_deploy(manifest)
56
- # Make sure plugin has been configured. If not, do nothing.
57
- if cert_manager = definition.kubernetes.plugin(:cert_manager)
58
- if ing = manifest.find(:ingress, ingress.metadata.name)
59
- cert_manager.annotate_ingress(ing)
60
- end
61
- end
62
-
63
- image_with_tag = "#{docker.metadata.image_url}:#{kubernetes.tag}"
64
-
65
- deployment do
66
- spec do
67
- template do
68
- spec do
69
- container(:web) do
70
- image image_with_tag
71
- end
72
-
73
- init_container(:create_db) do
74
- image image_with_tag
75
- end
76
-
77
- init_container(:migrate_db) do
78
- image image_with_tag
79
- end
80
- end
81
- end
82
- end
83
- end
84
- end
85
-
86
- def database(&block)
87
- @database.instance_eval(&block) if block
88
- @database
89
- end
90
-
91
- def service(&block)
92
- spec = self
93
-
94
- @service ||= KubeDSL.service do
95
- metadata do
96
- name "#{spec.selector_app}-svc"
97
- namespace spec.namespace.metadata.name
98
-
99
- labels do
100
- add :app, spec.selector_app
101
- add :role, spec.role
102
- end
103
- end
104
-
105
- spec do
106
- type 'NodePort'
107
-
108
- selector do
109
- add :app, spec.selector_app
110
- add :role, spec.role
111
- end
112
-
113
- port do
114
- name 'http'
115
- port 8080
116
- protocol 'TCP'
117
- target_port 'http'
118
- end
119
- end
120
- end
121
-
122
- @service.instance_eval(&block) if block
123
- @service
124
- end
125
-
126
- def service_account(&block)
127
- spec = self
128
-
129
- @service_account ||= KubeDSL.service_account do
130
- metadata do
131
- name "#{spec.selector_app}-sa"
132
- namespace spec.namespace.metadata.name
133
-
134
- labels do
135
- add :app, spec.selector_app
136
- add :role, spec.role
137
- end
138
- end
139
- end
140
-
141
- @service_account.instance_eval(&block) if block
142
- @service_account
143
- end
144
-
145
- def config_map(&block)
146
- spec = self
147
-
148
- @config_map ||= KubeDSL.config_map do
149
- metadata do
150
- name "#{spec.selector_app}-config"
151
- namespace spec.namespace.metadata.name
152
- end
153
-
154
- data do
155
- ENV.each_pair do |key, val|
156
- include_key = key.start_with?('RAILS_') &&
157
- !ENV_SECRETS.include?(key) &&
158
- !ENV_EXCLUDE.include?(key)
159
-
160
- if include_key
161
- add key.to_sym, val
162
- end
163
- end
164
- end
165
- end
166
-
167
- @config_map.instance_eval(&block) if block
168
- @config_map
169
- end
170
-
171
- def app_secrets(&block)
172
- spec = self
173
-
174
- @app_secrets ||= KubeDSL.secret do
175
- metadata do
176
- name "#{spec.selector_app}-secrets"
177
- namespace spec.namespace.metadata.name
178
- end
179
-
180
- type 'Opaque'
181
-
182
- data do
183
- if master_key = ENV[MASTER_KEY_VAR]
184
- add MASTER_KEY_VAR.to_sym, master_key
185
- else
186
- master_key_path = File.join(spec.root, 'config', 'master.key')
187
-
188
- if File.exist?(master_key_path)
189
- add MASTER_KEY_VAR.to_sym, File.read(master_key_path).strip
190
- end
191
- end
192
- end
193
- end
194
-
195
- @app_secrets.instance_eval(&block) if block
196
- @app_secrets
197
- end
198
-
199
- def deployment(&block)
200
- kube_spec = self
201
-
202
- @deployment ||= KubeDSL.deployment do
203
- metadata do
204
- name "#{kube_spec.selector_app}-#{kube_spec.role}"
205
- namespace kube_spec.namespace.metadata.name
206
-
207
- labels do
208
- add :app, kube_spec.selector_app
209
- add :role, kube_spec.role
210
- end
211
- end
212
-
213
- spec do
214
- replicas kube_spec.replicas
215
-
216
- selector do
217
- match_labels do
218
- add :app, kube_spec.selector_app
219
- add :role, kube_spec.role
220
- end
221
- end
222
-
223
- strategy do
224
- type 'RollingUpdate'
225
-
226
- rolling_update do
227
- max_surge '25%'
228
- max_unavailable 0
229
- end
230
- end
231
-
232
- template do
233
- metadata do
234
- labels do
235
- add :app, kube_spec.selector_app
236
- add :role, kube_spec.role
237
- end
238
- end
239
-
240
- spec do
241
- container(:web) do
242
- name "#{kube_spec.selector_app}-#{kube_spec.role}"
243
- image_pull_policy 'IfNotPresent'
244
-
245
- port do
246
- container_port kube_spec.docker.webserver_phase.port
247
- name 'http'
248
- protocol 'TCP'
249
- end
250
-
251
- env_from do
252
- config_map_ref do
253
- name kube_spec.config_map.metadata.name
254
- end
255
- end
256
-
257
- env_from do
258
- secret_ref do
259
- name kube_spec.app_secrets.metadata.name
260
- end
261
- end
262
-
263
- readiness_probe do
264
- success_threshold 1
265
- failure_threshold 2
266
- initial_delay_seconds 15
267
- period_seconds 3
268
- timeout_seconds 1
269
-
270
- http_get do
271
- path '/healthz'
272
- port kube_spec.docker.webserver_phase.port
273
- scheme 'HTTP'
274
- end
275
- end
276
- end
277
-
278
- init_container(:create_db) do
279
- name "#{kube_spec.selector_app}-create-db"
280
- command %w(bundle exec rake kuby:rails_app:db:create_unless_exists)
281
- end
282
-
283
- init_container(:migrate_db) do
284
- name "#{kube_spec.selector_app}-migrate-db"
285
- command %w(bundle exec rake db:migrate)
286
- end
287
-
288
- image_pull_secret do
289
- name kube_spec.definition.kubernetes.registry_secret.metadata.name
290
- end
291
-
292
- restart_policy 'Always'
293
- service_account_name kube_spec.service_account.metadata.name
294
- end
295
- end
296
- end
297
- end
298
-
299
- @deployment.instance_eval(&block) if block
300
- @deployment
301
- end
302
-
303
- def ingress(&block)
304
- spec = self
305
- tls_enabled = @tls_enabled
306
-
307
- @ingress ||= KubeDSL::DSL::Extensions::V1beta1::Ingress.new do
308
- metadata do
309
- name "#{spec.selector_app}-ingress"
310
- namespace spec.namespace.metadata.name
311
-
312
- annotations do
313
- add :'kubernetes.io/ingress.class', 'nginx'
314
- end
315
- end
316
-
317
- spec do
318
- rule do
319
- host spec.hostname
320
-
321
- http do
322
- path do
323
- backend do
324
- service_name spec.service.metadata.name
325
- service_port spec.service.spec.ports.first.port
326
- end
327
- end
328
- end
329
- end
330
-
331
- if tls_enabled
332
- tls do
333
- secret_name "#{spec.selector_app}-tls"
334
- hosts [spec.hostname]
335
- end
336
- end
337
- end
338
- end
339
-
340
- @ingress.instance_eval(&block) if block
341
- @ingress
342
- end
343
-
344
- def resources
345
- @resources ||= [
346
- service,
347
- service_account,
348
- config_map,
349
- app_secrets,
350
- deployment,
351
- ingress,
352
- *database&.resources
353
- ]
354
- end
355
-
356
- def selector_app
357
- definition.kubernetes.selector_app
358
- end
359
-
360
- def role
361
- WEB_ROLE
362
- end
363
-
364
- def docker
365
- definition.docker
366
- end
367
-
368
- def kubernetes
369
- definition.kubernetes
370
- end
371
-
372
- def namespace
373
- definition.kubernetes.namespace
374
- end
375
- end
376
- end
377
- end
378
- end
379
- end