kuby-core 0.2.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -0
- data/Gemfile +0 -4
- data/README.md +3 -160
- data/kuby-core.gemspec +5 -4
- data/lib/ext/krane/kubernetes_resource.rb +16 -0
- data/lib/kuby.rb +32 -17
- data/lib/kuby/definition.rb +20 -14
- data/lib/kuby/docker.rb +2 -1
- data/lib/kuby/docker/alpine.rb +0 -1
- data/lib/kuby/docker/assets_phase.rb +1 -1
- data/lib/kuby/docker/bundler_phase.rb +4 -2
- data/lib/kuby/docker/copy_phase.rb +1 -1
- data/lib/kuby/docker/inline_layer.rb +15 -0
- data/lib/kuby/docker/{phase.rb → layer.rb} +6 -5
- data/lib/kuby/docker/layer_stack.rb +30 -4
- data/lib/kuby/docker/metadata.rb +27 -1
- data/lib/kuby/docker/package_phase.rb +1 -1
- data/lib/kuby/docker/packages.rb +5 -4
- data/lib/kuby/docker/packages/simple_managed_package.rb +25 -0
- data/lib/kuby/docker/setup_phase.rb +1 -1
- data/lib/kuby/docker/spec.rb +4 -4
- data/lib/kuby/docker/tags.rb +18 -0
- data/lib/kuby/docker/webserver_phase.rb +1 -1
- data/lib/kuby/docker/yarn_phase.rb +1 -1
- data/lib/kuby/environment.rb +22 -0
- data/lib/kuby/kubernetes.rb +1 -0
- data/lib/kuby/kubernetes/deploy_task.rb +33 -0
- data/lib/kuby/kubernetes/deployer.rb +1 -2
- data/lib/kuby/kubernetes/minikube_provider.rb +5 -5
- data/lib/kuby/kubernetes/plugins/nginx_ingress.rb +12 -0
- data/lib/kuby/kubernetes/plugins/rails_app/database.rb +30 -9
- data/lib/kuby/kubernetes/plugins/rails_app/generators/kuby.rb +83 -0
- data/lib/kuby/kubernetes/plugins/rails_app/mysql.rb +17 -5
- data/lib/kuby/kubernetes/plugins/rails_app/plugin.rb +28 -42
- data/lib/kuby/kubernetes/plugins/rails_app/postgres.rb +132 -0
- data/lib/kuby/kubernetes/plugins/rails_app/sqlite.rb +20 -0
- data/lib/kuby/kubernetes/plugins/rails_app/tasks.rake +9 -4
- data/lib/kuby/kubernetes/spec.rb +52 -37
- data/lib/kuby/railtie.rb +0 -4
- data/lib/kuby/tasks.rb +18 -0
- data/lib/kuby/tasks/kuby.rake +24 -17
- data/lib/kuby/version.rb +1 -1
- metadata +21 -15
data/lib/kuby/docker/alpine.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
1
3
|
module Kuby
|
2
4
|
module Docker
|
3
|
-
class BundlerPhase <
|
5
|
+
class BundlerPhase < Layer
|
4
6
|
DEFAULT_WITHOUT = ['development', 'test', 'deploy'].freeze
|
5
7
|
|
6
8
|
attr_accessor :version, :gemfile, :without
|
@@ -48,7 +50,7 @@ module Kuby
|
|
48
50
|
.definition
|
49
51
|
.gemfiles
|
50
52
|
.first
|
51
|
-
.relative_path_from(
|
53
|
+
.relative_path_from(Pathname(Dir.getwd))
|
52
54
|
.to_s
|
53
55
|
end
|
54
56
|
end
|
@@ -1,18 +1,19 @@
|
|
1
1
|
module Kuby
|
2
2
|
module Docker
|
3
|
-
class
|
3
|
+
class Layer
|
4
4
|
attr_reader :definition
|
5
5
|
|
6
6
|
def initialize(definition)
|
7
7
|
@definition = definition
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
definition.app
|
10
|
+
def apply_to(dockerfile)
|
11
|
+
raise NotImplementedError,
|
12
|
+
"#{__method__} must be defined in derived classes"
|
14
13
|
end
|
15
14
|
|
15
|
+
private
|
16
|
+
|
16
17
|
def metadata
|
17
18
|
definition.docker.metadata
|
18
19
|
end
|
@@ -15,12 +15,31 @@ module Kuby
|
|
15
15
|
@stack.each { |name| yield layers[name] }
|
16
16
|
end
|
17
17
|
|
18
|
-
def use(name, layer)
|
18
|
+
def use(name, layer = nil, &block)
|
19
19
|
stack << name
|
20
|
-
|
20
|
+
|
21
|
+
if layer
|
22
|
+
layers[name] = layer
|
23
|
+
elsif block_given?
|
24
|
+
layers[name] = InlineLayer.new(block)
|
25
|
+
else
|
26
|
+
raise "Must either pass a layer object or a block to `#{__method__}'"
|
27
|
+
end
|
21
28
|
end
|
22
29
|
|
23
|
-
def insert(name, layer, options = {})
|
30
|
+
def insert(name, layer = nil, options = {}, &block)
|
31
|
+
# this is truly gross but it's the only way I can think of to be able
|
32
|
+
# to call insert these two ways:
|
33
|
+
#
|
34
|
+
# insert :foo, FooLayer.new, before: :bundler_phase
|
35
|
+
# insert :foo, before: :bundler_phase do
|
36
|
+
# ...
|
37
|
+
# end
|
38
|
+
if layer.is_a?(Hash)
|
39
|
+
insert(name, nil, options.merge(layer), &block)
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
24
43
|
existing_name = options[:before] || options[:after]
|
25
44
|
idx = stack.index(existing_name)
|
26
45
|
|
@@ -30,7 +49,14 @@ module Kuby
|
|
30
49
|
|
31
50
|
idx += 1 if options[:after]
|
32
51
|
stack.insert(idx, name)
|
33
|
-
|
52
|
+
|
53
|
+
if layer
|
54
|
+
layers[name] = layer
|
55
|
+
elsif block_given?
|
56
|
+
layers[name] = InlineLayer.new(block)
|
57
|
+
else
|
58
|
+
raise "Must either pass a layer object or a block to `#{__method__}'"
|
59
|
+
end
|
34
60
|
end
|
35
61
|
|
36
62
|
def delete(name)
|
data/lib/kuby/docker/metadata.rb
CHANGED
@@ -8,7 +8,7 @@ module Kuby
|
|
8
8
|
LATEST_TAG = 'latest'
|
9
9
|
|
10
10
|
attr_accessor :image_url
|
11
|
-
attr_reader :definition
|
11
|
+
attr_reader :definition
|
12
12
|
|
13
13
|
def initialize(definition)
|
14
14
|
@definition = definition
|
@@ -40,6 +40,32 @@ module Kuby
|
|
40
40
|
@tags.empty? ? default_tags : @tags
|
41
41
|
end
|
42
42
|
|
43
|
+
def tag
|
44
|
+
t = ENV.fetch('KUBY_DOCKER_TAG') do
|
45
|
+
definition.docker.tags.latest_timestamp_tag
|
46
|
+
end
|
47
|
+
|
48
|
+
unless t
|
49
|
+
raise MissingTagError, 'could not find latest timestamped tag'
|
50
|
+
end
|
51
|
+
|
52
|
+
t.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
def previous_tag(current_tag)
|
56
|
+
t = definition.docker.tags.previous_timestamp_tag(current_tag)
|
57
|
+
|
58
|
+
unless t
|
59
|
+
raise MissingTagError, 'could not find previous timestamped tag'
|
60
|
+
end
|
61
|
+
|
62
|
+
t.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def distro
|
66
|
+
@distro || DEFAULT_DISTRO
|
67
|
+
end
|
68
|
+
|
43
69
|
def distro=(distro_name)
|
44
70
|
@distro = distro_name
|
45
71
|
end
|
data/lib/kuby/docker/packages.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module Kuby
|
2
2
|
module Docker
|
3
3
|
module Packages
|
4
|
-
autoload :ManagedPackage,
|
5
|
-
autoload :Nodejs,
|
6
|
-
autoload :Package,
|
7
|
-
autoload :
|
4
|
+
autoload :ManagedPackage, 'kuby/docker/packages/managed_package'
|
5
|
+
autoload :Nodejs, 'kuby/docker/packages/nodejs'
|
6
|
+
autoload :Package, 'kuby/docker/packages/package'
|
7
|
+
autoload :SimpleManagedPackage, 'kuby/docker/packages/simple_managed_package'
|
8
|
+
autoload :Yarn, 'kuby/docker/packages/yarn'
|
8
9
|
end
|
9
10
|
end
|
10
11
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
module Packages
|
4
|
+
class SimpleManagedPackage
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
@name = name
|
9
|
+
end
|
10
|
+
|
11
|
+
def package_name_for(distro)
|
12
|
+
name
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_version(*)
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def managed?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/kuby/docker/spec.rb
CHANGED
@@ -50,12 +50,12 @@ module Kuby
|
|
50
50
|
metadata.image_url = url
|
51
51
|
end
|
52
52
|
|
53
|
-
def use(*args)
|
54
|
-
layer_stack.use(*args)
|
53
|
+
def use(*args, &block)
|
54
|
+
layer_stack.use(*args, &block)
|
55
55
|
end
|
56
56
|
|
57
|
-
def insert(*args)
|
58
|
-
layer_stack.insert(*args)
|
57
|
+
def insert(*args, &block)
|
58
|
+
layer_stack.insert(*args, &block)
|
59
59
|
end
|
60
60
|
|
61
61
|
def delete(*args)
|
data/lib/kuby/docker/tags.rb
CHANGED
@@ -19,10 +19,28 @@ module Kuby
|
|
19
19
|
(local.latest_tags + remote.latest_tags).uniq
|
20
20
|
end
|
21
21
|
|
22
|
+
def previous_timestamp_tag(current_tag)
|
23
|
+
current_tag = ::Kuby::Docker::TimestampTag.try_parse(current_tag)
|
24
|
+
all_tags = timestamp_tags.sort
|
25
|
+
|
26
|
+
idx = all_tags.index do |tag|
|
27
|
+
tag.time == current_tag.time
|
28
|
+
end
|
29
|
+
|
30
|
+
idx ||= 0
|
31
|
+
return nil unless idx > 0
|
32
|
+
|
33
|
+
all_tags[idx - 1]
|
34
|
+
end
|
35
|
+
|
22
36
|
def timestamp_tags
|
23
37
|
(local.timestamp_tags + remote.timestamp_tags).uniq
|
24
38
|
end
|
25
39
|
|
40
|
+
def latest_timestamp_tag
|
41
|
+
@latest_timestamp_tag ||= timestamp_tags.sort.last
|
42
|
+
end
|
43
|
+
|
26
44
|
def all
|
27
45
|
self
|
28
46
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kuby
|
2
|
+
class Environment
|
3
|
+
attr_reader :name, :definition
|
4
|
+
|
5
|
+
def initialize(name, definition, &block)
|
6
|
+
@name = name
|
7
|
+
@definition = definition
|
8
|
+
end
|
9
|
+
|
10
|
+
def docker(&block)
|
11
|
+
@docker ||= Docker::Spec.new(definition)
|
12
|
+
@docker.instance_eval(&block) if block
|
13
|
+
@docker
|
14
|
+
end
|
15
|
+
|
16
|
+
def kubernetes(&block)
|
17
|
+
@kubernetes ||= Kubernetes::Spec.new(definition)
|
18
|
+
@kubernetes.instance_eval(&block) if block
|
19
|
+
@kubernetes
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/kuby/kubernetes.rb
CHANGED
@@ -4,6 +4,7 @@ module Kuby
|
|
4
4
|
module Kubernetes
|
5
5
|
autoload :MinikubeProvider, 'kuby/kubernetes/minikube_provider'
|
6
6
|
autoload :Deployer, 'kuby/kubernetes/deployer'
|
7
|
+
autoload :DeployTask, 'kuby/kubernetes/deploy_task'
|
7
8
|
autoload :DockerConfig, 'kuby/kubernetes/docker_config'
|
8
9
|
autoload :Manifest, 'kuby/kubernetes/manifest'
|
9
10
|
autoload :Monitors, 'kuby/kubernetes/monitors'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'krane'
|
2
|
+
require 'ext/krane/kubernetes_resource'
|
3
|
+
require 'kubectl-rb'
|
4
|
+
|
5
|
+
module Kuby
|
6
|
+
module Kubernetes
|
7
|
+
class DeployTask
|
8
|
+
attr_reader :deploy_task
|
9
|
+
|
10
|
+
def initialize(**kwargs)
|
11
|
+
@deploy_task ||= ::Krane::DeployTask.new(**kwargs)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run!(**kwargs)
|
15
|
+
new_path = "#{File.dirname(KubectlRb.executable)}:#{ENV['PATH']}"
|
16
|
+
|
17
|
+
with_env('PATH' => new_path) do
|
18
|
+
deploy_task.run!(**kwargs)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def with_env(new_env)
|
25
|
+
old_env = ENV.to_h
|
26
|
+
ENV.replace(old_env.merge(new_env))
|
27
|
+
yield
|
28
|
+
ensure
|
29
|
+
ENV.replace(old_env)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'krane'
|
3
2
|
require 'securerandom'
|
4
3
|
require 'yaml'
|
5
4
|
|
@@ -62,7 +61,7 @@ module Kuby
|
|
62
61
|
File.write(resource_path, resource.to_resource.to_yaml)
|
63
62
|
end
|
64
63
|
|
65
|
-
task = ::
|
64
|
+
task = ::Kuby::Kubernetes::DeployTask.new(
|
66
65
|
namespace: namespace.metadata.name,
|
67
66
|
context: cli.current_context,
|
68
67
|
filenames: [tmpdir]
|
@@ -26,11 +26,6 @@ module Kuby
|
|
26
26
|
rails_app.resources.delete(rails_app.ingress)
|
27
27
|
rails_app.service.spec { type 'LoadBalancer' }
|
28
28
|
end
|
29
|
-
|
30
|
-
configure do
|
31
|
-
# default kubeconfig path
|
32
|
-
kubeconfig File.join(ENV['HOME'], '.kube', 'config')
|
33
|
-
end
|
34
29
|
end
|
35
30
|
|
36
31
|
def kubeconfig_path
|
@@ -45,6 +40,11 @@ module Kuby
|
|
45
40
|
|
46
41
|
def after_initialize
|
47
42
|
@config = Config.new
|
43
|
+
|
44
|
+
configure do
|
45
|
+
# default kubeconfig path
|
46
|
+
kubeconfig File.join(ENV['HOME'], '.kube', 'config')
|
47
|
+
end
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -27,6 +27,11 @@ module Kuby
|
|
27
27
|
def setup
|
28
28
|
Kuby.logger.info('Deploying nginx ingress resources')
|
29
29
|
|
30
|
+
if already_deployed?
|
31
|
+
Kuby.logger.info('Nginx ingress already deployed, skipping')
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
30
35
|
SETUP_RESOURCES.each do |uri|
|
31
36
|
uri = uri % { provider: @config.provider || DEFAULT_PROVIDER }
|
32
37
|
kubernetes_cli.apply_uri(uri)
|
@@ -48,6 +53,13 @@ module Kuby
|
|
48
53
|
|
49
54
|
private
|
50
55
|
|
56
|
+
def already_deployed?
|
57
|
+
kubernetes_cli.get_object('Service', 'ingress-nginx', 'ingress-nginx')
|
58
|
+
true
|
59
|
+
rescue KubernetesCLI::GetResourceError
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
51
63
|
def after_initialize
|
52
64
|
@config = Config.new
|
53
65
|
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'yaml'
|
3
|
+
|
1
4
|
module Kuby
|
2
5
|
module Kubernetes
|
3
6
|
module Plugins
|
@@ -11,27 +14,29 @@ module Kuby
|
|
11
14
|
'postgresql' => Postgres
|
12
15
|
}.freeze
|
13
16
|
|
14
|
-
def self.get(
|
15
|
-
|
17
|
+
def self.get(rails_app)
|
18
|
+
if rails_app.manage_database?
|
19
|
+
new(rails_app).database
|
20
|
+
end
|
16
21
|
end
|
17
22
|
|
18
23
|
def self.get_adapter(adapter)
|
19
24
|
ADAPTER_MAP.fetch(adapter) do
|
20
|
-
raise UnsupportedDatabaseError, "Kuby does not support the '#{adapter}'"\
|
25
|
+
raise UnsupportedDatabaseError, "Kuby does not support the '#{adapter}' "\
|
21
26
|
'database adapter'
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
25
|
-
attr_reader :
|
30
|
+
attr_reader :rails_app
|
26
31
|
|
27
|
-
def initialize(
|
28
|
-
@
|
32
|
+
def initialize(rails_app)
|
33
|
+
@rails_app = rails_app
|
29
34
|
end
|
30
35
|
|
31
36
|
def database
|
32
37
|
@database ||= self.class
|
33
38
|
.get_adapter(adapter)
|
34
|
-
.new(
|
39
|
+
.new(rails_app, environment, db_configs)
|
35
40
|
end
|
36
41
|
|
37
42
|
private
|
@@ -45,11 +50,27 @@ module Kuby
|
|
45
50
|
end
|
46
51
|
|
47
52
|
def environment
|
48
|
-
@environment ||= definition.environment
|
53
|
+
@environment ||= rails_app.definition.environment.name
|
49
54
|
end
|
50
55
|
|
51
56
|
def db_configs
|
52
|
-
@db_configs ||=
|
57
|
+
@db_configs ||= YAML.load(ERB.new(File.read(db_config_path)).result)
|
58
|
+
end
|
59
|
+
|
60
|
+
def db_config_path
|
61
|
+
@db_config_path ||= begin
|
62
|
+
db_config_paths.first or
|
63
|
+
raise "Couldn't find database config at #{rails_app.root}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def db_config_paths
|
68
|
+
@db_config_paths ||=
|
69
|
+
Dir.glob(
|
70
|
+
File.join(
|
71
|
+
rails_app.root, 'config', 'database.{yml,erb,yml.erb,yaml,yaml.erb}'
|
72
|
+
)
|
73
|
+
)
|
53
74
|
end
|
54
75
|
end
|
55
76
|
end
|