kuby-core 0.11.15 → 0.14.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 +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'