kuby-core 0.2.0 → 0.6.1

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -0
  3. data/Gemfile +0 -4
  4. data/README.md +3 -160
  5. data/kuby-core.gemspec +5 -4
  6. data/lib/ext/krane/kubernetes_resource.rb +16 -0
  7. data/lib/kuby.rb +32 -17
  8. data/lib/kuby/definition.rb +20 -14
  9. data/lib/kuby/docker.rb +2 -1
  10. data/lib/kuby/docker/alpine.rb +0 -1
  11. data/lib/kuby/docker/assets_phase.rb +1 -1
  12. data/lib/kuby/docker/bundler_phase.rb +4 -2
  13. data/lib/kuby/docker/copy_phase.rb +1 -1
  14. data/lib/kuby/docker/inline_layer.rb +15 -0
  15. data/lib/kuby/docker/{phase.rb → layer.rb} +6 -5
  16. data/lib/kuby/docker/layer_stack.rb +30 -4
  17. data/lib/kuby/docker/metadata.rb +27 -1
  18. data/lib/kuby/docker/package_phase.rb +1 -1
  19. data/lib/kuby/docker/packages.rb +5 -4
  20. data/lib/kuby/docker/packages/simple_managed_package.rb +25 -0
  21. data/lib/kuby/docker/setup_phase.rb +1 -1
  22. data/lib/kuby/docker/spec.rb +4 -4
  23. data/lib/kuby/docker/tags.rb +18 -0
  24. data/lib/kuby/docker/webserver_phase.rb +1 -1
  25. data/lib/kuby/docker/yarn_phase.rb +1 -1
  26. data/lib/kuby/environment.rb +22 -0
  27. data/lib/kuby/kubernetes.rb +1 -0
  28. data/lib/kuby/kubernetes/deploy_task.rb +33 -0
  29. data/lib/kuby/kubernetes/deployer.rb +1 -2
  30. data/lib/kuby/kubernetes/minikube_provider.rb +5 -5
  31. data/lib/kuby/kubernetes/plugins/nginx_ingress.rb +12 -0
  32. data/lib/kuby/kubernetes/plugins/rails_app/database.rb +30 -9
  33. data/lib/kuby/kubernetes/plugins/rails_app/generators/kuby.rb +83 -0
  34. data/lib/kuby/kubernetes/plugins/rails_app/mysql.rb +17 -5
  35. data/lib/kuby/kubernetes/plugins/rails_app/plugin.rb +28 -42
  36. data/lib/kuby/kubernetes/plugins/rails_app/postgres.rb +132 -0
  37. data/lib/kuby/kubernetes/plugins/rails_app/sqlite.rb +20 -0
  38. data/lib/kuby/kubernetes/plugins/rails_app/tasks.rake +9 -4
  39. data/lib/kuby/kubernetes/spec.rb +52 -37
  40. data/lib/kuby/railtie.rb +0 -4
  41. data/lib/kuby/tasks.rb +18 -0
  42. data/lib/kuby/tasks/kuby.rake +24 -17
  43. data/lib/kuby/version.rb +1 -1
  44. metadata +21 -15
