kuby-core 0.1.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 +7 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +16 -0
- data/LICENSE +21 -0
- data/README.md +186 -0
- data/Rakefile +14 -0
- data/kuby-core.gemspec +27 -0
- data/lib/kuby.rb +112 -0
- data/lib/kuby/basic_logger.rb +22 -0
- data/lib/kuby/cli_base.rb +75 -0
- data/lib/kuby/definition.rb +29 -0
- data/lib/kuby/docker.rb +27 -0
- data/lib/kuby/docker/alpine.rb +62 -0
- data/lib/kuby/docker/assets_phase.rb +11 -0
- data/lib/kuby/docker/bundler_phase.rb +56 -0
- data/lib/kuby/docker/cli.rb +72 -0
- data/lib/kuby/docker/copy_phase.rb +23 -0
- data/lib/kuby/docker/credentials.rb +11 -0
- data/lib/kuby/docker/debian.rb +66 -0
- data/lib/kuby/docker/dockerfile.rb +128 -0
- data/lib/kuby/docker/errors.rb +22 -0
- data/lib/kuby/docker/layer_stack.rb +42 -0
- data/lib/kuby/docker/local_tags.rb +38 -0
- data/lib/kuby/docker/metadata.rb +69 -0
- data/lib/kuby/docker/package_list.rb +34 -0
- data/lib/kuby/docker/package_phase.rb +59 -0
- data/lib/kuby/docker/packages.rb +10 -0
- data/lib/kuby/docker/packages/managed_package.rb +29 -0
- data/lib/kuby/docker/packages/nodejs.rb +29 -0
- data/lib/kuby/docker/packages/package.rb +22 -0
- data/lib/kuby/docker/packages/yarn.rb +47 -0
- data/lib/kuby/docker/phase.rb +21 -0
- data/lib/kuby/docker/remote_tags.rb +24 -0
- data/lib/kuby/docker/setup_phase.rb +29 -0
- data/lib/kuby/docker/spec.rb +147 -0
- data/lib/kuby/docker/tags.rb +39 -0
- data/lib/kuby/docker/timestamp_tag.rb +36 -0
- data/lib/kuby/docker/webserver_phase.rb +51 -0
- data/lib/kuby/docker/yarn_phase.rb +11 -0
- data/lib/kuby/kubernetes.rb +16 -0
- data/lib/kuby/kubernetes/deployer.rb +94 -0
- data/lib/kuby/kubernetes/docker_config.rb +27 -0
- data/lib/kuby/kubernetes/errors.rb +22 -0
- data/lib/kuby/kubernetes/manifest.rb +56 -0
- data/lib/kuby/kubernetes/minikube_provider.rb +51 -0
- data/lib/kuby/kubernetes/plugin.rb +55 -0
- data/lib/kuby/kubernetes/plugins.rb +8 -0
- data/lib/kuby/kubernetes/plugins/nginx_ingress.rb +61 -0
- data/lib/kuby/kubernetes/plugins/rails_app.rb +16 -0
- data/lib/kuby/kubernetes/plugins/rails_app/database.rb +58 -0
- data/lib/kuby/kubernetes/plugins/rails_app/mysql.rb +142 -0
- data/lib/kuby/kubernetes/plugins/rails_app/plugin.rb +393 -0
- data/lib/kuby/kubernetes/plugins/rails_app/postgres.rb +10 -0
- data/lib/kuby/kubernetes/plugins/rails_app/rewrite_db_config.rb +13 -0
- data/lib/kuby/kubernetes/plugins/rails_app/sqlite.rb +10 -0
- data/lib/kuby/kubernetes/plugins/rails_app/tasks.rake +23 -0
- data/lib/kuby/kubernetes/provider.rb +77 -0
- data/lib/kuby/kubernetes/registry_secret.rb +26 -0
- data/lib/kuby/kubernetes/spec.rb +152 -0
- data/lib/kuby/middleware.rb +5 -0
- data/lib/kuby/middleware/health_check.rb +16 -0
- data/lib/kuby/railtie.rb +18 -0
- data/lib/kuby/tasks.rb +135 -0
- data/lib/kuby/tasks/kuby.rake +63 -0
- data/lib/kuby/trailing_hash.rb +19 -0
- data/lib/kuby/version.rb +3 -0
- metadata +233 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
class BuildError < StandardError; end
|
4
|
+
class PushError < StandardError; end
|
5
|
+
|
6
|
+
class MissingTagError < StandardError
|
7
|
+
attr_reader :tag
|
8
|
+
|
9
|
+
def initialize(tag)
|
10
|
+
@tag = tag
|
11
|
+
end
|
12
|
+
|
13
|
+
def message
|
14
|
+
@message ||= "Could not find tag '#{tag}'."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class UnsupportedDistroError < StandardError; end
|
19
|
+
class MissingPackageError < StandardError; end
|
20
|
+
class MissingDistroError < StandardError; end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
class LayerStack
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_reader :stack, :layers
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@stack = []
|
10
|
+
@layers = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
return to_enum(__method__) unless block_given?
|
15
|
+
@stack.each { |name| yield layers[name] }
|
16
|
+
end
|
17
|
+
|
18
|
+
def use(name, layer)
|
19
|
+
stack << name
|
20
|
+
layers[name] = layer
|
21
|
+
end
|
22
|
+
|
23
|
+
def insert(name, layer, options = {})
|
24
|
+
existing_name = options[:before] || options[:after]
|
25
|
+
idx = stack.index(existing_name)
|
26
|
+
|
27
|
+
unless idx
|
28
|
+
raise ArgumentError, "Could not find existing layer '#{existing_name}'"
|
29
|
+
end
|
30
|
+
|
31
|
+
idx += 1 if options[:after]
|
32
|
+
stack.insert(idx, name)
|
33
|
+
layers[name] = layer
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete(name)
|
37
|
+
stack.delete(name)
|
38
|
+
layers.delete(name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
class LocalTags
|
4
|
+
attr_reader :cli, :metadata
|
5
|
+
|
6
|
+
def initialize(cli, metadata)
|
7
|
+
@cli = cli
|
8
|
+
@metadata = metadata
|
9
|
+
end
|
10
|
+
|
11
|
+
def tags
|
12
|
+
images = cli.images(metadata.image_url)
|
13
|
+
images.map { |image| image[:tag] }
|
14
|
+
end
|
15
|
+
|
16
|
+
def latest_tags
|
17
|
+
# find "latest" tag
|
18
|
+
images = cli.images(metadata.image_url)
|
19
|
+
latest = images.find { |image| image[:tag] == Tags::LATEST }
|
20
|
+
|
21
|
+
unless latest
|
22
|
+
raise MissingTagError.new(Tags::LATEST)
|
23
|
+
end
|
24
|
+
|
25
|
+
# find all tags that point to the same image as 'latest'
|
26
|
+
images.each_with_object([]) do |image_data, tags|
|
27
|
+
if image_data[:id] == latest[:id]
|
28
|
+
tags << image_data[:tag]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def timestamp_tags
|
34
|
+
tags.map { |t| TimestampTag.try_parse(t) }.compact
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Kuby
|
4
|
+
module Docker
|
5
|
+
class Metadata
|
6
|
+
DEFAULT_DISTRO = :debian
|
7
|
+
DEFAULT_REGISTRY_HOST = 'https://docker.io'.freeze
|
8
|
+
LATEST_TAG = 'latest'
|
9
|
+
|
10
|
+
attr_accessor :image_url
|
11
|
+
attr_reader :definition, :distro
|
12
|
+
|
13
|
+
def initialize(definition)
|
14
|
+
@definition = definition
|
15
|
+
@tags = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def image_url
|
19
|
+
@image_url || default_image_url
|
20
|
+
end
|
21
|
+
|
22
|
+
def image_host
|
23
|
+
@image_host ||= if image_url.include?('/')
|
24
|
+
uri = parse_url(image_url)
|
25
|
+
"#{uri.scheme}://#{uri.host}"
|
26
|
+
else
|
27
|
+
DEFAULT_REGISTRY_HOST
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def image_repo
|
32
|
+
@image_repo ||= if image_url.include?('/')
|
33
|
+
parse_url(image_url).path.sub(/\A\//, '')
|
34
|
+
else
|
35
|
+
image_url
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def tags
|
40
|
+
@tags.empty? ? default_tags : @tags
|
41
|
+
end
|
42
|
+
|
43
|
+
def distro=(distro_name)
|
44
|
+
@distro = distro_name
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def default_image_url
|
50
|
+
# assuming dockerhub by not specifying full url
|
51
|
+
@default_image_url ||= definition.app_name.downcase
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_tags
|
55
|
+
@default_tags ||= [
|
56
|
+
TimestampTag.new(Time.now).to_s, LATEST_TAG
|
57
|
+
]
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_url(url)
|
61
|
+
uri = URI.parse(url)
|
62
|
+
return uri if uri.scheme
|
63
|
+
|
64
|
+
# force a scheme because URI.parse won't work properly without one
|
65
|
+
URI.parse("https://#{url}")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
class PackageList
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_reader :packages
|
7
|
+
|
8
|
+
def initialize(package_tuples)
|
9
|
+
@packages = []
|
10
|
+
package_tuples.each { |pt| add(*pt) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](name)
|
14
|
+
packages.find { |pkg| pkg.name == name }
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(name, version = nil)
|
18
|
+
packages << Package.new(name, version)
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete(name)
|
22
|
+
packages.delete_if { |pkg| pkg.name == name }
|
23
|
+
end
|
24
|
+
|
25
|
+
def each(&block)
|
26
|
+
packages.each(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def empty?
|
30
|
+
packages.empty?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
class PackagePhase < Phase
|
4
|
+
attr_reader :operations
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
super
|
8
|
+
|
9
|
+
@operations = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(package_name, version = nil)
|
13
|
+
operations << [:add, package_name, version]
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove(package_name)
|
17
|
+
operations << [:remove, package_name]
|
18
|
+
end
|
19
|
+
|
20
|
+
def apply_to(dockerfile)
|
21
|
+
packages = distro_spec.default_packages.dup
|
22
|
+
|
23
|
+
operations.each do |operator, package_name, version|
|
24
|
+
if operator == :add
|
25
|
+
packages << [package_name, version]
|
26
|
+
else
|
27
|
+
packages.reject! do |pkg_name_to_del, *|
|
28
|
+
pkg_name_to_del == package_name
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
packages.map! do |package_name, version|
|
34
|
+
get_package(package_name, version)
|
35
|
+
end
|
36
|
+
|
37
|
+
distro_spec.install(packages, into: dockerfile)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def distro_spec
|
43
|
+
definition.docker.distro_spec
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_package(package_name, version)
|
47
|
+
if package = Kuby.packages[package_name]
|
48
|
+
package.with_version(version)
|
49
|
+
else
|
50
|
+
raise MissingPackageError, "package '#{package_name}' hasn't been registered"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def metadata
|
55
|
+
definition.docker.metadata
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
module Packages
|
4
|
+
autoload :ManagedPackage, 'kuby/docker/packages/managed_package'
|
5
|
+
autoload :Nodejs, 'kuby/docker/packages/nodejs'
|
6
|
+
autoload :Package, 'kuby/docker/packages/package'
|
7
|
+
autoload :Yarn, 'kuby/docker/packages/yarn'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
module Packages
|
4
|
+
class ManagedPackage
|
5
|
+
attr_reader :name, :names_per_distro
|
6
|
+
|
7
|
+
def initialize(name, names_per_distro)
|
8
|
+
@name = name
|
9
|
+
@names_per_distro = names_per_distro
|
10
|
+
end
|
11
|
+
|
12
|
+
def package_name_for(distro)
|
13
|
+
names_per_distro.fetch(distro) do
|
14
|
+
raise UnsupportedDistroError, "Couldn't install #{name} "\
|
15
|
+
"because #{distro} is an unsupported distro"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_version(*)
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def managed?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
module Packages
|
4
|
+
class Nodejs < Package
|
5
|
+
def install_on_debian(dockerfile)
|
6
|
+
install_from_image("node:#{version}", dockerfile)
|
7
|
+
end
|
8
|
+
|
9
|
+
def install_on_alpine(dockerfile)
|
10
|
+
install_from_image("node:#{version}-alpine", dockerfile)
|
11
|
+
end
|
12
|
+
|
13
|
+
def version
|
14
|
+
@version || 'current'
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def install_from_image(image, dockerfile)
|
20
|
+
dockerfile.insert_at(0) do
|
21
|
+
dockerfile.from(image, as: 'nodejs')
|
22
|
+
end
|
23
|
+
|
24
|
+
dockerfile.copy('/usr/local/bin/node', '/usr/local/bin/node', from: 'nodejs')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
module Packages
|
4
|
+
class Package
|
5
|
+
attr_reader :name, :version
|
6
|
+
|
7
|
+
def initialize(name, version = nil)
|
8
|
+
@name = name
|
9
|
+
@version = version
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_version(ver)
|
13
|
+
self.class.new(name, ver)
|
14
|
+
end
|
15
|
+
|
16
|
+
def managed?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
module Packages
|
4
|
+
class Yarn < Package
|
5
|
+
def install_on_debian(dockerfile)
|
6
|
+
dockerfile.run(<<~CMD.strip)
|
7
|
+
wget #{url} && \\
|
8
|
+
yarnv=$(basename $(ls yarn-*.tar.gz | cut -d'-' -f 2) .tar.gz) && \\
|
9
|
+
tar zxvf yarn-$yarnv.tar.gz -C /opt && \\
|
10
|
+
mv /opt/yarn-$yarnv /opt/yarn && \\
|
11
|
+
apt-get install -qq -y --no-install-recommends gnupg && \\
|
12
|
+
wget -qO- https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --import && \\
|
13
|
+
wget https://github.com/yarnpkg/yarn/releases/download/$yarnv/yarn-$yarnv.tar.gz.asc && \\
|
14
|
+
gpg --verify yarn-$yarnv.tar.gz.asc
|
15
|
+
CMD
|
16
|
+
|
17
|
+
dockerfile.env("PATH=$PATH:/opt/yarn/bin")
|
18
|
+
end
|
19
|
+
|
20
|
+
def install_on_alpine(dockerfile)
|
21
|
+
dockerfile.run(<<~CMD.strip)
|
22
|
+
wget #{url} && \\
|
23
|
+
yarnv=$(basename $(ls yarn-*.tar.gz | cut -d'-' -f 2) .tar.gz) && \\
|
24
|
+
tar zxvf yarn-$yarnv.tar.gz -C /opt && \\
|
25
|
+
mv /opt/yarn-$yarnv /opt/yarn && \\
|
26
|
+
apk add --no-cache gnupg && \\
|
27
|
+
wget -qO- https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --import && \\
|
28
|
+
wget https://github.com/yarnpkg/yarn/releases/download/$yarnv/yarn-$yarnv.tar.gz.asc && \\
|
29
|
+
gpg --verify yarn-$yarnv.tar.gz.asc
|
30
|
+
CMD
|
31
|
+
|
32
|
+
dockerfile.env("PATH=$PATH:/opt/yarn/bin")
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def url
|
38
|
+
@url ||= if version
|
39
|
+
"https://github.com/yarnpkg/yarn/releases/download/v#{version}/yarn-v#{version}.tar.gz"
|
40
|
+
else
|
41
|
+
"https://yarnpkg.com/latest.tar.gz"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
class Phase
|
4
|
+
attr_reader :definition
|
5
|
+
|
6
|
+
def initialize(definition)
|
7
|
+
@definition = definition
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def app
|
13
|
+
definition.app
|
14
|
+
end
|
15
|
+
|
16
|
+
def metadata
|
17
|
+
definition.docker.metadata
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Kuby
|
2
|
+
module Docker
|
3
|
+
class RemoteTags
|
4
|
+
attr_reader :remote_client, :metadata
|
5
|
+
|
6
|
+
def initialize(remote_client, metadata)
|
7
|
+
@remote_client = remote_client
|
8
|
+
@metadata = metadata
|
9
|
+
end
|
10
|
+
|
11
|
+
def tags
|
12
|
+
remote_client.tags
|
13
|
+
end
|
14
|
+
|
15
|
+
def latest_tags
|
16
|
+
raise NotImplementedError, 'latest tags are not available for remote repos'
|
17
|
+
end
|
18
|
+
|
19
|
+
def timestamp_tags
|
20
|
+
tags.map { |t| TimestampTag.try_parse(t) }.compact
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|