kuby-core 0.3.0 → 0.7.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/README.md +3 -160
- data/kuby-core.gemspec +2 -1
- 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/cli.rb +32 -0
- data/lib/kuby/docker/copy_phase.rb +1 -1
- data/lib/kuby/docker/errors.rb +1 -0
- 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 +9 -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/timestamp_tag.rb +1 -1
- 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 -3
- 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 +14 -4
- data/lib/kuby/kubernetes/plugins/rails_app/plugin.rb +15 -14
- 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 +1 -1
- data/lib/kuby/railtie.rb +0 -4
- data/lib/kuby/tasks.rb +35 -0
- data/lib/kuby/tasks/kuby.rake +24 -17
- data/lib/kuby/version.rb +1 -1
- metadata +10 -5
@@ -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
|
@@ -56,6 +56,20 @@ module Kuby
|
|
56
56
|
end
|
57
57
|
end
|
58
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
|
+
|
59
73
|
def secret(&block)
|
60
74
|
context = self
|
61
75
|
|
@@ -118,10 +132,6 @@ module Kuby
|
|
118
132
|
definition.kubernetes
|
119
133
|
end
|
120
134
|
|
121
|
-
def app
|
122
|
-
definition.app
|
123
|
-
end
|
124
|
-
|
125
135
|
private
|
126
136
|
|
127
137
|
def config
|
@@ -13,12 +13,17 @@ module Kuby
|
|
13
13
|
ENV_SECRETS = [MASTER_KEY_VAR].freeze
|
14
14
|
ENV_EXCLUDE = ['RAILS_ENV'].freeze
|
15
15
|
|
16
|
-
|
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
|
21
25
|
@replicas = 1
|
26
|
+
@manage_database = true
|
22
27
|
end
|
23
28
|
|
24
29
|
def configure(&block)
|
@@ -26,11 +31,7 @@ module Kuby
|
|
26
31
|
end
|
27
32
|
|
28
33
|
def after_configuration
|
29
|
-
|
30
|
-
# is here as a placeholder to indicate we'd like to be able to
|
31
|
-
# handle Rails apps that don't use a database, i.e. don't have
|
32
|
-
# activerecord configured
|
33
|
-
if @database = Database.get(definition)
|
34
|
+
if @database = Database.get(self)
|
34
35
|
definition.kubernetes.plugins[database] = @database
|
35
36
|
definition.kubernetes.add_plugin(:kube_db)
|
36
37
|
|
@@ -43,7 +44,11 @@ module Kuby
|
|
43
44
|
definition.kubernetes.add_plugin(:nginx_ingress)
|
44
45
|
|
45
46
|
if @tls_enabled
|
46
|
-
|
47
|
+
context = self
|
48
|
+
|
49
|
+
definition.kubernetes.add_plugin(:cert_manager) do
|
50
|
+
email context.definition.docker.credentials.email
|
51
|
+
end
|
47
52
|
end
|
48
53
|
end
|
49
54
|
|
@@ -178,9 +183,9 @@ module Kuby
|
|
178
183
|
if master_key = ENV[MASTER_KEY_VAR]
|
179
184
|
add MASTER_KEY_VAR.to_sym, master_key
|
180
185
|
else
|
181
|
-
master_key_path = spec.
|
186
|
+
master_key_path = File.join(spec.root, 'config', 'master.key')
|
182
187
|
|
183
|
-
if
|
188
|
+
if File.exist?(master_key_path)
|
184
189
|
add MASTER_KEY_VAR.to_sym, File.read(master_key_path).strip
|
185
190
|
end
|
186
191
|
end
|
@@ -344,7 +349,7 @@ module Kuby
|
|
344
349
|
app_secrets,
|
345
350
|
deployment,
|
346
351
|
ingress,
|
347
|
-
*database
|
352
|
+
*database&.resources
|
348
353
|
]
|
349
354
|
end
|
350
355
|
|
@@ -364,10 +369,6 @@ module Kuby
|
|
364
369
|
definition.kubernetes
|
365
370
|
end
|
366
371
|
|
367
|
-
def app
|
368
|
-
definition.app
|
369
|
-
end
|
370
|
-
|
371
372
|
def namespace
|
372
373
|
definition.kubernetes.namespace
|
373
374
|
end
|
@@ -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
|
+
)
|
@@ -3,11 +3,16 @@ require 'rake'
|
|
3
3
|
namespace :kuby do
|
4
4
|
namespace :rails_app do
|
5
5
|
namespace :db do
|
6
|
-
task rewrite_config
|
7
|
-
|
6
|
+
task :rewrite_config do
|
7
|
+
Kuby.load!
|
8
|
+
|
9
|
+
config_file = File.join(Kuby.definition.kubernetes.plugin(:rails_app).root, 'config', 'database.yml')
|
8
10
|
database = Kuby.definition.kubernetes.plugin(:rails_app).database
|
9
|
-
|
10
|
-
|
11
|
+
|
12
|
+
if database.respond_to?(:rewritten_configs)
|
13
|
+
File.write(config_file, YAML.dump(database.rewritten_configs))
|
14
|
+
Kuby.logger.info("Wrote #{config_file}")
|
15
|
+
end
|
11
16
|
end
|
12
17
|
|
13
18
|
task :create_unless_exists do
|
data/lib/kuby/kubernetes/spec.rb
CHANGED
data/lib/kuby/railtie.rb
CHANGED
@@ -7,10 +7,6 @@ module Kuby
|
|
7
7
|
load File.expand_path(File.join('tasks', 'kuby.rake'), __dir__)
|
8
8
|
end
|
9
9
|
|
10
|
-
initializer 'kuby.startup' do |_app|
|
11
|
-
Kuby.logger = Kuby::BasicLogger.new(STDERR)
|
12
|
-
end
|
13
|
-
|
14
10
|
initializer 'kuby.health_check_middleware' do |app|
|
15
11
|
app.middleware.use Kuby::Middleware::HealthCheck
|
16
12
|
end
|
data/lib/kuby/tasks.rb
CHANGED
@@ -16,6 +16,10 @@ module Kuby
|
|
16
16
|
puts formatter.format(tokens)
|
17
17
|
end
|
18
18
|
|
19
|
+
def setup
|
20
|
+
definition.kubernetes.setup
|
21
|
+
end
|
22
|
+
|
19
23
|
def build
|
20
24
|
docker.cli.build(
|
21
25
|
dockerfile: docker.to_dockerfile,
|
@@ -35,6 +39,24 @@ module Kuby
|
|
35
39
|
end
|
36
40
|
|
37
41
|
def push
|
42
|
+
hostname = docker.metadata.image_hostname
|
43
|
+
|
44
|
+
unless docker.cli.auths.include?(hostname)
|
45
|
+
Kuby.logger.info("Attempting to log in to registry at #{hostname}")
|
46
|
+
|
47
|
+
begin
|
48
|
+
docker.cli.login(
|
49
|
+
url: docker.metadata.image_host,
|
50
|
+
username: docker.credentials.username,
|
51
|
+
password: docker.credentials.password
|
52
|
+
)
|
53
|
+
rescue Kuby::Docker::LoginError => e
|
54
|
+
Kuby.logger.fatal("Couldn't log in to the registry at #{hostname}")
|
55
|
+
Kuby.logger.fatal(e.message)
|
56
|
+
return
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
38
60
|
image_url = docker.metadata.image_url
|
39
61
|
|
40
62
|
begin
|
@@ -46,9 +68,18 @@ module Kuby
|
|
46
68
|
'Docker image before running this task.'
|
47
69
|
|
48
70
|
Kuby.logger.fatal(msg)
|
71
|
+
Kuby.logger.fatal(e.message)
|
49
72
|
end
|
50
73
|
end
|
51
74
|
|
75
|
+
def deploy
|
76
|
+
definition.kubernetes.deploy
|
77
|
+
end
|
78
|
+
|
79
|
+
def rollback
|
80
|
+
definition.kubernetes.rollback
|
81
|
+
end
|
82
|
+
|
52
83
|
def print_resources
|
53
84
|
kubernetes.before_deploy
|
54
85
|
|
@@ -63,6 +94,10 @@ module Kuby
|
|
63
94
|
puts File.read(path)
|
64
95
|
end
|
65
96
|
|
97
|
+
def kubectl(*cmd)
|
98
|
+
kubernetes_cli.run_cmd(cmd)
|
99
|
+
end
|
100
|
+
|
66
101
|
def remote_logs
|
67
102
|
kubernetes_cli.logtail(namespace, match_labels.serialize)
|
68
103
|
end
|