@@ -0,0 +1,83 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/base'
3
+
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
+ def create_config_file
17
+ create_file(
18
+ 'kuby.rb',
19
+ <<~END
20
+ require 'active_support/encrypted_configuration'
21
+
22
+ # Define a production Kuby deploy environment
23
+ Kuby.define(:production) do
24
+ app_creds = ActiveSupport::EncryptedConfiguration.new(
25
+ config_path: File.join('config', 'credentials.yml.enc'),
26
+ key_path: File.join('config', 'master.key'),
27
+ env_key: 'RAILS_MASTER_KEY',
28
+ raise_if_missing_key: true
29
+ )
30
+
31
+ docker do
32
+ # Configure your Docker registry credentials here. Add them to your
33
+ # Rails credentials file by running `bundle exec rake credentials:edit`.
34
+ credentials do
35
+ username app_creds[:KUBY_DOCKER_USERNAME]
36
+ password app_creds[:KUBY_DOCKER_PASSWORD]
37
+ email app_creds[:KUBY_DOCKER_EMAIL]
38
+ end
39
+
40
+ # Configure the URL to your Docker image here, eg:
41
+ # image_url 'foo.bar.com/me/myproject'
42
+ #
43
+ # If you're using Gitlab's Docker registry, try something like this:
44
+ # image_url 'registry.gitlab.com/<username>/<repo>'
45
+ end
46
+
47
+ kubernetes do
48
+ # Add a plugin that facilitates deploying a Rails app.
49
+ add_plugin :rails_app
50
+
51
+ # Use minikube as the provider, which is the default installed by
52
+ # Docker Desktop.
53
+ # See: https://github.com/kubernetes/minikube
54
+ #
55
+ # Note: you will likely want to use a different provider when deploying
56
+ # your application into a production environment. To configure a different
57
+ # provider, add the corresponding gem to your gemfile and update the
58
+ # following line according to the provider gem's README.
59
+ provider :minikube
60
+ end
61
+ end
62
+ END
63
+ )
64
+ end
65
+
66
+ def create_dockerignore
67
+ create_file(
68
+ '.dockerignore',
69
+ <<~END
70
+ .bundle/
71
+ vendor/bundle
72
+ node_modules/
73
+ .node_modules/
74
+ **/.git*
75
+ tmp/
76
+ log/
77
+ engines/**/log/
78
+ engines/**/tmp/
79
+ public/assets
80
+ END
81
+ )
82
+ end
83
+ end
@@ -6,6 +6,8 @@ module Kuby
6
6
  module Plugins
7
7
  module RailsApp
8
8
  class MySQL < Kuby::Kubernetes::Plugin
9
+ ROLE = 'web'.freeze
10
+
9
11
  attr_reader :definition, :environment, :configs
10
12
 
11
13
  def initialize(definition, environment, configs)
@@ -54,6 +56,20 @@ module Kuby
54
56
  end
55
57
  end
56
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
+
57
73
  def secret(&block)
58
74
  context = self
59
75
 
@@ -109,17 +125,13 @@ module Kuby
109
125
  end
110
126
 
111
127
  def base_name
112
- @base_name ||= "#{kubernetes.selector_app}-#{environment}"
128
+ @base_name ||= "#{kubernetes.selector_app}-#{ROLE}"
113
129
  end
114
130
 
115
131
  def kubernetes
116
132
  definition.kubernetes
117
133
  end
118
134
 
119
- def app
120
- definition.app
121
- end
122
-
123
135
  private
124
136
 
125
137
  def config
@@ -13,11 +13,17 @@ module Kuby
13
13
  ENV_SECRETS = [MASTER_KEY_VAR].freeze
14
14
  ENV_EXCLUDE = ['RAILS_ENV'].freeze
15
15
 
16
- value_fields :hostname, :tls_enabled, :database
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
17
21
 
18
22
  def initialize(definition)
19
23
  @definition = definition
20
24
  @tls_enabled = true
25
+ @replicas = 1
26
+ @manage_database = true
21
27
  end
22
28
 
23
29
  def configure(&block)
@@ -25,11 +31,7 @@ module Kuby
25
31
  end
26
32
 
27
33
  def after_configuration
28
- # currently Database.get doesn't return nil, but this if statement
29
- # is here as a placeholder to indicate we'd like to be able to
30
- # handle Rails apps that don't use a database, i.e. don't have
31
- # activerecord configured
32
- if @database = Database.get(definition)
34
+ if @database = Database.get(self)
33
35
  definition.kubernetes.plugins[database] = @database
34
36
  definition.kubernetes.add_plugin(:kube_db)
35
37
 
@@ -42,7 +44,11 @@ module Kuby
42
44
  definition.kubernetes.add_plugin(:nginx_ingress)
