kuby-core 0.11.16 → 0.12.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 +18 -0
- data/Gemfile +1 -2
- data/kuby-core.gemspec +1 -1
- data/lib/kuby.rb +2 -20
- data/lib/kuby/commands.rb +13 -67
- data/lib/kuby/docker.rb +27 -25
- data/lib/kuby/docker/alpine.rb +2 -1
- data/lib/kuby/docker/app_image.rb +19 -0
- data/lib/kuby/docker/cli.rb +4 -12
- data/lib/kuby/docker/docker_uri.rb +18 -7
- data/lib/kuby/docker/errors.rb +1 -19
- data/lib/kuby/docker/image.rb +115 -0
- data/lib/kuby/docker/layer.rb +0 -7
- data/lib/kuby/docker/local_tags.rb +9 -10
- data/lib/kuby/docker/package_phase.rb +0 -5
- data/lib/kuby/docker/packages.rb +1 -0
- data/lib/kuby/docker/remote_tags.rb +10 -5
- data/lib/kuby/docker/setup_phase.rb +17 -9
- data/lib/kuby/docker/spec.rb +29 -62
- data/lib/kuby/docker/timestamp_tag.rb +8 -1
- data/lib/kuby/docker/timestamped_image.rb +113 -0
- data/lib/kuby/environment.rb +1 -10
- data/lib/kuby/kubernetes/bare_metal_provider.rb +16 -4
- data/lib/kuby/kubernetes/deployer.rb +1 -1
- data/lib/kuby/kubernetes/docker_desktop_provider.rb +0 -15
- data/lib/kuby/kubernetes/spec.rb +21 -17
- data/lib/kuby/plugin.rb +2 -2
- data/lib/kuby/plugins/rails_app.rb +1 -0
- data/lib/kuby/plugins/rails_app/assets.rb +60 -70
- data/lib/kuby/plugins/rails_app/assets_image.rb +55 -0
- data/lib/kuby/plugins/rails_app/plugin.rb +53 -236
- data/lib/kuby/tasks.rb +30 -69
- data/lib/kuby/version.rb +1 -1
- data/spec/docker/spec_spec.rb +9 -118
- data/spec/docker/timestamped_image_spec.rb +123 -0
- data/spec/spec_helper.rb +10 -11
- metadata +9 -10
- data/lib/kuby/dev_setup.rb +0 -346
- data/lib/kuby/docker/dev_spec.rb +0 -202
- data/lib/kuby/docker/metadata.rb +0 -90
- data/lib/kuby/docker/tags.rb +0 -92
- data/lib/kuby/rails_commands.rb +0 -84
- data/spec/docker/metadata_spec.rb +0 -73
@@ -0,0 +1,115 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module Kuby
|
4
|
+
module Docker
|
5
|
+
class Image
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
sig { returns(String) }
|
9
|
+
attr_reader :image_url
|
10
|
+
|
11
|
+
sig { returns(Credentials) }
|
12
|
+
attr_reader :credentials
|
13
|
+
|
14
|
+
sig { returns(T.nilable(String)) }
|
15
|
+
attr_reader :main_tag
|
16
|
+
|
17
|
+
sig { returns T::Array[String] }
|
18
|
+
attr_reader :alias_tags
|
19
|
+
|
20
|
+
sig {
|
21
|
+
params(
|
22
|
+
dockerfile: T.any(Dockerfile, T.proc.returns(Dockerfile)),
|
23
|
+
image_url: String,
|
24
|
+
credentials: Credentials,
|
25
|
+
main_tag: T.nilable(String),
|
26
|
+
alias_tags: T::Array[String]
|
27
|
+
).void
|
28
|
+
}
|
29
|
+
def initialize(dockerfile, image_url, credentials, main_tag = nil, alias_tags = [])
|
30
|
+
@dockerfile = T.let(dockerfile, T.any(Dockerfile, T.proc.returns(Dockerfile)))
|
31
|
+
@image_url = T.let(image_url, String)
|
32
|
+
@credentials = T.let(credentials, Credentials)
|
33
|
+
@main_tag = T.let(main_tag, T.nilable(String))
|
34
|
+
@alias_tags = T.let(alias_tags, T::Array[String])
|
35
|
+
|
36
|
+
@image_host = T.let(@image_host, T.nilable(String))
|
37
|
+
@image_hostname = T.let(@image_hostname, T.nilable(String))
|
38
|
+
@image_repo = T.let(@image_repo, T.nilable(String))
|
39
|
+
@full_image_uri = T.let(@full_image_uri, T.nilable(DockerURI))
|
40
|
+
@docker_cli = T.let(@docker_cli, T.nilable(Docker::CLI))
|
41
|
+
end
|
42
|
+
|
43
|
+
sig { returns(Image) }
|
44
|
+
def new_version
|
45
|
+
raise NotImplementedError, 'please use a Docker::Image subclass'
|
46
|
+
end
|
47
|
+
|
48
|
+
sig { returns(Image) }
|
49
|
+
def current_version
|
50
|
+
raise NotImplementedError, 'please use a Docker::Image subclass'
|
51
|
+
end
|
52
|
+
|
53
|
+
sig { params(current_tag: T.nilable(String)).returns(Image) }
|
54
|
+
def previous_version(current_tag = nil)
|
55
|
+
raise NotImplementedError, 'please use a Docker::Image subclass'
|
56
|
+
end
|
57
|
+
|
58
|
+
sig { returns(Dockerfile) }
|
59
|
+
def dockerfile
|
60
|
+
if @dockerfile.respond_to?(:call)
|
61
|
+
T.cast(@dockerfile, T.proc.returns(Dockerfile)).call
|
62
|
+
else
|
63
|
+
T.cast(@dockerfile, Dockerfile)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
sig { returns(String) }
|
68
|
+
def image_host
|
69
|
+
@image_host ||= "#{image_uri.host}:#{image_uri.port}"
|
70
|
+
end
|
71
|
+
|
72
|
+
sig { returns(String) }
|
73
|
+
def image_hostname
|
74
|
+
@image_hostname ||= image_uri.host
|
75
|
+
end
|
76
|
+
|
77
|
+
sig { returns(String) }
|
78
|
+
def image_repo
|
79
|
+
@image_repo ||= image_uri.path
|
80
|
+
end
|
81
|
+
|
82
|
+
sig { returns(DockerURI) }
|
83
|
+
def image_uri
|
84
|
+
@full_image_uri ||= DockerURI.parse(image_url)
|
85
|
+
end
|
86
|
+
|
87
|
+
sig { returns(T::Array[String]) }
|
88
|
+
def tags
|
89
|
+
[main_tag, *alias_tags].compact
|
90
|
+
end
|
91
|
+
|
92
|
+
sig { params(build_args: T::Hash[String, String]).void }
|
93
|
+
def build(build_args = {})
|
94
|
+
raise NotImplementedError, 'please use a Docker::Image subclass'
|
95
|
+
end
|
96
|
+
|
97
|
+
sig { params(tag: String).void }
|
98
|
+
def push(tag)
|
99
|
+
raise NotImplementedError, 'please use a Docker::Image subclass'
|
100
|
+
end
|
101
|
+
|
102
|
+
sig { returns(Docker::CLI) }
|
103
|
+
def docker_cli
|
104
|
+
@docker_cli ||= Docker::CLI.new
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
sig { params(main_tag: String, alias_tags: T::Array[String]).returns(Image) }
|
110
|
+
def duplicate_with_tags(main_tag, alias_tags)
|
111
|
+
self.class.new(dockerfile, image_url, credentials, main_tag, alias_tags)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/kuby/docker/layer.rb
CHANGED
@@ -8,37 +8,36 @@ module Kuby
|
|
8
8
|
sig { returns CLI }
|
9
9
|
attr_reader :cli
|
10
10
|
|
11
|
-
sig { returns(
|
12
|
-
attr_reader :
|
11
|
+
sig { returns(String) }
|
12
|
+
attr_reader :image_url
|
13
13
|
|
14
14
|
sig {
|
15
15
|
params(
|
16
16
|
cli: CLI,
|
17
|
-
|
17
|
+
image_url: String
|
18
18
|
)
|
19
19
|
.void
|
20
20
|
}
|
21
|
-
def initialize(cli,
|
21
|
+
def initialize(cli, image_url)
|
22
22
|
@cli = cli
|
23
|
-
@
|
24
|
-
|
23
|
+
@image_url = image_url
|
25
24
|
@latest_timestamp_tag = T.let(@latest_timestamp_tag, T.nilable(TimestampTag))
|
26
25
|
end
|
27
26
|
|
28
27
|
sig { returns(T::Array[String]) }
|
29
28
|
def tags
|
30
|
-
images = cli.images(
|
29
|
+
images = cli.images(image_url)
|
31
30
|
images.map { |image| T.must(image[:tag]) }
|
32
31
|
end
|
33
32
|
|
34
33
|
sig { returns(T::Array[String]) }
|
35
34
|
def latest_tags
|
36
35
|
# find "latest" tag
|
37
|
-
images = cli.images(
|
38
|
-
latest = images.find { |image| image[:tag] ==
|
36
|
+
images = cli.images(image_url)
|
37
|
+
latest = images.find { |image| image[:tag] == Kuby::Docker::LATEST_TAG }
|
39
38
|
|
40
39
|
unless latest
|
41
|
-
raise MissingTagError
|
40
|
+
raise MissingTagError, "could not find tag #{Kuby::Docker::LATEST_TAG}"
|
42
41
|
end
|
43
42
|
|
44
43
|
# find all tags that point to the same image as 'latest'
|
data/lib/kuby/docker/packages.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# typed: strict
|
2
2
|
|
3
|
+
require 'docker/remote'
|
4
|
+
|
3
5
|
module Kuby
|
4
6
|
module Docker
|
5
7
|
class RemoteTags
|
@@ -8,24 +10,27 @@ module Kuby
|
|
8
10
|
sig { returns(::Docker::Remote::Client) }
|
9
11
|
attr_reader :remote_client
|
10
12
|
|
11
|
-
sig { returns(
|
12
|
-
attr_reader :
|
13
|
+
sig { returns(String) }
|
14
|
+
attr_reader :image_url
|
13
15
|
|
14
16
|
sig {
|
15
17
|
params(
|
16
18
|
remote_client: ::Docker::Remote::Client,
|
17
|
-
|
19
|
+
image_url: String
|
18
20
|
)
|
19
21
|
.void
|
20
22
|
}
|
21
|
-
def initialize(remote_client,
|
23
|
+
def initialize(remote_client, image_url)
|
22
24
|
@remote_client = remote_client
|
23
|
-
@
|
25
|
+
@image_url = image_url
|
24
26
|
end
|
25
27
|
|
26
28
|
sig { returns(T::Array[String]) }
|
27
29
|
def tags
|
28
30
|
remote_client.tags
|
31
|
+
rescue ::Docker::Remote::UnknownRepoError
|
32
|
+
# this can happen if we've never pushed to the repo before
|
33
|
+
[]
|
29
34
|
end
|
30
35
|
|
31
36
|
sig { returns(T::Array[String]) }
|
@@ -7,9 +7,6 @@ module Kuby
|
|
7
7
|
|
8
8
|
DEFAULT_WORKING_DIR = T.let('/usr/src/app'.freeze, String)
|
9
9
|
|
10
|
-
sig { returns(T.nilable(String)) }
|
11
|
-
attr_reader :base_image
|
12
|
-
|
13
10
|
sig { params(base_image: String).void }
|
14
11
|
attr_writer :base_image
|
15
12
|
|
@@ -25,35 +22,46 @@ module Kuby
|
|
25
22
|
sig { params(rails_env: String).void }
|
26
23
|
attr_writer :rails_env
|
27
24
|
|
28
|
-
sig {
|
29
|
-
|
30
|
-
|
25
|
+
sig { returns(T.nilable(Docker::Spec)) }
|
26
|
+
attr_reader :docker_spec
|
27
|
+
|
28
|
+
sig { params(environment: Environment, docker_spec: Docker::Spec).void }
|
29
|
+
def initialize(environment, docker_spec)
|
30
|
+
super(environment)
|
31
31
|
|
32
32
|
@base_image = T.let(@base_image, T.nilable(String))
|
33
33
|
@working_dir = T.let(@working_dir, T.nilable(String))
|
34
34
|
@rails_env = T.let(@rails_env, T.nilable(String))
|
35
|
+
@docker_spec = T.let(docker_spec, T.nilable(Docker::Spec))
|
35
36
|
end
|
36
37
|
|
37
38
|
sig { override.params(dockerfile: Dockerfile).void }
|
38
39
|
def apply_to(dockerfile)
|
39
|
-
dockerfile.from(base_image
|
40
|
+
dockerfile.from(base_image)
|
40
41
|
dockerfile.workdir(working_dir || DEFAULT_WORKING_DIR)
|
41
42
|
dockerfile.env("RAILS_ENV=#{rails_env || Kuby.env}")
|
42
43
|
dockerfile.env("KUBY_ENV=#{Kuby.env}")
|
43
44
|
dockerfile.arg('RAILS_MASTER_KEY')
|
44
45
|
end
|
45
46
|
|
47
|
+
sig { returns(String) }
|
48
|
+
def base_image
|
49
|
+
@base_image || default_base_image
|
50
|
+
end
|
51
|
+
|
46
52
|
private
|
47
53
|
|
48
54
|
sig { returns(String) }
|
49
55
|
def default_base_image
|
50
|
-
|
56
|
+
spec = T.must(docker_spec)
|
57
|
+
|
58
|
+
case spec.distro_name
|
51
59
|
when :debian
|
52
60
|
"ruby:#{RUBY_VERSION}"
|
53
61
|
when :alpine
|
54
62
|
"ruby:#{RUBY_VERSION}-alpine"
|
55
63
|
else
|
56
|
-
raise MissingDistroError, "distro '#{
|
64
|
+
raise MissingDistroError, "distro '#{spec.distro_name}' hasn't been registered"
|
57
65
|
end
|
58
66
|
end
|
59
67
|
end
|
data/lib/kuby/docker/spec.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
# typed: strict
|
2
2
|
|
3
|
-
require 'docker/remote'
|
4
|
-
|
5
3
|
module Kuby
|
6
4
|
module Docker
|
7
5
|
class Spec
|
8
6
|
extend T::Sig
|
9
7
|
|
8
|
+
DEFAULT_DISTRO = :debian
|
9
|
+
|
10
10
|
sig { returns(Environment) }
|
11
11
|
attr_reader :environment
|
12
12
|
|
13
|
+
sig { returns(T.nilable(String)) }
|
14
|
+
attr_reader :image_url_str
|
15
|
+
|
13
16
|
sig { params(environment: Environment).void }
|
14
17
|
def initialize(environment)
|
15
18
|
@environment = environment
|
@@ -22,13 +25,18 @@ module Kuby
|
|
22
25
|
@copy_phase = T.let(@copy_phase, T.nilable(CopyPhase))
|
23
26
|
@assets_phase = T.let(@assets_phase, T.nilable(AssetsPhase))
|
24
27
|
@webserver_phase = T.let(@webserver_phase, T.nilable(WebserverPhase))
|
25
|
-
@metadata = T.let(@metadata, T.nilable(Metadata))
|
26
28
|
|
29
|
+
@distro_name = T.let(@distro_name, T.nilable(Symbol))
|
27
30
|
@distro_spec = T.let(@distro_spec, T.nilable(Distro))
|
28
|
-
@cli = T.let(@cli, T.nilable(CLI))
|
29
|
-
@remote_client = T.let(@remote_client, T.nilable(::Docker::Remote::Client))
|
30
|
-
@tags = T.let(@tags, T.nilable(Tags))
|
31
31
|
@layer_stack = T.let(@layer_stack, T.nilable(Kuby::Docker::LayerStack))
|
32
|
+
|
33
|
+
@image_url_str = T.let(@image_url_str, T.nilable(String))
|
34
|
+
@image = T.let(@image, T.nilable(Docker::AppImage))
|
35
|
+
end
|
36
|
+
|
37
|
+
sig { returns(Symbol) }
|
38
|
+
def distro_name
|
39
|
+
@distro_name || DEFAULT_DISTRO
|
32
40
|
end
|
33
41
|
|
34
42
|
sig { params(image_url: String).void }
|
@@ -69,7 +77,7 @@ module Kuby
|
|
69
77
|
|
70
78
|
sig { params(distro_name: Symbol).void }
|
71
79
|
def distro(distro_name)
|
72
|
-
|
80
|
+
@distro_name = distro_name
|
73
81
|
@distro_spec = nil
|
74
82
|
end
|
75
83
|
|
@@ -85,7 +93,7 @@ module Kuby
|
|
85
93
|
|
86
94
|
sig { params(url: String).void }
|
87
95
|
def image_url(url)
|
88
|
-
|
96
|
+
@image_url_str = url
|
89
97
|
end
|
90
98
|
|
91
99
|
sig {
|
@@ -132,16 +140,22 @@ module Kuby
|
|
132
140
|
@credentials
|
133
141
|
end
|
134
142
|
|
135
|
-
sig { returns(
|
136
|
-
def
|
137
|
-
|
138
|
-
|
143
|
+
sig { returns(Docker::AppImage) }
|
144
|
+
def image
|
145
|
+
@image ||= begin
|
146
|
+
dockerfile = Dockerfile.new.tap do |df|
|
147
|
+
layer_stack.each { |layer| layer.apply_to(df) }
|
148
|
+
end
|
149
|
+
|
150
|
+
Docker::AppImage.new(
|
151
|
+
dockerfile, T.must(image_url_str), credentials
|
152
|
+
)
|
139
153
|
end
|
140
154
|
end
|
141
155
|
|
142
156
|
sig { returns(SetupPhase) }
|
143
157
|
def setup_phase
|
144
|
-
@setup_phase ||= SetupPhase.new(environment)
|
158
|
+
@setup_phase ||= SetupPhase.new(environment, self)
|
145
159
|
end
|
146
160
|
|
147
161
|
sig { returns(PackagePhase) }
|
@@ -174,62 +188,15 @@ module Kuby
|
|
174
188
|
@webserver_phase ||= WebserverPhase.new(environment)
|
175
189
|
end
|
176
190
|
|
177
|
-
sig { returns(Metadata) }
|
178
|
-
def metadata
|
179
|
-
@metadata ||= Metadata.new(environment)
|
180
|
-
end
|
181
|
-
|
182
|
-
sig { returns(String) }
|
183
|
-
def tag
|
184
|
-
t = ENV.fetch('KUBY_DOCKER_TAG') do
|
185
|
-
tags.latest_timestamp_tag
|
186
|
-
end
|
187
|
-
|
188
|
-
unless t
|
189
|
-
raise MissingTagError, 'could not find latest timestamped tag'
|
190
|
-
end
|
191
|
-
|
192
|
-
t.to_s
|
193
|
-
end
|
194
|
-
|
195
|
-
sig { params(current_tag: String).returns(String) }
|
196
|
-
def previous_tag(current_tag)
|
197
|
-
t = tags.previous_timestamp_tag(current_tag)
|
198
|
-
|
199
|
-
unless t
|
200
|
-
raise MissingTagError, 'could not find previous timestamped tag'
|
201
|
-
end
|
202
|
-
|
203
|
-
t.to_s
|
204
|
-
end
|
205
|
-
|
206
|
-
sig { returns(CLI) }
|
207
|
-
def cli
|
208
|
-
@cli ||= Docker::CLI.new
|
209
|
-
end
|
210
|
-
|
211
|
-
sig { returns(::Docker::Remote::Client) }
|
212
|
-
def remote_client
|
213
|
-
@remote_client ||= ::Docker::Remote::Client.new(
|
214
|
-
metadata.image_host, metadata.image_repo,
|
215
|
-
credentials.username, credentials.password,
|
216
|
-
)
|
217
|
-
end
|
218
|
-
|
219
191
|
sig { returns(Distro) }
|
220
192
|
def distro_spec
|
221
|
-
@distro_spec ||= if distro_klass = Kuby.distros[
|
193
|
+
@distro_spec ||= if distro_klass = Kuby.distros[distro_name]
|
222
194
|
distro_klass.new(self)
|
223
195
|
else
|
224
|
-
raise MissingDistroError, "distro '#{
|
196
|
+
raise MissingDistroError, "distro '#{distro_name}' hasn't been registered"
|
225
197
|
end
|
226
198
|
end
|
227
199
|
|
228
|
-
sig { returns(Tags) }
|
229
|
-
def tags
|
230
|
-
@tags ||= Tags.new(cli, remote_client, metadata)
|
231
|
-
end
|
232
|
-
|
233
200
|
private
|
234
201
|
|
235
202
|
sig { returns(Kuby::Docker::LayerStack) }
|