kuby-core 0.11.15 → 0.14.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/Gemfile +1 -2
  4. data/README.md +2 -1
  5. data/kuby-core.gemspec +1 -1
  6. data/lib/kuby/commands.rb +24 -72
  7. data/lib/kuby/docker/alpine.rb +2 -1
  8. data/lib/kuby/docker/app_image.rb +33 -0
  9. data/lib/kuby/docker/bundler_phase.rb +10 -0
  10. data/lib/kuby/docker/cli.rb +7 -13
  11. data/lib/kuby/docker/docker_uri.rb +18 -7
  12. data/lib/kuby/docker/errors.rb +1 -19
  13. data/lib/kuby/docker/image.rb +119 -0
  14. data/lib/kuby/docker/layer.rb +0 -7
  15. data/lib/kuby/docker/local_tags.rb +9 -10
  16. data/lib/kuby/docker/package_phase.rb +0 -5
  17. data/lib/kuby/docker/packages.rb +1 -0
  18. data/lib/kuby/docker/remote_tags.rb +10 -5
  19. data/lib/kuby/docker/setup_phase.rb +17 -9
  20. data/lib/kuby/docker/spec.rb +29 -62
  21. data/lib/kuby/docker/timestamp_tag.rb +8 -1
  22. data/lib/kuby/docker/timestamped_image.rb +113 -0
  23. data/lib/kuby/docker/yarn_phase.rb +1 -4
  24. data/lib/kuby/docker.rb +27 -25
  25. data/lib/kuby/environment.rb +1 -10
  26. data/lib/kuby/kubernetes/bare_metal_provider.rb +16 -4
  27. data/lib/kuby/kubernetes/deployer.rb +1 -1
  28. data/lib/kuby/kubernetes/docker_desktop_provider.rb +0 -15
  29. data/lib/kuby/kubernetes/spec.rb +21 -17
  30. data/lib/kuby/plugin.rb +2 -2
  31. data/lib/kuby/plugins/rails_app/assets.rb +61 -70
  32. data/lib/kuby/plugins/rails_app/assets_image.rb +56 -0
  33. data/lib/kuby/plugins/rails_app/plugin.rb +53 -236
  34. data/lib/kuby/plugins/rails_app.rb +1 -0
  35. data/lib/kuby/tasks.rb +44 -70
  36. data/lib/kuby/version.rb +1 -1
  37. data/lib/kuby.rb +2 -20
  38. data/spec/docker/spec_spec.rb +21 -118
  39. data/spec/docker/timestamped_image_spec.rb +123 -0
  40. data/spec/spec_helper.rb +10 -11
  41. metadata +10 -14
  42. data/lib/kuby/dev_setup.rb +0 -346
  43. data/lib/kuby/docker/dev_spec.rb +0 -202
  44. data/lib/kuby/docker/metadata.rb +0 -90
  45. data/lib/kuby/docker/tags.rb +0 -92
  46. data/lib/kuby/rails_commands.rb +0 -84
  47. data/spec/docker/metadata_spec.rb +0 -73
  48. data/spec/dummy/Gemfile.lock +0 -223
  49. data/spec/dummy/config/master.key +0 -1
  50. data/spec/dummy/tmp/cache/bootsnap-load-path-cache +0 -0
@@ -47,38 +47,6 @@ module Kuby
47
47
  end
48
48
  end
49
49
 
50
- def configure_deployment(deployment, docker_image)
51
- spec = self
52
-
53
- deployment.spec.template.spec do
54
- init_container(:copy_assets) do
55
- name "#{spec.selector_app}-copy-assets"
56
- command %w(bundle exec rake kuby:rails_app:assets:copy)
57
- image docker_image
58
-
59
- volume_mount do
60
- name 'assets'
61
- mount_path RAILS_MOUNT_PATH
62
- end
63
- end
64
-
65
- container(:web) do
66
- volume_mount do
67
- name 'assets'
68
- mount_path NGINX_MOUNT_PATH
69
- end
70
- end
71
-
72
- volume do
73
- name 'assets'
74
-
75
- persistent_volume_claim do
76
- claim_name spec.volume_claim.metadata.name
77
- end
78
- end
79
- end
80
- end
81
-
82
50
  def copy_task
