kuby-core 0.7.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -0
  3. data/Gemfile +1 -0
  4. data/README.md +11 -1
  5. data/bin/kuby +4 -0
  6. data/kuby-core.gemspec +11 -4
  7. data/lib/kuby.rb +55 -23
  8. data/lib/kuby/basic_logger.rb +13 -0
  9. data/lib/kuby/cli_base.rb +81 -8
  10. data/lib/kuby/commands.rb +220 -0
  11. data/lib/kuby/definition.rb +1 -11
  12. data/lib/kuby/dev_setup.rb +255 -0
  13. data/lib/kuby/docker.rb +1 -0
  14. data/lib/kuby/docker/bundler_phase.rb +3 -3
  15. data/lib/kuby/docker/cli.rb +13 -1
  16. data/lib/kuby/docker/dev_spec.rb +131 -0
  17. data/lib/kuby/docker/dockerfile.rb +16 -1
  18. data/lib/kuby/docker/layer.rb +4 -4
  19. data/lib/kuby/docker/layer_stack.rb +4 -0
  20. data/lib/kuby/docker/local_tags.rb +4 -0
  21. data/lib/kuby/docker/metadata.rb +19 -39
  22. data/lib/kuby/docker/package_phase.rb +2 -2
  23. data/lib/kuby/docker/setup_phase.rb +3 -2
  24. data/lib/kuby/docker/spec.rb +42 -16
  25. data/lib/kuby/docker/timestamp_tag.rb +12 -3
  26. data/lib/kuby/environment.rb +15 -2
  27. data/lib/kuby/kubernetes.rb +9 -11
  28. data/lib/kuby/kubernetes/deploy_task.rb +4 -1
  29. data/lib/kuby/kubernetes/deployer.rb +67 -15
  30. data/lib/kuby/kubernetes/{minikube_provider.rb → docker_desktop_provider.rb} +8 -4
  31. data/lib/kuby/kubernetes/provider.rb +12 -8
  32. data/lib/kuby/kubernetes/spec.rb +30 -29
  33. data/lib/kuby/plugin.rb +59 -0
  34. data/lib/kuby/plugin_registry.rb +27 -0
  35. data/lib/kuby/plugins.rb +6 -0
  36. data/lib/kuby/plugins/nginx_ingress.rb +71 -0
  37. data/lib/kuby/plugins/rails_app.rb +18 -0
  38. data/lib/kuby/plugins/rails_app/asset_copy_task.rb +117 -0
  39. data/lib/kuby/plugins/rails_app/assets.rb +347 -0
  40. data/lib/kuby/plugins/rails_app/database.rb +75 -0
  41. data/lib/kuby/{kubernetes/plugins → plugins}/rails_app/generators/kuby.rb +3 -15
  42. data/lib/kuby/plugins/rails_app/mysql.rb +155 -0
  43. data/lib/kuby/plugins/rails_app/plugin.rb +588 -0
  44. data/lib/kuby/plugins/rails_app/postgres.rb +143 -0
  45. data/lib/kuby/plugins/rails_app/rewrite_db_config.rb +11 -0
  46. data/lib/kuby/plugins/rails_app/sqlite.rb +32 -0
  47. data/lib/kuby/plugins/rails_app/tasks.rake +36 -0
  48. data/lib/kuby/rails_commands.rb +89 -0
  49. data/lib/kuby/railtie.rb +0 -4
  50. data/lib/kuby/tasks.rb +84 -31
  51. data/lib/kuby/version.rb +1 -1
  52. data/spec/docker/metadata_spec.rb +84 -0
  53. data/spec/docker/spec_spec.rb +266 -0
  54. data/spec/docker/timestamp_tag_spec.rb +61 -0
  55. data/spec/dummy/Gemfile +54 -0
  56. data/spec/dummy/Gemfile.lock +223 -0
  57. data/spec/dummy/README.md +24 -0
  58. data/spec/dummy/Rakefile +6 -0
  59. data/spec/dummy/app/assets/config/manifest.js +2 -0
  60. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  61. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  62. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  63. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  64. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  65. data/spec/dummy/app/javascript/channels/consumer.js +6 -0
  66. data/spec/dummy/app/javascript/channels/index.js +5 -0
  67. data/spec/dummy/app/javascript/packs/application.js +17 -0
  68. data/spec/dummy/app/jobs/application_job.rb +7 -0
  69. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  70. data/spec/dummy/app/models/application_record.rb +3 -0
  71. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  72. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  73. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  74. data/spec/dummy/bin/bundle +114 -0
  75. data/spec/dummy/bin/rails +9 -0
  76. data/spec/dummy/bin/rake +9 -0
  77. data/spec/dummy/bin/setup +36 -0
  78. data/spec/dummy/bin/spring +17 -0
  79. data/spec/dummy/bin/yarn +11 -0
  80. data/spec/dummy/config.ru +5 -0
  81. data/spec/dummy/config/application.rb +19 -0
  82. data/spec/dummy/config/boot.rb +4 -0
  83. data/spec/dummy/config/cable.yml +10 -0
  84. data/spec/dummy/config/credentials.yml.enc +1 -0
  85. data/spec/dummy/config/database.yml +25 -0
  86. data/spec/dummy/config/environment.rb +5 -0
  87. data/spec/dummy/config/environments/development.rb +62 -0
  88. data/spec/dummy/config/environments/production.rb +112 -0
  89. data/spec/dummy/config/environments/test.rb +49 -0
  90. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  91. data/spec/dummy/config/initializers/assets.rb +14 -0
  92. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  93. data/spec/dummy/config/initializers/content_security_policy.rb +30 -0
  94. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  95. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  96. data/spec/dummy/config/initializers/inflections.rb +16 -0
  97. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  98. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  99. data/spec/dummy/config/locales/en.yml +33 -0
  100. data/spec/dummy/config/master.key +1 -0
  101. data/spec/dummy/config/puma.rb +38 -0
  102. data/spec/dummy/config/routes.rb +3 -0
  103. data/spec/dummy/config/spring.rb +6 -0
  104. data/spec/dummy/config/storage.yml +34 -0
  105. data/spec/dummy/db/seeds.rb +7 -0
  106. data/spec/dummy/package.json +11 -0
  107. data/spec/dummy/public/404.html +67 -0
  108. data/spec/dummy/public/422.html +67 -0
  109. data/spec/dummy/public/500.html +66 -0
  110. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  111. data/spec/dummy/public/apple-touch-icon.png +0 -0
  112. data/spec/dummy/public/favicon.ico +0 -0
  113. data/spec/dummy/public/robots.txt +1 -0
  114. data/spec/dummy/test/application_system_test_case.rb +5 -0
  115. data/spec/dummy/test/channels/application_cable/connection_test.rb +11 -0
  116. data/spec/dummy/test/test_helper.rb +13 -0
  117. data/spec/dummy/tmp/cache/bootsnap-load-path-cache +0 -0
  118. data/spec/spec_helper.rb +177 -0
  119. data/spec/support/docker/fake_cli.rb +54 -0
  120. data/spec/support/docker/remote/fake_client.rb +16 -0
  121. data/spec/trailing_hash_spec.rb +23 -0
  122. metadata +155 -30
  123. data/lib/ext/krane/kubernetes_resource.rb +0 -16
  124. data/lib/kuby/kubernetes/plugin.rb +0 -55
  125. data/lib/kuby/kubernetes/plugins.rb +0 -8
  126. data/lib/kuby/kubernetes/plugins/nginx_ingress.rb +0 -73
  127. data/lib/kuby/kubernetes/plugins/rails_app.rb +0 -16
  128. data/lib/kuby/kubernetes/plugins/rails_app/database.rb +0 -79
  129. data/lib/kuby/kubernetes/plugins/rails_app/mysql.rb +0 -154
  130. data/lib/kuby/kubernetes/plugins/rails_app/plugin.rb +0 -379
  131. data/lib/kuby/kubernetes/plugins/rails_app/postgres.rb +0 -142
  132. data/lib/kuby/kubernetes/plugins/rails_app/rewrite_db_config.rb +0 -13
  133. data/lib/kuby/kubernetes/plugins/rails_app/sqlite.rb +0 -30
  134. data/lib/kuby/kubernetes/plugins/rails_app/tasks.rake +0 -28
  135. data/lib/kuby/tasks/kuby.rake +0 -70
