kuby-core 0.11.16 → 0.12.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 +18 -0
- data/Gemfile +1 -2
- data/kuby-core.gemspec +1 -1
- data/lib/kuby.rb +2 -20
- data/lib/kuby/commands.rb +13 -67
- data/lib/kuby/docker.rb +27 -25
- data/lib/kuby/docker/alpine.rb +2 -1
- data/lib/kuby/docker/app_image.rb +19 -0
- data/lib/kuby/docker/cli.rb +4 -12
- data/lib/kuby/docker/docker_uri.rb +18 -7
- data/lib/kuby/docker/errors.rb +1 -19
- data/lib/kuby/docker/image.rb +115 -0
- data/lib/kuby/docker/layer.rb +0 -7
- data/lib/kuby/docker/local_tags.rb +9 -10
- data/lib/kuby/docker/package_phase.rb +0 -5
- data/lib/kuby/docker/packages.rb +1 -0
- data/lib/kuby/docker/remote_tags.rb +10 -5
- data/lib/kuby/docker/setup_phase.rb +17 -9
- data/lib/kuby/docker/spec.rb +29 -62
- data/lib/kuby/docker/timestamp_tag.rb +8 -1
- data/lib/kuby/docker/timestamped_image.rb +113 -0
- data/lib/kuby/environment.rb +1 -10
- data/lib/kuby/kubernetes/bare_metal_provider.rb +16 -4
- data/lib/kuby/kubernetes/deployer.rb +1 -1
- data/lib/kuby/kubernetes/docker_desktop_provider.rb +0 -15
- data/lib/kuby/kubernetes/spec.rb +21 -17
- data/lib/kuby/plugin.rb +2 -2
- data/lib/kuby/plugins/rails_app.rb +1 -0
- data/lib/kuby/plugins/rails_app/assets.rb +60 -70
- data/lib/kuby/plugins/rails_app/assets_image.rb +55 -0
- data/lib/kuby/plugins/rails_app/plugin.rb +53 -236
- data/lib/kuby/tasks.rb +30 -69
- data/lib/kuby/version.rb +1 -1
- data/spec/docker/spec_spec.rb +9 -118
- data/spec/docker/timestamped_image_spec.rb +123 -0
- data/spec/spec_helper.rb +10 -11
- metadata +9 -10
- data/lib/kuby/dev_setup.rb +0 -346
- data/lib/kuby/docker/dev_spec.rb +0 -202
- data/lib/kuby/docker/metadata.rb +0 -90
- data/lib/kuby/docker/tags.rb +0 -92
- data/lib/kuby/rails_commands.rb +0 -84
- data/spec/docker/metadata_spec.rb +0 -73
@@ -0,0 +1,55 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Plugins
|
3
|
+
module RailsApp
|
4
|
+
class AssetsImage < ::Kuby::Docker::Image
|
5
|
+
attr_reader :base_image
|
6
|
+
|
7
|
+
def initialize(base_image, dockerfile, main_tag = nil, alias_tags = [])
|
8
|
+
super(dockerfile, base_image.image_url, base_image.credentials, main_tag, alias_tags)
|
9
|
+
@base_image = base_image
|
10
|
+
end
|
11
|
+
|
12
|
+
def new_version
|
13
|
+
# Asset images track the base image, so return the current version
|
14
|
+
# here. There can be no asset image without a base image.
|
15
|
+
current_version
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_version
|
19
|
+
@current_version ||= duplicate_with_annotated_tags(
|
20
|
+
base_image.current_version
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def previous_version
|
25
|
+
@previous_version ||= duplicate_with_annotated_tags(
|
26
|
+
base_image.previous_version
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def build(build_args = {})
|
31
|
+
docker_cli.build(current_version, build_args: build_args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def push(tag)
|
35
|
+
docker_cli.push(image_url, tag)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def duplicate_with_annotated_tags(image)
|
41
|
+
self.class.new(
|
42
|
+
base_image,
|
43
|
+
dockerfile,
|
44
|
+
annotate_tag(image.main_tag),
|
45
|
+
image.alias_tags.map { |at| annotate_tag(at) }
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def annotate_tag(tag)
|
50
|
+
"#{tag}-assets"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -47,27 +47,23 @@ module Kuby
|
|
47
47
|
environment.kubernetes.plugins[@database.plugin_name] = @database.plugin
|
48
48
|
environment.kubernetes.add_plugin(:kube_db)
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
insert :rewrite_db_config, RewriteDbConfig.new, after: :copy_phase
|
53
|
-
end
|
50
|
+
environment.docker do
|
51
|
+
insert :rewrite_db_config, RewriteDbConfig.new, after: :copy_phase
|
54
52
|
end
|
55
53
|
end
|
56
54
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
55
|
+
environment.kubernetes.add_plugin(:nginx_ingress)
|
56
|
+
environment.kubernetes.add_plugin(:rails_assets) do
|
57
|
+
asset_url context.asset_url
|
58
|
+
packs_url context.packs_url
|
59
|
+
asset_path context.asset_path
|
60
|
+
end
|
64
61
|
|
65
|
-
|
66
|
-
|
62
|
+
if @tls_enabled
|
63
|
+
context = self
|
67
64
|
|
68
|
-
|
69
|
-
|
70
|
-
end
|
65
|
+
environment.kubernetes.add_plugin(:cert_manager) do
|
66
|
+
email context.environment.docker.credentials.email
|
71
67
|
end
|
72
68
|
end
|
73
69
|
end
|
@@ -79,14 +75,13 @@ module Kuby
|
|
79
75
|
def before_deploy(manifest)
|
80
76
|
# Make sure plugin has been configured. If not, do nothing.
|
81
77
|
if cert_manager = environment.kubernetes.plugin(:cert_manager)
|
82
|
-
cert_manager.annotate_ingress(ingress)
|
78
|
+
cert_manager.annotate_ingress(ingress) if tls_enabled
|
83
79
|
end
|
84
80
|
|
85
|
-
image_with_tag = "#{docker.
|
81
|
+
image_with_tag = "#{docker.image.image_url}:#{kubernetes.tag || Kuby::Docker::LATEST_TAG}"
|
86
82
|
|
87
83
|
if assets = environment.kubernetes.plugin(:rails_assets)
|
88
84
|
assets.configure_ingress(ingress, hostname)
|
89
|
-
assets.configure_deployment(deployment, image_with_tag)
|
90
85
|
end
|
91
86
|
|
92
87
|
spec = self
|
@@ -99,14 +94,12 @@ module Kuby
|
|
99
94
|
image image_with_tag
|
100
95
|
end
|
101
96
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
97
|
+
init_container(:create_db) do
|
98
|
+
image image_with_tag
|
99
|
+
end
|
106
100
|
|
107
|
-
|
108
|
-
|
109
|
-
end
|
101
|
+
init_container(:migrate_db) do
|
102
|
+
image image_with_tag
|
110
103
|
end
|
111
104
|
end
|
112
105
|
end
|
@@ -248,7 +241,7 @@ module Kuby
|
|
248
241
|
annotations do
|
249
242
|
add(
|
250
243
|
'getkuby.io/dockerfile-checksum',
|
251
|
-
kube_spec.environment.docker.
|
244
|
+
kube_spec.environment.docker.image.dockerfile.checksum
|
252
245
|
)
|
253
246
|
end
|
254
247
|
end
|
@@ -303,117 +296,57 @@ module Kuby
|
|
303
296
|
end
|
304
297
|
end
|
305
298
|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
scheme 'HTTP'
|
318
|
-
end
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
if kube_spec.environment.development?
|
323
|
-
env do
|
324
|
-
name 'BUNDLE_PATH'
|
325
|
-
value '/bundle'
|
326
|
-
end
|
327
|
-
|
328
|
-
env do
|
329
|
-
name 'GEM_HOME'
|
330
|
-
value '/bundle'
|
331
|
-
end
|
332
|
-
|
333
|
-
env do
|
334
|
-
name 'BOOTSNAP_CACHE_DIR'
|
335
|
-
value '/usr/src/bootsnap'
|
336
|
-
end
|
337
|
-
|
338
|
-
volume_mount do
|
339
|
-
name "#{kube_spec.selector_app}-code"
|
340
|
-
mount_path '/usr/src/app'
|
341
|
-
end
|
342
|
-
|
343
|
-
volume_mount do
|
344
|
-
name "#{kube_spec.selector_app}-bundle"
|
345
|
-
mount_path '/bundle'
|
346
|
-
end
|
347
|
-
|
348
|
-
volume_mount do
|
349
|
-
name "#{kube_spec.selector_app}-bootsnap"
|
350
|
-
mount_path '/usr/src/bootsnap'
|
299
|
+
readiness_probe do
|
300
|
+
success_threshold 1
|
301
|
+
failure_threshold 2
|
302
|
+
initial_delay_seconds 15
|
303
|
+
period_seconds 3
|
304
|
+
timeout_seconds 1
|
305
|
+
|
306
|
+
http_get do
|
307
|
+
path '/healthz'
|
308
|
+
port kube_spec.docker.webserver_phase.port
|
309
|
+
scheme 'HTTP'
|
351
310
|
end
|
352
311
|
end
|
353
312
|
end
|
354
313
|
|
355
|
-
|
356
|
-
|
357
|
-
|
314
|
+
init_container(:create_db) do
|
315
|
+
name "#{kube_spec.selector_app}-create-db"
|
316
|
+
command %w(bundle exec rake kuby:rails_app:db:create_unless_exists)
|
358
317
|
|
359
|
-
|
360
|
-
|
318
|
+
env_from do
|
319
|
+
config_map_ref do
|
320
|
+
name kube_spec.config_map.metadata.name
|
361
321
|
end
|
362
322
|
end
|
363
323
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
persistent_volume_claim do
|
368
|
-
claim_name kube_spec.bundle_volume_claim.metadata.name
|
324
|
+
env_from do
|
325
|
+
secret_ref do
|
326
|
+
name kube_spec.app_secrets.metadata.name
|
369
327
|
end
|
370
328
|
end
|
329
|
+
end
|
371
330
|
|
372
|
-
|
373
|
-
|
331
|
+
init_container(:migrate_db) do
|
332
|
+
name "#{kube_spec.selector_app}-migrate-db"
|
333
|
+
command %w(bundle exec rake db:migrate)
|
374
334
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
end
|
379
|
-
else
|
380
|
-
init_container(:create_db) do
|
381
|
-
name "#{kube_spec.selector_app}-create-db"
|
382
|
-
command %w(bundle exec rake kuby:rails_app:db:create_unless_exists)
|
383
|
-
|
384
|
-
env_from do
|
385
|
-
config_map_ref do
|
386
|
-
name kube_spec.config_map.metadata.name
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
env_from do
|
391
|
-
secret_ref do
|
392
|
-
name kube_spec.app_secrets.metadata.name
|
393
|
-
end
|
335
|
+
env_from do
|
336
|
+
config_map_ref do
|
337
|
+
name kube_spec.config_map.metadata.name
|
394
338
|
end
|
395
339
|
end
|
396
340
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
env_from do
|
402
|
-
config_map_ref do
|
403
|
-
name kube_spec.config_map.metadata.name
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
|
-
env_from do
|
408
|
-
secret_ref do
|
409
|
-
name kube_spec.app_secrets.metadata.name
|
410
|
-
end
|
341
|
+
env_from do
|
342
|
+
secret_ref do
|
343
|
+
name kube_spec.app_secrets.metadata.name
|
411
344
|
end
|
412
345
|
end
|
346
|
+
end
|
413
347
|
|
414
|
-
|
415
|
-
|
416
|
-
end
|
348
|
+
image_pull_secret do
|
349
|
+
name kube_spec.environment.kubernetes.registry_secret.metadata.name
|
417
350
|
end
|
418
351
|
|
419
352
|
restart_policy 'Always'
|
@@ -470,118 +403,6 @@ module Kuby
|
|
470
403
|
@ingress
|
471
404
|
end
|
472
405
|
|
473
|
-
def code_volume(&block)
|
474
|
-
spec = self
|
475
|
-
|
476
|
-
if environment.development?
|
477
|
-
@code_volume ||= KubeDSL.persistent_volume do
|
478
|
-
metadata do
|
479
|
-
name "#{spec.selector_app}-code"
|
480
|
-
end
|
481
|
-
|
482
|
-
spec do
|
483
|
-
access_modes ['ReadWriteMany']
|
484
|
-
|
485
|
-
capacity do
|
486
|
-
add :storage, '1Mi'
|
487
|
-
end
|
488
|
-
|
489
|
-
host_path do
|
490
|
-
path File.expand_path(spec.root)
|
491
|
-
end
|
492
|
-
|
493
|
-
storage_class_name 'hostpath'
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
@code_volume.instance_eval(&block) if block
|
498
|
-
@code_volume
|
499
|
-
end
|
500
|
-
end
|
501
|
-
|
502
|
-
def code_volume_claim(&block)
|
503
|
-
spec = self
|
504
|
-
|
505
|
-
if environment.development?
|
506
|
-
@code_volume_claim ||= KubeDSL.persistent_volume_claim do
|
507
|
-
metadata do
|
508
|
-
name "#{spec.selector_app}-code"
|
509
|
-
namespace spec.namespace.metadata.name
|
510
|
-
end
|
511
|
-
|
512
|
-
spec do
|
513
|
-
access_modes ['ReadWriteMany']
|
514
|
-
|
515
|
-
resources do
|
516
|
-
requests do
|
517
|
-
add :storage, '1Mi'
|
518
|
-
end
|
519
|
-
end
|
520
|
-
|
521
|
-
storage_class_name 'hostpath'
|
522
|
-
volume_name spec.code_volume.metadata.name
|
523
|
-
end
|
524
|
-
end
|
525
|
-
|
526
|
-
@code_volume_claim.instance_eval(&block) if block
|
527
|
-
@code_volume_claim
|
528
|
-
end
|
529
|
-
end
|
530
|
-
|
531
|
-
def bundle_volume_claim(&block)
|
532
|
-
spec = self
|
533
|
-
|
534
|
-
if environment.development?
|
535
|
-
@bundle_volume_claim ||= KubeDSL.persistent_volume_claim do
|
536
|
-
metadata do
|
537
|
-
name "#{spec.selector_app}-bundle"
|
538
|
-
namespace spec.namespace.metadata.name
|
539
|
-
end
|
540
|
-
|
541
|
-
spec do
|
542
|
-
access_modes ['ReadWriteMany']
|
543
|
-
storage_class_name 'hostpath'
|
544
|
-
|
545
|
-
resources do
|
546
|
-
requests do
|
547
|
-
add :storage, '2Gi'
|
548
|
-
end
|
549
|
-
end
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
@bundle_volume_claim.instance_eval(&block) if block
|
554
|
-
@bundle_volume_claim
|
555
|
-
end
|
556
|
-
end
|
557
|
-
|
558
|
-
def bootsnap_volume_claim(&block)
|
559
|
-
spec = self
|
560
|
-
|
561
|
-
if environment.development?
|
562
|
-
@bootsnap_volume_claim ||= KubeDSL.persistent_volume_claim do
|
563
|
-
metadata do
|
564
|
-
name "#{spec.selector_app}-bootsnap"
|
565
|
-
namespace spec.namespace.metadata.name
|
566
|
-
end
|
567
|
-
|
568
|
-
spec do
|
569
|
-
access_modes ['ReadWriteMany']
|
570
|
-
storage_class_name 'hostpath'
|
571
|
-
|
572
|
-
resources do
|
573
|
-
requests do
|
574
|
-
add :storage, '2Gi'
|
575
|
-
end
|
576
|
-
end
|
577
|
-
end
|
578
|
-
end
|
579
|
-
|
580
|
-
@bootsnap_volume_claim.instance_eval(&block) if block
|
581
|
-
@bootsnap_volume_claim
|
582
|
-
end
|
583
|
-
end
|
584
|
-
|
585
406
|
def resources
|
586
407
|
@resources ||= [
|
587
408
|
service,
|
@@ -590,10 +411,6 @@ module Kuby
|
|
590
411
|
app_secrets,
|
591
412
|
deployment,
|
592
413
|
ingress,
|
593
|
-
code_volume,
|
594
|
-
code_volume_claim,
|
595
|
-
bundle_volume_claim,
|
596
|
-
bootsnap_volume_claim,
|
597
414
|
*database&.plugin&.resources
|
598
415
|
]
|
599
416
|
end
|
data/lib/kuby/tasks.rb
CHANGED
@@ -9,65 +9,60 @@ module Kuby
|
|
9
9
|
@environment = environment
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
def print_dockerfiles
|
13
|
+
kubernetes.docker_images.each do |image|
|
14
|
+
image = image.current_version
|
15
|
+
Kuby.logger.info("Dockerfile for image #{image.image_url} with tags #{image.tags.join(', ')}")
|
16
|
+
theme = Rouge::Themes::Base16::Solarized.new
|
17
|
+
formatter = Rouge::Formatters::Terminal256.new(theme)
|
18
|
+
lexer = Rouge::Lexers::Docker.new
|
19
|
+
tokens = lexer.lex(image.dockerfile.to_s)
|
20
|
+
puts formatter.format(tokens)
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
def setup
|
21
25
|
environment.kubernetes.setup
|
22
26
|
end
|
23
27
|
|
24
|
-
def build
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
build_args
|
28
|
+
def build(build_args = {})
|
29
|
+
kubernetes.docker_images.each do |image|
|
30
|
+
image = image.new_version
|
31
|
+
Kuby.logger.info("Building image #{image.image_url} with tags #{image.tags.join(', ')}")
|
32
|
+
image.build(build_args)
|
29
33
|
end
|
30
|
-
|
31
|
-
docker.cli.build(
|
32
|
-
dockerfile: docker.to_dockerfile,
|
33
|
-
image_url: docker.metadata.image_url,
|
34
|
-
tags: docker.metadata.tags,
|
35
|
-
build_args: build_args
|
36
|
-
)
|
37
34
|
end
|
38
35
|
|
39
36
|
def push
|
40
|
-
|
41
|
-
|
37
|
+
kubernetes.docker_images.each do |image|
|
38
|
+
image = image.current_version
|
39
|
+
Kuby.logger.info("Pushing image #{image.image_url} with tags #{image.tags.join(', ')}")
|
40
|
+
push_image(image)
|
42
41
|
end
|
42
|
+
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
Kuby.logger.info("Attempting to log in to registry at #{host}")
|
44
|
+
def push_image(image)
|
45
|
+
if image.credentials.username && !image.docker_cli.auths.include?(image.image_host)
|
46
|
+
Kuby.logger.info("Attempting to log in to registry at #{image.image_host}")
|
48
47
|
|
49
48
|
begin
|
50
|
-
|
51
|
-
url:
|
52
|
-
username:
|
53
|
-
password:
|
49
|
+
image.docker_cli.login(
|
50
|
+
url: image.image_host,
|
51
|
+
username: image.credentials.username,
|
52
|
+
password: image.credentials.password
|
54
53
|
)
|
55
54
|
rescue Kuby::Docker::LoginError => e
|
56
|
-
Kuby.logger.fatal("Couldn't log in to the registry at #{
|
55
|
+
Kuby.logger.fatal("Couldn't log in to the registry at #{image.image_host}")
|
57
56
|
Kuby.logger.fatal(e.message)
|
58
57
|
return
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
62
|
-
image_url = docker.metadata.image_url
|
63
|
-
|
64
61
|
begin
|
65
|
-
|
66
|
-
docker.cli.push(image_url, tag)
|
67
|
-
end
|
62
|
+
image.tags.each { |tag| image.push(tag) }
|
68
63
|
rescue Kuby::Docker::MissingTagError => e
|
69
64
|
msg = "#{e.message} Run kuby build to build the "\
|
70
|
-
'Docker
|
65
|
+
'Docker images before running this task.'
|
71
66
|
|
72
67
|
Kuby.logger.fatal(msg)
|
73
68
|
Kuby.logger.fatal(e.message)
|
@@ -135,40 +130,6 @@ module Kuby
|
|
135
130
|
kubernetes_cli.restart_deployment(namespace, deployment)
|
136
131
|
end
|
137
132
|
|
138
|
-
def dev_deployment_ok
|
139
|
-
return true unless Kuby.environment.development?
|
140
|
-
|
141
|
-
deployments = kubernetes_cli.get_objects(
|
142
|
-
'deployments', namespace, match_labels.serialize
|
143
|
-
)
|
144
|
-
|
145
|
-
if deployments.empty?
|
146
|
-
puts 'No development environment detected.'
|
147
|
-
STDOUT.write('Set up development environment? (y/n): ')
|
148
|
-
answer = STDIN.gets.strip.downcase
|
149
|
-
return false unless answer =~ /ye?s?/
|
150
|
-
return DevSetup.new(environment).run
|
151
|
-
else
|
152
|
-
depl = deployments.first
|
153
|
-
deployed_checksum = depl.dig('metadata', 'annotations', 'getkuby.io/dockerfile-checksum')
|
154
|
-
current_checksum = docker.to_dockerfile.checksum
|
155
|
-
|
156
|
-
if deployed_checksum != current_checksum
|
157
|
-
puts "Development environment appears to be out-of-date."
|
158
|
-
puts "Environment checksum: #{deployed_checksum}"
|
159
|
-
puts "Current checksum: #{current_checksum}"
|
160
|
-
STDOUT.write('Update development environment? (y/n): ')
|
161
|
-
answer = STDIN.gets.strip.downcase
|
162
|
-
# return true here to prevent letting an out-of-date deployment
|
163
|
-
# stop us from running commands
|
164
|
-
return true unless answer =~ /ye?s?/
|
165
|
-
return DevSetup.new(environment).run
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
true
|
170
|
-
end
|
171
|
-
|
172
133
|
private
|
173
134
|
|
174
135
|
def get_first_pod
|