keel 0.1.2 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae5771e28c49313b1b90d71a280c481c0268de00
4
- data.tar.gz: 85969874e3bd3d217946c1a62058b91ffb2b09ff
3
+ metadata.gz: 3837deed0bba2d9618d452af738a4dca69c109e5
4
+ data.tar.gz: a069e3ba4d3bf4035b49d98ec60369f54b5a2669
5
5
  SHA512:
6
- metadata.gz: a580124ef47f0ddc0f9cc723dcea47f273020d606d60a60402fa6488ce062ba8a1c264c710f801f5a51d300fe56119b8214dfadae01a4aeb50680f81705220c0
7
- data.tar.gz: dca6f0cfc23daf0c9dc4aa56d62189647b4bd66ad7f9b7cac798ea136a47533bd8b6858da180854a2a4e0b88c8a330054da61a143795a410cb2b1360a2e67165
6
+ metadata.gz: 55344a32cc6baf594e379ce440e00317435fb0e0e53d54276a1030604c2b3145c6ddb63863c012b5bdd648161dc5586a8d85728975a7fad9a818f28d846df064
7
+ data.tar.gz: 73c7f65984d998f7b177263321c6504e22c9b4b3afd5ca2f67d45393ea89bea8f517ce883d95778f3619fcb2d5fa11c24ad738fc75088ccc3cc126dfee81552b
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.5
data/README.md CHANGED
@@ -106,6 +106,11 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
106
106
 
107
107
  Bug reports and pull requests are welcome on GitHub at https://github.com/o19s/keel. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
108
108
 