@@ -0,0 +1,75 @@
1
+ require 'erb'
2
+ require 'yaml'
3
+
4
+ module Kuby
5
+ module Plugins
6
+ module RailsApp
7
+ class UnsupportedDatabaseError < StandardError; end
8
+
9
+ class Database
10
+ ADAPTER_MAP = {
11
+ sqlite3: Sqlite,
12
+ mysql2: MySQL,
13
+ postgresql: Postgres
14
+ }.freeze
15
+
16
+ def self.get(rails_app)
17
+ if rails_app.manage_database?
18
+ new(rails_app)
19
+ end
20
+ end
21
+
22
+ def self.get_adapter(adapter_name)
23
+ ADAPTER_MAP.fetch(adapter_name) do
24
+ raise UnsupportedDatabaseError, "Kuby does not support the '#{adapter}' "\
25
+ 'database adapter'
26
+ end
27
+ end
28
+
29
+ attr_reader :rails_app
30
+
31
+ def initialize(rails_app)
32
+ @rails_app = rails_app
33
+ end
34
+
35
+ def plugin
36
+ @plugin ||= self.class
37
+ .get_adapter(adapter_name)
38
+ .new(rails_app.environment, db_configs)
39
+ end
40
+
41
+ def adapter_name
42
+ @adapter_name ||= db_config['adapter'].to_sym
43
+ end
44
+
45
+ alias_method :plugin_name, :adapter_name
46
+
47
+ private
48
+
49
+ def db_config
50
+ @db_config ||= db_configs[rails_app.environment.name]
51
+ end
52
+
53
+ def db_configs
54
+ @db_configs ||= YAML.load(ERB.new(File.read(db_config_path)).result)
55
+ end
56
+
57
+ def db_config_path
58
+ @db_config_path ||= begin
59
+ db_config_paths.first or
60
+ raise "Couldn't find database config at #{rails_app.root}"
61
+ end
62
+ end
63
+
64
+ def db_config_paths
65
+ @db_config_paths ||=
66
+ Dir.glob(
67
+ File.join(
68
+ rails_app.root, 'config', 'database.{yml,erb,yml.erb,yaml,yaml.erb}'
69
+ )
70
+ )
71
+ end
72
+ end
73
+ end
74
+ end
75
+ 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 minikube as the provider, which is the default installed by
52
- # Docker Desktop.
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 :minikube
47
+ provider :docker_desktop
60
48
  end