83
51
  @copy_task ||= AssetCopyTask.new(
84
52
  from: asset_path, to: RAILS_MOUNT_PATH
@@ -238,7 +206,7 @@ module Kuby
238
206
  container(:nginx) do
239
207
  name "#{kube_spec.selector_app}-#{kube_spec.role}"
240
208
  image_pull_policy 'IfNotPresent'
241
- image NGINX_IMAGE
209
+ image "#{kube_spec.image.image_url}:#{kube_spec.kubernetes.tag || Kuby::Docker::LATEST_TAG}-assets"
242
210
 
243
211
  port do
244
212
  container_port NGINX_PORT
@@ -252,11 +220,6 @@ module Kuby
252
220
  sub_path 'nginx.conf'
253
221
  end
254
222
 
255
- volume_mount do
256
- name 'assets'
257
- mount_path NGINX_MOUNT_PATH
258
- end
259
-
260
223
  readiness_probe do
261
224
  success_threshold 1
262
225
  failure_threshold 2
@@ -272,6 +235,10 @@ module Kuby
272
235
  end
273
236
  end
274
237
 
238
+ image_pull_secret do
239
+ name kube_spec.environment.kubernetes.registry_secret.metadata.name
240
+ end
241
+
275
242
  volume do
276
243
  name 'nginx-config'
277
244
 
@@ -280,14 +247,6 @@ module Kuby
280
247
  end
281
248
  end
282
249
 
283
- volume do
284
- name 'assets'
285
-
286
- persistent_volume_claim do
287
- claim_name kube_spec.volume_claim.metadata.name
288
- end
289
- end
290
-
291
250
  restart_policy 'Always'
292
251
  service_account_name kube_spec.service_account.metadata.name
293
252
  end
@@ -299,38 +258,19 @@ module Kuby
299
258
  @deployment
300
259
  end
301
260
 
302
- def volume_claim
303
- spec = self
304
-
305
- @volume_claim ||= KubeDSL.persistent_volume_claim do
306
- metadata do
307
- name "#{spec.selector_app}-#{spec.role}"
308
- namespace spec.namespace.metadata.name
309
- end
310
-
311
- spec do
312
- access_modes ['ReadWriteOnce']
313
- storage_class_name spec.environment.kubernetes.provider.storage_class_name
314
-
315
- resources do
316
- requests do
317
- add :storage, '10Gi'
318
- end
319
- end
320
- end
321
- end
322
- end
323
-
324
261
  def resources
325
262
  @resources ||= [
326
263
  service,
327
264
  service_account,
328
265
  nginx_config,
329
- deployment,
330
- volume_claim
266
+ deployment
331
267
  ]
332
268
  end
333
269
 
270
+ def docker_images
271
+ @docker_images ||= [docker_spec]
272
+ end
273
+
334
274
  def namespace
335
275
  environment.kubernetes.namespace
336
276
  end
@@ -342,6 +282,57 @@ module Kuby
342
282
  def role
343
283
  ROLE
344
284
  end
285
+
286
+ def docker
287
+ environment.docker
288
+ end
289
+
290
+ def kubernetes
291
+ environment.kubernetes
292
+ end
293
+
294
+ def docker_images
295
+ @docker_images ||= [image]
296
+ end
297
+
298
+ def image
299
+ @image ||= RailsApp::AssetsImage.new(docker.image, -> { dockerfile })
300
+ end
301
+
302
+ private
303
+
304
+ def dockerfile
305
+ Docker::Dockerfile.new.tap do |df|
306
+ base_image = docker.image.current_version
307
+ cur_tag = base_image.main_tag
308
+ app_name = environment.app_name.downcase
309
+
310
+ tags = begin
311
+ [base_image.previous_timestamp_tag(cur_tag).to_s, cur_tag]
312
+ rescue Kuby::Docker::MissingTagError
313
+ [cur_tag, nil]
314
+ end
315
+
316
+ # this can handle more than 2 tags by virtue of using each_cons :)
317
+ tags.each_cons(2) do |prev_tag, tag|
318
+ prev_image_name = "#{app_name}-#{prev_tag}"
319
+ df.from("#{base_image.image_url}:#{prev_tag}", as: prev_image_name)
320
+ df.arg('RAILS_MASTER_KEY')
321
+ df.run("mkdir -p #{RAILS_MOUNT_PATH}")
322
+ df.run("env RAILS_MASTER_KEY=$RAILS_MASTER_KEY bundle exec rake kuby:rails_app:assets:copy")
323
+
324
+ if tag
325
+ image_name = "#{app_name}-#{tag}"
326
+ df.from("#{base_image.image_url}:#{tag}", as: image_name)
327
+ df.copy("--from=#{prev_image_name} #{RAILS_MOUNT_PATH}", RAILS_MOUNT_PATH)
328
+ df.run("env RAILS_MASTER_KEY=$RAILS_MASTER_KEY bundle exec rake kuby:rails_app:assets:copy")
329
+ end
330
+ end
331
+
332
+ df.from(NGINX_IMAGE)
333
+ df.copy("--from=#{"#{app_name}-#{tags.compact.last}"} #{RAILS_MOUNT_PATH}", NGINX_MOUNT_PATH)
334
+ end
335
+ end
345
336
  end
346
337
  end
347
338
  end
@@ -0,0 +1,56 @@
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
+ @identifier = "assets"
11
+ end
12
+
13
+ def new_version
14
+ # Asset images track the base image, so return the current version
15
+ # here. There can be no asset image without a base image.
16
+ current_version
17
+ end
18
+
19
+ def current_version
20
+ @current_version ||= duplicate_with_annotated_tags(
21
+ base_image.current_version
22
+ )
23
+ end
24
+
25
+ def previous_version
26
+ @previous_version ||= duplicate_with_annotated_tags(
27
+ base_image.previous_version
28
+ )
29
+ end
30
+
31
+ def build(build_args = {}, docker_args = [])
32
+ docker_cli.build(current_version, build_args: build_args, docker_args: docker_args)
33
+ end
34
+
35
+ def push(tag)
36
+ docker_cli.push(image_url, tag)
37
+ end
38
+
39
+ private
40
+
41
+ def duplicate_with_annotated_tags(image)
42
+ self.class.new(
43
+ base_image,
44
+ dockerfile,
45
+ annotate_tag(image.main_tag),
46
+ image.alias_tags.map { |at| annotate_tag(at) }
47
+ )
48
+ end
49
+
50
+ def annotate_tag(tag)
51
+ "#{tag}-assets"
52
+ end
53
+ end
54
+ end
55
+ end
56
+ 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
- unless environment.development?
51
- environment.docker do
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
- unless environment.development?
58
- environment.kubernetes.add_plugin(:nginx_ingress)
59
- environment.kubernetes.add_plugin(:rails_assets) do
60
- asset_url context.asset_url
61
- packs_url context.packs_url
62
- asset_path context.asset_path
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
- if @tls_enabled
66
- context = self
62
+ if @tls_enabled
63
+ context = self
67
64
 
68
- environment.kubernetes.add_plugin(:cert_manager) do
69
- email context.environment.docker.credentials.email
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.metadata.image_url}:#{kubernetes.tag}"
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
- unless spec.environment.development?
103
- init_container(:create_db) do
104
- image image_with_tag
105
- end
97
+ init_container(:create_db) do
98
+ image image_with_tag
99
+ end
106
100
 
107
- init_container(:migrate_db) do
108
- image image_with_tag
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.to_dockerfile.checksum
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
- unless kube_spec.environment.development?
307
- readiness_probe do
308
- success_threshold 1
309
- failure_threshold 2
310
- initial_delay_seconds 15
311
- period_seconds 3
312
- timeout_seconds 1
313
-
314
- http_get do
315
- path '/healthz'
316
- port kube_spec.docker.webserver_phase.port
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
- if kube_spec.environment.development?
356
- volume do
357
- name "#{kube_spec.selector_app}-code"
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
- persistent_volume_claim do
360
- claim_name kube_spec.code_volume_claim.metadata.name
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
- volume do
365
- name "#{kube_spec.selector_app}-bundle"
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
- volume do
373
- name "#{kube_spec.selector_app}-bootsnap"
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
- persistent_volume_claim do
376
- claim_name kube_spec.bootsnap_volume_claim.metadata.name
377
- end
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
- init_container(:migrate_db) do
398
- name "#{kube_spec.selector_app}-migrate-db"
399
- command %w(bundle exec rake db:migrate)
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
- image_pull_secret do
415
- name kube_spec.environment.kubernetes.registry_secret.metadata.name
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
@@ -3,6 +3,7 @@ module Kuby
3
3
  module Plugins
4
4
  module RailsApp
5
5
  autoload :AssetCopyTask, 'kuby/plugins/rails_app/asset_copy_task'
6
+ autoload :AssetsImage, 'kuby/plugins/rails_app/assets_image'
6
7
  autoload :Assets, 'kuby/plugins/rails_app/assets'
7
8
  autoload :Database, 'kuby/plugins/rails_app/database'
8
9
  autoload :MySQL, 'kuby/plugins/rails_app/mysql'