109
+ ## Contributors
110
+
111
+ * [Chris Bradford](https://github.com/bradfordcp) did the original work
112
+ * [Youssef Chaker](https://github.com/ychaker) extracted out the gem
113
+ * [Matt Overstreet](https://github.com/omnifroodle) added support for kubernetes deployments
109
114
 
110
115
  ## License
111
116
 
data/circle.yml ADDED
@@ -0,0 +1,7 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.2.3
4
+ dependencies:
5
+ pre:
6
+ - echo Y | rvm @global do gem uninstall bundler
7
+ - gem install bundler -v '1.11'
@@ -7,6 +7,7 @@ module Keel
7
7
 
8
8
  def copy_config
9
9
  copy_file "gcloud.yml", "config/gcloud.yml"
10
+ copy_file "Dockerfile", "Dockerfile"
10
11
  end
11
12
  end
12
13
  end
@@ -1,3 +1,4 @@
1
+ # TODO, kill these and their templates
1
2
  module Keel
2
3
  module Generators
3
4
  class ControllerGenerator < ::Rails::Generators::Base
@@ -1,3 +1,4 @@
1
+ # TODO, kill these and their templates
1
2
  module Keel
2
3
  module Generators
3
4
  class ServiceGenerator < ::Rails::Generators::Base
@@ -0,0 +1 @@
1
+ FROM rails:onbuild
@@ -0,0 +1,13 @@
1
+ module Keel::Docker
2
+ class Image
3
+ def self.create(label, project_id, app_name)
4
+ command = "docker build -t gcr.io/#{project_id}/#{app_name}:#{label} ."
5
+ Keel::GCloud::Cli.new.execute(command)
6
+ end
7
+
8
+ def self.push(label, project_id, app_name)
9
+ command = "gcloud docker push gcr.io/#{project_id}/#{app_name}:#{label}"
10
+ Keel::GCloud::Cli.new.execute(command)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1 @@
1
+ require_relative 'docker/image'
@@ -1,3 +1,4 @@
1
+ require 'open3'
1
2
  module Keel::GCloud
2
3
  #
3
4
  # A helper class to run system commands and handle interrupts.
@@ -5,7 +6,17 @@ module Keel::GCloud
5
6
  class Cli
6
7
  def execute command
7
8
  begin
8
- `#{command}`
9
+ out = ""
10
+ Open3.popen3(command) do |stdout, stderr, stdin, thread|
11
+ # TODO do smarter things with status and stdout
12
+ while line=stderr.gets do
13
+ out += line
14
+ print '.'
15
+ end
16
+ print "\n"
17
+ raise "error while processing. " + out unless thread.value.success?
18
+ return out
19
+ end
9
20
  rescue Interrupt
10
21
  puts 'Task interrupted.'
11
22
  end
@@ -0,0 +1,41 @@
1
+ module Keel::GCloud
2
+ #
3
+ # A helper for prompts that integrate other services
4
+ #
5
+ class Interactions
6
+ @@namespace = nil
7
+ @@label = nil
8
+
9
+ #
10
+ # Prompts for the deployment namespace if there are multiple available and one has
11
+ # not been already chosen
12
+ #
13
+ # @param namespace [String] the default option to present for the namespace
14
+ #
15
+ def self.pick_namespace(namespace)
16
+ unless @@namespace
17
+ prompter = Keel::GCloud::Prompter.new
18
+ namespaces = Keel::GCloud::Kubernetes::Namespace.fetch_all
19
+ unless namespaces
20
+ message = 'Unable to connect to Kubernetes, please try again later...'
21
+ prompter.print message, :error
22
+ abort
23
+ end
24
+ @@namespace = prompter.prompt_for_namespace namespaces, namespace
25
+ end
26
+ @@namespace
27
+ end
28
+
29
+ #
30
+ # Prompts for a Docker image label if one has not already been selected
31
+ #
32
+ # @params label [String] the default value to present to the user
33
+ def self.pick_image_label(label)
34
+ unless @@label
35
+ prompter = Keel::GCloud::Prompter.new
36
+ @@label = prompter.prompt_for_label label
37
+ end
38
+ @@label
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ module Keel::GCloud
2
+ module Kubernetes
3
+ #
4
+ # A class to represent a Kubernetes Deployment
5
+ class Deployment < ReplicationController
6
+
7
+ #
8
+ # Fetches the correct deployment or replication controller from Kubernetes.
9
+ #
10
+ # @param env [String] the namespace/environment for which to fetch the controllers
11
+ # @param app [String] the app for which to fetch the controllers
12
+ # @return [Hash] the parsed result of the API call
13
+ #
14
+ def self.fetch_all env, app
15
+ command = "kubectl get deployment --namespace=#{env} -l app=#{app} -o yaml"
16
+ rcs_yaml = YAML.load Cli.new.execute(command)
17
+ return false unless rcs_yaml["items"].count > 0
18
+ self.from_yaml rcs_yaml
19
+ end
20
+
21
+ #
22
+ # Create a Deployment and expose it on kubernetes
23
+ #
24
+ def self.create app_name, image_path, port, sha, namespace
25
+ cli = Cli.new
26
+ deploy_command = "kubectl run #{app_name} --image=#{image_path}:#{sha} --namespace=#{namespace}"
27
+ expose_command = "kubectl expose deployment #{app_name} --port=80 --target-port=#{port} --type=LoadBalancer --namespace=#{namespace}"
28
+ cli.execute(deploy_command)
29
+ cli.execute(expose_command)
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -35,24 +35,22 @@ module Keel::GCloud
35
35
  original: item,
36
36
  uid: item['metadata']['uid'],
37
37
  }
38
-
39
38
  self.new params
40
39
  end
41
40
  end
42
41
 
43
42
  #
44
- # Fetches all the controllers from Kubernetes.
43
+ # Fetches the correct deployment or replication controller from Kubernetes.
45
44
  #
46
45
  # @param env [String] the namespace/environment for which to fetch the controllers
47
46
  # @param app [String] the app for which to fetch the controllers
48
47
  # @return [Hash] the parsed result of the API call
49
48
  #
50
49
  def self.fetch_all env, app
51
- command = "kubectl get rc --namespace=#{env} -l app=#{app} -o yaml"
52
- rcs_yaml = YAML.load Cli.new.execute(command)
53
- return false unless rcs_yaml
54
-
55
- self.from_yaml rcs_yaml
50
+ command = "kubectl get rc --namespace=#{env} -l app=#{app} -o yaml"
51
+ rcs_yaml = YAML.load Cli.new.execute(command)
52
+ return false unless rcs_yaml["items"].count > 0
53
+ self.from_yaml rcs_yaml
56
54
  end
57
55
 
58
56
  #
@@ -1,3 +1,4 @@
1
1
  require_relative 'kubernetes/namespace'
2
2
  require_relative 'kubernetes/replication_controller'
3
+ require_relative 'kubernetes/deployment'
3
4
  require_relative 'kubernetes/pod'
@@ -35,23 +35,27 @@ module Keel::GCloud
35
35
  def prompt_for_namespace namespaces, default=nil
36
36
  return default unless default.blank?
37
37
 
38
- options = namespaces.map { |namespace| namespace.name }
39
- index = Ask.list 'Please choose an environment (destination)', options
40
- options[index]
38
+ options = namespaces.map { |namespace| namespace.name } - ['kube-system']
39
+ if options.count > 1
40
+ index = Ask.list 'Please choose an environment (destination)', options
41
+ options[index]
42
+ else
43
+ options[0]
44
+ end
41
45
  end
42
46
 
43
47
  #
44
- # Prompts the user to provide a SHA.
48
+ # Prompts the user to provide a label. Defaults to the current git branch shortened SHA.
45
49
  # If a default is provided it returns that instead.
46
50
  #
47
51
  # @param default [String, nil] the default choice
48
52
  #
49
- def prompt_for_sha default=nil
53
+ def prompt_for_label default=nil
50
54
  return default unless default.blank?
51
55
 
52
56
  # Get current git SHA
53
57
  current_sha = `git rev-parse --short HEAD`.lines.first.split(' ')[0]
54
- Ask.input 'Git SHA', default: current_sha
58
+ Ask.input 'Image Label (defaults to Git SHA)', default: current_sha
55
59
  end
56
60
 
57
61
  #
data/lib/keel/gcloud.rb CHANGED
@@ -4,3 +4,4 @@ require_relative 'gcloud/component'
4
4
  require_relative 'gcloud/config'
5
5
  require_relative 'gcloud/kubernetes'
6
6
  require_relative 'gcloud/prompter'
7
+ require_relative 'gcloud/interactions'
data/lib/keel/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Keel
2
- VERSION = "0.1.2" # :nodoc:
2
+ VERSION = "0.1.5" # :nodoc:
3
3
  end
data/lib/keel.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'keel/version'
2
2
  require 'keel/railtie' if defined?(Rails)
3
3
  require 'keel/gcloud'
4
+ require 'keel/docker'
4
5
  require 'keel/notifier'
5
6
 
6
7
  # {file:README.md Usage#usage}
data/lib/tasks/keel.rake CHANGED
@@ -1,24 +1,57 @@
1
1
  namespace :keel do
2
- desc 'Deploy the specified SHA to a given environment'
3
- task :deploy, [:environment, :deploy_sha] do |_, args|
4
- prompter = Keel::GCloud::Prompter.new
5
- config = Keel::GCloud::Config.new
6
- app = config.app_name
2
+ config = Keel::GCloud::Config.new
3
+ prompter = Keel::GCloud::Prompter.new
4
+
5
+ desc "build a docker image suitable for pushing"
6
+ task :pack, [:deploy_sha] do |_, args|
7
+ prompter.print 'Building Docker image', :info
8
+ image_label = Keel::GCloud::Interactions.pick_image_label args[:deploy_sha]
9
+ Keel::Docker::Image.create image_label, config.project_id, config.app_name
10
+ prompter.print 'finished build', :info
11
+ end
7
12
 
8
- # Fetch namespaces from k8s
9
- namespaces = Keel::GCloud::Kubernetes::Namespace.fetch_all
10
- unless namespaces
11
- message = 'Unable to connect to Kubernetes, please try again later...'
12
- prompter.print message, :error
13
- abort
13
+ desc "ship the image to gcloud"
14
+ task :push, [:deploy_sha] do |_, args|
15
+ prompter.print 'Pushing image to Docker repository, this may take some time', :info
16
+ image_label = Keel::GCloud::Interactions.pick_image_label args[:deploy_sha]
17
+ Keel::Docker::Image.push image_label, config.project_id, config.app_name
18
+ prompter.print 'finished push', :info
19
+ end
20
+
21
+ desc "provision a deployment and service on kubernetes"
22
+ task :provision, [:deploy_sha] do |_, args|
23
+ image_label = Keel::GCloud::Interactions.pick_image_label args[:deploy_sha]
24
+ deploy_env = Keel::GCloud::Interactions.pick_namespace args[:environment]
25
+
26
+ # Retrieve a replication controller configuration from the cluster
27
+ rcs = Keel::GCloud::Kubernetes::ReplicationController.fetch_all deploy_env, config.app_name
28
+ if rcs
29
+ message = "Found an existing deployment or replication controller for #{config.app_name}"
30
+ prompter.print message, :success
31
+ else
32
+ message = Keel::GCloud::Kubernetes::ReplicationController.create config.app_name, config.container_app_image_path, "3000", image_label, deploy_env
33
+ prompter.print message, :success
14
34
  end
35
+ end
15
36
 
16
- # Prompt the user for the env and git commit to deploy
17
- deploy_env = prompter.prompt_for_namespace namespaces, args[:environment]
18
- deploy_sha = prompter.prompt_for_sha args[:deploy_sha]
37
+ task :shipit, [:deploy_sha] => [:set_gcloud_properties,
38
+ :pack,
39
+ :push,
40
+ :provision,
41
+ :deploy] do |_, args|
42
+ prompter.print "packed, pushed, provisioned and deployed #{config.app_name}!", :success
43
+ end
44
+
45
+ desc 'Deploy the specified SHA to a given environment'
46
+ task :deploy, [:environment, :deploy_sha] do |_, args|
47
+ app = config.app_name
48
+ deploy_sha = Keel::GCloud::Interactions.pick_image_label args[:deploy_sha]
49
+ deploy_env = Keel::GCloud::Interactions.pick_namespace args[:environment]
50
+ #rc_type = :replication_controller
19
51
 
20
52
  # Retrieve a replication controller configuration from the cluster
21
- rcs = Keel::GCloud::Kubernetes::ReplicationController.fetch_all deploy_env, app
53
+ rcs = Keel::GCloud::Kubernetes::ReplicationController.fetch_all(deploy_env, app) || Keel::GCloud::Kubernetes::Deployment.fetch_all(deploy_env, app)
54
+
22
55
  unless rcs
23
56
  message = 'Unable to connect to Kubernetes, please try again later...'
24
57
  prompter.print message, :error
@@ -34,54 +67,60 @@ namespace :keel do
34
67
 
35
68
  # Prep deployment:
36
69
  # 1. Update image
37
- # 2. Update replica count
38
- # 3. Write out to a tmp file
39
- # 4. Replace the running controller
40
- # - this will create 1 new pod with the updated code
41
-
42
- # We can get away with first since it is a single container pod
43
70
  container = rc.containers.first
44
71
  container['image'] = "#{config.container_app_image_path}:#{deploy_sha}"
45
- rc.increment_replica_count
46
- rc.update
47
72
 
48
- # Get a list of pods for the RC, this must be done pre-change
49
- pods = Keel::GCloud::Kubernetes::Pod.fetch_all deploy_env, app
50
- unless pods
51
- message = 'Unable to connect to Kubernetes, please try again later...'
52
- prompter.print message, :error
53
- abort
54
- end
73
+ if rc.is_a? Keel::GCloud::Kubernetes::Deployment
74
+ rc.update
75
+ else
76
+ # Additionally for replication controllers
77
+ # 2. Update replica count
78
+ # 3. Write out to a tmp file
79
+ # 4. Replace the running controller
80
+ # - this will create 1 new pod with the updated code
81
+
82
+ # We can get away with first since it is a single container pod
83
+
84
+ rc.increment_replica_count
85
+ rc.update
86
+
87
+ # Get a list of pods for the RC, this must be done pre-change
88
+ pods = Keel::GCloud::Kubernetes::Pod.fetch_all deploy_env, app
89
+ unless pods
90
+ message = 'Unable to connect to Kubernetes, please try again later...'
91
+ prompter.print message, :error
92
+ abort
93
+ end
55
94
 
56
- # Iterate over all pods, checking to see if they are running
57
- all_pods_running = false
58
- while !all_pods_running do
59
- prompter.print 'Waiting for new pods to start', :info
60
- sleep 5
61
- new_pods = Keel::GCloud::Kubernetes::Pod.fetch_all deploy_env, app
62
-
63
- all_pods_running = true
64
- new_pods.each do |pod|
65
- if !pod.running?
66
- prompter.print "Pod \"#{pod.name}\" is not running", :info
67
- all_pods_running = false
95
+ # Iterate over all pods, checking to see if they are running
96
+ all_pods_running = false
97
+ while !all_pods_running do
98
+ prompter.print 'Waiting for new pods to start', :info
99
+ sleep 5
100
+ new_pods = Keel::GCloud::Kubernetes::Pod.fetch_all deploy_env, app
101
+
102
+ all_pods_running = true
103
+ new_pods.each do |pod|
104
+ if !pod.running?
105
+ prompter.print "Pod \"#{pod.name}\" is not running", :info
106
+ all_pods_running = false
107
+ end
68
108
  end
69
109
  end
70
- end
71
-
72
- # Nuke old pods
73
- pods.each do |pod|
74
- pod.delete
75
- sleep 3
76
- end
77
110
 
78
- # Bring the replica count down and resubmit to the cluster,
79
- # this kills the 1 extra pod
80
- rcs = Keel::GCloud::Kubernetes::ReplicationController.fetch_all deploy_env, app
81
- rc = rcs.first
82
- rc.decrement_replica_count
83
- rc.update
111
+ # Nuke old pods
112
+ pods.each do |pod|
113
+ pod.delete
114
+ sleep 3
115
+ end
84
116
 
117
+ # Bring the replica count down and resubmit to the cluster,
118
+ # this kills the 1 extra pod
119
+ rcs = Keel::GCloud::Kubernetes::ReplicationController.fetch_all deploy_env, app
120
+ rc = rcs.first
121
+ rc.decrement_replica_count
122
+ rc.update
123
+ end
85
124
  prompter.print 'Notifying NewRelic of deployment', :info
86
125
  notifier = Keel::Notifier::NewRelic.new env: deploy_env, sha: deploy_sha
87
126
  notifier.notify
@@ -90,9 +129,15 @@ namespace :keel do
90
129
  end
91
130
 
92
131
  desc 'Configures the local machine for communication with gcloud and k8s'
93
- task :setup do |_|
94
- prompter = Keel::GCloud::Prompter.new
95
- config = Keel::GCloud::Config.new
132
+ task :setup => [:check_gcloud_executables,
133
+ :check_configuration,
134
+ :update_tools,
135
+ :gcloud_auth,
136
+ :set_gcloud_properties,
137
+ :install_k8s,
138
+ :authenticate_k8s]
139
+
140
+ task :check_gcloud_executables do
96
141
 
97
142
  if config.executable_missing?
98
143
  message = 'Install Google Cloud command line tools'
@@ -101,44 +146,46 @@ namespace :keel do
101
146
 
102
147
  abort message.red
103
148
  end
149
+ end
150
+
151
+ task :check_configuration do
104
152
 
105
153
  if config.system_configured?
106
154
  abort 'App appears to already be configured on your system.'.green
107
155
  end
156
+ end
108
157
 
109
- prompter.print 'Updating tools', :info
110
- Keel::GCloud::Component.update
158
+ task :install_k8s do
159
+ prompter.print 'Install Kubernetes', :info
160
+ Keel::GCloud::Component.install_k8s
161
+ end
111
162
 
163
+ task :authenticate_k8s do
164
+ prompter.print 'Pulling Kubernetes auth configuration', :info
165
+ auth = Keel::GCloud::Auth.new config: config
166
+ auth.authenticate_k8s
167
+ end
168
+
169
+ task :gcloud_auth do
112
170
  prompter.print 'Authenticating with Google Cloud', :info
113
171
  Keel::GCloud::Auth.authenticate
172
+ end
114
173
 
115
- prompter.print 'Install Kubernetes', :info
116
- Keel::GCloud::Component.install_k8s
174
+ task :update_tools do
175
+ prompter.print 'Updating tools', :info
176
+ Keel::GCloud::Component.update
177
+ end
117
178
 
179
+ task :set_gcloud_properties do
118
180
  prompter.print 'Setting gcloud properties', :info
119
181
  config.set_properties
120
-
121
- prompter.print 'Pulling Kubernetes auth configuration', :info
122
- auth = Keel::GCloud::Auth.new config: config
123
- auth.authenticate_k8s
124
182
  end
125
183
 
126
184
  desc 'Pulls logs for a given environment'
127
185
  task :logs, [:environment] do |_, args|
128
- prompter = Keel::GCloud::Prompter.new
129
- config = Keel::GCloud::Config.new
130
- app = config.app_name
131
-
132
- # Fetch namespaces from k8s
133
- namespaces = Keel::GCloud::Kubernetes::Namespace.fetch_all
134
- unless namespaces
135
- message = 'Unable to connect to Kubernetes, please try again later...'
136
- prompter.print message, :error
137
- abort
138
- end
139
-
186
+ app = config.app_name
140
187
  # Prompt the user for the env and to log and whether to tail the logs
141
- deploy_env = prompter.prompt_for_namespace namespaces, args[:environment]
188
+ deploy_env = Keel::GCloud::Interactions.pick_namespace args[:environment]
142
189
  tail = prompter.prompt_for_tailing_logs
143
190
 
144
191
  prompter.print "Getting pod information for #{deploy_env}", :info
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Youssef Chaker
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-06-17 00:00:00.000000000 Z
11
+ date: 2016-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -88,6 +88,7 @@ extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
90
  - ".gitignore"
91
+ - ".ruby-version"
91
92
  - ".travis.yml"
92
93
  - CODE_OF_CONDUCT.md
93
94
  - Gemfile
@@ -96,20 +97,26 @@ files:
96
97
  - Rakefile
97
98
  - bin/console
98
99
  - bin/setup
100
+ - circle.yml
99
101
  - keel.gemspec
100
102
  - lib/generators/keel/config_generator.rb
101
103
  - lib/generators/keel/controller_generator.rb
102
104
  - lib/generators/keel/service_generator.rb
105
+ - lib/generators/keel/templates/Dockerfile
103
106
  - lib/generators/keel/templates/gc-controller.yml.erb
104
107
  - lib/generators/keel/templates/gc-service.yml.erb
105
108
  - lib/generators/keel/templates/gcloud.yml
106
109
  - lib/keel.rb
110
+ - lib/keel/docker.rb
111
+ - lib/keel/docker/image.rb
107
112
  - lib/keel/gcloud.rb
108
113
  - lib/keel/gcloud/auth.rb
109
114
  - lib/keel/gcloud/cli.rb
110
115
  - lib/keel/gcloud/component.rb
111
116
  - lib/keel/gcloud/config.rb
117
+ - lib/keel/gcloud/interactions.rb
112
118
  - lib/keel/gcloud/kubernetes.rb
119
+ - lib/keel/gcloud/kubernetes/deployment.rb
113
120
  - lib/keel/gcloud/kubernetes/namespace.rb
114
121
  - lib/keel/gcloud/kubernetes/pod.rb
115
122
  - lib/keel/gcloud/kubernetes/replication_controller.rb
@@ -140,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
147
  version: '0'
141
148
  requirements: []
142
149
  rubyforge_project:
143
- rubygems_version: 2.4.5
150
+ rubygems_version: 2.4.5.1
144
151
  signing_key:
145
152
  specification_version: 4
146
153
  summary: Deploy your Rails app to Kubernetes.