43
45
 
44
46
  if @tls_enabled
45
- definition.kubernetes.add_plugin(:cert_manager)
47
+ context = self
48
+
49
+ definition.kubernetes.add_plugin(:cert_manager) do
50
+ email context.definition.docker.credentials.email
51
+ end
46
52
  end
47
53
  end
48
54
 
@@ -53,14 +59,9 @@ module Kuby
53
59
  cert_manager.annotate_ingress(ing)
54
60
  end
55
61
  end
56
- end
57
62
 
58
- def database(&block)
59
- @database.instance_eval(&block) if block
60
- @database
61
- end
63
+ image_with_tag = "#{docker.metadata.image_url}:#{kubernetes.tag}"
62
64
 
63
- def set_image(image_with_tag)
64
65
  deployment do
65
66
  spec do
66
67
  template do
@@ -82,6 +83,11 @@ module Kuby
82
83
  end
83
84
  end
84
85
 
86
+ def database(&block)
87
+ @database.instance_eval(&block) if block
88
+ @database
89
+ end
90
+
85
91
  def service(&block)
86
92
  spec = self
87
93
 
@@ -177,9 +183,9 @@ module Kuby
177
183
  if master_key = ENV[MASTER_KEY_VAR]
178
184
  add MASTER_KEY_VAR.to_sym, master_key
179
185
  else
180
- master_key_path = spec.app.root.join('config', 'master.key')
186
+ master_key_path = File.join(spec.root, 'config', 'master.key')
181
187
 
182
- if master_key_path.exist?
188
+ if File.exist?(master_key_path)
183
189
  add MASTER_KEY_VAR.to_sym, File.read(master_key_path).strip
184
190
  end
185
191
  end
@@ -190,33 +196,12 @@ module Kuby
190
196
  @app_secrets
191
197
  end
192
198
 
193
- def registry_secret(&block)
194
- spec = self
195
-
196
- @registry_secret ||= RegistrySecret.new do
197
- metadata do
198
- name "#{spec.selector_app}-registry-secret"
199
- namespace spec.namespace.metadata.name
200
- end
201
-
202
- docker_config do
203
- registry_host spec.docker.metadata.image_host
204
- username spec.docker.credentials.username
205
- password spec.docker.credentials.password
206
- email spec.docker.credentials.email
207
- end
208
- end
209
-
210
- @registry_secret.instance_eval(&block) if block
211
- @registry_secret
212
- end
213
-
214
199
  def deployment(&block)
215
200
  kube_spec = self
216
201
 
217
202
  @deployment ||= KubeDSL.deployment do
218
203
  metadata do
219
- name "#{kube_spec.selector_app}-deployment"
204
+ name "#{kube_spec.selector_app}-#{kube_spec.role}"
220
205
  namespace kube_spec.namespace.metadata.name
221
206
 
222
207
  labels do
@@ -226,6 +211,8 @@ module Kuby
226
211
  end
227
212
 
228
213
  spec do
214
+ replicas kube_spec.replicas
215
+
229
216
  selector do
230
217
  match_labels do
231
218
  add :app, kube_spec.selector_app
@@ -299,7 +286,7 @@ module Kuby
299
286
  end
300
287
 
301
288
  image_pull_secret do
302
- name kube_spec.registry_secret.metadata.name
289
+ name kube_spec.definition.kubernetes.registry_secret.metadata.name
303
290
  end
304
291
 
305
292
  restart_policy 'Always'
@@ -360,10 +347,9 @@ module Kuby
360
347
  service_account,
361
348
  config_map,
362
349
  app_secrets,
363
- registry_secret,
364
350
  deployment,
365
351
  ingress,
366
- *database.resources
352
+ *database&.resources
367
353
  ]
368
354
  end
369
355
 
@@ -379,8 +365,8 @@ module Kuby
379
365
  definition.docker
380
366
  end
381
367
 
382
- def app
383
- definition.app
368
+ def kubernetes
369
+ definition.kubernetes
384
370
  end