61
49
  end
62
50
  END
@@ -0,0 +1,155 @@
1
+ require 'kube-dsl'
2
+ require 'kuby/kube-db'
3
+
4
+ module Kuby
5
+ module Plugins
6
+ module RailsApp
7
+ class MySQL < ::Kuby::Plugin
8
+ ROLE = 'web'.freeze
9
+
10
+ attr_reader :environment, :configs
11
+
12
+ def initialize(environment, configs)
13
+ @environment = environment
14
+ @configs = configs
15
+
16
+ user(config['username'])
17
+ password(config['password'])
18
+ end
19
+
20
+ def name
21
+ :mysql
22
+ end
23
+
24
+ def resources
25
+ @resources ||= [secret, database]
26
+ end
27
+
28
+ def after_configuration
29
+ environment.docker.package_phase.add(:mysql_dev)
30
+ environment.docker.package_phase.add(:mysql_client)
31
+ end
32
+
33
+ def host
34
+ # host is the same as the name thanks to k8s DNS
35
+ @host ||= database.metadata.name
36
+ end
37
+
38
+ def rewritten_configs
39
+ # deep dup
40
+ @rewritten_configs ||= Marshal.load(Marshal.dump(configs)).tap do |new_configs|
41
+ new_configs[environment.name]['host'] = host
42
+ end
43
+ end
44
+
45
+ def user(user)
46
+ secret do
47
+ data do
48
+ set :user, user
49
+ end
50
+ end
51
+ end
52
+
53
+ def password(password)
54
+ secret do
55
+ data do
56
+ set :password, password
57
+ end
58
+ end
59
+ end
60
+
61
+ def storage(amount)
62
+ database do
63
+ spec do
64
+ storage do
65
+ resources do
66
+ requests do
67
+ set :storage, amount
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ def secret(&block)
76
+ context = self
77
+
78
+ @secret ||= KubeDSL.secret do
79
+ metadata do
80
+ name "#{context.base_name}-mysql-secret"
81
+ namespace context.kubernetes.namespace.metadata.name
82
+ end
83
+
84
+ type 'Opaque'
85
+ end
86
+
87
+ @secret.instance_eval(&block) if block
88
+ @secret
89
+ end
90
+
91
+ def database(&block)
92
+ context = self
93
+
94
+ @database ||= Kuby::KubeDB.my_sql do
95
+ api_version 'kubedb.com/v1alpha1'
96
+
97
+ metadata do
98
+ name "#{context.base_name}-mysql"
99
+ namespace context.kubernetes.namespace.metadata.name
100
+ end
101
+
102
+ spec do
103
+ database_secret do
104
+ secret_name context.secret.metadata.name
105
+ end
106
+
107
+ version '5.7-v2'
108
+ storage_type 'Durable'
109
+
110
+ storage do
111
+ storage_class_name context.kubernetes.provider.storage_class_name
112
+ access_modes ['ReadWriteOnce']
113
+
114
+ resources do
115
+ requests do
116
+ add :storage, '10Gi'
117
+ end
118
+ end
119
+ end
120
+
121
+ termination_policy 'DoNotTerminate'
122
+ end
123
+ end
124
+
125
+ @database.instance_eval(&block) if block
126
+ @database
127
+ end
128
+
129
+ def base_name
130
+ @base_name ||= "#{kubernetes.selector_app}-#{ROLE}"
131
+ end
132
+
133
+ def kubernetes
134
+ environment.kubernetes
135
+ end
136
+
137
+ private
138
+
139
+ def config
140
+ configs[environment.name]
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ Kuby.register_package(:mysql_client,
148
+ debian: 'default-mysql-client',
149
+ alpine: 'mariadb-client'
150
+ )
151
+
152
+ Kuby.register_package(:mysql_dev,
153
+ debian: 'default-libmysqlclient-dev',
154
+ alpine: 'mariadb-dev'
155
+ )
@@ -0,0 +1,588 @@
1
+ require 'kube-dsl'
2
+ require 'kuby/cert-manager'
3
+
4
+ module Kuby
5
+ module Plugins
6
+ module RailsApp
7
+ class Plugin < ::Kuby::Plugin
8
+ extend ::KubeDSL::ValueFields
9
+
10
+ WEB_ROLE = 'web'.freeze
11
+ DEFAULT_HOSTNAME = 'localhost'.freeze
12
+ MASTER_KEY_VAR = 'RAILS_MASTER_KEY'.freeze
13
+ ENV_SECRETS = [MASTER_KEY_VAR].freeze
14
+ ENV_EXCLUDE = ['RAILS_ENV'].freeze
15
+ DEFAULT_ASSET_URL = '/assets'.freeze
16
+ DEFAULT_PACKS_URL = '/packs'.freeze
17
+ DEFAULT_ASSET_PATH = './public'.freeze
18
+
19
+ value_field :root, default: '.'
20
+ value_fields :hostname, :tls_enabled
21
+ value_fields :manage_database, :database, :replicas
22
+ value_fields :asset_url, :packs_url, :asset_path
23
+
24
+ alias_method :manage_database?, :manage_database
25
+
26
+ def initialize(environment)
27
+ @environment = environment
28
+ @tls_enabled = true
29
+ @replicas = 1
30
+ @manage_database = true
31
+ @hostname = DEFAULT_HOSTNAME
32
+ @asset_url = DEFAULT_ASSET_URL
33
+ @packs_url = DEFAULT_PACKS_URL
34
+ @asset_path = DEFAULT_ASSET_PATH
35
+ end
36
+
37
+ def configure(&block)
38
+ instance_eval(&block) if block
39
+ end
40
+
41
+ def after_configuration
42
+ context = self
43
+
44
+ if @database = Database.get(self)
45
+ environment.kubernetes.plugins[database.plugin_name] = @database.plugin
46
+ environment.kubernetes.add_plugin(:kube_db)
47
+
48
+ unless environment.development?
49
+ environment.docker do
50
+ insert :rewrite_db_config, RewriteDbConfig.new, after: :copy_phase
51
+ end
52
+ end
53
+ end
54
+
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
62
+
63
+ if @tls_enabled
64
+ context = self
65
+
66
+ environment.kubernetes.add_plugin(:cert_manager) do
67
+ email context.environment.docker.credentials.email
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def before_deploy(manifest)
74
+ # Make sure plugin has been configured. If not, do nothing.
75
+ if cert_manager = environment.kubernetes.plugin(:cert_manager)
76
+ cert_manager.annotate_ingress(ingress)
77
+ end
78
+
79
+ image_with_tag = "#{docker.metadata.image_url}:#{kubernetes.tag}"
80
+
81
+ if assets = environment.kubernetes.plugin(:rails_assets)
82
+ assets.configure_ingress(ingress, hostname)
83
+ assets.configure_deployment(deployment, image_with_tag)
84
+ end
85
+
86
+ spec = self
87
+
88
+ deployment do
89
+ spec do
90
+ template do
91
+ spec do
92
+ container(:web) do
93
+ image image_with_tag
94
+ end
95
+
96
+ unless spec.environment.development?
97
+ init_container(:create_db) do
98
+ image image_with_tag
99
+ end
100
+
101
+ init_container(:migrate_db) do
102
+ image image_with_tag
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def database(&block)
112
+ @database.instance_eval(&block) if block
113
+ @database
114
+ end
115
+
116
+ def service(&block)
117
+ spec = self
118
+
119
+ @service ||= KubeDSL.service do
120
+ metadata do
121
+ name "#{spec.selector_app}-svc"
122
+ namespace spec.namespace.metadata.name
123
+
124
+ labels do
125
+ add :app, spec.selector_app
126
+ add :role, spec.role
127
+ end
128
+ end
129
+
130
+ spec do
131
+ type 'NodePort'
132
+
133
+ selector do
134
+ add :app, spec.selector_app
135
+ add :role, spec.role
136
+ end
137
+
138
+ port do
139
+ name 'http'
140
+ port spec.docker.webserver_phase.port
141
+ protocol 'TCP'
142
+ target_port 'http'
143
+ end
144
+ end
145
+ end
146
+
147
+ @service.instance_eval(&block) if block
148
+ @service
149
+ end
150
+
151
+ def service_account(&block)
152
+ spec = self
153
+
154
+ @service_account ||= KubeDSL.service_account do
155
+ metadata do
156
+ name "#{spec.selector_app}-sa"
157
+ namespace spec.namespace.metadata.name
158
+
159
+ labels do
160
+ add :app, spec.selector_app
161
+ add :role, spec.role
162
+ end
163
+ end
164
+ end
165
+
166
+ @service_account.instance_eval(&block) if block
167
+ @service_account
168
+ end
169
+
170
+ def config_map(&block)
171
+ spec = self
172
+
173
+ @config_map ||= KubeDSL.config_map do
174
+ metadata do
175
+ name "#{spec.selector_app}-config"
176
+ namespace spec.namespace.metadata.name
177
+ end
178
+
179
+ data do
180
+ ENV.each_pair do |key, val|
181
+ include_key = key.start_with?('RAILS_') &&
182
+ !ENV_SECRETS.include?(key) &&
183
+ !ENV_EXCLUDE.include?(key)
184
+
185
+ if include_key
186
+ add key.to_sym, val
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ @config_map.instance_eval(&block) if block
193
+ @config_map
194
+ end
195
+
196
+ def app_secrets(&block)
197
+ spec = self
198
+
199
+ @app_secrets ||= KubeDSL.secret do
200
+ metadata do
201
+ name "#{spec.selector_app}-secrets"
202
+ namespace spec.namespace.metadata.name
203
+ end
204
+
205
+ type 'Opaque'
206
+
207
+ data do
208
+ if master_key = ENV[MASTER_KEY_VAR]
209
+ add MASTER_KEY_VAR.to_sym, master_key
210
+ else
211
+ master_key_path = File.join(spec.root, 'config', 'master.key')
212
+
213
+ if File.exist?(master_key_path)
214
+ add MASTER_KEY_VAR.to_sym, File.read(master_key_path).strip
215
+ end
216
+ end
217
+ end
218
+ end
219
+
220
+ @app_secrets.instance_eval(&block) if block
221
+ @app_secrets
222
+ end
223
+
224
+ def deployment(&block)
225
+ kube_spec = self
226
+
227
+ @deployment ||= KubeDSL.deployment do
228
+ metadata do
229
+ name "#{kube_spec.selector_app}-#{kube_spec.role}"
230
+ namespace kube_spec.namespace.metadata.name
231
+
232
+ labels do
233
+ add :app, kube_spec.selector_app
234
+ add :role, kube_spec.role
235
+ end
236
+
237
+ annotations do
238
+ add(
239
+ 'getkuby.io/dockerfile-checksum',
240
+ kube_spec.environment.docker.to_dockerfile.checksum
241
+ )
242
+ end
243
+ end
244
+
245
+ spec do
246
+ replicas kube_spec.replicas
247
+
248
+ selector do
249
+ match_labels do
250
+ add :app, kube_spec.selector_app
251
+ add :role, kube_spec.role
252
+ end
253
+ end
254
+
255
+ strategy do
256
+ type 'RollingUpdate'
257
+
258
+ rolling_update do
259
+ max_surge '25%'
260
+ max_unavailable 0
261
+ end
262
+ end
263
+
264
+ template do
265
+ metadata do
266
+ labels do
267
+ add :app, kube_spec.selector_app
268
+ add :role, kube_spec.role
269
+ end
270
+ end
271
+
272
+ spec do
273
+ container(:web) do
274
+ name "#{kube_spec.selector_app}-#{kube_spec.role}"
275
+ image_pull_policy 'IfNotPresent'
276
+
277
+ port do
278
+ container_port kube_spec.docker.webserver_phase.port
279
+ name 'http'
280
+ protocol 'TCP'
281
+ end
282
+
283
+ env_from do
284
+ config_map_ref do
285
+ name kube_spec.config_map.metadata.name
286
+ end
287
+ end
288
+
289
+ env_from do
290
+ secret_ref do
291
+ name kube_spec.app_secrets.metadata.name
292
+ end
293
+ end
294
+
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
308
+ end
309
+ end
310
+
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
336
+
337
+ volume_mount do
338
+ name "#{kube_spec.selector_app}-bootsnap"
339
+ mount_path '/usr/src/bootsnap'
340
+ end
341
+ end
342
+ end
343
+
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
382
+ end
383
+
384
+ restart_policy 'Always'
385
+ service_account_name kube_spec.service_account.metadata.name
386
+ end
387
+ end
388
+ end
389
+ end
390
+
391
+ @deployment.instance_eval(&block) if block
392
+ @deployment
393
+ end
394
+
395
+ def ingress(&block)
396
+ spec = self
397
+ tls_enabled = @tls_enabled
398
+
399
+ @ingress ||= KubeDSL::DSL::Extensions::V1beta1::Ingress.new do
400
+ metadata do
401
+ name "#{spec.selector_app}-ingress"
402
+ namespace spec.namespace.metadata.name
403
+
404
+ annotations do
405
+ add :'kubernetes.io/ingress.class', 'nginx'
406
+ end
407
+ end
408
+
409
+ spec do
410
+ rule do
411
+ host spec.hostname
412
+
413
+ http do
414
+ path do
415
+ path '/'
416
+
417
+ backend do
418
+ service_name spec.service.metadata.name
419
+ service_port spec.service.spec.ports.first.port
420
+ end
421
+ end
422
+ end
423
+ end
424
+
425
+ if tls_enabled
426
+ tls do
427
+ secret_name "#{spec.selector_app}-tls"
428
+ hosts [spec.hostname]
429
+ end
430
+ end
431
+ end
432
+ end
433
+
434
+ @ingress.instance_eval(&block) if block
435
+ @ingress
436
+ end
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
+
550
+ def resources
551
+ @resources ||= [
552
+ service,
553
+ service_account,
554
+ config_map,
555
+ app_secrets,
556
+ deployment,
557
+ ingress,
558
+ code_volume,
559
+ code_volume_claim,
560
+ bundle_volume_claim,
561
+ bootsnap_volume_claim,
562
+ *database&.plugin&.resources
563
+ ]
564
+ end
565
+
566
+ def selector_app
567
+ environment.kubernetes.selector_app
568
+ end
569
+
570
+ def role
571
+ WEB_ROLE
572
+ end
573
+
574
+ def docker
575
+ environment.docker
576
+ end
577
+
578
+ def kubernetes
579
+ environment.kubernetes
580
+ end
581
+
582
+ def namespace
583
+ environment.kubernetes.namespace
584
+ end
585
+ end
586
+ end
587
+ end
588
+ end