kuby-core 0.8.1 → 0.9.0
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/CHANGELOG.md +12 -1
- data/README.md +11 -1
- data/bin/kuby +4 -0
- data/kuby-core.gemspec +5 -2
- data/lib/kuby.rb +46 -18
- data/lib/kuby/basic_logger.rb +13 -0
- data/lib/kuby/cli_base.rb +81 -8
- data/lib/kuby/commands.rb +220 -0
- data/lib/kuby/definition.rb +1 -3
- data/lib/kuby/dev_setup.rb +255 -0
- data/lib/kuby/docker.rb +1 -0
- data/lib/kuby/docker/bundler_phase.rb +3 -3
- data/lib/kuby/docker/cli.rb +13 -1
- data/lib/kuby/docker/dev_spec.rb +131 -0
- data/lib/kuby/docker/dockerfile.rb +16 -1
- data/lib/kuby/docker/layer_stack.rb +4 -0
- data/lib/kuby/docker/local_tags.rb +4 -0
- data/lib/kuby/docker/metadata.rb +0 -22
- data/lib/kuby/docker/setup_phase.rb +3 -2
- data/lib/kuby/docker/spec.rb +31 -5
- data/lib/kuby/environment.rb +10 -1
- data/lib/kuby/kubernetes.rb +9 -9
- data/lib/kuby/kubernetes/deploy_task.rb +4 -0
- data/lib/kuby/kubernetes/deployer.rb +63 -11
- data/lib/kuby/kubernetes/{minikube_provider.rb → docker_desktop_provider.rb} +4 -4
- data/lib/kuby/kubernetes/provider.rb +8 -4
- data/lib/kuby/kubernetes/spec.rb +23 -22
- data/lib/kuby/plugin_registry.rb +27 -0
- data/lib/kuby/plugins/rails_app/generators/kuby.rb +3 -15
- data/lib/kuby/plugins/rails_app/plugin.rb +230 -40
- data/lib/kuby/rails_commands.rb +89 -0
- data/lib/kuby/railtie.rb +0 -4
- data/lib/kuby/tasks.rb +76 -23
- data/lib/kuby/version.rb +1 -1
- data/spec/docker/metadata_spec.rb +0 -108
- data/spec/docker/spec_spec.rb +266 -0
- data/spec/spec_helper.rb +8 -1
- metadata +44 -9
- data/lib/kuby/tasks/kuby.rake +0 -70
@@ -0,0 +1,27 @@
|
|
1
|
+
module Kuby
|
2
|
+
class PluginRegistry
|
3
|
+
ANY = 'any'.freeze
|
4
|
+
|
5
|
+
def register(plugin_name, plugin_klass, environment: ANY)
|
6
|
+
plugins[plugin_name] ||= {}
|
7
|
+
plugins[plugin_name][environment] ||= plugin_klass
|
8
|
+
end
|
9
|
+
|
10
|
+
def find(plugin_name, environment: Kuby.env)
|
11
|
+
plugins_by_env = plugins[plugin_name]
|
12
|
+
|
13
|
+
unless plugins_by_env
|
14
|
+
raise MissingPluginError, "no plugin registered with name #{plugin_name}, "\
|
15
|
+
'do you need to add a gem to your Gemfile?'
|
16
|
+
end
|
17
|
+
|
18
|
+
plugins_by_env[environment] || plugins_by_env[ANY]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def plugins
|
24
|
+
@plugins ||= {}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -2,17 +2,6 @@ require 'rails/generators'
|
|
2
2
|
require 'rails/generators/base'
|
3
3
|
|
4
4
|
class KubyGenerator < Rails::Generators::Base
|
5
|
-
def create_initializer_file
|
6
|
-
initializer(
|
7
|
-
'kuby.rb',
|
8
|
-
<<~END
|
9
|
-
require 'kuby'
|
10
|
-
|
11
|
-
Kuby.load!
|
12
|
-
END
|
13
|
-
)
|
14
|
-
end
|
15
|
-
|
16
5
|
def create_config_file
|
17
6
|
create_file(
|
18
7
|
'kuby.rb',
|
@@ -48,15 +37,14 @@ class KubyGenerator < Rails::Generators::Base
|
|
48
37
|
# Add a plugin that facilitates deploying a Rails app.
|
49
38
|
add_plugin :rails_app
|
50
39
|
|
51
|
-
# Use
|
52
|
-
#
|
53
|
-
# See: https://github.com/kubernetes/minikube
|
40
|
+
# Use Docker Desktop as the provider.
|
41
|
+
# See: https://www.docker.com/products/docker-desktop
|
54
42
|
#
|
55
43
|
# Note: you will likely want to use a different provider when deploying
|
56
44
|
# your application into a production environment. To configure a different
|
57
45
|
# provider, add the corresponding gem to your gemfile and update the
|
58
46
|
# following line according to the provider gem's README.
|
59
|
-
provider :
|
47
|
+
provider :docker_desktop
|
60
48
|
end
|
61
49
|
end
|
62
50
|
END
|
@@ -45,24 +45,27 @@ module Kuby
|
|
45
45
|
environment.kubernetes.plugins[database.plugin_name] = @database.plugin
|
46
46
|
environment.kubernetes.add_plugin(:kube_db)
|
47
47
|
|
48
|
-
environment.
|
49
|
-
|
48
|
+
unless environment.development?
|
49
|
+
environment.docker do
|
50
|
+
insert :rewrite_db_config, RewriteDbConfig.new, after: :copy_phase
|
51
|
+
end
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
unless environment.development?
|
56
|
+
environment.kubernetes.add_plugin(:nginx_ingress)
|
57
|
+
environment.kubernetes.add_plugin(:rails_assets) do
|
58
|
+
asset_url context.asset_url
|
59
|
+
packs_url context.packs_url
|
60
|
+
asset_path context.asset_path
|
61
|
+
end
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
+
if @tls_enabled
|
64
|
+
context = self
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
+
environment.kubernetes.add_plugin(:cert_manager) do
|
67
|
+
email context.environment.docker.credentials.email
|
68
|
+
end
|
66
69
|
end
|
67
70
|
end
|
68
71
|
end
|
@@ -80,6 +83,8 @@ module Kuby
|
|
80
83
|
assets.configure_deployment(deployment, image_with_tag)
|
81
84
|
end
|
82
85
|
|
86
|
+
spec = self
|
87
|
+
|
83
88
|
deployment do
|
84
89
|
spec do
|
85
90
|
template do
|
@@ -88,12 +93,14 @@ module Kuby
|
|
88
93
|
image image_with_tag
|
89
94
|
end
|
90
95
|
|
91
|
-
|
92
|
-
|
93
|
-
|
96
|
+
unless spec.environment.development?
|
97
|
+
init_container(:create_db) do
|
98
|
+
image image_with_tag
|
99
|
+
end
|
94
100
|
|
95
|
-
|
96
|
-
|
101
|
+
init_container(:migrate_db) do
|
102
|
+
image image_with_tag
|
103
|
+
end
|
97
104
|
end
|
98
105
|
end
|
99
106
|
end
|
@@ -130,7 +137,7 @@ module Kuby
|
|
130
137
|
|
131
138
|
port do
|
132
139
|
name 'http'
|
133
|
-
port
|
140
|
+
port spec.docker.webserver_phase.port
|
134
141
|
protocol 'TCP'
|
135
142
|
target_port 'http'
|
136
143
|
end
|
@@ -226,6 +233,13 @@ module Kuby
|
|
226
233
|
add :app, kube_spec.selector_app
|
227
234
|
add :role, kube_spec.role
|
228
235
|
end
|
236
|
+
|
237
|
+
annotations do
|
238
|
+
add(
|
239
|
+
'getkuby.io/dockerfile-checksum',
|
240
|
+
kube_spec.environment.docker.to_dockerfile.checksum
|
241
|
+
)
|
242
|
+
end
|
229
243
|
end
|
230
244
|
|
231
245
|
spec do
|
@@ -278,33 +292,93 @@ module Kuby
|
|
278
292
|
end
|
279
293
|
end
|
280
294
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
295
|
+
unless kube_spec.environment.development?
|
296
|
+
readiness_probe do
|
297
|
+
success_threshold 1
|
298
|
+
failure_threshold 2
|
299
|
+
initial_delay_seconds 15
|
300
|
+
period_seconds 3
|
301
|
+
timeout_seconds 1
|
302
|
+
|
303
|
+
http_get do
|
304
|
+
path '/healthz'
|
305
|
+
port kube_spec.docker.webserver_phase.port
|
306
|
+
scheme 'HTTP'
|
307
|
+
end
|
292
308
|
end
|
293
309
|
end
|
294
|
-
end
|
295
310
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
311
|
+
if kube_spec.environment.development?
|
312
|
+
env do
|
313
|
+
name 'BUNDLE_PATH'
|
314
|
+
value '/bundle'
|
315
|
+
end
|
316
|
+
|
317
|
+
env do
|
318
|
+
name 'GEM_HOME'
|
319
|
+
value '/bundle'
|
320
|
+
end
|
321
|
+
|
322
|
+
env do
|
323
|
+
name 'BOOTSNAP_CACHE_DIR'
|
324
|
+
value '/usr/src/bootsnap'
|
325
|
+
end
|
326
|
+
|
327
|
+
volume_mount do
|
328
|
+
name "#{kube_spec.selector_app}-code"
|
329
|
+
mount_path '/usr/src/app'
|
330
|
+
end
|
331
|
+
|
332
|
+
volume_mount do
|
333
|
+
name "#{kube_spec.selector_app}-bundle"
|
334
|
+
mount_path '/bundle'
|
335
|
+
end
|
300
336
|
|
301
|
-
|
302
|
-
|
303
|
-
|
337
|
+
volume_mount do
|
338
|
+
name "#{kube_spec.selector_app}-bootsnap"
|
339
|
+
mount_path '/usr/src/bootsnap'
|
340
|
+
end
|
341
|
+
end
|
304
342
|
end
|
305
343
|
|
306
|
-
|
307
|
-
|
344
|
+
if kube_spec.environment.development?
|
345
|
+
volume do
|
346
|
+
name "#{kube_spec.selector_app}-code"
|
347
|
+
|
348
|
+
persistent_volume_claim do
|
349
|
+
claim_name kube_spec.code_volume_claim.metadata.name
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
volume do
|
354
|
+
name "#{kube_spec.selector_app}-bundle"
|
355
|
+
|
356
|
+
persistent_volume_claim do
|
357
|
+
claim_name kube_spec.bundle_volume_claim.metadata.name
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
volume do
|
362
|
+
name "#{kube_spec.selector_app}-bootsnap"
|
363
|
+
|
364
|
+
persistent_volume_claim do
|
365
|
+
claim_name kube_spec.bootsnap_volume_claim.metadata.name
|
366
|
+
end
|
367
|
+
end
|
368
|
+
else
|
369
|
+
init_container(:create_db) do
|
370
|
+
name "#{kube_spec.selector_app}-create-db"
|
371
|
+
command %w(bundle exec rake kuby:rails_app:db:create_unless_exists)
|
372
|
+
end
|
373
|
+
|
374
|
+
init_container(:migrate_db) do
|
375
|
+
name "#{kube_spec.selector_app}-migrate-db"
|
376
|
+
command %w(bundle exec rake db:migrate)
|
377
|
+
end
|
378
|
+
|
379
|
+
image_pull_secret do
|
380
|
+
name kube_spec.environment.kubernetes.registry_secret.metadata.name
|
381
|
+
end
|
308
382
|
end
|
309
383
|
|
310
384
|
restart_policy 'Always'
|
@@ -361,6 +435,118 @@ module Kuby
|
|
361
435
|
@ingress
|
362
436
|
end
|
363
437
|
|
438
|
+
def code_volume(&block)
|
439
|
+
spec = self
|
440
|
+
|
441
|
+
if environment.development?
|
442
|
+
@code_volume ||= KubeDSL.persistent_volume do
|
443
|
+
metadata do
|
444
|
+
name "#{spec.selector_app}-code"
|
445
|
+
end
|
446
|
+
|
447
|
+
spec do
|
448
|
+
access_modes ['ReadWriteMany']
|
449
|
+
|
450
|
+
capacity do
|
451
|
+
add :storage, '1Mi'
|
452
|
+
end
|
453
|
+
|
454
|
+
host_path do
|
455
|
+
path File.expand_path(spec.root)
|
456
|
+
end
|
457
|
+
|
458
|
+
storage_class_name 'hostpath'
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
@code_volume.instance_eval(&block) if block
|
463
|
+
@code_volume
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
def code_volume_claim(&block)
|
468
|
+
spec = self
|
469
|
+
|
470
|
+
if environment.development?
|
471
|
+
@code_volume_claim ||= KubeDSL.persistent_volume_claim do
|
472
|
+
metadata do
|
473
|
+
name "#{spec.selector_app}-code"
|
474
|
+
namespace spec.namespace.metadata.name
|
475
|
+
end
|
476
|
+
|
477
|
+
spec do
|
478
|
+
access_modes ['ReadWriteMany']
|
479
|
+
|
480
|
+
resources do
|
481
|
+
requests do
|
482
|
+
add :storage, '1Mi'
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
storage_class_name 'hostpath'
|
487
|
+
volume_name spec.code_volume.metadata.name
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
@code_volume_claim.instance_eval(&block) if block
|
492
|
+
@code_volume_claim
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
def bundle_volume_claim(&block)
|
497
|
+
spec = self
|
498
|
+
|
499
|
+
if environment.development?
|
500
|
+
@bundle_volume_claim ||= KubeDSL.persistent_volume_claim do
|
501
|
+
metadata do
|
502
|
+
name "#{spec.selector_app}-bundle"
|
503
|
+
namespace spec.namespace.metadata.name
|
504
|
+
end
|
505
|
+
|
506
|
+
spec do
|
507
|
+
access_modes ['ReadWriteMany']
|
508
|
+
storage_class_name 'hostpath'
|
509
|
+
|
510
|
+
resources do
|
511
|
+
requests do
|
512
|
+
add :storage, '2Gi'
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
@bundle_volume_claim.instance_eval(&block) if block
|
519
|
+
@bundle_volume_claim
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
def bootsnap_volume_claim(&block)
|
524
|
+
spec = self
|
525
|
+
|
526
|
+
if environment.development?
|
527
|
+
@bootsnap_volume_claim ||= KubeDSL.persistent_volume_claim do
|
528
|
+
metadata do
|
529
|
+
name "#{spec.selector_app}-bootsnap"
|
530
|
+
namespace spec.namespace.metadata.name
|
531
|
+
end
|
532
|
+
|
533
|
+
spec do
|
534
|
+
access_modes ['ReadWriteMany']
|
535
|
+
storage_class_name 'hostpath'
|
536
|
+
|
537
|
+
resources do
|
538
|
+
requests do
|
539
|
+
add :storage, '2Gi'
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
@bootsnap_volume_claim.instance_eval(&block) if block
|
546
|
+
@bootsnap_volume_claim
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
364
550
|
def resources
|
365
551
|
@resources ||= [
|
366
552
|
service,
|
@@ -369,6 +555,10 @@ module Kuby
|
|
369
555
|
app_secrets,
|
370
556
|
deployment,
|
371
557
|
ingress,
|
558
|
+
code_volume,
|
559
|
+
code_volume_claim,
|
560
|
+
bundle_volume_claim,
|
561
|
+
bootsnap_volume_claim,
|
372
562
|
*database&.plugin&.resources
|
373
563
|
]
|
374
564
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Kuby
|
2
|
+
class Args
|
3
|
+
attr_reader :args, :flag_aliases
|
4
|
+
|
5
|
+
def initialize(args, flag_aliases = [])
|
6
|
+
@args = args
|
7
|
+
@flag_aliases = flag_aliases
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](flag)
|
11
|
+
idx = find_arg_index(flag)
|
12
|
+
idx ? args[idx] : nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def []=(flag, new_value)
|
16
|
+
idx = find_arg_index(flag)
|
17
|
+
|
18
|
+
if idx
|
19
|
+
args[idx] = new_value
|
20
|
+
else
|
21
|
+
@args += [flag, new_value]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def find_arg_index(flag)
|
28
|
+
idx = args.find_index do |arg|
|
29
|
+
flag_aliases.any? { |fas| fas.include?(arg) && fas.include?(flag) }
|
30
|
+
end
|
31
|
+
|
32
|
+
idx ? idx + 1 : nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class RailsCommands
|
37
|
+
PREFIX = %w(bundle exec rails).freeze
|
38
|
+
SERVER_ARG_ALIASES = [['--binding', '-b'], ['-p', '--port']].freeze
|
39
|
+
|
40
|
+
class << self
|
41
|
+
def run(args = ARGV)
|
42
|
+
subcommand = args[0]
|
43
|
+
arglist = nil
|
44
|
+
|
45
|
+
case subcommand
|
46
|
+
when 'server', 's'
|
47
|
+
arglist = Args.new([*PREFIX, *args], SERVER_ARG_ALIASES)
|
48
|
+
arglist['-b'] ||= '0.0.0.0'
|
49
|
+
arglist['-p'] ||= '3000'
|
50
|
+
when 'runner', 'r'
|
51
|
+
when 'console', 'c'
|
52
|
+
else
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
setup
|
57
|
+
|
58
|
+
arglist ||= Args.new([*PREFIX, *args])
|
59
|
+
tasks = Kuby::Tasks.new(environment)
|
60
|
+
tasks.remote_exec(arglist.args)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def setup
|
66
|
+
require 'rubygems'
|
67
|
+
require 'bundler'
|
68
|
+
|
69
|
+
Bundler.setup
|
70
|
+
|
71
|
+
require 'kuby'
|
72
|
+
|
73
|
+
Kuby.load!
|
74
|
+
end
|
75
|
+
|
76
|
+
def kubernetes_cli
|
77
|
+
kubernetes.provider.kubernetes.cli
|
78
|
+
end
|
79
|
+
|
80
|
+
def kubernetes
|
81
|
+
environment.kubernetes
|
82
|
+
end
|
83
|
+
|
84
|
+
def environment
|
85
|
+
Kuby.definition.environment
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|