385
371
 
386
372
  def namespace
@@ -1,10 +1,142 @@
1
+ require 'kube-dsl'
2
+ require 'kuby/kube-db'
3
+
1
4
  module Kuby
2
5
  module Kubernetes
3
6
  module Plugins
4
7
  module RailsApp
5
8
  class Postgres < 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(:postgres_dev)
28
+ definition.docker.package_phase.add(:postgres_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 :POSTGRES_USER, user
47
+ end
48
+ end
49
+ end
50
+
51
+ def password(password)
52
+ secret do
53
+ data do
54
+ set :POSTGRES_PASSWORD, password
55
+ end
56
+ end
57
+ end
58
+
59
+ def secret(&block)
60
+ context = self
61
+
62
+ @secret ||= KubeDSL.secret do
63
+ metadata do
64
+ name "#{context.base_name}-postgres-secret"
65
+ namespace context.kubernetes.namespace.metadata.name
66
+ end
67
+
68
+ type 'Opaque'
69
+ end
70
+
71
+ @secret.instance_eval(&block) if block
72
+ @secret
73
+ end
74
+
75
+ def database(&block)
76
+ context = self
77
+
78
+ @database ||= Kuby::KubeDB.postgres do
79
+ api_version 'kubedb.com/v1alpha1'
80
+
81
+ metadata do
82
+ name "#{context.base_name}-postgres"
83
+ namespace context.kubernetes.namespace.metadata.name
84
+ end
85
+
86
+ spec do
87
+ database_secret do
88
+ secret_name context.secret.metadata.name
89
+ end
90
+
91
+ version '11.2'
92
+ standby_mode 'Hot'
93
+ streaming_mode 'asynchronous'
94
+ storage_type 'Durable'
95
+
96
+ storage do
97
+ storage_class_name context.kubernetes.provider.storage_class_name
98
+ access_modes ['ReadWriteOnce']
99
+
100
+ resources do
101
+ requests do
102
+ add :storage, '10Gi'
103
+ end
104
+ end
105
+ end
106
+
107
+ termination_policy 'DoNotTerminate'
108
+ end
109
+ end
110
+
111
+ @database.instance_eval(&block) if block
112
+ @database
113
+ end
114
+
115
+ def base_name
116
+ @base_name ||= "#{kubernetes.selector_app}-#{ROLE}"
117
+ end
118
+
119
+ def kubernetes
120
+ definition.kubernetes
121
+ end
122
+
123
+ private
124
+
125
+ def config
126
+ configs[environment]
127
+ end
6
128
  end
7
129
  end
8
130
  end
9
131
  end
10
132
  end
133
+
134
+ Kuby.register_package(:postgres_dev,
135
+ debian: 'postgresql-client',
136
+ alpine: 'postgresql-dev'
137
+ )
138
+
139
+ Kuby.register_package(:postgres_client,
140
+ debian: 'postgresql-client',
141
+ alpine: 'postgresql-client'
142
+ )
@@ -3,8 +3,28 @@ module Kuby
3
3
  module Plugins
4
4
  module RailsApp
5
5
  class Sqlite < Kuby::Kubernetes::Plugin
6
+ attr_reader :definition
7
+
8
+ def initialize(definition, *)
9
+ @definition = definition
10
+ end
11
+
12
+ def after_configuration
13
+ definition.docker.package_phase.add(:sqlite_dev)
14
+ definition.docker.package_phase.add(:sqlite_client)
15
+ end
6
16
  end
7
17
  end
8
18
  end
9
19
  end
10
20
  end
21
+
22
+ Kuby.register_package(:sqlite_dev,
23
+ debian: 'libsqlite3-dev',
24
+ alpine: 'sqlite-dev'
25
+ )
26
+
27
+ Kuby.register_package(:sqlite_client,
28
+ debian: 'sqlite3',
29
+ alpine: 'sqlite'
30
+ )